/* drvproc.c contains MMSYSTEMs DriverProc Copyright (c) Microsoft Corporation 1990. All rights reserved */ #include #include #include "mmsystem.h" #include "mmsysi.h" #include "drvr.h" #include "mmioi.h" extern IOProcMapEntry NEAR * gIOProcMapHead; // in MMIO.C /**************************************************************************** internal prototypes ****************************************************************************/ static void FAR PASCAL SetPrivateProfileInt(LPSTR szSection, LPSTR szKey, int i, LPSTR szIniFile); static BYTE fFirstTime=TRUE; // First enable extern BOOL FAR PASCAL DrvLoad(void); // in init.c extern BOOL FAR PASCAL DrvFree(void); extern char far szStartupSound[]; // in mmwnd.c static SZCODE szExitSound[] = "SystemExit"; #ifdef DEBUG_RETAIL extern char far szMMSystem[]; extern char far szSystemIni[]; extern char far szDebugOutput[]; extern char far szMci[]; // extern WORD fDebugOutput; extern int DebugmciSendCommand; // in MCI.C #ifdef DEBUG extern char far szDebug[]; extern WORD fDebug; #endif #endif void NEAR PASCAL AppExit(HTASK hTask, BOOL fNormalExit); /***************************************************************************** * * @doc INTERNAL * * @api LRESULT | DriverProc | This is the standard DLL entry point. It is * called from user (3.1) or mmsound.drv (3.0) when MMSYSTEM.DLL is * loaded, enabled, or disabled. * ****************************************************************************/ LRESULT CALLBACK DriverProc( DWORD dwDriver, HDRVR hDriver, UINT wMessage, LPARAM lParam1, LPARAM lParam2 ) { switch (wMessage) { case DRV_LOAD: // // first load message, initialize mmsystem. // sent from USER when loading drivers from drivers= line // if (fFirstTime) return (LRESULT)(LONG)DrvLoad(); // // a normal load message, a app is trying to open us // with OpenDriver() // break; // return success all other times (1L) case DRV_FREE: // // a free message, this is send just before the DLL is unloaded // by the driver interface. // // sent by user just before system exit, after sending // the DRV_DISABLE message. // DrvFree(); break; // return success (1L) case DRV_OPEN: // FALL-THROUGH case DRV_CLOSE: break; // return success (1L) case DRV_ENABLE: DOUT("MMSYSTEM: Enable\r\n"); fFirstTime = FALSE; break; // return success (1L) case DRV_DISABLE: DOUT("MMSYSTEM: Disable\r\n"); break; // return success (1L) // // sent when a application is terminating // // lParam1: // DRVEA_ABNORMALEXIT // DRVEA_NORMALEXIT // case DRV_EXITAPPLICATION: AppExit(GetCurrentTask(), (BOOL)lParam1 == DRVEA_NORMALEXIT); break; case DRV_EXITSESSION: sndPlaySound(szExitSound, SND_SYNC | SND_NODEFAULT); break; #ifdef DEBUG_RETAIL case MM_GET_DEBUG: break; case MM_GET_DEBUGOUT: return (LRESULT)(LONG)fDebugOutput; case MM_SET_DEBUGOUT: fDebugOutput = (BYTE)(LONG)lParam1; SetPrivateProfileInt(szMMSystem,szDebugOutput,fDebugOutput,szSystemIni); break; case MM_GET_MCI_DEBUG: return (LRESULT)(LONG)DebugmciSendCommand; case MM_SET_MCI_DEBUG: DebugmciSendCommand = (WORD)(LONG)lParam1; SetPrivateProfileInt(szMMSystem,szMci,DebugmciSendCommand,szSystemIni); break; #ifdef DEBUG case MM_GET_MM_DEBUG: return (LRESULT)(LONG)fDebug; case MM_SET_MM_DEBUG: fDebug = (BYTE)(LONG)lParam1; SetPrivateProfileInt(szMMSystem,szDebug,fDebug,szSystemIni); break; #ifdef DEBUG case MM_DRV_RESTART: break; #endif case MM_HINFO_MCI: if ((HLOCAL)(LONG)lParam2 == (HLOCAL)NULL) return (LRESULT)(LONG)MCI_wNextDeviceID; if (MCI_VALID_DEVICE_ID((UINT)(LONG)lParam1)) { *(LPMCI_DEVICE_NODE)lParam2 = *MCI_lpDeviceList[(UINT)(LONG)lParam1]; break; } return (LRESULT)FALSE; case MM_HINFO_NEXT: if ((HLOCAL)(LONG)lParam1 == (HLOCAL)NULL) return (LRESULT)(LONG)(UINT)GetHandleFirst(); else return (LRESULT)(LONG)(UINT)GetHandleNext((HLOCAL)(LONG)lParam1); case MM_HINFO_TASK: return (LRESULT)(LONG)(UINT)GetHandleOwner((HLOCAL)(LONG)lParam1); case MM_HINFO_TYPE: return GetHandleType((HLOCAL)(LONG)lParam1); #endif // ifdef DEBUG #endif // ifdef DEBUG_RETAIL default: return DefDriverProc(dwDriver, hDriver, wMessage, lParam1, lParam2); } return (LRESULT)1L; } /***************************************************************************** * @doc INTERNAL * * @func void | AppExit | * a application is exiting, free any MMSYS resources it may own * ****************************************************************************/ void NEAR PASCAL AppExit(HTASK hTask, BOOL fNormalExit) { HLOCAL h; HLOCAL hNext; WORD wDebugFlags; UINT wDeviceID; UINT cFree; UINT cHeap; UINT err; if (hdrvDestroy != (HLOCAL)-1) { DOUT("MMSYSTEM: Hey! AppExit has been re-entered!\r\n"); } #ifdef DEBUG if (!fNormalExit) ROUT("MMSYSTEM: Abnormal app termination"); #endif // // either log a error or a warning depending on wether it was // a normal exit or not. // if (fNormalExit) wDebugFlags = DBF_MMSYSTEM | DBF_ERROR; else wDebugFlags = DBF_MMSYSTEM | DBF_WARNING; // DBF_TRACE? // // now free MCI devices. // for (wDeviceID=1; wDeviceIDhCreatorTask == hTask) { DebugErr2(wDebugFlags, "MCI device %ls (%d) not released.", MCI_lpDeviceList[wDeviceID]->lpstrInstallName, wDeviceID); // // clear these to force MCI to close the device // MCI_lpDeviceList[wDeviceID]->dwMCIFlags &= ~MCINODE_ISCLOSING; MCI_lpDeviceList[wDeviceID]->dwMCIFlags &= ~MCINODE_ISAUTOCLOSING; err = (UINT)mciSendCommand(wDeviceID, MCI_CLOSE, NULL, NULL); #ifdef DEBUG if (err != 0) DebugErr1(DBF_WARNING, "Unable to close MCI device (err = %04X).", err); #endif } } // // free all WAVE/MIDI/MMIO handles // start_over: for (h=GetHandleFirst(); h; h=hNext) { hNext = GetHandleNext(h); if (GetHandleOwner(h) == hTask) { // // hack for the wave/midi mapper, always free handle's backward. // if (hNext && GetHandleOwner(hNext) == hTask) continue; // // do this so even if the close fails we will not // find it again. // SetHandleOwner(h, NULL); // // set the hdrvDestroy global so DriverCallback will not // do anything for this device // hdrvDestroy = h; switch(GetHandleType(h)) { case TYPE_WAVEOUT: DebugErr1(wDebugFlags, "WaveOut handle (%04X) was not released.", h); waveOutReset((HWAVEOUT)h); err = waveOutClose((HWAVEOUT)h); break; case TYPE_WAVEIN: DebugErr1(wDebugFlags, "WaveIn handle (%04X) was not released.", h); waveInStop((HWAVEIN)h); waveInReset((HWAVEIN)h); err = waveInClose((HWAVEIN)h); break; case TYPE_MIDIOUT: DebugErr1(wDebugFlags, "MidiOut handle (%04X) was not released.", h); midiOutReset((HMIDIOUT)h); err = midiOutClose((HMIDIOUT)h); break; case TYPE_MIDIIN: DebugErr1(wDebugFlags, "MidiIn handle (%04X) was not released.", h); midiInStop((HMIDIIN)h); midiInReset((HMIDIIN)h); err = midiInClose((HMIDIIN)h); break; case TYPE_MMIO: DebugErr1(wDebugFlags, "MMIO handle (%04X) was not released.", h); err = mmioClose((HMMIO)h, 0); break; case TYPE_IOPROC: DebugErr1(wDebugFlags, "MMIO handler '%4.4ls' not removed.", (LPSTR)&((IOProcMapEntry*)h)->fccIOProc); err = !mmioInstallIOProc(((IOProcMapEntry*)h)->fccIOProc, NULL, MMIO_REMOVEPROC); break; } #ifdef DEBUG if (err != 0) DebugErr1(DBF_WARNING, "Unable to close handle (err = %04X).", err); #endif // // unset hdrvDestroy so DriverCallback will work. // some hosebag drivers (like the TIMER driver) // may pass NULL as their driver handle. // so dont set it to NULL. // hdrvDestroy = (HLOCAL)-1; // // the reason we start over is because a single free may cause // multiple free's (ie MIDIMAPPER has another HMIDI open, ...) // goto start_over; } } // // what about timeSetEvent()!!!??? // // any outstanding timer events till be killed by the timer driver // it self. // mciAppExit( hTask ); // shrink our heap, down to minimal size. if ((cFree = LocalCountFree()) > 1024) { cHeap = LocalHeapSize() - (cFree - 512); LocalShrink(NULL, cHeap); DPRINTF(("MMSYSTEM: Shrinking the heap (%d)\r\n", cHeap)); } } #ifdef DEBUG_RETAIL /***************************************************************************** * @doc INTERNAL * * @func void | SetPrivateProfileInt | windows should have this function * * @comm used by DriverProc to set debug state in SYSTEM.INI * ****************************************************************************/ static void FAR PASCAL SetPrivateProfileInt(LPSTR szSection, LPSTR szKey, int i, LPSTR szIniFile) { char ach[32] ; if (i != (int)GetPrivateProfileInt(szSection, szKey, ~i, szIniFile)) { wsprintf(ach, "%d", i); WritePrivateProfileString(szSection, szKey, ach, szIniFile); } } #endif //ifdef DEBUG_RETAIL