windows-nt/Source/XPSP1/NT/base/mvdm/wow16/mmsystem/drvproc.c
2020-09-26 16:20:57 +08:00

380 lines
11 KiB
C

/*
drvproc.c
contains MMSYSTEMs DriverProc
Copyright (c) Microsoft Corporation 1990. All rights reserved
*/
#include <windows.h>
#include <mmsysver.h>
#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; wDeviceID<MCI_wNextDeviceID; wDeviceID++)
{
if (MCI_VALID_DEVICE_ID(wDeviceID) && MCI_lpDeviceList[wDeviceID]->hCreatorTask == 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