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.
 
 
 
 
 
 

559 lines
15 KiB

/* Installable drivers for windows. Less common code.
*/
#include "user.h"
/*--------------------------------------------------------------------------*\
**
** NewSignalProc() -
**
\*--------------------------------------------------------------------------*/
#define SG_EXIT 0x0020
#define SG_LOAD_DLL 0x0040
#define SG_EXIT_DLL 0x0080
#define SG_GP_FAULT 0x0666
BOOL
CALLBACK NewSignalProc(
HTASK hTask,
WORD message,
WPARAM wParam,
LPARAM lParam
)
{
BOOL fRet;
// Notify installable drivers this app is going away.
if ( message == SG_EXIT || message == SG_GP_FAULT ) {
InternalBroadcastDriverMessage( NULL, DRV_EXITAPPLICATION,
(message == SG_GP_FAULT
? DRVEA_ABNORMALEXIT
: DRVEA_NORMALEXIT),
0L, IBDM_FIRSTINSTANCEONLY );
}
//
// Pass notification on to WOW32 (which passes on to USER32)
//
fRet = SignalProc( hTask, message, wParam, lParam );
//
// After letting WOW32 and User32 cleanup, destroy the shadow
// message queue created by InitApp.
//
if ( message == SG_EXIT || message == SG_GP_FAULT ) {
DeleteQueue();
}
return fRet;
}
HINSTANCE LoadAliasedLibrary(LPCSTR szLibFileName,
LPCSTR szSection,
LPCSTR szIniFile,
LPSTR lpstrTail,
WORD cbTail)
{
char sz[128];
LPSTR pch;
OFSTRUCT os;
HFILE fd;
HINSTANCE h;
WORD errMode;
if (!szLibFileName || !*szLibFileName)
return((HINSTANCE)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. Remember, DS!=SS so we need to get a lpstr
* to our stack allocated sz.
*/
pch = (LPSTR)sz;
while (*pch)
{
if (*pch == ' ')
{
*pch++ = '\0';
break;
}
pch++;
}
// pch pts to ch after first space or null ch
fd = OpenFile(sz, &os, OF_EXIST|OF_SHARE_DENY_NONE);
if (HFILE_ERROR == fd)
return((HINSTANCE)2);
/* copy additional info. to lpstrTail
*/
if (lpstrTail && cbTail)
{
while (cbTail-- && (*lpstrTail++ = *pch++))
;
*(lpstrTail-1) = 0;
}
errMode = SetErrorMode(0x8001);
h = LoadLibrary(sz);
SetErrorMode(errMode);
return (h);
}
int GetDrvrUsage(HMODULE hModule)
/* effects: 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.
*/
{
LPDRIVERTABLE lpdt;
int index;
int count;
if (!hInstalledDriverList || !cInstalledDrivers || !hModule)
return(0);
count = 0;
lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
for (index=0;index<cInstalledDrivers;index++)
{
if (lpdt->hModule==hModule)
count++;
lpdt++;
}
return(count);
}
BOOL PASCAL CheckValidDriverProc(LPDRIVERTABLE lpdt, HDRVR hdrv)
/* effects: Some vendors shipped multimedia style installable drivers with
* bogus entry procs. This test checks for these bogus drivers and refuses to
* install them.
*/
{
WORD currentSP;
WORD saveSP;
_asm mov saveSP, sp
(void)(lpdt->lpDriverEntryPoint)(0, hdrv, 0, 0L, 0L);
_asm mov currentSP, sp
_asm mov sp, saveSP
if (saveSP != currentSP)
DebugErr(DBF_ERROR, "Invalid driver entry proc address");
return (saveSP == currentSP);
}
LRESULT FAR InternalLoadDriver(LPCSTR szDriverName,
LPCSTR szSectionName,
LPCSTR lpstrTail,
WORD cbTail,
BOOL fSendEnable)
{
int index;
int i;
LPDRIVERTABLE lpdt;
LPDRIVERTABLE lpdtBegin;
LRESULT result;
HGLOBAL h;
HINSTANCE hInstance;
char szDrivers[20];
char szSystemIni[20];
/* Drivers receive the following messages: if the driver was loaded,
* DRV_LOAD. If DRV_LOAD returns non-zero and fSendEnable, DRV_ENABLE.
*/
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 slot but rather in an intermediate
* slot which was freed.
*/
h = GlobalReAlloc(hInstalledDriverList,
(DWORD)((WORD)sizeof(DRIVERTABLE)*(cInstalledDrivers+1)),
GHND|GMEM_SHARE);
if (!h)
return(0L);
cInstalledDrivers++;
hInstalledDriverList = h;
if (!szSectionName)
LoadString(hInstanceWin, STR_DRIVERS, szDrivers, sizeof(szDrivers));
LoadString(hInstanceWin, STR_SYSTEMINI, szSystemIni, sizeof(szSystemIni));
lpdtBegin = lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList, NULL);
/* Find an empty driver entry */
for (i = 0; i < cInstalledDrivers; i++)
{
if (lpdt->hModule == NULL)
{
index = i;
break;
}
lpdt++;
}
if (index + 1 < cInstalledDrivers)
/* The driver went into an unused slot in the middle somewhere so
* decrement cInstalledDrivers count.
*/
cInstalledDrivers--;
/* Temporarly use an hModule to 1 to reserve this entry in case the driver
* loads another driver in its LibMain.
*/
lpdt->hModule = (HMODULE)1;
hInstance = LoadAliasedLibrary((LPSTR)szDriverName,
(LPSTR)(szSectionName ? szSectionName : szDrivers),
szSystemIni,
(LPSTR)lpstrTail,
cbTail);
if (hInstance < HINSTANCE_ERROR)
{
lpdt->hModule = NULL;
/* Load failed with an error. Return error code in highword.
*/
return(MAKELRESULT(0, hInstance));
}
(FARPROC)lpdt->lpDriverEntryPoint = GetProcAddress(hInstance, "DriverProc");
if (!lpdt->lpDriverEntryPoint)
{
FreeLibrary(hInstance);
lpdt->hModule = 0;
result = 0L;
goto LoadCleanUp;
}
lpdt->hModule = hInstance;
/* Save either the alias or filename of this driver. (depends on what the
* app passed to us to load it)
*/
lstrcpy(lpdt->szAliasName, szDriverName);
if (GetDrvrUsage(hInstance) == 1)
{
/* If this is the first instance, send the drv_load message. Don't use
* SendDriverMessage because we haven't initialized the linked list yet
*/
if (!CheckValidDriverProc(lpdt, (HDRVR)(index+1)) ||
!(lpdt->lpDriverEntryPoint)(lpdt->dwDriverIdentifier,
(HDRVR)(index+1),
DRV_LOAD,
0L, 0L))
{
/* Driver failed load call.
*/
lpdt->lpDriverEntryPoint = NULL;
lpdt->hModule = NULL;
FreeLibrary(hInstance);
result = 0L;
goto LoadCleanUp;
}
lpdt->fFirstEntry = 1;
}
/* Put driver in the load order linked list
*/
if (idFirstDriver == -1)
{
/* Initialize everything when first driver is loaded.
*/
idFirstDriver = index;
idLastDriver = index;
lpdt->idNextDriver = -1;
lpdt->idPrevDriver = -1;
}
else
{
/* Insert this driver at the end of the load chain.
*/
lpdtBegin[idLastDriver].idNextDriver = index;
lpdt->idPrevDriver = idLastDriver;
lpdt->idNextDriver = -1;
idLastDriver = index;
}
if (fSendEnable && lpdt->fFirstEntry)
SendDriverMessage((HDRVR)(index+1), DRV_ENABLE, 0L, 0L);
result = MAKELRESULT(index+1, hInstance);
LoadCleanUp:
return(result);
}
WORD FAR InternalFreeDriver(HDRVR hDriver, BOOL fSendDisable)
{
LPDRIVERTABLE lpdt;
WORD w;
int id;
/* The driver will receive the following message sequence:
*
* if usage count of driver is 1
* DRV_DISABLE (normally)
* DRV_FREE
*/
if ((int)hDriver > cInstalledDrivers || !hDriver)
return(0);
lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
if (!lpdt[(int)hDriver-1].hModule)
return(0);
/* 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[(int)hDriver-1].dwDriverIdentifier = 0;
w = GetDrvrUsage(lpdt[(int)hDriver-1].hModule);
if (w == 1)
{
if (fSendDisable)
SendDriverMessage(hDriver, DRV_DISABLE, 0L, 0L);
SendDriverMessage(hDriver, DRV_FREE, 0L, 0L);
}
FreeLibrary(lpdt[(int)hDriver-1].hModule);
// Clear the rest of the table entry
lpdt[(int)hDriver-1].hModule = 0; // this indicates free entry
lpdt[(int)hDriver-1].fFirstEntry = 0; // this is also just to be tidy
lpdt[(int)hDriver-1].lpDriverEntryPoint = 0; // this is also just to be tidy
/* Fix up the driver load linked list */
if (idFirstDriver == (int)hDriver-1)
{
idFirstDriver = lpdt[(int)hDriver-1].idNextDriver;
if (idFirstDriver == -1)
{
/* No more drivers in the chain */
idFirstDriver = -1;
idLastDriver = -1;
cInstalledDrivers= 0;
goto Done;
}
else
{
/* Make prev entry of new first driver -1 */
lpdt[idFirstDriver].idPrevDriver = -1;
}
}
else if (idLastDriver == (int)hDriver-1)
{
/* We are freeing the last driver. So find a new last driver. */
idLastDriver = lpdt[(int)hDriver-1].idPrevDriver;
lpdt[idLastDriver].idNextDriver = -1;
}
else
{
/* We are freeing a driver in the middle of the list somewhere. */
id = lpdt[(int)hDriver-1].idPrevDriver;
lpdt[id].idNextDriver = lpdt[(int)hDriver-1].idNextDriver;
id = lpdt[(int)hDriver-1].idNextDriver;
lpdt[id].idPrevDriver = lpdt[(int)hDriver-1].idPrevDriver;
}
Done:
return(w-1);
}
LRESULT InternalOpenDriver(LPCSTR szDriverName,
LPCSTR szSectionName,
LPARAM lParam2,
BOOL fSendEnable)
{
HDRVR hDriver;
LPDRIVERTABLE lpdt;
LRESULT result;
char sz[128];
if (hDriver = (HDRVR)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)MAKELP(hInstalledDriverList,0);
lpdt[(int)hDriver-1].dwDriverIdentifier = (DWORD)(WORD)hDriver;
result = SendDriverMessage(hDriver,
DRV_OPEN,
(LPARAM)(LPSTR)sz,
lParam2);
if (!result)
InternalFreeDriver(hDriver, fSendEnable);
else
{
lpdt = (LPDRIVERTABLE)MAKELONG(0,hInstalledDriverList);
lpdt[(int)hDriver-1].dwDriverIdentifier = (DWORD)result;
result = (LRESULT)(DWORD)(WORD)hDriver;
}
}
else
result = 0L;
return(result);
}
LRESULT InternalCloseDriver(HDRVR hDriver, LPARAM lParam1, LPARAM lParam2, BOOL fSendDisable)
{
LPDRIVERTABLE lpdt;
LRESULT result;
int index;
BOOL f;
HMODULE hm;
// check handle in valid range.
if ((int)hDriver > cInstalledDrivers)
return(FALSE);
lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
if (!lpdt[(int)hDriver-1].hModule)
return(FALSE);
result = SendDriverMessage(hDriver, DRV_CLOSE, lParam1, lParam2);
if (result)
{
// Driver didn't abort close
f = lpdt[(int)hDriver-1].fFirstEntry;
hm = lpdt[(int)hDriver-1].hModule;
if (InternalFreeDriver(hDriver, fSendDisable) && f)
{
lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
/* 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 == hm && !lpdt[index].fFirstEntry)
{
lpdt[index].fFirstEntry = 1;
break;
}
}
}
return(result);
}
HDRVR API IOpenDriver(LPCSTR szDriverName, LPCSTR szSectionName, LPARAM lParam)
{
LRESULT result;
/* The driver receives the following messages when it is opened. If it isn't
* loaded, the library is loaded and the DRV_LOAD message is sent. If
* DRV_LOAD returns nonzero, the DRV_ENABLE message is sent. Once the
* driver is loaded or if it was previously loaded, the DRV_OPEN message is
* sent.
*/
result = InternalOpenDriver(szDriverName, szSectionName, lParam, TRUE);
return((HDRVR)LOWORD(result));
}
LRESULT API ICloseDriver(HDRVR 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
*/
return(InternalCloseDriver(hDriver, lParam1, lParam2, TRUE));
}
HINSTANCE API IGetDriverModuleHandle(HDRVR hDriver)
/* effects: Returns the module handle associated with the given driver ID.
*/
{
LPDRIVERTABLE lpdt;
HINSTANCE hModule = NULL;
if (hDriver && ((int)hDriver <= cInstalledDrivers))
{
lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
return lpdt[(int)hDriver-1].hModule;
}
else
return NULL;
}