/******************************Module*Header*******************************\ * Module Name: mmwow32.c * * This file thunks for the Multi-Media functions. * * Created: 1-Jul-1993 * Author: Stephen Estrop [StephenE] * * Copyright (c) 1993 - 1995 Microsoft Corporation. All rights reserved. \**************************************************************************/ #define NO_GDI #ifndef WIN32 #define WIN32 #endif #include "winmmi.h" #define _INC_ALL_WOWSTUFF #include "mmwow32.h" #include "mmwowcb.h" // #define TELL_THE_TRUTH #define MIN_TIME_PERIOD_WE_RETURN 1 #if DBG /* ** ---------------------------------------------------------------- ** Debugging, Profiling and Tracing variables. ** ---------------------------------------------------------------- */ int TraceAux = 0; int TraceJoy = 0; int TraceTime = 0; int TraceMix = 0; int TraceWaveOut = 0; int TraceWaveIn = 0; int TraceMidiOut = 0; int TraceMidiIn = 0; int DebugLevel = 0; int AllocWaveCount; int AllocMidiCount; #endif PCALLBACK_DATA pCallBackData; // A 32 bit ptr to the 16 bit callback data CRITICAL_SECTION mmCriticalSection; TIMECAPS g_TimeCaps32; LPCALL_ICA_HW_INTERRUPT GenerateInterrupt; LPGETVDMPOINTER GetVDMPointer; LPWOWHANDLE32 lpWOWHandle32; LPWOWHANDLE16 lpWOWHandle16; DWORD NotifyCallbackData( UINT uDevID, UINT uMsg, DWORD dwInstance, DWORD dwParam1, VPCALLBACK_DATA parg16 ); BOOL APIENTRY WOW32ResolveMultiMediaHandle( UINT uHandleType, UINT uMappingDirection, WORD wHandle16_In, LPWORD lpwHandle16_Out, DWORD dwHandle32_In, LPDWORD lpdwHandle32_Out ); /* ** Constants for use with WOW32ResolveMultiMediaHandle */ #define WOW32_DIR_16IN_32OUT 0x0001 #define WOW32_DIR_32IN_16OUT 0x0002 #define WOW32_WAVEIN_HANDLE 0x0003 #define WOW32_WAVEOUT_HANDLE 0x0004 #define WOW32_MIDIOUT_HANDLE 0x0005 #define WOW32_MIDIIN_HANDLE 0x0006 /* ** Constans for auxOutMessage, waveInMessage, waveOutMessage, midiInMessage ** and midiOutMessage. */ #define DRV_BUFFER_LOW (DRV_USER - 0x1000) // 0x3000 #define DRV_BUFFER_USER (DRV_USER - 0x0800) // 0x3800 #define DRV_BUFFER_HIGH (DRV_USER - 0x0001) // 0x3FFF /******************************Public*Routine******************************\ * NotifyCallbackData * * This function is called by the 16 bit mmsystem.dll to notify us of the * address of the callback data structure. The callback data structure * has been paged locked so that it can be accessed at interrupt time, this * also means that we can safely keep a 32 bit pointer to the data. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD NotifyCallbackData( UINT uDevID, UINT uMsg, DWORD dwInstance, DWORD dwParam1, VPCALLBACK_DATA parg16 ) { HMODULE hModNTVDM; if ( parg16 ) { InitializeCriticalSection( &mmCriticalSection ); hModNTVDM = GetModuleHandleW( (LPCWSTR)L"NTVDM.EXE" ); if ( hModNTVDM ) { *(FARPROC *)&GenerateInterrupt = GetProcAddress( hModNTVDM, "call_ica_hw_interrupt" ); } timeGetDevCaps( &g_TimeCaps32, sizeof(g_TimeCaps32) ); #if !defined(i386) /* ** Although the Risc PC's support a uPeriodMin of 1ms, WOW does not ** seem capable of delivering interrupts at that rate on non ** intel platforms. */ g_TimeCaps32.wPeriodMin = 10; #endif } else { DeleteCriticalSection( &mmCriticalSection ); } dprintf1(( "Notified of callback address %X", parg16 )); pCallBackData = GETVDMPTR( parg16 ); return 0L; } /******************************Public*Routine******************************\ * wod32Message * * Thunks WODM_Xxxx messages * * The dwInstance field is used to save the 32 bit version of the decives * handle. So for example a WODM_PAUSE message can be thunked thus. * case WODM_PAUSE: * return waveOutPause( (HWAVEOUT)dwInstance ); * * * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD WINAPI wod32Message( UINT uDeviceID, UINT uMessage, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) { #if DBG static MSG_NAME name_map[] = { WODM_GETNUMDEVS, "WODM_GETNUMDEVS", WODM_GETDEVCAPS, "WODM_GETDEVCAPS", WODM_OPEN, "WODM_OPEN", WODM_CLOSE, "WODM_CLOSE", WODM_PREPARE, "WODM_PREPARE", WODM_UNPREPARE, "WODM_UNPREPARE", WODM_WRITE, "WODM_WRITE", WODM_PAUSE, "WODM_PAUSE", WODM_RESTART, "WODM_RESTART", WODM_RESET, "WODM_RESET", WODM_GETPOS, "WODM_GETPOS", WODM_GETPITCH, "WODM_GETPITCH", WODM_SETPITCH, "WODM_SETPITCH", WODM_GETVOLUME, "WODM_GETVOLUME", WODM_SETVOLUME, "WODM_SETVOLUME", WODM_GETPLAYBACKRATE, "WODM_GETPLAYBACKRATE", WODM_SETPLAYBACKRATE, "WODM_SETPLAYBACKRATE", WODM_BREAKLOOP, "WODM_BREAKLOOP", WODM_BUSY, "WODM_BUSY", WODM_MAPPER_STATUS, "WODM_MAPPER_STATUS" }; int i; int n; #endif static DWORD dwNumWaveOutDevs; DWORD dwRet = MMSYSERR_NOTSUPPORTED; DWORD dwTmp; DWORD UNALIGNED *lpdwTmp; WAVEOUTCAPSA woCaps; MMTIME mmTime32; #if DBG for( i = 0, n = sizeof(name_map) / sizeof(name_map[0]); i < n; i++ ) { if ( name_map[i].uMsg == uMessage ) { break; } } if ( i != n ) { trace_waveout(( "wod32Message( 0x%X, %s, 0x%X, 0x%X, 0x%X)", uDeviceID, name_map[i].lpstrName, dwInstance, dwParam1, dwParam2 )); } else { trace_waveout(( "wod32Message( 0x%X, 0x%X, 0x%X, 0x%X, 0x%X)", uDeviceID, uMessage, dwInstance, dwParam1, dwParam2 )); } #endif /* ** Make sure that we are consistent with the WAVE_MAPPER */ if ( LOWORD(uDeviceID) == 0xFFFF ) { uDeviceID = (UINT)-1; } switch ( uMessage ) { case WODM_GETNUMDEVS: dwRet = waveOutGetNumDevs(); break; case WODM_OPEN: dwRet = ThunkCommonWaveOpen( WAVE_OUT_DEVICE, uDeviceID, dwParam1, dwParam2, dwInstance ); break; case WODM_CLOSE: dwRet = waveOutClose( (HWAVEOUT)dwInstance ); break; case WODM_BREAKLOOP: case WODM_PAUSE: case WODM_RESET: case WODM_RESTART: dwRet = waveOutMessage( (HWAVEOUT)dwInstance, uMessage, 0L, 0L ); break; case WODM_GETDEVCAPS: dwRet = waveOutGetDevCapsA( uDeviceID, &woCaps, sizeof(woCaps)); if ( dwRet == MMSYSERR_NOERROR ) { CopyWaveOutCaps( (LPWAVEOUTCAPS16)GETVDMPTR( dwParam1 ), &woCaps, dwParam2 ); } break; case WODM_GETVOLUME: /* ** An application might try to get the volume using either ** the device ID (waveOutGetVolume) or a handle to the device ** waveOutMessage( WODM_GETVOLUME...), if the later is the case ** we must also call waveOutMessage as the device ID will not ** necessarily be valid. Same applies for waveOutSetVolume below. */ if ( dwInstance == 0 ) { dwRet = waveOutGetVolume( (HWAVEOUT)uDeviceID, &dwTmp ); } else { dwRet = waveOutMessage( (HWAVEOUT)dwInstance, uMessage, (DWORD)&dwTmp, 0L ); } lpdwTmp = GETVDMPTR( dwParam1 ); *lpdwTmp = dwTmp; break; case WODM_GETPITCH: case WODM_GETPLAYBACKRATE: dwRet = waveOutMessage( (HWAVEOUT)dwInstance, uMessage, (DWORD)&dwTmp, 0L ); lpdwTmp = GETVDMPTR( dwParam1 ); *lpdwTmp = dwTmp; break; case WODM_GETPOS: GetMMTime( (LPMMTIME16)GETVDMPTR( dwParam1 ), &mmTime32 ); dwRet = waveOutGetPosition( (HWAVEOUT)dwInstance, &mmTime32, sizeof(mmTime32) ); if ( dwRet == MMSYSERR_NOERROR ) { PutMMTime( (LPMMTIME16)GETVDMPTR( dwParam1 ), &mmTime32 ); } break; case WODM_UNPREPARE: dwRet = ThunkCommonWaveUnprepareHeader( (HWAVE)dwInstance, dwParam1, WAVE_OUT_DEVICE ); break; case WODM_PREPARE: dwRet = ThunkCommonWavePrepareHeader( (HWAVE)dwInstance, dwParam1, WAVE_OUT_DEVICE ); break; case WODM_SETVOLUME: /* ** An application might try to set the volume using either ** the device ID (waveOutSetVolume) or a handle to the device ** waveOutMessage( WODM_SETVOLUME...), if the later is the case ** we must also call waveOutMessage as the device ID will not ** necessarily be valid. Same applies for waveOutGetVolume above. */ if ( dwInstance == 0 ) { dwRet = waveOutSetVolume( (HWAVEOUT)uDeviceID, dwParam1 ); } else { dwRet = waveOutMessage( (HWAVEOUT)dwInstance, uMessage, dwParam1, dwParam2 ); } break; case WODM_SETPITCH: case WODM_SETPLAYBACKRATE: dwRet = waveOutMessage( (HWAVEOUT)dwInstance, uMessage, dwParam1, 0L ); break; case WODM_WRITE: dwRet = ThunkCommonWaveReadWrite( WAVE_OUT_DEVICE, dwParam1, dwParam2, dwInstance ); break; case WODM_MAPPER_STATUS: { WAVEFORMATEX waveFmtEx; switch ( dwParam1 ) { case WAVEOUT_MAPPER_STATUS_DEVICE: case WAVEOUT_MAPPER_STATUS_MAPPED: dwRet = waveOutMessage( (HWAVEOUT)dwInstance, uMessage, dwParam1, (DWORD)&dwTmp ); lpdwTmp = GETVDMPTR( dwParam2 ); *lpdwTmp = dwTmp; break; case WAVEOUT_MAPPER_STATUS_FORMAT: dwRet = waveOutMessage( (HWAVEOUT)dwInstance, uMessage, dwParam1, (DWORD)&waveFmtEx ); CopyMemory( (LPVOID)GETVDMPTR( dwParam2 ), (LPVOID)&waveFmtEx, sizeof(WAVEFORMATEX) ); break; default: dwRet = MMSYSERR_NOTSUPPORTED; } } break; default: if ( uMessage >= DRV_BUFFER_LOW && uMessage <= DRV_BUFFER_HIGH ) { lpdwTmp = GETVDMPTR( dwParam1 ); } else { lpdwTmp = (LPDWORD)dwParam1; } dwRet = waveOutMessage( (HWAVEOUT)dwInstance, uMessage, (DWORD)lpdwTmp, dwParam2 ); break; } trace_waveout(( "-> 0x%X", dwRet )); return dwRet; } /******************************Public*Routine******************************\ * wid32Message * * Thunks WIDM_Xxxx messages * * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD WINAPI wid32Message( UINT uDeviceID, UINT uMessage, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) { #if DBG static MSG_NAME name_map[] = { WIDM_GETNUMDEVS, "WIDM_GETNUMDEVS", WIDM_GETDEVCAPS, "WIDM_GETDEVCAPS", WIDM_OPEN, "WIDM_OPEN", WIDM_CLOSE, "WIDM_CLOSE", WIDM_PREPARE, "WIDM_PREPARE", WIDM_UNPREPARE, "WIDM_UNPREPARE", WIDM_ADDBUFFER, "WIDM_ADDBUFFER", WIDM_START, "WIDM_START", WIDM_STOP, "WIDM_STOP", WIDM_RESET, "WIDM_RESET", WIDM_GETPOS, "WIDM_GETPOS", WIDM_MAPPER_STATUS, "WIDM_MAPPER_STATUS" }; int i; int n; #endif static DWORD dwNumWaveInDevs; DWORD dwRet = MMSYSERR_NOTSUPPORTED; WAVEINCAPSA wiCaps; MMTIME mmTime32; DWORD dwTmp; DWORD UNALIGNED *lpdwTmp; #if DBG for( i = 0, n = sizeof(name_map) / sizeof(name_map[0]); i < n; i++ ) { if ( name_map[i].uMsg == uMessage ) { break; } } if ( i != n ) { trace_wavein(( "wid32Message( 0x%X, %s, 0x%X, 0x%X, 0x%X)", uDeviceID, name_map[i].lpstrName, dwInstance, dwParam1, dwParam2 )); } else { trace_wavein(( "wid32Message( 0x%X, 0x%X, 0x%X, 0x%X, 0x%X)", uDeviceID, uMessage, dwInstance, dwParam1, dwParam2 )); } #endif /* ** Make sure that we are consistent with the WAVE_MAPPER */ if ( LOWORD(uDeviceID) == 0xFFFF ) { uDeviceID = (UINT)-1; } switch ( uMessage ) { case WIDM_GETNUMDEVS: dwRet = waveInGetNumDevs(); break; case WIDM_GETDEVCAPS: dwRet = waveInGetDevCapsA( uDeviceID, &wiCaps, sizeof(wiCaps)); if ( dwRet == MMSYSERR_NOERROR ) { CopyWaveInCaps( (LPWAVEINCAPS16)GETVDMPTR( dwParam1 ), &wiCaps, dwParam2 ); } break; case WIDM_OPEN: dwRet = ThunkCommonWaveOpen( WAVE_IN_DEVICE, uDeviceID, dwParam1, dwParam2, dwInstance ); break; case WIDM_UNPREPARE: dwRet = ThunkCommonWaveUnprepareHeader( (HWAVE)dwInstance, dwParam1, WAVE_IN_DEVICE ); break; case WIDM_PREPARE: dwRet = ThunkCommonWavePrepareHeader( (HWAVE)dwInstance, dwParam1, WAVE_IN_DEVICE ); break; case WIDM_ADDBUFFER: dwRet = ThunkCommonWaveReadWrite( WAVE_IN_DEVICE, dwParam1, dwParam2, dwInstance ); break; case WIDM_CLOSE: dwRet = waveInClose( (HWAVEIN)dwInstance ); break; case WIDM_START: case WIDM_STOP: case WIDM_RESET: dwRet = waveInMessage( (HWAVEIN)dwInstance, uMessage, 0L, 0L ); break; case WIDM_GETPOS: GetMMTime( (LPMMTIME16)GETVDMPTR( dwParam1 ), &mmTime32 ); dwRet = waveInGetPosition( (HWAVEIN)dwInstance, &mmTime32, sizeof(mmTime32) ); if ( dwRet == MMSYSERR_NOERROR ) { PutMMTime( (LPMMTIME16)GETVDMPTR( dwParam1 ), &mmTime32 ); } break; case WIDM_MAPPER_STATUS: { WAVEFORMATEX waveFmtEx; switch ( dwParam1 ) { case WAVEIN_MAPPER_STATUS_DEVICE: case WAVEIN_MAPPER_STATUS_MAPPED: dwRet = waveInMessage( (HWAVEIN)dwInstance, uMessage, dwParam1, (DWORD)&dwTmp ); lpdwTmp = GETVDMPTR( dwParam2 ); *lpdwTmp = dwTmp; break; case WAVEIN_MAPPER_STATUS_FORMAT: dwRet = waveInMessage( (HWAVEIN)dwInstance, uMessage, dwParam1, (DWORD)&waveFmtEx ); CopyMemory( (LPVOID)GETVDMPTR( dwParam2 ), (LPVOID)&waveFmtEx, sizeof(WAVEFORMATEX) ); break; default: dwRet = MMSYSERR_NOTSUPPORTED; } } break; default: if ( uMessage >= DRV_BUFFER_LOW && uMessage <= DRV_BUFFER_HIGH ) { lpdwTmp = GETVDMPTR( dwParam1 ); } else { lpdwTmp = (LPDWORD)dwParam1; } dwRet = waveInMessage( (HWAVEIN)dwInstance, uMessage, (DWORD)lpdwTmp, dwParam2 ); } trace_wavein(( "-> 0x%X", dwRet )); return dwRet; } /*****************************Private*Routine******************************\ * ThunkCommonWaveOpen * * Thunks all wave device opens * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD ThunkCommonWaveOpen( int iWhich, UINT uDeviceID, DWORD dwParam1, DWORD dwParam2, DWORD dwInstance ) { /* ** dwParam1 is a 16:16 pointer to a WAVEOPENDESC16 structure. ** dwParam2 specifies any option flags used when opening the device. */ LPWAVEOPENDESC16 lpOpenDesc16; WAVEFORMATEX UNALIGNED *lpFormat16; DWORD dwRet; WAVEFORMAT wf[4]; WAVEFORMATEX *lpFormat32; lpOpenDesc16 = GETVDMPTR( dwParam1 ); lpFormat16 = GETVDMPTR( lpOpenDesc16->lpFormat ); /* ** Thunk the wave format structure. If the wave format tag is PCM ** we just copy the structure as is. If the wave format size ** is less than or equal to sizeof(wf) again just copy the ** structure as is, otherwise we allocate a new structure and then ** copy 16 bit wave format into it. */ switch ( lpFormat16->wFormatTag ) { case WAVE_FORMAT_PCM: CopyMemory( (LPVOID)&wf[0], (LPVOID)lpFormat16, sizeof(PCMWAVEFORMAT) ); lpFormat32 = (WAVEFORMATEX *)&wf[0]; break; default: if ( sizeof(WAVEFORMATEX) + lpFormat16->cbSize > sizeof(wf) ) { lpFormat32 = winmmAlloc( sizeof(WAVEFORMATEX) + lpFormat16->cbSize ); if (lpFormat32 == NULL) { return MMSYSERR_NOMEM; } } else { lpFormat32 = (WAVEFORMATEX *)&wf[0]; } CopyMemory( (LPVOID)lpFormat32, (LPVOID)lpFormat16, sizeof(WAVEFORMATEX) + lpFormat16->cbSize ); break; } /* ** If the app is only querying the device we don't have to do very ** much, just pass the mapped format to waveOutOpen. */ if ( dwParam2 & WAVE_FORMAT_QUERY ) { if ( iWhich == WAVE_OUT_DEVICE ) { dwRet = waveOutOpen( NULL, uDeviceID, lpFormat32, lpOpenDesc16->dwCallback, lpOpenDesc16->dwInstance, dwParam2 ); } else { dwRet = waveInOpen( NULL, uDeviceID, lpFormat32, lpOpenDesc16->dwCallback, lpOpenDesc16->dwInstance, dwParam2 ); } } else { HWAVE Hand32; PINSTANCEDATA pInstanceData; /* ** Create InstanceData block to be used by our callback routine. ** ** NOTE: Although we malloc it here we don't free it. ** This is not a mistake - it must not be freed before the ** callback routine has used it - so it does the freeing. ** ** If the malloc fails we bomb down to the bottom, ** set dwRet to MMSYSERR_NOMEM and exit gracefully. ** ** We always have a callback functions. This is to ensure that ** the WAVEHDR structure keeps getting copied back from ** 32 bit space to 16 bit, as it contains flags which ** applications are liable to keep checking. */ pInstanceData = winmmAlloc(sizeof(INSTANCEDATA) ); if ( pInstanceData != NULL ) { DWORD dwNewFlags = CALLBACK_FUNCTION; dprintf2(( "WaveCommonOpen: Allocated instance buffer at 0x%8X", pInstanceData )); dprintf2(( "16 bit callback = 0x%X", lpOpenDesc16->dwCallback )); pInstanceData->Hand16 = lpOpenDesc16->hWave; pInstanceData->dwCallback = lpOpenDesc16->dwCallback; pInstanceData->dwCallbackInstance = lpOpenDesc16->dwInstance; pInstanceData->dwFlags = dwParam2; dwNewFlags |= (dwParam2 & WAVE_ALLOWSYNC); if ( iWhich == WAVE_OUT_DEVICE ) { dwRet = waveOutOpen( (LPHWAVEOUT)&Hand32, uDeviceID, lpFormat32, (DWORD)W32CommonDeviceCB, (DWORD)pInstanceData, dwNewFlags ); } else { dwRet = waveInOpen( (LPHWAVEIN)&Hand32, uDeviceID, lpFormat32, (DWORD)W32CommonDeviceCB, (DWORD)pInstanceData, dwNewFlags ); } /* ** If the call returns success save a copy of the 32 bit handle ** otherwise free the memory we malloc'd earlier, as the ** callback that would have freed it will never get callled. */ if ( dwRet == MMSYSERR_NOERROR ) { DWORD UNALIGNED *lpDw; lpDw = GETVDMPTR( dwInstance ); *lpDw = (DWORD)Hand32; SetWOWHandle( Hand32, lpOpenDesc16->hWave ); trace_waveout(( "Handle -> %x", Hand32 )); } else { dprintf2(( "WaveCommonOpen: Freeing instance buffer at %8X " "because open failed", pInstanceData )); winmmFree( pInstanceData ); } } else { dwRet = MMSYSERR_NOMEM; } } /* ** Free the wave format structure if one was allocated. */ if (lpFormat32 != (WAVEFORMATEX *)&wf[0] ) { winmmFree( lpFormat32 ); } return dwRet; } /*****************************Private*Routine******************************\ * ThunkCommonWaveReadWrite * * Thunks all wave reads and writes. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD ThunkCommonWaveReadWrite( int iWhich, DWORD dwParam1, DWORD dwParam2, DWORD dwInstance ) { UINT ul; PWAVEHDR32 p32WaveHdr; WAVEHDR16 UNALIGNED *lp16; /* ** Get a pointer to the shadow WAVEHDR buffer. */ lp16 = GETVDMPTR( dwParam1 ); p32WaveHdr = (PWAVEHDR32)lp16->reserved; /* ** Make sure that the wave headers are consistent. */ p32WaveHdr->Wavehdr.lpData = GETVDMPTR( (PWAVEHDR32)lp16->lpData ); p32WaveHdr->pWavehdr32 = lp16; CopyMemory( (LPVOID)&p32WaveHdr->Wavehdr.dwBufferLength, (LPVOID)&lp16->dwBufferLength, (sizeof(WAVEHDR) - sizeof(LPSTR) - sizeof(DWORD)) ); /* ** Call either waveInAddBuffer or waveOutWrite as determined by ** iWhich. */ if ( iWhich == WAVE_OUT_DEVICE ) { ul = waveOutWrite( (HWAVEOUT)dwInstance, &p32WaveHdr->Wavehdr, sizeof(WAVEHDR) ); } else { ul = waveInAddBuffer( (HWAVEIN)dwInstance, &p32WaveHdr->Wavehdr, sizeof(WAVEHDR) ); } /* ** If the call worked reflect any change in the wave header back into ** the header that the application gave use. */ if ( ul == MMSYSERR_NOERROR ) { PutWaveHdr16( lp16, &p32WaveHdr->Wavehdr ); } return ul; } /*****************************Private*Routine******************************\ * ThunkCommonWavePrepareHeader * * This function sets up the following structure... * * * +-------------+ +-------------+ * 0:32 | pWavehdr32 |------>| Original | * +-------------+ | header | * 16:16 | pWavehdr16 |------>| passed by | * +-------------+<--+ | the 16 bit | * | New 32 bit | | | | * | header thats| | | | * | used instead| | | | * | of the one | | +-------------+ * | passed to by| +---| reserved | * | application.| +-------------+ * | | * +-------------+ * * ... and then calls waveXxxPrepareHeader as determioned by iWhich. * * Used by: * waveOutPrepareHdr * waveInPrepareHdr * * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ DWORD ThunkCommonWavePrepareHeader( HWAVE hWave, DWORD dwParam1, int iWhich ) { PWAVEHDR32 p32WaveHdr; DWORD ul; WAVEHDR16 UNALIGNED *lp16; lp16 = GETVDMPTR( dwParam1 ); /* ** Allocate some storage for the new wave header structure. ** On debug builds we keep track of the number of wave headers allocated ** and freed. */ p32WaveHdr = (PWAVEHDR32)winmmAlloc( sizeof(WAVEHDR32) ); if ( p32WaveHdr != NULL ) { #if DBG AllocWaveCount++; dprintf2(( "WH>> 0x%X (%d)", p32WaveHdr, AllocWaveCount )); #endif /* ** Copy the header given to us by the application into the newly ** allocated header. Note that GetWaveHdr returns a 0:32 pointer ** to the applications 16 bit header, which we save for later use. */ p32WaveHdr->pWavehdr16 = (PWAVEHDR16)dwParam1; p32WaveHdr->pWavehdr32 = GetWaveHdr16( dwParam1, &p32WaveHdr->Wavehdr ); /* ** Prepare the real header */ if ( iWhich == WAVE_OUT_DEVICE ) { ul = waveOutPrepareHeader( (HWAVEOUT)hWave, &p32WaveHdr->Wavehdr, sizeof(WAVEHDR) ); } else { ul = waveInPrepareHeader( (HWAVEIN)hWave, &p32WaveHdr->Wavehdr, sizeof(WAVEHDR) ); } if ( ul == MMSYSERR_NOERROR ) { /* ** Copy back the prepared header so that any changed fields are ** updated. */ PutWaveHdr16( lp16, &p32WaveHdr->Wavehdr ); /* ** Save a back pointer to the newly allocated header in the ** reserved field. */ lp16->reserved = (DWORD)p32WaveHdr; } else { /* ** Some error happened, anyway the wave header is now trash so ** free the allocated storage etc. */ winmmFree( p32WaveHdr ); #if DBG AllocWaveCount--; dprintf2(( "WH<< 0x%X (%d)", p32WaveHdr, AllocWaveCount )); #endif } } else { dprintf2(( "Could not allocate shadow wave header!!" )); ul = MMSYSERR_NOMEM; } return ul; } /*****************************Private*Routine******************************\ * ThunkCommonWaveUnprepareHeader * * * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ DWORD ThunkCommonWaveUnprepareHeader( HWAVE hWave, DWORD dwParam1, int iWhich ) { DWORD ul; PWAVEHDR32 p32WaveHdr; WAVEHDR16 UNALIGNED *lp16; BOOL fDoneBitSet; lp16 = (WAVEHDR16 UNALIGNED *)GETVDMPTR( dwParam1 ); p32WaveHdr = (PWAVEHDR32)lp16->reserved; /* ** The DK Stowaway app clears the done bit before calling ** waveOutUnprepareHeader and depends on the done bit being cleared when ** this api returns. ** ** So when we copy the 32 bit flags back we make sure that the done ** is left in the same state that we found it */ fDoneBitSet = (lp16->dwFlags & WHDR_DONE); /* ** Now call waveXxxUnprepare header with the shadow buffer as determined ** by iWhich. */ if ( iWhich == WAVE_OUT_DEVICE ) { ul = waveOutUnprepareHeader( (HWAVEOUT)hWave, &p32WaveHdr->Wavehdr, sizeof(WAVEHDR) ); } else { ul = waveInUnprepareHeader( (HWAVEIN)hWave, &p32WaveHdr->Wavehdr, sizeof(WAVEHDR) ); } /* ** Reflect any changes made by waveOutUnprepareHeader back into the ** the buffer that the application gave us. */ if ( ul == MMSYSERR_NOERROR ) { PutWaveHdr16( lp16, &p32WaveHdr->Wavehdr ); /* ** Make sure that we leave the done bit in the same state that we ** found it. */ if (fDoneBitSet) { lp16->dwFlags |= WHDR_DONE; } else { lp16->dwFlags &= ~WHDR_DONE; } /* ** If everything worked OK we should free the shadow wave header ** here. */ #if DBG AllocWaveCount--; dprintf2(( "WH<< 0x%X (%d)", p32WaveHdr, AllocWaveCount )); #endif winmmFree( p32WaveHdr ); } return ul; } /*****************************Private*Routine******************************\ * CopyWaveOutCaps * * Copies 32 bit wave out caps info into the passed 16bit storage. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void CopyWaveOutCaps( LPWAVEOUTCAPS16 lpCaps16, LPWAVEOUTCAPSA lpCaps32, DWORD dwSize ) { WAVEOUTCAPS16 Caps16; Caps16.wMid = lpCaps32->wMid; Caps16.wPid = lpCaps32->wPid; Caps16.vDriverVersion = LOWORD( lpCaps32->vDriverVersion ); CopyMemory( Caps16.szPname, lpCaps32->szPname, MAXPNAMELEN ); Caps16.dwFormats = lpCaps32->dwFormats; Caps16.wChannels = lpCaps32->wChannels; Caps16.dwSupport = lpCaps32->dwSupport; CopyMemory( (LPVOID)lpCaps16, (LPVOID)&Caps16, (UINT)dwSize ); } /*****************************Private*Routine******************************\ * CopyWaveInCaps * * Copies 32 bit wave in caps info into the passed 16bit storage. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void CopyWaveInCaps( LPWAVEINCAPS16 lpCaps16, LPWAVEINCAPSA lpCaps32, DWORD dwSize ) { WAVEINCAPS16 Caps16; Caps16.wMid = lpCaps32->wMid; Caps16.wPid = lpCaps32->wPid; Caps16.vDriverVersion = LOWORD( lpCaps32->vDriverVersion ); CopyMemory( Caps16.szPname, lpCaps32->szPname, MAXPNAMELEN ); Caps16.dwFormats = lpCaps32->dwFormats; Caps16.wChannels = lpCaps32->wChannels; CopyMemory( (LPVOID)lpCaps16, (LPVOID)&Caps16, (UINT)dwSize ); } /******************************Public*Routine******************************\ * GetWaveHdr16 * * Thunks a WAVEHDR structure from 16 bit to 32 bit space. * * Used by: * waveOutWrite * waveInAddBuffer * * Returns a 32 bit pointer to the 16 bit wave header. This wave header * should have been locked down by wave(In|Out)PrepareHeader. Therefore, * it is to store this pointer for use during the WOM_DONE callback message. * * With the WAVEHDR and MIDIHDR structs I am assured by Robin that the ->lpNext * field is only used by the driver, and is therefore in 32 bit space. It * therefore doesn't matter what gets passed back and forth (I hope !). * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ PWAVEHDR16 GetWaveHdr16( DWORD vpwhdr, LPWAVEHDR lpwhdr ) { register PWAVEHDR16 pwhdr16; pwhdr16 = GETVDMPTR(vpwhdr); if ( pwhdr16 == NULL ) { dprintf1(( "getwavehdr16 GETVDMPTR returned an invalid pointer" )); return NULL; } CopyMemory( (LPVOID)lpwhdr, (LPVOID)pwhdr16, sizeof(*lpwhdr) ); lpwhdr->lpData = GETVDMPTR( pwhdr16->lpData ); return pwhdr16; } /******************************Public*Routine******************************\ * PutWaveHdr16 * * Thunks a WAVEHDR structure from 32 bit back to 16 bit space. * * Used by: * waveOutPrepareHeader * waveOutUnprepareHeader * waveOutWrite * waveInPrepareHeader * waveInUnprepareHeader * waveInAddBuffer * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void PutWaveHdr16( WAVEHDR16 UNALIGNED *pwhdr16, LPWAVEHDR lpwhdr ) { LPSTR lpDataSave = pwhdr16->lpData; DWORD dwReservedSave = pwhdr16->reserved; CopyMemory( (LPVOID)pwhdr16, (LPVOID)lpwhdr, sizeof(WAVEHDR) ); pwhdr16->lpData = lpDataSave; pwhdr16->reserved = dwReservedSave; } /******************************Public*Routine******************************\ * mod32Message * * Thunks all midi out apis. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD WINAPI mod32Message( UINT uDeviceID, UINT uMessage, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) { #if DBG static MSG_NAME name_map[] = { MODM_GETNUMDEVS, "MODM_GETNUMDEVS", MODM_GETDEVCAPS, "MODM_GETDEVCAPS", MODM_OPEN, "MODM_OPEN", MODM_CLOSE, "MODM_CLOSE", MODM_PREPARE, "MODM_PREPARE", MODM_UNPREPARE, "MODM_UNPREPARE", MODM_DATA, "MODM_DATA", MODM_RESET, "MODM_RESET", MODM_LONGDATA, "MODM_LONGDATA", MODM_GETVOLUME, "MODM_GETVOLUME", MODM_SETVOLUME, "MODM_SETVOLUME" , MODM_CACHEDRUMPATCHES, "MODM_CACHEDRUMPATCHES", MODM_CACHEPATCHES, "MODM_CACHEPATCHES" }; int i; int n; #endif static DWORD dwNumMidiOutDevs; DWORD dwRet = MMSYSERR_NOTSUPPORTED; DWORD dwTmp; DWORD UNALIGNED *lpdwTmp; MIDIOUTCAPSA moCaps; #if DBG for( i = 0, n = sizeof(name_map) / sizeof(name_map[0]); i < n; i++ ) { if ( name_map[i].uMsg == uMessage ) { break; } } if ( i != n ) { trace_midiout(( "mod32Message( 0x%X, %s, 0x%X, 0x%X, 0x%X)", uDeviceID, name_map[i].lpstrName, dwInstance, dwParam1, dwParam2 )); } else { trace_midiout(( "mod32Message( 0x%X, 0x%X, 0x%X, 0x%X, 0x%X)", uDeviceID, uMessage, dwInstance, dwParam1, dwParam2 )); } #endif if ( LOWORD(uDeviceID) == 0xFFFF ) { uDeviceID = (UINT)-1; } switch ( uMessage ) { case MODM_GETNUMDEVS: dwRet = midiOutGetNumDevs(); break; case MODM_GETDEVCAPS: dwRet = midiOutGetDevCapsA( uDeviceID, &moCaps, sizeof(moCaps)); if ( dwRet == MMSYSERR_NOERROR ) { CopyMidiOutCaps( (LPMIDIOUTCAPS16)GETVDMPTR( dwParam1 ), &moCaps, dwParam2 ); } break; case MODM_OPEN: dwRet = ThunkCommonMidiOpen( MIDI_OUT_DEVICE, uDeviceID, dwParam1, dwParam2, dwInstance ); break; case MODM_LONGDATA: dwRet = ThunkCommonMidiReadWrite( MIDI_OUT_DEVICE, dwParam1, dwParam2, dwInstance ); break; case MODM_PREPARE: dwRet = ThunkCommonMidiPrepareHeader( (HMIDI)dwInstance, dwParam1, MIDI_OUT_DEVICE ); break; case MODM_UNPREPARE: dwRet = ThunkCommonMidiUnprepareHeader( (HMIDI)dwInstance, dwParam1, MIDI_OUT_DEVICE ); break; case MODM_DATA: dwRet = midiOutShortMsg( (HMIDIOUT)dwInstance, dwParam1 ); break; case MODM_CLOSE: dwRet = midiOutClose( (HMIDIOUT)dwInstance ); break; case MODM_RESET: dwRet = midiOutMessage( (HMIDIOUT)dwInstance, uMessage, dwParam1, dwParam2 ); break; case MODM_SETVOLUME: /* ** An application might try to set the volume using either ** the device ID (midiOutSetVolume) or a handle to the device ** midiOutMessage( MODM_SETVOLUME...), if the later is the case ** we must also call midiOutMessage as the device ID will not ** necessarily be valid. Same applies for midiOutGetVolume below. */ if ( dwInstance == 0 ) { dwRet = midiOutSetVolume( (HMIDIOUT)uDeviceID, dwParam1 ); } else { dwRet = midiOutMessage( (HMIDIOUT)dwInstance, uMessage, dwParam1, dwParam2 ); } break; case MODM_GETVOLUME: if ( dwInstance == 0 ) { dwRet = midiOutGetVolume( (HMIDIOUT)uDeviceID, &dwTmp ); } else { dwRet = midiOutMessage( (HMIDIOUT)dwInstance, uMessage, (DWORD)&dwTmp, dwParam2 ); } lpdwTmp = GETVDMPTR( dwParam1 ); *lpdwTmp = dwTmp; break; case MODM_CACHEPATCHES: case MODM_CACHEDRUMPATCHES: { LPWORD lpCache; lpCache = winmmAlloc( MIDIPATCHSIZE * sizeof(WORD) ); if ( lpCache != NULL ) { lpdwTmp = GETVDMPTR( dwParam1 ); CopyMemory( (LPVOID)lpCache, (LPVOID)lpdwTmp, MIDIPATCHSIZE * sizeof(WORD) ); dwRet = midiOutMessage( (HMIDIOUT)dwInstance, uMessage, (DWORD)lpCache, dwParam2 ); winmmFree( lpCache ); } else { dwRet = MMSYSERR_NOMEM; } } break; default: if ( uMessage >= DRV_BUFFER_LOW && uMessage <= DRV_BUFFER_HIGH ) { lpdwTmp = GETVDMPTR( dwParam1 ); } else { lpdwTmp = (LPDWORD)dwParam1; } dwRet = midiOutMessage( (HMIDIOUT)dwInstance, uMessage, (DWORD)lpdwTmp, dwParam2 ); } trace_midiout(( "-> 0x%X", dwRet )); return dwRet; } /******************************Public*Routine******************************\ * mid32Message * * Thunks all midi in apis. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD WINAPI mid32Message( UINT uDeviceID, UINT uMessage, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) { #if DBG static MSG_NAME name_map[] = { MIDM_GETNUMDEVS, "MIDM_GETNUMDEVS", MIDM_GETDEVCAPS, "MIDM_GETDEVCAPS", MIDM_OPEN, "MIDM_OPEN", MIDM_ADDBUFFER, "MIDM_ADDBUFFER", MIDM_CLOSE, "MIDM_CLOSE", MIDM_PREPARE, "MIDM_PREPARE", MIDM_UNPREPARE, "MIDM_UNPREPARE", MIDM_RESET, "MIDM_RESET", MIDM_START, "MIDM_START", MIDM_STOP, "MIDM_STOP", }; int i; int n; #endif static DWORD dwNumMidiInDevs; DWORD dwRet = MMSYSERR_NOTSUPPORTED; MIDIINCAPSA miCaps; DWORD UNALIGNED *lpdwTmp; #if DBG for( i = 0, n = sizeof(name_map) / sizeof(name_map[0]); i < n; i++ ) { if ( name_map[i].uMsg == uMessage ) { break; } } if ( i != n ) { trace_midiin(( "mid32Message( 0x%X, %s, 0x%X, 0x%X, 0x%X)", uDeviceID, name_map[i].lpstrName, dwInstance, dwParam1, dwParam2 )); } else { trace_midiin(( "mid32Message( 0x%X, 0x%X, 0x%X, 0x%X, 0x%X)", uDeviceID, uMessage, dwInstance, dwParam1, dwParam2 )); } #endif if ( LOWORD(uDeviceID) == 0xFFFF ) { uDeviceID = (UINT)-1; } switch ( uMessage ) { case MIDM_GETNUMDEVS: dwRet = midiInGetNumDevs(); break; case MIDM_GETDEVCAPS: dwRet = midiInGetDevCapsA( uDeviceID, &miCaps, sizeof(miCaps)); if ( dwRet == MMSYSERR_NOERROR ) { CopyMidiInCaps( (LPMIDIINCAPS16)GETVDMPTR( dwParam1 ), &miCaps, dwParam2 ); } break; case MIDM_OPEN: dwRet = ThunkCommonMidiOpen( MIDI_IN_DEVICE, uDeviceID, dwParam1, dwParam2, dwInstance ); break; case MIDM_ADDBUFFER: dwRet = ThunkCommonMidiReadWrite( MIDI_IN_DEVICE, dwParam1, dwParam2, dwInstance ); break; case MIDM_PREPARE: dwRet = ThunkCommonMidiPrepareHeader( (HMIDI)dwInstance, dwParam1, MIDI_IN_DEVICE ); break; case MIDM_UNPREPARE: dwRet = ThunkCommonMidiUnprepareHeader( (HMIDI)dwInstance, dwParam1, MIDI_IN_DEVICE ); break; case MIDM_CLOSE: dwRet = midiInClose( (HMIDIIN)dwInstance ); break; case MIDM_START: case MIDM_STOP: case MIDM_RESET: dwRet = midiInMessage( (HMIDIIN)dwInstance, uMessage, dwParam1, dwParam2 ); break; default: if ( uMessage >= DRV_BUFFER_LOW && uMessage <= DRV_BUFFER_HIGH ) { lpdwTmp = GETVDMPTR( dwParam1 ); } else { lpdwTmp = (LPDWORD)dwParam1; } dwRet = midiInMessage( (HMIDIIN)dwInstance, uMessage, (DWORD)lpdwTmp, dwParam2 ); } trace_midiin(( "-> 0x%X", dwRet )); return dwRet; } /*****************************Private*Routine******************************\ * ThunkCommonMidiOpen * * Thunks all midi open requests. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD ThunkCommonMidiOpen( int iWhich, UINT uDeviceID, DWORD dwParam1, DWORD dwParam2, DWORD dwInstance ) { /* ** dwParam1 is a 16:16 pointer to a MIDIOPENDESC16 structure. ** dwParam2 specifies any option flags used when opening the device. */ LPMIDIOPENDESC16 lpOpenDesc16; DWORD dwRet; HMIDI Hand32; PINSTANCEDATA pInstanceData; lpOpenDesc16 = GETVDMPTR( dwParam1 ); /* ** Create InstanceData block to be used by our callback routine. ** ** NOTE: Although we malloc it here we don't free it. ** This is not a mistake - it must not be freed before the ** callback routine has used it - so it does the freeing. ** ** If the malloc fails we bomb down to the bottom, ** set dwRet to MMSYSERR_NOMEM and exit gracefully. ** ** We always have a callback functions. This is to ensure that ** the MIDIHDR structure keeps getting copied back from ** 32 bit space to 16 bit, as it contains flags which ** applications are liable to keep checking. */ pInstanceData = winmmAlloc(sizeof(INSTANCEDATA) ); if ( pInstanceData != NULL ) { DWORD dwNewFlags = CALLBACK_FUNCTION; dprintf2(( "MidiCommonOpen: Allocated instance buffer at 0x%8X", pInstanceData )); dprintf2(( "16 bit callback = 0x%X", lpOpenDesc16->dwCallback )); pInstanceData->Hand16 = lpOpenDesc16->hMidi; pInstanceData->dwCallback = lpOpenDesc16->dwCallback; pInstanceData->dwCallbackInstance = lpOpenDesc16->dwInstance; pInstanceData->dwFlags = dwParam2; if ( iWhich == MIDI_OUT_DEVICE ) { dwRet = midiOutOpen( (LPHMIDIOUT)&Hand32, uDeviceID, (DWORD)W32CommonDeviceCB, (DWORD)pInstanceData, dwNewFlags ); } else { dwRet = midiInOpen( (LPHMIDIIN)&Hand32, uDeviceID, (DWORD)W32CommonDeviceCB, (DWORD)pInstanceData, dwNewFlags ); } /* ** If the call returns success save a copy of the 32 bit handle ** otherwise free the memory we malloc'd earlier, as the ** callback that would have freed it will never get callled. */ if ( dwRet == MMSYSERR_NOERROR ) { DWORD UNALIGNED *lpDw; lpDw = GETVDMPTR( dwInstance ); *lpDw = (DWORD)Hand32; SetWOWHandle( Hand32, lpOpenDesc16->hMidi ); #if DBG if ( iWhich == MIDI_OUT_DEVICE ) { trace_midiout(( "Handle -> %x", Hand32 )); } else { trace_midiout(( "Handle -> %x", Hand32 )); } #endif } else { dprintf2(( "MidiCommonOpen: Freeing instance buffer at %8X " "because open failed", pInstanceData )); winmmFree( pInstanceData ); } } else { dwRet = MMSYSERR_NOMEM; } return dwRet; } /*****************************Private*Routine******************************\ * ThunkCommonMidiReadWrite * * Thunks all midi read/write requests. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD ThunkCommonMidiReadWrite( int iWhich, DWORD dwParam1, DWORD dwParam2, DWORD dwInstance ) { UINT ul; PMIDIHDR32 p32MidiHdr; MIDIHDR UNALIGNED *lp16; /* ** Get a pointer to the shadow MIDIHDR buffer. */ lp16 = GETVDMPTR( dwParam1 ); p32MidiHdr = (PMIDIHDR32)lp16->reserved; /* ** Make sure that the midi headers are consistent. */ CopyMemory( (LPVOID)&p32MidiHdr->Midihdr.dwBufferLength, (LPVOID)&lp16->dwBufferLength, (sizeof(MIDIHDR) - sizeof(LPSTR) - sizeof(DWORD)) ); p32MidiHdr->Midihdr.reserved = p32MidiHdr->reserved; /* ** Call either midiInAddBuffer or midiOutWrite as determined by ** iWhich. */ if ( iWhich == MIDI_OUT_DEVICE ) { ul = midiOutLongMsg( (HMIDIOUT)dwInstance, &p32MidiHdr->Midihdr, sizeof(MIDIHDR) ); } else { ul = midiInAddBuffer( (HMIDIIN)dwInstance, &p32MidiHdr->Midihdr, sizeof(MIDIHDR) ); } /* ** If the call worked reflect any change in the midi header back into ** the header that the application gave use. */ if ( ul == MMSYSERR_NOERROR ) { PutMidiHdr16( lp16, &p32MidiHdr->Midihdr ); } return ul; } /*****************************Private*Routine******************************\ * ThunkCommonMidiPrepareHeader * * This function sets up the following structure... * * * +-------------+ +-------------+ * 0:32 | pMidihdr32 |------>| Original | * +-------------+ | header | * 16:16 | pMidihdr16 |------>| passed by | * +-------------+<--+ | the 16 bit | * | New 32 bit | | | | * | header thats| | | | * | used instead| | | | * | of the one | | +-------------+ * | passed to by| +---| reserved | * | application.| +-------------+ * | | * +-------------+ * * ... and then calls midiXxxPrepareHeader as determioned by iWhich. * * Used by: * midiOutPrepareHdr * midiInPrepareHdr * * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ DWORD ThunkCommonMidiPrepareHeader( HMIDI hMidi, DWORD dwParam1, int iWhich ) { PMIDIHDR32 p32MidiHdr; DWORD ul; MIDIHDR UNALIGNED *lp16; lp16 = GETVDMPTR( dwParam1 ); /* ** Allocate some storage for the new midi header structure. ** On debug builds we keep track of the number of midi headers allocated ** and freed. */ p32MidiHdr = (PMIDIHDR32)winmmAlloc( sizeof(MIDIHDR32) ); if ( p32MidiHdr != NULL ) { #if DBG AllocMidiCount++; dprintf2(( "MH>> 0x%X (%d)", p32MidiHdr, AllocMidiCount )); #endif /* ** Copy the header given to us by the application into the newly ** allocated header. Note that GetMidiHdr returns a 0:32 pointer ** to the applications 16 bit header, which we save for later use. */ p32MidiHdr->pMidihdr16 = (PMIDIHDR16)dwParam1; p32MidiHdr->pMidihdr32 = GetMidiHdr16( dwParam1, &p32MidiHdr->Midihdr ); /* ** Prepare the real header */ if ( iWhich == MIDI_OUT_DEVICE ) { ul = midiOutPrepareHeader( (HMIDIOUT)hMidi, &p32MidiHdr->Midihdr, sizeof(MIDIHDR) ); } else { ul = midiInPrepareHeader( (HMIDIIN)hMidi, &p32MidiHdr->Midihdr, sizeof(MIDIHDR) ); } if ( ul == MMSYSERR_NOERROR ) { /* ** Save a copy of the reserved field, MidiMap uses it. */ p32MidiHdr->reserved = p32MidiHdr->Midihdr.reserved; /* ** Copy back the prepared header so that any changed fields are ** updated. */ PutMidiHdr16( lp16, &p32MidiHdr->Midihdr ); /* ** Save a back pointer to the newly allocated header in the ** reserved field. */ lp16->reserved = (DWORD)p32MidiHdr; } else { /* ** Some error happened, anyway the midi header is now trash so ** free the allocated storage etc. */ winmmFree( p32MidiHdr ); #if DBG AllocMidiCount--; dprintf2(( "MH<< 0x%X (%d)", p32MidiHdr, AllocMidiCount )); #endif } } else { dprintf2(( "Could not allocate shadow midi header!!" )); ul = MMSYSERR_NOMEM; } return ul; } /*****************************Private*Routine******************************\ * ThunkCommonMidiUnprepareHeader * * * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ DWORD ThunkCommonMidiUnprepareHeader( HMIDI hMidi, DWORD dwParam1, int iWhich ) { DWORD ul; PMIDIHDR32 p32MidiHdr; MIDIHDR UNALIGNED *lp16; lp16 = (MIDIHDR UNALIGNED *)GETVDMPTR( dwParam1 ); p32MidiHdr = (PMIDIHDR32)lp16->reserved; p32MidiHdr->Midihdr.reserved = p32MidiHdr->reserved; /* ** Now call midiXxxUnprepare header with the shadow buffer as determined ** by iWhich. */ if ( iWhich == MIDI_OUT_DEVICE ) { ul = midiOutUnprepareHeader( (HMIDIOUT)hMidi, &p32MidiHdr->Midihdr, sizeof(MIDIHDR) ); } else { ul = midiInUnprepareHeader( (HMIDIIN)hMidi, &p32MidiHdr->Midihdr, sizeof(MIDIHDR) ); } /* ** Reflect any changes made by midiOutUnprepareHeader back into the ** the buffer that the application gave us. */ if ( ul == MMSYSERR_NOERROR ) { PutMidiHdr16( lp16, &p32MidiHdr->Midihdr ); /* ** If everything worked OK we should free the shadow midi header ** here. */ #if DBG AllocMidiCount--; dprintf2(( "MH<< 0x%X (%d)", p32MidiHdr, AllocMidiCount )); #endif winmmFree( p32MidiHdr ); } return ul; } /*****************************Private*Routine******************************\ * CopyMidiOutCaps * * Copies 32 bit midi out caps info into the passed 16bit storage. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void CopyMidiOutCaps( LPMIDIOUTCAPS16 lpCaps16, LPMIDIOUTCAPSA lpCaps32, DWORD dwSize ) { MIDIOUTCAPS16 Caps16; Caps16.wMid = lpCaps32->wMid; Caps16.wPid = lpCaps32->wPid; CopyMemory( Caps16.szPname, lpCaps32->szPname, MAXPNAMELEN ); Caps16.vDriverVersion = LOWORD( lpCaps32->vDriverVersion ); Caps16.wTechnology = lpCaps32->wTechnology; Caps16.wVoices = lpCaps32->wVoices; Caps16.wNotes = lpCaps32->wNotes; Caps16.wChannelMask = lpCaps32->wChannelMask; Caps16.dwSupport = lpCaps32->dwSupport; CopyMemory( (LPVOID)lpCaps16, (LPVOID)&Caps16, (UINT)dwSize ); } /*****************************Private*Routine******************************\ * CopyMidiInCaps * * Copies 32 bit midi in caps info into the passed 16bit storage. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void CopyMidiInCaps( LPMIDIINCAPS16 lpCaps16, LPMIDIINCAPSA lpCaps32, DWORD dwSize ) { MIDIINCAPS16 Caps16; Caps16.wMid = lpCaps32->wMid; Caps16.wPid = lpCaps32->wPid; Caps16.vDriverVersion = LOWORD( lpCaps32->vDriverVersion ); CopyMemory( Caps16.szPname, lpCaps32->szPname, MAXPNAMELEN ); CopyMemory( (LPVOID)lpCaps16, (LPVOID)&Caps16, (UINT)dwSize ); } /******************************Public*Routine******************************\ * GetMidiHdr16 * * Thunks a MIDIHDR structure from 16 bit to 32 bit space. * * Used by: * midiOutLongMsg * midiInAddBuffer * * Returns a 32 bit pointer to the 16 bit midi header. This midi header * should have been locked down by midi(In|Out)PrepareHeader. Therefore, * it is to store this pointer for use during the WOM_DONE callback message. * * With the MIDIHDR and MIDIHDR structs I am assured by Robin that the ->lpNext * field is only used by the driver, and is therefore in 32 bit space. It * therefore doesn't matter what gets passed back and forth (I hope !). * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ PMIDIHDR16 GetMidiHdr16( DWORD vpmhdr, LPMIDIHDR lpmhdr ) { register PMIDIHDR16 pmhdr16; pmhdr16 = GETVDMPTR(vpmhdr); if ( pmhdr16 == NULL ) { dprintf1(( "getmidihdr16 GETVDMPTR returned an invalid pointer" )); return NULL; } CopyMemory( (LPVOID)lpmhdr, (LPVOID)pmhdr16, sizeof(*lpmhdr) ); lpmhdr->lpData = GETVDMPTR( pmhdr16->lpData ); return pmhdr16; } /******************************Public*Routine******************************\ * PutMidiHdr16 * * Thunks a MIDIHDR structure from 32 bit back to 16 bit space. * * Used by: * midiOutPrepareHeader * midiOutUnprepareHeader * midiOutLongMsg * midiInPrepareHeader * midiInUnprepareHeader * midiInAddBuffer * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void PutMidiHdr16( MIDIHDR UNALIGNED *pmhdr16, LPMIDIHDR lpmhdr ) { LPSTR lpDataSave = pmhdr16->lpData; DWORD dwReservedSave = pmhdr16->reserved; CopyMemory( (LPVOID)pmhdr16, (LPVOID)lpmhdr, sizeof(MIDIHDR) ); pmhdr16->lpData = lpDataSave; pmhdr16->reserved = dwReservedSave; } /*****************************Private*Routine******************************\ * PutMMTime * * Puts an MMTIME structure from 32 bit storage into 16 bit storage * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void PutMMTime( LPMMTIME16 lpTime16, LPMMTIME lpTime32 ) { lpTime16->wType = LOWORD(lpTime32->wType); switch ( lpTime32->wType ) { case TIME_MS: lpTime16->u.ms = lpTime32->u.ms; break; case TIME_SAMPLES: lpTime16->u.sample = lpTime32->u.sample; break; case TIME_BYTES: lpTime16->u.cb = lpTime32->u.cb; break; case TIME_SMPTE: lpTime16->u.smpte.hour = lpTime32->u.smpte.hour; lpTime16->u.smpte.min = lpTime32->u.smpte.min; lpTime16->u.smpte.sec = lpTime32->u.smpte.sec; lpTime16->u.smpte.frame = lpTime32->u.smpte.frame; lpTime16->u.smpte.fps = lpTime32->u.smpte.fps; lpTime16->u.smpte.dummy = lpTime32->u.smpte.dummy; break; case TIME_MIDI: lpTime16->u.midi.songptrpos = lpTime32->u.midi.songptrpos; break; } } /*****************************Private*Routine******************************\ * GetMMTime * * Gets an MMTIME structure from 16 bit storage into 32 bit storage * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void GetMMTime( LPMMTIME16 lpTime16, LPMMTIME lpTime32 ) { lpTime32->wType = lpTime16->wType; switch ( lpTime32->wType ) { case TIME_MS: lpTime32->u.ms = lpTime16->u.ms; break; case TIME_SAMPLES: lpTime32->u.sample = lpTime16->u.sample; break; case TIME_BYTES: lpTime32->u.cb = lpTime16->u.cb; break; case TIME_SMPTE: lpTime32->u.smpte.hour = lpTime16->u.smpte.hour; lpTime32->u.smpte.min = lpTime16->u.smpte.min; lpTime32->u.smpte.sec = lpTime16->u.smpte.sec; lpTime32->u.smpte.frame = lpTime16->u.smpte.frame; lpTime32->u.smpte.fps = lpTime16->u.smpte.fps; lpTime32->u.smpte.dummy = lpTime16->u.smpte.dummy; break; case TIME_MIDI: lpTime32->u.midi.songptrpos = lpTime16->u.midi.songptrpos; break; } } /******************************Public*Routine******************************\ * W32CommonDeviceCB * * This routine is the callback which is ALWAYS called by wave and midi * functions. This is done to ensure that the XXXXHDR structure keeps * getting copied back from 32 bit space to 16 bit, as it contains flags * which the application is liable to keep checking. * * The way this whole business works is that the wave/midi data stays in 16 * bit space, but the XXXXHDR is copied to the 32 bit side, with the * address of the data thunked accordingly so that Robin's device driver * can still get at the data but we don't have the performance penalty of * copying it back and forth all the time, not least because it is liable * to be rather large... * * It also handles the tidying up of memory which is reserved to store * the XXXXHDR, and the instance data (HWND/Callback address; instance * data; flags) which the xxxxOpen calls pass to this routine, enabling * it to forward messages or call callback as required. * * This routine handles all the messages that get sent from Robin's * driver, and in fact thunks them back to the correct 16 bit form. In * theory there should be no MM_ format messages from the 16 bit side, so * I can zap 'em out of WMSG16. However the 32 bit side should thunk the * mesages correctly and forward them to the 16 bit side and thence to * the app. * * For the MM_WIM_DATA and MM_WOM_DONE message dwParam1 points to the * following data struture. * * P32HDR is a 32 bit pointer to the original 16 bit header * P16HDR is a 16 bit far pointer to the original 16 bit header * * If we need to refernece the original header we must do via the * P32HDR pointer. * * +---------+ * | P32HDR +----->+---------+ * +---------+ | 16 bit | * | P16HDR +----->| | This is the original * dwParam1 ----->+---------+ | Wave | wave header passed to * | 32 bit | | Header | us by the Win 16 app. * This is the 32 | | | | * bit wave | Wave | +---------+ * header that we | Header | * thunked at | | * earlier. +---------+ * * * We must ensure that the 32 bit structure is completely hidden from the * 16 bit application, ie. the 16 bit app only see's the wave header that it * passed to us earlier. * * * NOTE: dwParam2 is junk * * * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ VOID W32CommonDeviceCB( HANDLE handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) { PWAVEHDR32 pWavehdr32; PMIDIHDR32 pMidiThunkHdr; PINSTANCEDATA pInstanceData; HANDLE16 Hand16; pInstanceData = (PINSTANCEDATA)dwInstance; WinAssert( pInstanceData ); switch (uMsg) { /* ------------------------------------------------------------ ** MIDI INPUT MESSAGES ** ------------------------------------------------------------ */ case MM_MIM_LONGDATA: /* ** This message is sent to a window when an input buffer has been ** filled with MIDI system-exclusive data and is being returned to ** the application. */ case MM_MIM_LONGERROR: /* ** This message is sent to a window when an invalid MIDI ** system-exclusive message is received. */ pMidiThunkHdr = CONTAINING_RECORD(dwParam1, MIDIHDR32, Midihdr); WinAssert( pMidiThunkHdr ); COPY_MIDIINHDR16_FLAGS( pMidiThunkHdr->pMidihdr32, pMidiThunkHdr->Midihdr ); dwParam1 = (DWORD)pMidiThunkHdr->pMidihdr16; case MM_MIM_DATA: /* ** This message is sent to a window when a MIDI message is ** received by a MIDI input device. */ case MM_MIM_ERROR: /* ** This message is sent to a window when an invalid MIDI message ** is received. */ case MM_MIM_OPEN: /* ** This message is sent to a window when a MIDI input device is opened. ** We process this message the same way as MM_MIM_CLOSE (see below) */ case MM_MIM_CLOSE: /* ** This message is sent to a window when a MIDI input device is ** closed. The device handle is no longer valid once this message ** has been sent. */ Hand16 = pInstanceData->Hand16; break; /* ------------------------------------------------------------ ** MIDI OUTPUT MESSAGES ** ------------------------------------------------------------ */ case MM_MOM_DONE: /* ** This message is sent to a window when the specified ** system-exclusive buffer has been played and is being returned to ** the application. */ pMidiThunkHdr = CONTAINING_RECORD(dwParam1, MIDIHDR32, Midihdr); WinAssert( pMidiThunkHdr ); COPY_MIDIOUTHDR16_FLAGS( pMidiThunkHdr->pMidihdr32, pMidiThunkHdr->Midihdr ); dwParam1 = (DWORD)pMidiThunkHdr->pMidihdr16; case MM_MOM_OPEN: /* ** This message is sent to a window when a MIDI output device is opened. ** We process this message the same way as MM_MOM_CLOSE (see below) */ case MM_MOM_CLOSE: /* ** This message is sent to a window when a MIDI output device is ** closed. The device handle is no longer valid once this message ** has been sent. */ Hand16 = pInstanceData->Hand16; break; /* ------------------------------------------------------------ ** WAVE INPUT MESSAGES ** ------------------------------------------------------------ */ case MM_WIM_DATA: /* ** This message is sent to a window when waveform data is present ** in the input buffer and the buffer is being returned to the ** application. The message can be sent either when the buffer ** is full, or after the waveInReset function is called. */ pWavehdr32 = (PWAVEHDR32)( (PBYTE)dwParam1 - (sizeof(PWAVEHDR16) * 2)); WinAssert( pWavehdr32 ); COPY_WAVEINHDR16_FLAGS( pWavehdr32->pWavehdr32, pWavehdr32->Wavehdr ); dwParam1 = (DWORD)pWavehdr32->pWavehdr16; case MM_WIM_OPEN: /* ** This message is sent to a window when a waveform input ** device is opened. ** ** We process this message the same way as MM_WIM_CLOSE (see below) */ case MM_WIM_CLOSE: /* ** This message is sent to a window when a waveform input device is ** closed. The device handle is no longer valid once the message has ** been sent. */ Hand16 = pInstanceData->Hand16; break; /* ------------------------------------------------------------ ** WAVE OUTPUT MESSAGES ** ------------------------------------------------------------ */ case MM_WOM_DONE: /* ** This message is sent to a window when the specified output ** buffer is being returned to the application. Buffers are returned ** to the application when they have been played, or as the result of ** a call to waveOutReset. */ pWavehdr32 = (PWAVEHDR32)( (PBYTE)dwParam1 - (sizeof(PWAVEHDR16) * 2)); WinAssert( pWavehdr32 ); COPY_WAVEOUTHDR16_FLAGS( pWavehdr32->pWavehdr32, pWavehdr32->Wavehdr ); dwParam1 = (DWORD)pWavehdr32->pWavehdr16; case MM_WOM_OPEN: /* ** This message is sent to a window when a waveform output device ** is opened. ** ** We process this message the same way as MM_WOM_CLOSE (see below) */ case MM_WOM_CLOSE: /* ** This message is sent to a window when a waveform output device ** is closed. The device handle is no longer valid once the ** message has been sent. */ Hand16 = pInstanceData->Hand16; break; #if DBG default: dprintf(( "Unknown message received in CallBack function " )); return; #endif } /* ** Now make the CallBack, or PostMessage call depending ** on the flags passed to original (wave|midi)(In|Out)Open call. */ pInstanceData = (PINSTANCEDATA)dwInstance; WinAssert( pInstanceData ); switch (pInstanceData->dwFlags & CALLBACK_TYPEMASK) { case CALLBACK_WINDOW: dprintf3(( "WINDOW callback identified" )); PostMessage( HWND32( LOWORD(pInstanceData->dwCallback) ), uMsg, Hand16, dwParam1 ); break; case CALLBACK_TASK: case CALLBACK_FUNCTION: { DWORD dwFlags; if ( (pInstanceData->dwFlags & CALLBACK_TYPEMASK) == CALLBACK_TASK ) { dprintf3(( "TASK callback identified" )); dwFlags = DCB_TASK; } else { dprintf3(( "FUNCTION callback identified" )); dwFlags = DCB_FUNCTION; } WOW32DriverCallback( pInstanceData->dwCallback, dwFlags, Hand16, LOWORD( uMsg ), pInstanceData->dwCallbackInstance, dwParam1, dwParam2 ); } break; } /* ** Now, free up any storage that was allocated during the waveOutOpen ** and waveInOpen. This should only be freed during the MM_WOM_CLOSE or ** MM_WIM_CLOSE message. */ switch (uMsg) { case MM_MIM_CLOSE: case MM_MOM_CLOSE: case MM_WIM_CLOSE: case MM_WOM_CLOSE: dprintf2(( "W32CommonDeviceOpen: Freeing device open buffer at %X", pInstanceData )); dprintf2(( "Alloc Midi count = %d", AllocMidiCount )); dprintf2(( "Alloc Wave count = %d", AllocWaveCount )); winmmFree( pInstanceData ); break; } } /******************************Public*Routine******************************\ * WOW32DriverCallback * * Callback stub, which invokes the "real" 16 bit callback. * The parameters to this function must be in the format that the 16 bit * code expects, i.e. all handles must be 16 bit handles, all addresses must * be 16:16 ones. * * * It is possible that this function will have been called with the * DCB_WINDOW set in which case the 16 bit interrupt handler will call * PostMessage. Howver, it is much more efficient if PostMessage is called * from the 32 bit side. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ BOOL WOW32DriverCallback( DWORD dwCallback, DWORD dwFlags, WORD wID, WORD wMsg, DWORD dwUser, DWORD dw1, DWORD dw2 ) { PCALLBACK_ARGS pArgs; WORD tempSendCount; /* ** If this is window callback post the message here and let WOW ** take care of it. */ if ( (dwFlags & DCB_TYPEMASK) == DCB_WINDOW ) { return PostMessage( HWND32( LOWORD(dwCallback) ), wMsg, wID, dw1 ); } /* ** Now we put the parameters into the global callback data array ** and increment the wSendCount field. Then we simulate ** an interrupt to the 16 bit code. ** ** If tempSendCount == wRecvCount then we have filled the callback buffer. ** We throw this interrupt away, but still simulate an interrupt to the ** 16 bit side in an attempt to get it procesing the interrupt still in ** the buffer. */ EnterCriticalSection( &mmCriticalSection ); tempSendCount = ((pCallBackData->wSendCount + 1) % CALLBACK_ARGS_SIZE); if (tempSendCount != pCallBackData->wRecvCount) { pArgs = &pCallBackData->args[ pCallBackData->wSendCount ]; pArgs->dwFlags = dwFlags; pArgs->dwFunctionAddr = dwCallback; pArgs->wHandle = wID; pArgs->wMessage = wMsg; pArgs->dwInstance = dwUser; pArgs->dwParam1 = dw1; pArgs->dwParam2 = dw2; /* ** Increment the send count. Use of the % operator above makes ** sure that we wrap around to the begining of the array correctly. */ pCallBackData->wSendCount = tempSendCount; } dprintf4(( "Send count = %d, Receive count = %d", pCallBackData->wSendCount, pCallBackData->wRecvCount )); LeaveCriticalSection( &mmCriticalSection ); /* ** Dispatch the interrupt to the 16 bit code. */ dprintf4(( "Dispatching HW interrupt callback" )); GenerateInterrupt( MULTIMEDIA_ICA, MULTIMEDIA_LINE, 1 ); /* ** Dummy return code, used to keep api consistent with Win31 and Win NT. */ return TRUE; } /******************************Public*Routine******************************\ * aux32Message * * Thunk the aux apis. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD WINAPI aux32Message( UINT uDeviceID, UINT uMessage, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) { #if DBG static MSG_NAME name_map[] = { AUXDM_GETNUMDEVS, "AUXDM_GETNUMDEVS", AUXDM_GETDEVCAPS, "AUXDM_GETDEVCAPS", AUXDM_GETVOLUME, "AUXDM_GETVOLUME", AUXDM_SETVOLUME, "AUXDM_SETVOLUME", }; int i; int n; #endif static DWORD dwNumAuxDevs; DWORD dwRet = MMSYSERR_NOTSUPPORTED; DWORD dwTmp; DWORD UNALIGNED *lpdwTmp; AUXCAPSA aoCaps; #if DBG for( i = 0, n = sizeof(name_map) / sizeof(name_map[0]); i < n; i++ ) { if ( name_map[i].uMsg == uMessage ) { break; } } if ( i != n ) { trace_aux(( "aux32Message( 0x%X, %s, 0x%X, 0x%X, 0x%X)", uDeviceID, name_map[i].lpstrName, dwInstance, dwParam1, dwParam2 )); } else { trace_aux(( "aux32Message( 0x%X, 0x%X, 0x%X, 0x%X, 0x%X)", uDeviceID, uMessage, dwInstance, dwParam1, dwParam2 )); } #endif if ( LOWORD(uDeviceID) == 0xFFFF ) { uDeviceID = (UINT)-1; } dprintf2(( "aux32Message (0x%x)", uMessage )); switch ( uMessage ) { case AUXDM_GETNUMDEVS: dwRet = auxGetNumDevs(); break; case AUXDM_GETDEVCAPS: dwRet = auxGetDevCapsA( uDeviceID, &aoCaps, sizeof(aoCaps) ); if ( dwRet == MMSYSERR_NOERROR ) { CopyAuxCaps( (LPAUXCAPS16)GETVDMPTR( dwParam1 ), &aoCaps, dwParam2 ); } break; case AUXDM_GETVOLUME: dwRet = auxGetVolume( uDeviceID, &dwTmp ); lpdwTmp = GETVDMPTR( dwParam1 ); *lpdwTmp = dwTmp; break; case AUXDM_SETVOLUME: dwRet = auxSetVolume( uDeviceID, dwParam1 ); break; default: if ( uMessage >= DRV_BUFFER_LOW && uMessage <= DRV_BUFFER_HIGH ) { lpdwTmp = GETVDMPTR( dwParam1 ); } else { lpdwTmp = (LPDWORD)dwParam1; } dwRet = auxOutMessage( uDeviceID, uMessage, (DWORD)lpdwTmp, dwParam2 ); } trace_aux(( "-> 0x%X", dwRet )); return dwRet; } /*****************************Private*Routine******************************\ * CopyAuxCaps * * Copies 32 bit aux out caps info into the passed 16bit storage. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void CopyAuxCaps( LPAUXCAPS16 lpCaps16, LPAUXCAPSA lpCaps32, DWORD dwSize ) { AUXCAPS16 Caps16; Caps16.wMid = lpCaps32->wMid; Caps16.wPid = lpCaps32->wPid; Caps16.vDriverVersion = LOWORD( lpCaps32->vDriverVersion ); CopyMemory( Caps16.szPname, lpCaps32->szPname, MAXPNAMELEN ); Caps16.wTechnology = lpCaps32->wTechnology; Caps16.dwSupport = lpCaps32->dwSupport; CopyMemory( (LPVOID)lpCaps16, (LPVOID)&Caps16, (UINT)dwSize ); } /******************************Public*Routine******************************\ * tid32Message * * Thunk the timer apis * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD WINAPI tid32Message( UINT uDevId, UINT uMessage, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) { #if DBG static MSG_NAME name_map[] = { TDD_SETTIMEREVENT, "timeSetEvent", TDD_KILLTIMEREVENT, "timeKillEvent", TDD_GETSYSTEMTIME, "timeGetTime", TDD_GETDEVCAPS, "timeGetDevCaps", TDD_BEGINMINPERIOD, "timeBeginPeriod", TDD_ENDMINPERIOD, "timeEndPeriod", }; int i; int n; #endif DWORD dwRet = TIMERR_NOCANDO; LPTIMECAPS16 lp16TimeCaps; LPTIMEREVENT16 lp16TimeEvent; #if DBG for( i = 0, n = sizeof(name_map) / sizeof(name_map[0]); i < n; i++ ) { if ( name_map[i].uMsg == uMessage ) { break; } } if ( i != n ) { trace_time(( "tid32Message( %s, 0x%X, 0x%X)", name_map[i].lpstrName, dwParam1, dwParam2 )); } else { trace_time(( "tid32Message( 0x%X, 0x%X, 0x%X)", uMessage, dwParam1, dwParam2 )); } #endif switch (uMessage) { case TDD_SETTIMEREVENT: lp16TimeEvent = (LPTIMEREVENT16)GETVDMPTR( dwParam1); trace_time(( "tid32Message: timeSetEvent(%#X, %#X, %#X, %#X)", lp16TimeEvent->wDelay, lp16TimeEvent->wResolution, lp16TimeEvent->lpFunction, lp16TimeEvent->wFlags )); /* ** The only difference for WOW is that WOW32DriverCallback is ** called for the callback rather than DriverCallback. The ** last parameter to timeSetEventInternal makes this happen. */ dwRet = timeSetEventInternal( max( lp16TimeEvent->wDelay, g_TimeCaps32.wPeriodMin ), lp16TimeEvent->wResolution, (LPTIMECALLBACK)lp16TimeEvent->lpFunction, (DWORD)lp16TimeEvent->dwUser, lp16TimeEvent->wFlags & TIME_PERIODIC, TRUE); dprintf4(( "timeSetEvent: 32 bit time ID %8X", dwRet )); break; case TDD_KILLTIMEREVENT: dwRet = timeKillEvent( dwParam1 ); { /* ** Purge the callback queue of any messages were ** generated with this timer id. */ int i; EnterCriticalSection( &mmCriticalSection ); for ( i = 0; i < CALLBACK_ARGS_SIZE; i++ ) { if ( pCallBackData->args[ i ].wHandle == LOWORD(dwParam1) && pCallBackData->args[ i ].wMessage == 0 ) { pCallBackData->args[ i ].dwFunctionAddr = 0L; } } LeaveCriticalSection( &mmCriticalSection ); } break; case TDD_GETSYSTEMTIME: dwRet = timeGetTime(); break; case TDD_GETDEVCAPS: dwRet = 0; lp16TimeCaps = GETVDMPTR( dwParam1 ); /* ** Under NT, the minimum time period is about 15ms. ** But Win3.1 on a 386 always returns 1ms. Encarta doesn't even ** bother testing the CD-ROM's speed if the minimum period ** is > 2ms, it just assumes it is too slow. So here we lie ** to WOW apps and always tell them 1ms just like Win3.1. ** John Vert (jvert) 17-Jun-1993 */ #ifdef TELL_THE_TRUTH lp16TimeCaps->wPeriodMin = g_TimeCaps32.wPeriodMin; #else lp16TimeCaps->wPeriodMin = MIN_TIME_PERIOD_WE_RETURN; #endif /* ** In windows 3.1 the wPeriodMax value is 0xFFFF which is the ** max value you can store in a word. In windows NT the ** wPeriodMax is 0xF4240 (1000 seconds). ** ** If we just cast the 32 bit value down to a 16bit value we ** end up with 0x4240 which very small compared to real 32 bit ** value. ** ** Therefore I will take the minimum of wPeriodMax and 0xFFFF ** that way will should remain consistent with Win 3.1 if ** wPeriodMax is greater than 0xFFFF. */ lp16TimeCaps->wPeriodMax = (WORD)min(0xFFFF, g_TimeCaps32.wPeriodMax); break; case TDD_ENDMINPERIOD: dwParam1 = max(dwParam1, g_TimeCaps32.wPeriodMin); dwRet = timeEndPeriod( dwParam1 ); break; case TDD_BEGINMINPERIOD: dwParam1 = max(dwParam1, g_TimeCaps32.wPeriodMin); dwRet = timeBeginPeriod( dwParam1 ); break; } trace_time(( "-> 0x%X", dwRet )); return dwRet; } /******************************Public*Routine******************************\ * joy32Message * * Thunk the joystick apis * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD WINAPI joy32Message( UINT uID, UINT uMessage, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) { #if DBG static MSG_NAME name_map[] = { JDD_GETDEVCAPS, "joyGetDevCaps", JDD_GETPOS, "joyGetPos", JDD_SETCALIBRATION, "joySetCalibration", JDD_GETNUMDEVS, "joyGetNumDevs" }; int i; int n; #endif UINT wXbase; UINT wXdelta; UINT wYbase; UINT wYdelta; UINT wZbase; UINT wZdelta; WORD UNALIGNED *lpw; DWORD dwRet = TIMERR_NOCANDO; JOYCAPSA JoyCaps32; JOYINFO JoyInfo32; LPJOYCAPS16 lp16JoyCaps; LPJOYINFO16 lp16JoyInfo; #if DBG for( i = 0, n = sizeof(name_map) / sizeof(name_map[0]); i < n; i++ ) { if ( name_map[i].uMsg == uMessage ) { break; } } if ( i != n ) { trace_joy(( "joy32Message( %s, 0x%X, 0x%X)", name_map[i].lpstrName, dwParam1, dwParam2 )); } else { trace_joy(( "joy32Message( 0x%X, 0x%X, 0x%X)", uMessage, dwParam1, dwParam2 )); } #endif switch (uMessage) { case JDD_GETDEVCAPS: dwRet = joyGetDevCapsA( uID, &JoyCaps32, sizeof(JoyCaps32) ); if ( dwRet == 0 ) { JOYCAPS16 JoyCaps16; lp16JoyCaps = GETVDMPTR( dwParam1 ); JoyCaps16.wMid = JoyCaps32.wMid; JoyCaps16.wPid = JoyCaps32.wPid; CopyMemory( JoyCaps16.szPname, JoyCaps32.szPname, MAXPNAMELEN ); JoyCaps16.wXmin = LOWORD( JoyCaps32.wXmin ); JoyCaps16.wXmax = LOWORD( JoyCaps32.wXmax ); JoyCaps16.wYmin = LOWORD( JoyCaps32.wYmin ); JoyCaps16.wYmax = LOWORD( JoyCaps32.wYmax ); JoyCaps16.wZmin = LOWORD( JoyCaps32.wZmin ); JoyCaps16.wZmax = LOWORD( JoyCaps32.wZmax ); JoyCaps16.wNumButtons = LOWORD( JoyCaps32.wNumButtons ); JoyCaps16.wPeriodMin = LOWORD( JoyCaps32.wPeriodMin ); JoyCaps16.wPeriodMax = LOWORD( JoyCaps32.wPeriodMax ); CopyMemory( (LPVOID)lp16JoyCaps, (LPVOID)&JoyCaps16, (UINT)dwParam2 ); } break; case JDD_GETNUMDEVS: dwRet = joyGetNumDevs(); break; case JDD_GETPOS: dwRet = joyGetPos( uID, &JoyInfo32 ); if ( dwRet == MMSYSERR_NOERROR ) { lp16JoyInfo = GETVDMPTR( dwParam1 ); lp16JoyInfo->wXpos = LOWORD( JoyInfo32.wXpos ); lp16JoyInfo->wYpos = LOWORD( JoyInfo32.wYpos ); lp16JoyInfo->wZpos = LOWORD( JoyInfo32.wZpos ); lp16JoyInfo->wButtons = LOWORD( JoyInfo32.wButtons ); } break; case JDD_SETCALIBRATION: lpw = GETVDMPTR( dwParam1 ); wXbase = (UINT)*lpw++; wXdelta = (UINT)*lpw++; wYbase = (UINT)*lpw++; wYdelta = (UINT)*lpw++; wZbase = (UINT)*lpw++; wZdelta = (UINT)*lpw; dwRet = joySetCalibration( uID, &wXbase, &wXdelta, &wYbase, &wYdelta, &wZbase, &wZdelta ); lpw -= 5; *lpw++ = LOWORD(wXbase); *lpw++ = LOWORD(wXdelta); *lpw++ = LOWORD(wYbase); *lpw++ = LOWORD(wYdelta); *lpw++ = LOWORD(wZbase); *lpw = LOWORD(wZdelta); break; } trace_joy(( "-> 0x%X", dwRet )); return dwRet; } /******************************Public*Routine******************************\ * mxd32Message * * 32 bit thunk function. On NT all the 16 bit mixer apis get routed to * here. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ DWORD CALLBACK mxd32Message( UINT uId, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) { #if DBG static MSG_NAME name_map[] = { MXDM_INIT, "mixerInit", MXDM_GETNUMDEVS, "mixerGetNumDevs", MXDM_GETDEVCAPS, "mixerGetDevCaps", MXDM_OPEN, "mixerOpen", MXDM_GETLINEINFO, "mixerGetLineInfo", MXDM_GETLINECONTROLS, "mixerGetLineControls", MXDM_GETCONTROLDETAILS, "mixerGetControlsDetails", MXDM_SETCONTROLDETAILS, "mixerSetControlsDetails" }; int i; int n; #endif DWORD dwRet = MMSYSERR_NOTSUPPORTED; DWORD fdwOpen; LPVOID lpOldAddress; LPMIXERCONTROLDETAILS pmxcd; LPMIXERLINECONTROLSA pmxlc; MIXERCONTROLDETAILS mxcdA; HMIXEROBJ hmixobj; MIXERCAPSA caps32; MIXERCAPS16 caps16; LPMIXERCAPS16 lpcaps16; MIXERLINEA line32; LPMIXERLINE16 lpline16; LPMIXEROPENDESC16 lpmxod16; HMIXER UNALIGNED *phmx; HMIXER hmx; #if DBG for( i = 0, n = sizeof(name_map) / sizeof(name_map[0]); i < n; i++ ) { if ( name_map[i].uMsg == uMsg ) { break; } } if ( i != n ) { trace_mix(( "mxd32Message( %s, 0x%X, 0x%X, 0x%X)", name_map[i].lpstrName, dwInstance, dwParam1, dwParam2 )); } else { trace_mix(( "mxd32Message( 0x%X, 0x%X, 0x%X, 0x%X)", uMsg, dwInstance, dwParam1, dwParam2 )); } #endif if ( dwInstance == 0L ) { hmixobj = (HMIXEROBJ)uId; } else { hmixobj = (HMIXEROBJ)dwInstance; } switch ( uMsg ) { case MXDM_INIT: dwRet = 0; break; case MXDM_GETNUMDEVS: dwRet = mixerGetNumDevs(); break; case MXDM_CLOSE: dwRet = mixerClose( (HMIXER)dwInstance ); break; case MXDM_GETDEVCAPS: dwRet = mixerGetDevCapsA( uId, &caps32, sizeof(caps32) ); if ( dwRet == MMSYSERR_NOERROR ) { lpcaps16 = GETVDMPTR( dwParam1 ); caps16.wMid = caps32.wMid; caps16.wPid = caps32.wPid; caps16.vDriverVersion = LOWORD( caps32.vDriverVersion ); CopyMemory( caps16.szPname, caps32.szPname, MAXPNAMELEN ); caps16.fdwSupport = caps32.fdwSupport; caps16.cDestinations = caps32.cDestinations; CopyMemory( (LPVOID)lpcaps16, (LPVOID)&caps16, (UINT)dwParam2 ); } break; case MXDM_OPEN: lpmxod16 = GETVDMPTR( dwParam1 ); /* ** fdwOpen has already mapped all device handles into device ID's on ** the 16 bit side. Therefore mangle the flags to reflect this. */ fdwOpen = (DWORD)lpmxod16->pReserved0; if ( ( fdwOpen & CALLBACK_TYPEMASK ) == CALLBACK_WINDOW ) { lpmxod16->dwCallback = (DWORD)HWND32(LOWORD(lpmxod16->dwCallback)); } else if ( ( fdwOpen & CALLBACK_TYPEMASK ) == CALLBACK_TASK ) { lpmxod16->dwCallback = GetCurrentThreadId(); } dwRet = mixerOpen( &hmx, dwParam2, lpmxod16->dwCallback, lpmxod16->dwInstance, fdwOpen ); if ( dwRet == MMSYSERR_NOERROR ) { SetWOWHandle( hmx, lpmxod16->hmx ); phmx = GETVDMPTR( dwInstance ); *phmx = hmx; } break; case MXDM_GETLINEINFO: lpline16 = GETVDMPTR( dwParam1 ); GetLineInfo( lpline16, &line32 ); dwRet = mixerGetLineInfoA( hmixobj, &line32, dwParam2 ); if ( dwRet == MMSYSERR_NOERROR ) { PutLineInfo( lpline16, &line32 ); } break; case MXDM_GETLINECONTROLS: pmxlc = (LPMIXERLINECONTROLSA)GETVDMPTR( dwParam1 ); lpOldAddress = pmxlc->pamxctrl; pmxlc->pamxctrl = GETVDMPTR( lpOldAddress ); dwRet = mixerGetLineControlsA(hmixobj, pmxlc, dwParam2); pmxlc->pamxctrl = lpOldAddress; break; /* ** CAREFUL !!! ** ** The ONLY reason we don't copy the details themselves is because ** somewhere down the line (usually in the IO subsystem) they're ** copied anyway */ case MXDM_GETCONTROLDETAILS: pmxcd = (LPMIXERCONTROLDETAILS)GETVDMPTR( dwParam1 ); CopyMemory(&mxcdA, pmxcd, sizeof(mxcdA)); mxcdA.paDetails = GETVDMPTR( pmxcd->paDetails ); dwRet = mixerGetControlDetailsA(hmixobj, &mxcdA, dwParam2); break; case MXDM_SETCONTROLDETAILS: pmxcd = (LPMIXERCONTROLDETAILS)GETVDMPTR( dwParam1 ); CopyMemory(&mxcdA, pmxcd, sizeof(mxcdA)); mxcdA.paDetails = GETVDMPTR( pmxcd->paDetails ); dwRet = mixerSetControlDetails( hmixobj, &mxcdA, dwParam2 ); break; default: dprintf3(( "Unkown mixer message 0x%X", uMsg )); dwRet = mixerMessage( (HMIXER)hmixobj, uMsg, dwParam1, dwParam2 ); break; } dprintf3(( "-> 0x%X", dwRet )); return dwRet; } /*****************************Private*Routine******************************\ * GetLineInfo * * Copies fields from the 16 bit line info structure to the 32 bit line info * structure. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void GetLineInfo( LPMIXERLINE16 lpline16, LPMIXERLINEA lpline32 ) { CopyMemory( lpline32, (LPVOID)lpline16, FIELD_OFFSET(MIXERLINEA, Target.vDriverVersion ) ); lpline32->Target.vDriverVersion = (DWORD)lpline16->Target.vDriverVersion; CopyMemory( lpline32->Target.szPname, lpline16->Target.szPname, MAXPNAMELEN ); lpline32->cbStruct += sizeof(UINT) - sizeof(WORD); } /*****************************Private*Routine******************************\ * PutLineInfo * * Copies fields from the 32 bit line info structure to the 16 bit line info * structure. * * History: * 22-11-93 - StephenE - Created * \**************************************************************************/ void PutLineInfo( LPMIXERLINE16 lpline16, LPMIXERLINEA lpline32 ) { CopyMemory( (LPVOID)lpline16, lpline32, FIELD_OFFSET(MIXERLINEA, Target.vDriverVersion ) ); lpline16->Target.vDriverVersion = (WORD)lpline32->Target.vDriverVersion; CopyMemory( lpline16->Target.szPname, lpline32->Target.szPname, MAXPNAMELEN ); lpline16->cbStruct -= sizeof(UINT) - sizeof(WORD); } /******************************Public*Routine******************************\ * WOW32ResolveMultiMediaHandle * * * * History: * dd-mm-93 - StephenE - Created * \**************************************************************************/ BOOL APIENTRY WOW32ResolveMultiMediaHandle( UINT uHandleType, UINT uMappingDirection, WORD wHandle16_In, LPWORD lpwHandle16_Out, DWORD dwHandle32_In, LPDWORD lpdwHandle32_Out ) { BOOL fReturn = FALSE; DWORD dwHandle32; WORD wHandle16; HANDLE h; /* ** Protect ourself from being given a duff pointer. */ try { if ( uMappingDirection == WOW32_DIR_16IN_32OUT ) { dwHandle32 = 0L; if ( wHandle16_In != 0 ) { switch ( uHandleType ) { case WOW32_WAVEIN_HANDLE: case WOW32_WAVEOUT_HANDLE: case WOW32_MIDIOUT_HANDLE: case WOW32_MIDIIN_HANDLE: EnterCriticalSection(&HandleListCritSec); h = GetHandleFirst(); while ( h ) { if ( GetWOWHandle(h) == wHandle16_In ) { dwHandle32 = (DWORD)h; break; } h = GetHandleNext(h); } LeaveCriticalSection(&HandleListCritSec); break; } *lpdwHandle32_Out = dwHandle32; if ( dwHandle32 ) { fReturn = TRUE; } } } else if ( uMappingDirection == WOW32_DIR_32IN_16OUT ) { switch ( uHandleType ) { case WOW32_WAVEIN_HANDLE: case WOW32_WAVEOUT_HANDLE: case WOW32_MIDIOUT_HANDLE: case WOW32_MIDIIN_HANDLE: wHandle16 = GetWOWHandle(dwHandle32_In); break; } *lpwHandle16_Out = wHandle16; if ( wHandle16 ) { fReturn = TRUE; } } } except( EXCEPTION_EXECUTE_HANDLER ) { fReturn = FALSE; } return fReturn; }