|
|
/******************************************************************************
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); }
|