Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

873 lines
26 KiB

/******************************************************************************
Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
Title: drvrrare.c - Installable driver code. Less common code
Version: 1.00
Date: 10-Jun-1990
Author: DAVIDDS ROBWI
*****************************************************************************/
#include <windows.h>
#include "drvr.h"
#define MMNOSOUND
#define MMNOWAVE
#define MMNOMIDI
#define MMNOSEQ
#define MMNOTIMER
#define MMNOJOY
#define MMNOMCI
#include "mmsystem.h"
#define NOTIMERDEV
#define NOJOYDEV
#define NOMCIDEV
#define NOSEQDEV
#define NOWAVEDEV
#define NOMIDIDEV
#define NOTASKDEV
#include "mmddk.h"
#include "mmsysi.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, HANDLE hdrv, WORD msg, DWORD dw1, DWORD dw2);
/* Support for using 3.1 APIs if available */
typedef HANDLE (FAR PASCAL *OPENDRIVER31)(LPSTR, LPSTR, LONG);
typedef LONG (FAR PASCAL *CLOSEDRIVER31)(HANDLE, LONG, LONG);
typedef HANDLE (FAR PASCAL *GETDRIVERMODULEHANDLE31)(HANDLE);
typedef LONG (FAR PASCAL *SENDDRIVERMESSAGE31)(HANDLE, WORD, LONG, LONG);
typedef LONG (FAR PASCAL *DEFDRIVERPROC31)(DWORD, HANDLE, WORD, LONG, LONG);
OPENDRIVER31 lpOpenDriver;
CLOSEDRIVER31 lpCloseDriver;
GETDRIVERMODULEHANDLE31 lpGetDriverModuleHandle;
SENDDRIVERMESSAGE31 lpSendDriverMessage;
DEFDRIVERPROC31 lpDefDriverProc;
BOOL fUseWinAPI;
#pragma alloc_text( INIT, DrvInit )
/***************************************************************************
strings
****************************************************************************/
extern char far szSystemIni[]; // INIT.C
extern char far szDrivers[];
extern char far szBoot[];
extern char far szNull[];
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[];
/***************************************************************************
*
* @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 LONG | lParam1 | Specifies the first message parameter for
* the DRV_CLOSE message. This data is passed directly to the driver.
*
* @parm LONG | 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
*
***************************************************************************/
LONG API DrvClose(HANDLE hDriver, LONG lParam1, LONG 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(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 LONG | 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 WORD | 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 API DrvOpen(LPSTR szDriverName,
LPSTR szSectionName,
LONG 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
*/
HANDLE hdrv;
if (fUseWinAPI)
hdrv = ((*lpOpenDriver)(szDriverName, szSectionName, lParam2));
else
hdrv = (HANDLE)InternalOpenDriver(szDriverName, szSectionName, lParam2, TRUE);
#ifdef DEBUG
if (hdrv) {
char ach[80];
static SZCODE szFormat[] = "MMSYSTEM: Opened %ls (%ls)\r\n";
GetModuleFileName(DrvGetModuleHandle(hdrv), ach, sizeof(ach));
DPRINTF((szFormat, (LPSTR)szDriverName, (LPSTR)ach));
}
#endif
return 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.
*
***************************************************************************/
HANDLE API DrvGetModuleHandle(HANDLE hDriver)
{
LPDRIVERTABLE lpdt;
HANDLE h = 0;
if (fUseWinAPI)
return ((*lpGetDriverModuleHandle)(hDriver));
if (hDriver && ((WORD)hDriver <= cInstalledDrivers))
{
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
h = lpdt[hDriver-1].hModule;
GlobalUnlock(hInstalledDriverList);
}
return(h);
}
LONG FAR PASCAL InternalCloseDriver(WORD hDriver,
LONG lParam1,
LONG lParam2,
BOOL fSendDisable)
{
LPDRIVERTABLE lpdt;
LONG result;
HANDLE h;
int index;
BOOL f;
// check handle in valid range.
if (hDriver > cInstalledDrivers)
return(FALSE);
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
result = DrvSendMessage(hDriver, DRV_CLOSE, lParam1, lParam2);
if (result)
{
// Driver didn't abort close
f = lpdt[hDriver-1].fFirstEntry;
if (InternalFreeDriver(hDriver, fSendDisable) && f)
{
/* 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.
*/
for (index=0;index<cInstalledDrivers;index++)
if (lpdt[index].hModule == lpdt[hDriver-1].hModule && !lpdt[index].fFirstEntry)
{
lpdt[index].fFirstEntry = 1;
break;
}
}
}
GlobalUnlock(hInstalledDriverList);
return(result);
}
LONG FAR PASCAL InternalOpenDriver(LPSTR szDriverName,
LPSTR szSectionName,
LONG lParam2,
BOOL fSendEnable)
{
int hDriver;
LPDRIVERTABLE lpdt;
LONG result;
HANDLE h;
char sz[128];
if (hDriver = LOWORD(InternalLoadDriver(szDriverName,
szSectionName,
sz,
sizeof(sz),
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.
*/
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
lpdt[hDriver-1].dwDriverIdentifier = hDriver;
GlobalUnlock(hInstalledDriverList);
result = DrvSendMessage(hDriver,
DRV_OPEN,
(LONG)(LPSTR)sz,
lParam2);
if (!result)
InternalFreeDriver(hDriver, fSendEnable);
else
{
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
lpdt[hDriver-1].dwDriverIdentifier = result;
GlobalUnlock(hInstalledDriverList);
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 WORD | cbTail | size of supplied buffer.
*
* @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
*
****************************************************************************/
LONG FAR PASCAL InternalLoadDriver(LPSTR szDriverName,
LPSTR szSectionName,
LPSTR lpstrTail,
WORD cbTail,
BOOL fSendEnable)
{
int index;
LPDRIVERTABLE lpdt;
LONG result;
HANDLE h;
/* 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 */
if (!hInstalledDriverList)
h = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)((WORD)sizeof(DRIVERTABLE)));
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)((WORD)sizeof(DRIVERTABLE)*(cInstalledDrivers+1)),
GHND | GMEM_SHARE);
if (!h)
return(0L);
cInstalledDrivers++;
hInstalledDriverList = h;
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
/* find an unused entry in the table */
for (index=0;index<cInstalledDrivers;index++)
{
if (lpdt->hModule || lpdt->fBusy)
lpdt++;
else
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->fBusy = 1;
h = LoadAliasedLibrary(szDriverName,
szSectionName ? szSectionName : szDrivers,
szSystemIni,
lpstrTail,
cbTail);
if (h < 32)
{
result = MAKELONG(0,h);
goto LoadCleanUp;
}
lpdt->lpDriverEntryPoint = (DRIVERPROC)GetProcAddress(h, szDriverProc);
if (!lpdt->lpDriverEntryPoint)
{
// Driver does not have correct entry point
FreeLibrary(h);
result = 0L;
goto LoadCleanUp;
}
// Set hModule here so that GetDrvrUsage() and DrvSendMessage() work
lpdt->hModule = h;
if (GetDrvrUsage(h) == 1)
{
// First instance of the driver.
if (!DrvSendMessage(index+1, DRV_LOAD, 0L, 0L))
{
// Driver failed load call.
lpdt->lpDriverEntryPoint = NULL;
lpdt->hModule = NULL;
FreeLibrary(h);
result = 0L;
goto LoadCleanUp;
}
lpdt->fFirstEntry = 1;
if (fSendEnable)
DrvSendMessage(index+1, DRV_ENABLE, 0L, 0L);
}
result = MAKELONG(index+1,h);
LoadCleanUp:
lpdt->fBusy = 0;
GlobalUnlock(hInstalledDriverList);
return(result);
}
/***************************************************************************
*
* @doc INTERNAL
*
* @api WORD | 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
*
***************************************************************************/
WORD FAR PASCAL InternalFreeDriver(WORD hDriver, BOOL fSendDisable)
{
LPDRIVERTABLE lpdt;
HANDLE h;
WORD w;
/* The driver will receive the following message sequence:
*
* if usage count of driver is 1
* DRV_DISABLE (normally)
* DRV_FREE
*/
if (hDriver > cInstalledDrivers || !hDriver)
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;
w = GetDrvrUsage(lpdt[hDriver-1].hModule);
if (w == 1)
{
if (fSendDisable)
DrvSendMessage(hDriver, DRV_DISABLE, 0L, 0L);
DrvSendMessage(hDriver, DRV_FREE, 0L, 0L);
}
FreeLibrary(lpdt[hDriver-1].hModule);
// 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);
return(w-1);
}
#ifdef DEBUG
WORD GetWinVer()
{
WORD w = GetVersion();
return (w>>8) | (w<<8);
}
#endif
void NEAR PASCAL DrvInit(void)
{
HANDLE hlibUser;
LPDRIVERTABLE lpdt;
/* If the window's driver interface is present then use it.
*/
DOUT("MMSYSTEM: DrvInit");
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 enableing it.
//
cInstalledDrivers = 1;
hInstalledDriverList = GlobalAlloc(GHND|GMEM_SHARE, (DWORD)((WORD)sizeof(DRIVERTABLE)));
#ifdef DEBUG
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);
}
if (fUseWinAPI)
{
DOUT(" - Windows Driver I/F detected\r\n");
#ifdef DEBUG
if (GetWinVer() < 0x30A)
DOUT("MMSYSTEM: WARNING !!! WINDOWS DRIVER I/F BUT VERSION LESS THAN 3.1\r\n");
#endif
// 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);
}
}
/***************************************************************************
*
* @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
*/
GetPrivateProfileString(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;
}
}
}
/***************************************************************************
*
* @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 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 WORD | cbTail | size of supplied buffer.
*
* @rdesc Returns the library's module handle.
*
* @xref LoadLibrary
*
***************************************************************************/
HANDLE FAR PASCAL LoadAliasedLibrary(LPSTR szLibFileName,
LPSTR szSection,
LPSTR szIniFile,
LPSTR lpstrTail,
WORD cbTail)
{
HANDLE h;
char sz[128];
LPSTR pch;
OFSTRUCT of;
if (!szLibFileName || !*szLibFileName)
return(2); // File not found
// read the filename and additional info. into sz
GetPrivateProfileString(szSection, // ini section
szLibFileName, // key name
szLibFileName, // default if no match
sz, // return buffer
sizeof(sz), // return buffer size
szIniFile); // ini. file
sz[sizeof(sz)-1] = 0;
// strip off the additional info.
pch = (LPSTR)sz;
while (*pch)
{
if (*pch == ' ')
{
*pch++ = '\0';
break;
}
pch++;
}
// pch pts to ch after first space or null ch
if (!GetModuleHandle(sz) &&
OpenFile(sz, &of, OF_EXIST|OF_READ|OF_SHARE_DENY_NONE) == -1)
return(2);
// copy additional info. to lpstrTail
if (lpstrTail && cbTail)
{
while (cbTail-- && (*lpstrTail++ = *pch++))
;
*(lpstrTail-1) = 0;
}
return (LoadLibrary(sz));
}
/***************************************************************************
*
* @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;
if (!hInstalledDriverList || !cInstalledDrivers)
return(0);
count = 0;
lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
for (index=0;index<cInstalledDrivers;index++)
{
if (lpdt->hModule==h)
{
count++;
}
lpdt++;
}
GlobalUnlock(hInstalledDriverList);
return(count);
}