/****************************************************************************** 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 #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

is * not null, the specified section of the SYSTEM.INI file is * searched instead of the [Drivers] section. If *

is null, the default [Drivers] section is used. * * @parm LONG | lParam | Specifies a message parameter to * pass to the driver procedure with the message. * * @rdesc Returns a handle to the driver. * * @comm Installable drivers must export a 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

. * * @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;indexhModule || 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;indexhModule==h) { count++; } lpdt++; } GlobalUnlock(hInstalledDriverList); return(count); }