You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
11 KiB
379 lines
11 KiB
/*
|
|
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
|