/*++
 *
 *  WOW v1.0
 *
 *  Copyright (c) 1991, Microsoft Corporation
 *
 *  WMMSTRU2.C
 *  WOW32 16-bit MultiMedia structure conversion support
 *               Contains support for mciSendCommand UnThunk message Parms.
 *
 *  History:
 *  Created  17-Jul-1992 by Stephen Estrop (stephene)
 *
--*/

//
// We define NO_STRICT so that the compiler doesn't moan and groan when
// I use the FARPROC type for the Multi-Media api loading.
//
#define NO_STRICT

#include "precomp.h"
#pragma hdrstop

#if 0

MODNAME(wmmstru2.c);

//
// The following are required for the dynamic linking of Multi-Media code
// from within WOW.  They are all defined in wmmedia.c
//

extern FARPROC      mmAPIEatCmdEntry;
extern FARPROC      mmAPIGetParamSize;
extern FARPROC      mmAPIUnlockCmdTable;
extern FARPROC      mmAPISendCmdW;

/**********************************************************************\
*
* UnThunkMciCommand16
*
* This function "unthunks" a 32 bit mci send command request.
*
* The ideas behind this function were stolen from UnThunkWMMsg16,
* see wmsg16.c
*
\**********************************************************************/
INT UnThunkMciCommand16( MCIDEVICEID devID, UINT OrigCommand, DWORD OrigFlags,
                         DWORD OrigParms, DWORD NewParms, LPWSTR lpCommand,
                         UINT uTable )
{
    BOOL        fReturnValNotThunked = FALSE;

#if DBG
    static      LPSTR   f_name = "UnThunkMciCommand16: ";
    register    int     i;
                int     n;

    dprintf3(( "UnThunkMciCommand :" ));
    n = sizeof(mciMessageNames) / sizeof(MCI_MESSAGE_NAMES);
    for ( i = 0; i < n; i++ ) {
        if ( mciMessageNames[i].uMsg == OrigCommand ) {
            break;
        }
    }
    dprintf3(( "OrigCommand -> %lX", (DWORD)OrigCommand ));
    dprintf3(( "       Name -> %s", i != n ? mciMessageNames[i].lpstMsgName : "Unkown Name" ));

    dprintf5(( "  OrigFlags -> %lX", OrigFlags ));
    dprintf5(( "  OrigParms -> %lX", OrigParms ));
    dprintf5(( "   NewParms -> %lX", NewParms ));

    //
    // If NewParms is 0 we shouldn't be here, I haven't got an assert
    // macro, but the following we do the same thing.
    //
    if ( NewParms == 0 ) {
        dprintf(( "%scalled with NewParms == NULL !!", f_name ));
        dprintf(( "Call StephenE NOW !!" ));
        DebugBreak();
    }
#endif

    //
    // We have to do a manual unthunk of MCI_SYSINFO because the
    // command table is not consistent.  As a command table should be
    // available now we can load it and then use it to unthunk MCI_OPEN.
    //
    switch ( OrigCommand ) {

    case MCI_OPEN:
        UnThunkOpenCmd( OrigFlags, OrigParms, NewParms );
        break;

    case MCI_SYSINFO:
        UnThunkSysInfoCmd( OrigFlags, OrigParms, NewParms );
        break;

    case MCI_STATUS:
        UnThunkStatusCmd( devID, OrigFlags, OrigParms, NewParms );
        break;

    default:
        fReturnValNotThunked = TRUE;
        break;
    }

    //
    // Do we have a command table ?  It is possible that we have
    // a custom command but we did not find a custom command table, in which
    // case we should just free the pNewParms storage.
    //
    if ( lpCommand != NULL ) {

        //
        // We now parse the custom command table to see if there is a
        // return field in the parms structure.
        //
        dprintf3(( "%sUnthunking via command table", f_name ));
        UnThunkCommandViaTable( lpCommand, OrigFlags, OrigParms,
                                NewParms, fReturnValNotThunked );

        //
        // Now we have finished with the command table we should unlock it.
        //
        dprintf4(( "%sUnlocking custom command table", f_name ));
        (*mmAPIUnlockCmdTable)( uTable );
    }

    //
    // All that needs to be done now is to free the storage
    // that was allocated during the ThunkXxxCmd function.
    //
    dprintf4(( "%sFreeing storage.", f_name ));
    free_w( (PBYTE)NewParms );
    return 0;
}


/**********************************************************************\
* UnThunkOpenCmd
*
* UnThunk the Open mci command parms.
\**********************************************************************/
VOID UnThunkOpenCmd( DWORD OrigFlags, DWORD OrigParms, DWORD NewParms )
{

#if DBG
    static  LPSTR   f_name = "UnThunkOpenCmd: ";
#endif

    LPMCI_OPEN_PARMS     lpOpeParms = (LPMCI_OPEN_PARMS)NewParms;
    PMCI_OPEN_PARMS16    lpOpeParms16;
    WORD                 wDevice;

    dprintf4(( "%sCopying Device ID.", f_name ));

    GETVDMPTR( OrigParms, sizeof(MCI_OPEN_PARMS16), lpOpeParms16 );
    wDevice = LOWORD( lpOpeParms->wDeviceID );
    STOREWORD( lpOpeParms16->wDeviceID, wDevice );
    FLUSHVDMPTR( OrigParms, sizeof(MCI_OPEN_PARMS16), lpOpeParms16 );
    FREEVDMPTR( lpOpeParms16 );

    dprintf5(( "wDeviceID -> %u", wDevice ));

    if ( (OrigParms & MCI_OPEN_TYPE) && !(OrigParms & MCI_OPEN_TYPE_ID ) ) {

        dprintf3(( "%sFreeing a STRING pointer", f_name ));
        FREEPSZPTR( lpOpeParms->lpstrDeviceType );
    }

    if ( (OrigParms & MCI_OPEN_ELEMENT)
     && !(OrigParms & MCI_OPEN_ELEMENT_ID ) ) {

        dprintf3(( "%sFreeing a STRING pointer", f_name ));
        FREEPSZPTR( lpOpeParms->lpstrElementName );
    }
}


/**********************************************************************\
* UnThunkSysInfoCmd
*
* UnThunk the SysInfo mci command parms.
\**********************************************************************/
VOID UnThunkSysInfoCmd( DWORD OrigFlags, DWORD OrigParms, DWORD NewParms )
{

#if DBG
    static  LPSTR   f_name = "UnThunkSysInfoCmd: ";
#endif

    LPMCI_SYSINFO_PARMS     lpSysParms = (LPMCI_SYSINFO_PARMS)NewParms;

    //
    // Had better check that we did actually allocate
    // a pointer.
    //
    if ( lpSysParms->lpstrReturn && lpSysParms->dwRetSize ) {

#if DBG
        if ( !(OrigFlags & MCI_SYSINFO_QUANTITY) ) {
            dprintf5(( "lpstrReturn -> %s", lpSysParms->lpstrReturn ));
        }
        else {
            dprintf5(( "lpstrReturn -> %d", *(LPDWORD)lpSysParms->lpstrReturn ));
        }
#endif

        //
        // Free lpSysParms->lpstrReturn;
        //
        dprintf4(( "%sFreeing lpstrReturn", f_name ));
        FREEVDMPTR( lpSysParms->lpstrReturn );
    }
}


/**********************************************************************\
* UnThunkMciStatus
*
* UnThunk the Status mci command parms.
\**********************************************************************/
VOID UnThunkStatusCmd( MCIDEVICEID devID, DWORD OrigFlags,
                       DWORD OrigParms, DWORD NewParms )
{
#if DBG
    static  LPSTR   f_name = "UnThunkStatusCmd: ";
#endif

    MCI_GETDEVCAPS_PARMS        GetDevCaps;
    DWORD                       dwRetVal;
    DWORD                       dwParm16;
    PDWORD                      pdwOrig16;
    PDWORD                      pdwParm32;
    int                         iReturnType = MCI_INTEGER;

    /*
    ** If the MCI_STATUS_ITEM flag is not specified don't bother
    ** doing any unthunking.
    */
    if ( !(OrigFlags & MCI_STATUS_ITEM) ) {
        return;
    }

    /*
    ** We need to determine what type of device we are
    ** dealing with.  We can do this by send an MCI_GETDEVCAPS
    ** command to the device. (We might as well use the Unicode
    ** version of mciSendCommand and avoid another thunk).
    */
    RtlZeroMemory( &GetDevCaps, sizeof(MCI_GETDEVCAPS_PARMS) );
    GetDevCaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;
    dwRetVal = (*mmAPISendCmdW)( devID, MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM,
                                 (DWORD)&GetDevCaps );
    /*
    ** If we can't get the DevCaps then we are doomed.
    */
    if ( dwRetVal ) {
        dprintf(("%sFailure to get devcaps", f_name));
        return;
    }

    /*
    ** Determine the dwReturn type.
    */
    switch ( GetDevCaps.dwReturn ) {

    case MCI_DEVTYPE_ANIMATION:
        switch ( ((LPDWORD)NewParms)[2] ) {

        case MCI_ANIM_STATUS_HWND:
            iReturnType = MCI_HWND;
            break;

        case MCI_ANIM_STATUS_HPAL:
            iReturnType = MCI_HPAL;
            break;
        }
        break;

    case MCI_DEVTYPE_OVERLAY:
        if ( ((LPDWORD)NewParms)[2] == MCI_OVLY_STATUS_HWND ) {
            iReturnType = MCI_HWND;
        }
        break;

    case MCI_DEVTYPE_DIGITAL_VIDEO:
        switch ( ((LPDWORD)NewParms)[2] ) {

        case MCI_DGV_STATUS_HWND:
            iReturnType = MCI_HWND;
            break;

        case MCI_DGV_STATUS_HPAL:
            iReturnType = MCI_HPAL;
            break;
        }
        break;
    }


    /*
    ** Thunk the dwReturn value according to the required type
    */
    GETVDMPTR( OrigParms, sizeof( MCI_STATUS_PARMS), pdwOrig16 );
    pdwParm32 = (LPDWORD)((LPBYTE)NewParms + 4);

    switch ( iReturnType ) {
    case MCI_HPAL:
        dprintf4(( "%sFound an HPAL return field", f_name ));
        dwParm16 = MAKELONG( GETHPALETTE16( (HPALETTE)*pdwParm32 ), 0 );
        STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), dwParm16 );
        dprintf5(( "HDC32 -> 0x%lX", *pdwParm32 ));
        dprintf5(( "HDC16 -> 0x%lX", dwParm16 ));
        break;

    case MCI_HWND:
        dprintf4(( "%sFound an HWND return field", f_name ));
        dwParm16 = MAKELONG( GETHWND16( (HWND)*pdwParm32 ), 0 );
        STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), dwParm16 );
        dprintf5(( "HWND32 -> 0x%lX", *pdwParm32 ));
        dprintf5(( "HWND16 -> 0x%lX", dwParm16 ));
        break;

    case MCI_INTEGER:
        dprintf4(( "%sFound an INTEGER return field", f_name ));
        STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), *pdwParm32 );
        dprintf5(( "INTEGER -> %ld", *pdwParm32 ));
        break;

    // no default: all possible cases accounted for
    }

    /*
    ** Free the VDM pointer as we have finished with it
    */
    FLUSHVDMPTR( OrigParms, sizeof( MCI_STATUS_PARMS), pdwOrig16 );
    FREEVDMPTR( pdwOrig16 );

}
/**********************************************************************\
*  UnThunkCommandViaTable
*
* Thunks the return field if there is one and then frees and pointers
* that were got via GETVDMPTR or GETPSZPTR.
\**********************************************************************/
INT UnThunkCommandViaTable( LPWSTR lpCommand, DWORD dwFlags, DWORD OrigParms,
                            DWORD pNewParms, BOOL fReturnValNotThunked )
{

#if DBG
    static  LPSTR   f_name = "UnThunkCommandViaTable: ";
#endif

    LPWSTR  lpFirstParameter;

    UINT    wID;
    DWORD   dwValue;

    UINT    wOffset32, wOffset1stParm32;

    DWORD   dwParm16;
    DWORD   Size;
    PDWORD  pdwOrig16;
    PDWORD  pdwParm32;

    DWORD   dwMask = 1;

    //
    // Calculate the size of this command parameter block in terms
    // of bytes, then get a VDM pointer to the OrigParms.
    //
    Size = GetSizeOfParameter( lpCommand );

    //
    // Skip past command entry
    //
    lpCommand = (LPWSTR)((LPBYTE)lpCommand +
                    (*mmAPIEatCmdEntry)( lpCommand, NULL, NULL ));
    //
    // Get the next entry
    //
    lpFirstParameter = lpCommand;

    //
    // Skip past the DWORD return value
    //
    wOffset1stParm32 = 4;

    lpCommand = (LPWSTR)((LPBYTE)lpCommand +
                    (*mmAPIEatCmdEntry)( lpCommand, &dwValue, &wID ));
    //
    // If it is a return value, skip it
    //
    if ( (wID == MCI_RETURN) && (fReturnValNotThunked) ) {

        GETVDMPTR( OrigParms, Size, pdwOrig16 );
        pdwParm32 = (LPDWORD)((LPBYTE)pNewParms + 4);

        //
        // Look for a string return type, these are a special case.
        //
        switch ( dwValue ) {

        case MCI_STRING:
            dprintf4(( "%sFound a STRING return field", f_name ));
            //
            // Get string pointer and length
            //
            Size = *(LPDWORD)((LPBYTE)pNewParms + 8);

            //
            // Get the 32 bit string pointer
            //
            if ( Size > 0 ) {

                dprintf4(( "%sFreeing a return STRING pointer", f_name ));
                dprintf5(( "STRING -> %s", (LPSTR)*pdwParm32 ));
                FREEVDMPTR( (LPSTR)*pdwParm32 );
            }
            break;

        case MCI_RECT:
            {
                PRECT   pRect32 = (PRECT)((LPBYTE)pNewParms + 4);
                PRECT16 pRect16 = (PRECT16)((LPBYTE)pdwOrig16 + 4);

                dprintf4(( "%sFound a RECT return field", f_name ));
                STORESHORT( pRect16->top,    (SHORT)pRect32->top );
                STORESHORT( pRect16->bottom, (SHORT)pRect32->bottom );
                STORESHORT( pRect16->left,   (SHORT)pRect32->left );
                STORESHORT( pRect16->right,  (SHORT)pRect32->right );
            }
            break;

        case MCI_INTEGER:
            //
            // Get the 32 bit return integer and store it in the
            // 16 bit parameter structure.
            //
            dprintf4(( "%sFound an INTEGER return field", f_name ));
            STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), *pdwParm32 );
            dprintf5(( "INTEGER -> %ld", *pdwParm32 ));
            break;

        case MCI_HWND:
            dprintf4(( "%sFound an HWND return field", f_name ));
            dwParm16 = MAKELONG( GETHWND16( (HWND)*pdwParm32 ), 0 );
            STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), dwParm16 );
            dprintf5(( "HWND32 -> 0x%lX", *pdwParm32 ));
            dprintf5(( "HWND16 -> 0x%lX", dwParm16 ));
            break;

        case MCI_HPAL:
            dprintf4(( "%sFound an HPAL return field", f_name ));
            dwParm16 = MAKELONG( GETHPALETTE16( (HPALETTE)*pdwParm32 ), 0 );
            STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), dwParm16 );
            dprintf5(( "HDC32 -> 0x%lX", *pdwParm32 ));
            dprintf5(( "HDC16 -> 0x%lX", dwParm16 ));
            break;

        case MCI_HDC:
            dprintf4(( "%sFound an HDC return field", f_name ));
            dwParm16 = MAKELONG( GETHDC16( (HDC)*pdwParm32 ), 0 );
            STOREDWORD( *(LPDWORD)((LPBYTE)pdwOrig16 + 4), dwParm16 );
            dprintf5(( "HDC32 -> 0x%lX", *pdwParm32 ));
            dprintf5(( "HDC16 -> 0x%lX", dwParm16 ));
            break;
        }

        //
        // Free the VDM pointer as we have finished with it
        //
        FLUSHVDMPTR( OrigParms, Size, pdwOrig16 );
        FREEVDMPTR( pdwOrig16 );

        //
        // Adjust the offset of the first parameter.
        //
        wOffset1stParm32 = (*mmAPIGetParamSize)( dwValue, wID );

        //
        // Save the new first parameter
        //
        lpFirstParameter = lpCommand;
    }

    //
    // Walk through each flag looking for strings to free
    //
    while ( dwMask != 0 ) {

        //
        // Is this bit set?
        //
        if ( (dwFlags & dwMask) != 0 ) {

            wOffset32 = wOffset1stParm32;
            lpCommand = (LPWSTR)((LPBYTE)lpFirstParameter +
                            (*mmAPIEatCmdEntry)( lpFirstParameter,
                                                &dwValue, &wID ));

            //
            // What parameter uses this bit?
            //
            while ( wID != MCI_END_COMMAND && dwValue != dwMask ) {

                wOffset32 = (*mmAPIGetParamSize)( dwValue, wID );

                if ( wID == MCI_CONSTANT ) {

                    while ( wID != MCI_END_CONSTANT ) {

                        lpCommand = (LPWSTR)((LPBYTE)lpCommand +
                                (*mmAPIEatCmdEntry)( lpCommand, NULL, &wID ));
                    }
                }
                lpCommand = (LPWSTR)((LPBYTE)lpCommand +
                             (*mmAPIEatCmdEntry)( lpCommand, &dwValue, &wID ));
            }

            if ( wID == MCI_STRING ) {
                dprintf4(( "%sFreeing a STRING pointer", f_name ));
                pdwParm32 = (LPDWORD)((LPBYTE)pNewParms + wOffset32);
                FREEPSZPTR( (LPSTR)*pdwParm32 );
            }
        }

        //
        // Go to the next flag
        //
        dwMask <<= 1;
    }

    return 0;
}
#endif