windows-nt/Source/XPSP1/NT/multimedia/media/winmm/drvrrare.c
2020-09-26 16:20:57 +08:00

1204 lines
34 KiB
C

/******************************************************************************
Copyright (c) 1985-1998 Microsoft Corporation
Title: drvrrare.c - Installable driver code. Less common code
Version: 1.00
Date: 10-Jun-1990
Author: DAVIDDS ROBWI
------------------------------------------------------------------------------
Change log:
DATE REV DESCRIPTION
----------- ----- -----------------------------------------------------------
28-FEB-1992 ROBINSP Port to NT
23-Apr-1992 StephenE Unicoded
22-Apr-1993 RobinSp Add NT multithread protection
Multithread design :
Uses 2 critical sections :
DriverListCritSec :
protects the list of drivers :
hInstalledDriverList - handle of global driver list
cInstalledDrivers - high water mark of installed drivers
so that only 1 thread at a time has the list locked and can refer
to or update it.
DriverLoadFreeCritSec
Makes sure that actual loads and frees of drivers don't overlap
and that the actual loading of a driver via LoadLibrary coincides
with its first message being DRV_LOAD.
This can easily happen if the DRV_OPEN from another thread can get
in before the DRV_LOAD has been sent.
*****************************************************************************/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#define MMNOSOUND
#define MMNOWAVE
#define MMNOMIDI
#define MMNOSEQ
#define MMNOTIMER
#define MMNOJOY
#define MMNOMCI
#define NOTIMERDEV
#define NOJOYDEV
#define NOMCIDEV
#define NOSEQDEV
#define NOWAVEDEV
#define NOMIDIDEV
#define NOTASKDEV
#include <winmmi.h>
#include "drvr.h"
extern HANDLE hInstalledDriverList; // List of installed driver instances
extern int cInstalledDrivers; // High water count of installed driver instances
extern DWORD FAR PASCAL DriverProc(DWORD dwID, HDRVR hdrv, UINT msg, DWORD dw1, DWORD dw2);
/* Support for using 3.1 APIs if available */
typedef HANDLE (FAR PASCAL *OPENDRIVER31)(LPCSTR, LPCSTR, LPARAM);
typedef LONG (FAR PASCAL *CLOSEDRIVER31)(HANDLE, LPARAM, LPARAM);
typedef HANDLE (FAR PASCAL *GETDRIVERMODULEHANDLE31)(HANDLE);
typedef LONG (FAR PASCAL *SENDDRIVERMESSAGE31)(HANDLE, UINT, LPARAM, LPARAM);
typedef LONG (FAR PASCAL *DEFDRIVERPROC31)(DWORD, HANDLE, UINT, LPARAM, LPARAM);
OPENDRIVER31 lpOpenDriver;
CLOSEDRIVER31 lpCloseDriver;
GETDRIVERMODULEHANDLE31 lpGetDriverModuleHandle;
SENDDRIVERMESSAGE31 lpSendDriverMessage;
DEFDRIVERPROC31 lpDefDriverProc;
#if 0
BOOL fUseWinAPI = 0;
// NOTE: fUseWinAPI is not being used at present
// as we only have a partial device loading story
#endif
/***************************************************************************
strings
****************************************************************************/
#if 0
extern char far szBoot[];
extern char far szUser[];
extern char far szOpenDriver[];
extern char far szCloseDriver[];
extern char far szDrvModuleHandle[];
extern char far szSendDriverMessage[];
extern char far szDefDriverProc[];
extern char far szDriverProc[];
#endif
/***************************************************************************
*
* @doc DDK
*
* @api LONG | DrvClose | This function closes an open driver
* instance and decrements
* the driver's open count. Once the driver's open count becomes zero,
* the driver is unloaded.
*
* @parm HANDLE | hDriver | Specifies the handle of the installable
* driver to close.
*
* @parm LPARAM | lParam1 | Specifies the first message parameter for
* the DRV_CLOSE message. This data is passed directly to the driver.
*
* @parm LPARAM | lParam2 | Specifies the second message parameter
* for DRV_CLOSE message. This data is passed directly to the driver.
*
* @rdesc Returns zero if the driver aborted the close;
* otherwise, returns the return result from the driver.
* @xref DrvOpen
*
***************************************************************************/
LRESULT APIENTRY DrvClose(HANDLE hDriver, LPARAM lParam1, LPARAM lParam2)
{
/* The driver will receive the following message sequence:
*
* DRV_CLOSE
* if DRV_CLOSE returns non-zero
* if driver usage count = 1
* DRV_DISABLE
* DRV_FREE
*/
if (fUseWinAPI)
return ((*lpCloseDriver)(hDriver, lParam1, lParam2));
else
return InternalCloseDriver((UINT)(UINT_PTR)hDriver, lParam1, lParam2, TRUE);
}
/***************************************************************************
*
* @doc DDK
*
* @api LONG | DrvOpen | This function opens an installable driver.
* The first time a driver is opened it is loaded
* and enabled. A driver must be opened before messages are sent
* to it.
*
* @parm LPSTR | szDriverName | Specifies a far pointer to a
* null-terminated character string
* containing a driver filename or a keyname from a
* section of the SYSTEM.INI file.
*
* @parm LPSTR | szSectionName | Specifies a far pointer to a
* null-terminated character string containing the name of
* the driver section to search. If <p szSectionName> is
* not null, the specified section of the SYSTEM.INI file is
* searched instead of the [Drivers] section. If
* <p szSectionName> is null, the default [Drivers] section is used.
*
* @parm LPARAM | lParam | Specifies a message parameter to
* pass to the driver procedure with the <m DRV_OPEN> message.
*
* @rdesc Returns a handle to the driver.
*
* @comm Installable drivers must export a <f DriverProc> routine of
* the form:
*
* @cb LONG FAR PASCAL | DriverProc | This entry point receives the
* messages sent to an installable driver. This entry will always
* handle the system messages as a minimum set of messages.
*
* @parm DWORD | dwDriverIdentifier | Specifies the device driver
* identifier.
*
* @parm HANDLE | hDriver | Specifies the device driver handle.
*
* @parm UINT | wMessage | Specifies the message for the device
* driver.
*
* @parm LONG | lParm1 | Specifies message dependent data.
*
* @parm LONG | lParm2 | Specifies message dependent data.
*
* @xref DrvClose
*
****************************************************************************/
HANDLE APIENTRY DrvOpen( LPCWSTR szDriverName,
LPCWSTR szSectionName,
LPARAM lParam2)
{
/* The driver will receive the following message sequence:
*
* if driver not loaded and can be found
* DRV_LOAD
* if DRV_LOAD returns non-zero
* DRV_ENABLE
* if driver loaded correctly
* DRV_OPEN
*/
HDRVR hdrv;
if (fUseWinAPI) {
/*------------------------------------------------------------*\
* UNICODE: convert szDriver and szSectionName to ascii
* and then call WIN31 driver
\*------------------------------------------------------------*/
LPSTR aszDriver;
LPSTR aszSectionName;
INT lenD;
INT lenS;
lenD = lstrlenW( szDriverName ) * sizeof( WCHAR ) + sizeof( WCHAR );
aszDriver = HeapAlloc( hHeap, 0, lenD );
if ( aszDriver == (LPSTR)NULL ) {
return NULL;
}
lenS = lstrlenW( szSectionName ) * sizeof( WCHAR ) + sizeof( WCHAR );
aszSectionName = HeapAlloc( hHeap, 0, lenS );
if ( aszSectionName == (LPSTR)NULL ) {
HeapFree( hHeap, 0, aszDriver );
return NULL;
}
// Unicode to Ascii
UnicodeStrToAsciiStr( (PBYTE)aszDriver,
(PBYTE)aszDriver + lenD,
szDriverName );
UnicodeStrToAsciiStr( (PBYTE)aszSectionName,
(PBYTE)aszSectionName + lenS,
szSectionName );
hdrv = (HDRVR)((*lpOpenDriver)( aszDriver, aszSectionName, lParam2 ));
HeapFree( hHeap, 0, aszDriver );
HeapFree( hHeap, 0, aszSectionName );
}
else {
dprintf2(("DrvOpen(%ls), Looking in Win.ini [%ls]", szDriverName, szSectionName ? szSectionName : L"NULL !!" ));
hdrv = (HDRVR)InternalOpenDriver(szDriverName, szSectionName, lParam2, TRUE);
}
#if DBG
if (hdrv) {
WCHAR ach[255];
static SZCODE szFormat[] = "DrvOpen(): Opened %ls (%ls)\r\n";
GetModuleFileNameW( DrvGetModuleHandle( hdrv ),
ach,
sizeof(ach) / sizeof(WCHAR)
);
dprintf2((szFormat, szDriverName, ach));
}
#endif
return (HANDLE)hdrv;
}
/***************************************************************************
*
* @doc DDK
*
* @api HANDLE | DrvGetModuleHandle | This function returns the library
* module handle of the specified installable driver.
*
* @parm HANDLE | hDriver | Specifies the handle of the installable driver.
*
* @rdesc Returns the module handle of the driver specified by the
* driver handle <p hDriver>.
*
* @comm A module handle is not the same as an installable driver handle.
*
***************************************************************************/
HMODULE APIENTRY DrvGetModuleHandle(HDRVR hDriver)
{
LPDRIVERTABLE lpdt;
HMODULE h = 0;
if (fUseWinAPI)
return ((*lpGetDriverModuleHandle)(hDriver));
DrvEnter();
if (hDriver && ((int)(UINT_PTR)hDriver <= cInstalledDrivers))
{
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
h = (HMODULE)lpdt[(UINT)(UINT_PTR)hDriver-1].hModule;
GlobalUnlock(hInstalledDriverList);
}
DrvLeave();
return(h);
}
LRESULT FAR PASCAL InternalCloseDriver(UINT hDriver,
LPARAM lParam1,
LPARAM lParam2,
BOOL fSendDisable)
{
LRESULT result;
// check handle in valid range.
DrvEnter();
if ((int)hDriver > cInstalledDrivers) {
DrvLeave();
return(FALSE);
}
DrvLeave();
result = DrvSendMessage((HANDLE)(UINT_PTR)hDriver, DRV_CLOSE, lParam1, lParam2);
if (result) {
InternalFreeDriver(hDriver, fSendDisable);
}
return(result);
}
LRESULT FAR PASCAL InternalOpenDriver( LPCWSTR szDriverName,
LPCWSTR szSectionName,
LPARAM lParam2,
BOOL fSendEnable)
{
DWORD_PTR hDriver;
LPDRIVERTABLE lpdt;
LRESULT result;
WCHAR sz[128];
if (0 != (hDriver = InternalLoadDriver( szDriverName,
szSectionName,
sz,
sizeof(sz) / sizeof(WCHAR),
fSendEnable ) ) )
{
/*
* Set the driver identifier to the DRV_OPEN call to the
* driver handle. This will let people build helper functions
* that the driver can call with a unique identifier if they
* want to.
*/
DrvEnter();
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
lpdt[hDriver-1].dwDriverIdentifier = (DWORD)hDriver;
GlobalUnlock(hInstalledDriverList);
DrvLeave();
result = DrvSendMessage( (HANDLE)hDriver, DRV_OPEN, (LPARAM)(LPSTR)sz,
lParam2);
if (!result) {
dprintf1(("DrvSendMessage failed, result = %8x",result));
InternalFreeDriver((UINT)hDriver, fSendEnable);
} else {
DrvEnter();
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
lpdt[hDriver-1].dwDriverIdentifier = result;
GlobalUnlock(hInstalledDriverList);
DrvLeave();
result = hDriver;
}
}
else
result = 0L;
return result;
}
/***************************************************************************
*
* @doc INTERNAL
*
* @api LONG | InternalLoadDriver | Loads an installable driver. If this is
* the first time that the driver is opened, the driver will be loaded
* and enabled.
*
* @parm LPSTR | szDriverName | A null-terminated character string
* containing a driver filename or a keyname from the [Drivers]
* section of system.ini.
*
* @parm LPSTR | szSectionName | A null-terminated character string
* that specifies a driver section to search. If szSectionName is
* not null, the specified section of system.ini is searched instead
* of the [Drivers] section. If szSectionName is null, the
* default [Drivers] section is used.
*
* @parm LPSTR | lpstrTail | caller supplied buffer to return the "tail"
* of the system.ini line in. The tail is any characters that follow
* the filename.
*
* @parm UINT | cbTail | size of supplied buffer as a character count.
*
* @parm BOOL | fSendEnable | TRUE if driver should be enabled
*
* @rdesc Returns a long whose loword is the handle to the driver and whose
* high word is an error code or the module handle
*
* @xref InternalOpenDriver
*
****************************************************************************/
LRESULT FAR PASCAL InternalLoadDriver(LPCWSTR szDriverName,
LPCWSTR szSectionName,
LPWSTR lpstrTail,
UINT cbTail,
BOOL fSendEnable)
{
int index;
LPDRIVERTABLE lpdt;
LONG result;
HANDLE h;
DRIVERPROC lpDriverEntryPoint;
/* The driver will receive the following message sequence:
*
* if driver not loaded and can be found
* DRV_LOAD
* if DRV_LOAD returns non-zero and fSendEnable
* DRV_ENABLE
*/
/* Allocate a table entry */
// This can be made more efficient by keeping a count of how many drivers
// we have loaded and how many entries there are in the table. Then when
// we should reuse an entry we would not reallocate - unlike at present.
DrvEnter();
if (!hInstalledDriverList) {
h = GlobalAlloc(GHND, (DWORD)((UINT)sizeof(DRIVERTABLE)));
// Note: it is valid to assume that the memory has been ZERO'ed
// ...might want to add a debug WinAssert to verify...
} else {
/* Alloc space for the next driver we will install. We may not really
* install the driver in the last entry but rather in an intermediate
* entry which was freed.
*/
h = GlobalReAlloc(hInstalledDriverList,
(DWORD)((UINT)sizeof(DRIVERTABLE)*(cInstalledDrivers+1)),
GHND);
// Note: it is valid to assume that the new memory has been ZERO'ed
// ...might want to add a debug WinAssert to verify...
}
if (!h) {
dprintf1(("Failed to allocate space for Installed driver list"));
DrvLeave();
return(0L);
}
cInstalledDrivers++;
hInstalledDriverList = h;
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
/* find an unused entry in the table */
for (index=0;index<cInstalledDrivers;index++)
{
if (lpdt[index].hModule == 0 && !lpdt[index].fBusy)
break;
}
if (index+1 < cInstalledDrivers) {
/* The driver went into an unused entry in the middle somewhere so
* restore table size.
*/
cInstalledDrivers--;
}
/* Protect the entry we just allocated so that OpenDriver
* can be called at any point from now on without overriding
* the entry
*/
lpdt[index].fBusy = 1;
GlobalUnlock(hInstalledDriverList);
DrvLeave();
/*
* Make sure Loadlibrary and DRV_LOAD messages to driver are consistent
*/
EnterCriticalSection(&DriverLoadFreeCritSec);
h = LoadAliasedLibrary( szDriverName,
szSectionName ? szSectionName : wszDrivers,
wszSystemIni,
lpstrTail,
cbTail );
if (0 == h)
{
dprintf1(("Failed to LoadLibrary %ls Error is %d", szDriverName, GetLastError()));
LeaveCriticalSection(&DriverLoadFreeCritSec);
result = 0;
goto LoadCleanUp;
}
lpDriverEntryPoint =
(DRIVERPROC)GetProcAddress(h, DRIVER_PROC_NAME);
if (lpDriverEntryPoint == NULL)
{
// Driver does not have correct entry point
dprintf1(("Cannot find entry point %ls in %ls", DRIVER_PROC_NAME, szDriverName));
FreeLibrary(h);
LeaveCriticalSection(&DriverLoadFreeCritSec);
result = 0L;
goto LoadCleanUp;
}
DrvEnter();
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
lpdt[index].lpDriverEntryPoint = lpDriverEntryPoint;
// Set hModule here so that GetDrvrUsage() and DrvSendMessage() work
lpdt[index].hModule = (UINT_PTR)h;
GlobalUnlock(hInstalledDriverList);
DrvLeave();
if (GetDrvrUsage(h) == 1)
{
LRESULT LoadResult;
// First instance of the driver.
LoadResult = DrvSendMessage((HANDLE)(UINT_PTR)(index+1), DRV_LOAD, 0L, 0L);
DrvEnter();
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
if (!LoadResult)
{
// Driver failed load call.
lpdt[index].lpDriverEntryPoint = NULL;
lpdt[index].hModule = (UINT_PTR)NULL;
GlobalUnlock(hInstalledDriverList);
DrvLeave();
FreeLibrary(h);
LeaveCriticalSection(&DriverLoadFreeCritSec);
result = 0L;
goto LoadCleanUp;
}
lpdt[index].fFirstEntry = 1;
GlobalUnlock(hInstalledDriverList);
DrvLeave();
if (fSendEnable) {
DrvSendMessage((HANDLE)(UINT_PTR)(index+1), DRV_ENABLE, 0L, 0L);
}
}
LeaveCriticalSection(&DriverLoadFreeCritSec);
result = index + 1;
LoadCleanUp:
DrvEnter();
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
lpdt[index].fBusy = 0;
GlobalUnlock(hInstalledDriverList);
DrvLeave();
return(result);
}
/***************************************************************************
*
* @doc INTERNAL
*
* @api UINT | InternalFreeDriver | This function decrements the usage
* count of the specified driver. When the driver usage count reaches
* 0, the driver is sent a DRV_FREE message and then freed.
*
* @parm HANDLE | hDriver | Driver handle of the installable driver to be
* freed.
*
* @parm BOOL | fSendDisable | TRUE if a DRV_DISABLE message should be sent
* before the DRV_FREE message if the usage count reaches zero.
*
* @rdesc Returns current driver usage count.
*
* @comm Using LoadLibrary or FreeLibrary directly on a library installed
* with OpenDriver will break this function. A module handle is not
* the same as an installable driver handle.
*
* @xref CloseDriver
*
***************************************************************************/
UINT FAR PASCAL InternalFreeDriver(UINT hDriver, BOOL fSendDisable)
{
LPDRIVERTABLE lpdt;
UINT w;
int index;
HMODULE hModule;
/* The driver will receive the following message sequence:
*
* if usage count of driver is 1
* DRV_DISABLE (normally)
* DRV_FREE
*/
EnterCriticalSection(&DriverLoadFreeCritSec);
DrvEnter();
if ((int)hDriver > cInstalledDrivers || !hDriver) {
DrvLeave();
LeaveCriticalSection(&DriverLoadFreeCritSec);
return(0);
}
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
/*
* If the driver usage count is 1, then send
* free and disable messages.
*/
/*
Clear dwDriverIdentifier so that the sendmessage for
DRV_OPEN and DRV_ENABLE have dwDriverIdentifier = 0
if an entry gets reused and so that the DRV_DISABLE and DRV_FREE
messages below also get dwDriverIdentifier = 0.
*/
lpdt[hDriver-1].dwDriverIdentifier = 0;
hModule = (HMODULE)lpdt[hDriver-1].hModule;
GlobalUnlock(hInstalledDriverList);
DrvLeave();
w = GetDrvrUsage((HANDLE)hModule);
if (w == 1)
{
if (fSendDisable)
DrvSendMessage((HANDLE)(UINT_PTR)hDriver, DRV_DISABLE, 0L, 0L);
DrvSendMessage((HANDLE)(UINT_PTR)hDriver, DRV_FREE, 0L, 0L);
}
FreeLibrary(hModule);
DrvEnter();
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
/* Only one entry for the driver in the driver list has the first
* instance flag set. This is to make it easier to handle system
* messages that only need to be sent to a driver once.
*
* To maintain the flag, we must set the flag in one of the other
* entries if we remove the driver entry with the flag set.
*
* Note that InternalFreeDriver returns the new usage count of
* the driver so if it is zero, we know that there are no other
* entries for the driver in the list and so we don't have to
* do this loop.
*/
if (lpdt[hDriver - 1].fFirstEntry) {
for (index=0;index<cInstalledDrivers;index++)
if (lpdt[index].hModule == lpdt[hDriver-1].hModule && !lpdt[index].fFirstEntry)
{
lpdt[index].fFirstEntry = 1;
break;
}
}
// Clear the rest of the table entry
lpdt[hDriver-1].hModule = 0; // this indicates free entry
lpdt[hDriver-1].fFirstEntry = 0; // this is also just to be tidy
lpdt[hDriver-1].lpDriverEntryPoint = 0; // this is also just to be tidy
GlobalUnlock(hInstalledDriverList);
DrvLeave();
LeaveCriticalSection(&DriverLoadFreeCritSec);
return(w-1);
}
#if 0
UINT GetWinVer()
{
WORD w = GetVersion();
return (w>>8) | (w<<8);
}
#endif
#if 0
void NEAR PASCAL DrvInit(void)
{
HANDLE hlibUser;
LPDRIVERTABLE lpdt;
/* If the window's driver interface is present then use it.
*/
DOUT(("DrvInit\r\n"));
hlibUser = GetModuleHandle(szUser);
if(lpOpenDriver = (OPENDRIVER31)GetProcAddress(hlibUser,szOpenDriver))
fUseWinAPI = TRUE;
else
{
fUseWinAPI = FALSE;
DOUT((" - No Windows Driver I/F detected. Using MMSYSTEM\r\n"));
//
// force MMSYSTEM into the driver table, without enabling it.
//
DrvEnter();
cInstalledDrivers = 0;
hInstalledDriverList = GlobalAlloc(GHND|GMEM_SHARE, (DWORD)((UINT)sizeof(DRIVERTABLE)));
#if DBG
if (hInstalledDriverList == NULL)
{
DOUT(("no memory for driver table\r\n"));
// FatalExit(-1);
return;
}
#endif
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
//
// NOTE! we are not setting fFirstEntry==TRUE
//
// because under windows 3.0 MMSOUND will enable/disable us
// we *dont* wan't the driver interface doing it!
//
lpdt->lpDriverEntryPoint = (DRIVERPROC)DriverProc;
lpdt->hModule = ghInst;
lpdt->fFirstEntry = 0;
GlobalUnlock(hInstalledDriverList);
DrvLeave();
}
if (fUseWinAPI)
{
DOUT((" - Windows Driver I/F detected\r\n"));
if (GetWinVer() < 0x30A)
DOUT(("MMSYSTEM: WARNING !!! WINDOWS DRIVER I/F BUT VERSION LESS THAN 3.1\r\n"));
// link to the relevant user APIs.
lpCloseDriver = (CLOSEDRIVER31)GetProcAddress(hlibUser, szCloseDriver);
lpGetDriverModuleHandle = (GETDRIVERMODULEHANDLE31)GetProcAddress(hlibUser, szDrvModuleHandle);
lpSendDriverMessage = (SENDDRIVERMESSAGE31)GetProcAddress(hlibUser, szSendDriverMessage);
lpDefDriverProc = (DEFDRIVERPROC31)GetProcAddress(hlibUser, szDefDriverProc);
}
}
#endif
#if 0
/***************************************************************************
*
* @doc INTERNAL
*
* @api void | InternalInstallDriverChain | This function loads the
* drivers specified on the Drivers= line of the [Boot] section
* of system.ini. The Drivers are loaded but not opened.
*
* @rdesc None
*
***************************************************************************/
void FAR PASCAL InternalInstallDriverChain(void)
{
char szBuffer[150];
BOOL bFinished;
int iStart;
int iEnd;
if (!fUseWinAPI)
{
/* Load DLL's from DRIVERS section in system.ini
*/
szBuffer[0] = TEXT('\0');
winmmGetPrivateProfileString(szBoot, /* [Boot] section */
szDrivers, /* Drivers= */
szNull, /* Default if no match */
szBuffer, /* Return buffer */
sizeof(szBuffer),
szSystemIni);
if (!*szBuffer) {
return;
}
bFinished = FALSE;
iStart = 0;
while (!bFinished)
{
iEnd = iStart;
while (szBuffer[iEnd] && (szBuffer[iEnd] != ' ') &&
(szBuffer[iEnd] != ','))
iEnd++;
if (szBuffer[iEnd] == NULL)
bFinished = TRUE;
else
szBuffer[iEnd] = NULL;
/* Load and enable the driver.
*/
InternalLoadDriver(&(szBuffer[iStart]), NULL, NULL, 0, TRUE);
iStart = iEnd+1;
}
}
}
#endif
/***************************************************************************
*
* @doc INTERNAL
*
* @api void | InternalDriverEnable | This function enables all the
* currently loaded installable drivers. If the user driver i/f
* has been detected, this function will do nothing.
*
* @rdesc None
*
***************************************************************************/
void FAR PASCAL InternalDriverEnable(void)
{
if (!fUseWinAPI)
InternalBroadcastDriverMessage(1, DRV_ENABLE, 0L, 0L, IBDM_ONEINSTANCEONLY);
}
/***************************************************************************
*
* @doc INTERNAL
*
* @api void | InternalDriverDisable | This function disables all the
* currently loaded installable drivers. If the user driver I/F
* has been detected, this function will do nothing.
*
*
* @rdesc None
*
***************************************************************************/
void FAR PASCAL InternalDriverDisable(void)
{
if (!fUseWinAPI)
InternalBroadcastDriverMessage(0, DRV_DISABLE, 0L, 0L,
IBDM_ONEINSTANCEONLY | IBDM_REVERSE);
}
/***************************************************************************
*
* @doc INTERNAL
*
* @api BOOL | TestExeFormat | This function tests if the executable
* supplied is loadable as a 32-bit executable
*
* @parm LPWSTR | szExe | The file to test
*
* @rdesc BOOL | TRUE if format was OK, FALSE otherwise
*
***************************************************************************/
BOOL TestExeFormat(LPWSTR szExe)
{
HANDLE SectionHandle;
HANDLE FileHandle;
PVOID BaseAddress;
SIZE_T ViewSize;
WCHAR ExpandedName[MAX_PATH];
LPWSTR FilePart;
//
// See if it's already loaded
//
if (GetModuleHandleW(szExe)) {
return TRUE;
}
//
// Search for our DLL
//
if (!SearchPathW(NULL,
szExe,
NULL,
MAX_PATH,
ExpandedName,
&FilePart)) {
return FALSE;
}
//
// Get a handle for it
//
FileHandle = CreateFileW(ExpandedName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE) {
return FALSE;
}
//
// We create and map a section for this file as an IMAGE
// to make sure it's recognized as such
//
if (!NT_SUCCESS(NtCreateSection(
&SectionHandle,
SECTION_ALL_ACCESS,
NULL,
NULL,
PAGE_READONLY,
SEC_IMAGE,
FileHandle))) {
CloseHandle(FileHandle);
return FALSE;
}
//
// Map it whereever it will go
//
ViewSize = 0;
BaseAddress = NULL;
//
// See if the loader is happy with the format
//
if (!NT_SUCCESS(NtMapViewOfSection(SectionHandle,
NtCurrentProcess(),
&BaseAddress,
0L,
0L,
NULL,
&ViewSize,
ViewShare,
0L,
PAGE_READONLY))) {
NtClose(SectionHandle);
CloseHandle(FileHandle);
return FALSE;
}
NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
NtClose(SectionHandle);
CloseHandle(FileHandle);
return TRUE;
}
/***************************************************************************
*
* @doc INTERNAL
*
* @api HANDLE | LoadAliasedLibrary | This function loads the library module
* contained in the specified file and returns its module handle
* unless the specified name matches a keyname in the
* specified section section of the specified ini file in which case
* the library module in the file specified on the ini line is loaded.
*
* @parm LPSTR | szLibFileName | points to a null-terminated character
* string containing the filename or system.ini keyname.
*
* @parm LPSTR | szSection | points to a null-terminated character
* string containing the section name.
*
* @parm LPSTR | szIniFile | points to a null-terminated character
* string containing the ini filename.
*
* @parm LPSTR | lpstrTail | caller supplied buffer to return the "tail"
* of the system.ini line in. The tail is any characters that follow
* the filename.
*
* @parm UINT | cbTail | size of supplied buffer.
*
* @rdesc Returns the library's module handle.
*
* @xref LoadLibrary
*
***************************************************************************/
HANDLE LoadAliasedLibrary( LPCWSTR szLibFileName,
LPCWSTR szSection,
LPWSTR szIniFile,
LPWSTR lpstrTail,
UINT cbTail)
{
#define SZ_SIZE 128
#define SZ_SIZE_BYTES (SZ_SIZE * sizeof( WCHAR ))
WCHAR sz[SZ_SIZE];
LPWSTR pch;
HANDLE hReturn;
DWORD OldErrorMode;
// OFSTRUCT of;
if (!szLibFileName || !*szLibFileName)
return(NULL); // File not found
// read the filename and additional info. into sz
sz[0] = L'\0';
if (winmmGetPrivateProfileString(szSection, // ini section
szLibFileName, // key name
szLibFileName, // default if no match
sz, // return buffer
SZ_SIZE, // sizeof of return buffer
szIniFile)==0) // ini. file
{
return NULL;
}
sz[SZ_SIZE - 1] = 0;
#if 1
if (0 == lstrcmpiW(sz, L"wdmaud.drv"))
{
if (0 != lstrcmpiW(sz, szLibFileName))
{
// Squirt("LoadAliasedLibrary: [%ls:%ls]", szLibFileName, sz);
// Squirt("Should not load [%ls]", szLibFileName);
return NULL;
}
}
#endif
//
// strip off the additional info.
//
pch = (LPWSTR)sz;
//
// at exit from loop pch pts to ch after first space or null ch
//
while (*pch) {
if ( *pch == ' ' ) {
*pch++ = '\0';
break;
}
pch++;
}
//
// These lines are removed for unicode because:
// there is not a unicode version of OpenFile.
// LoadLibrary performs the same test as the one below anyway
//
// if (!GetModuleHandle( sz ) &&
// OpenFile(sz, &of, OF_EXIST|OF_READ|OF_SHARE_DENY_NONE) == -1) {
//
// return(NULL);
// }
//
// copy additional info. to lpstrTail
//
if (lpstrTail && cbTail) {
while (cbTail-- && (0 != (*lpstrTail++ = *pch++)))
;
*(lpstrTail-1) = 0;
}
//
// If we're running in the server check if it's a good image.
// The server bug checks if it tries to load bad images (LoadLibrary
// inconsistency).
//
// To do this we simulate the load process far enough to make
// the check that it's a valid image
//
if (WinmmRunningInServer && !TestExeFormat(sz)) {
return NULL;
}
//
// Disable hard error popups
//
OldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
//
// Try to load it
//
hReturn = LoadLibraryW( sz );
SetErrorMode(OldErrorMode);
return hReturn;
#undef SZ_SIZE_BYTES
#undef SZ_SIZE
}
/***************************************************************************
*
* @doc INTERNAL
*
* @api int | GetDrvrUsage | Runs through the driver list and figures
* out how many instances of this driver module handle we have.
* We use this instead of GetModuleUsage so that we can have drivers
* loaded as normal DLLs and as installable drivers.
*
* @parm HANDLE | h | Driver's module handle
*
* @rdesc Returns the library's driver usage count.
*
***************************************************************************/
int FAR PASCAL GetDrvrUsage(HANDLE h)
{
LPDRIVERTABLE lpdt;
int index;
int count;
DrvEnter();
if (!hInstalledDriverList || !cInstalledDrivers) {
DrvLeave();
return(0);
}
count = 0;
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
for (index=0;index<cInstalledDrivers;index++)
{
if (lpdt->hModule==(UINT_PTR)h)
{
count++;
}
lpdt++;
}
GlobalUnlock(hInstalledDriverList);
DrvLeave();
return(count);
}