Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

3504 lines
109 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
rmisc.c
Abstract:
This module contains the server-side misc configuration manager routines.
Author:
Paula Tomlinson (paulat) 6-28-1995
Environment:
User-mode only.
Revision History:
28-June-1995 paulat
Creation and initial implementation.
--*/
//
// includes
//
#include "precomp.h"
#include "setupapi.h"
#include "umpnpdat.h"
#include "pnpipc.h"
#include <objbase.h>
#include <initguid.h>
#include <devguid.h>
#include <tchar.h>
#include <wchar.h>
//
// global definitions
//
#define MAX_DESCRIPTION_LEN 128 //??
#define MAX_POINTERS 12
#define MAX_KEYBOARDS 1
#define SETUPAPI_DLL TEXT("setupapi.dll")
#define PNP_INIT_MUTEX TEXT("PnP_Init_Mutex")
#define HARDWARE_DEVICEMAP TEXT("hardware\\devicemap\\")
#define ADAPTER_PATH TEXT("Hardware\\Description\\System\\")
#define TEMP_KEYBOARD TEXT("PCAT_ENHANCED")
#define TEMP_POINTER TEXT("NONE")
#define DEFAULT_SERVICE TEXT(" ")
#define CONFIGURATION_DATA TEXT("Configuration Data")
#define IDENTIFIER TEXT("Identifier")
#define MULTI_ADAPTER TEXT("MultifunctionAdapter")
#define EISA_ADAPTER TEXT("EisaAdapter")
#define KBD_PERIPHERAL TEXT("KeyboardPeripheral")
#define POINTER_PERIPHERAL TEXT("PointerPeripheral")
#define KBD_PORT TEXT("KeyboardPort")
#define POINTER_PORT TEXT("PointerPort")
#define KBD_DEVICE TEXT("\\Device\\KeyboardPort%d")
#define POINTER_DEVICE TEXT("\\Device\\PointerPort%d")
#define POINTER_CONTROLLER TEXT("PointerController")
#define KBD_CONTROLLER TEXT("KeyboardController")
#define SERIAL_CONTROLLER TEXT("SerialController")
#define KBD_INF_FILE TEXT("keyboard.inf")
#define POINTER_INF_FILE TEXT("msmouse.inf")
#define INF_LEGACY_DEV_SECT TEXT("LegacyXlate.DevId")
#define DEFAULT_KBD_DRIVER TEXT("i8042prt")
typedef struct {
WCHAR szDescription[MAX_DESCRIPTION_LEN];
WCHAR szDeviceID[MAX_DEVICE_ID_LEN];
//
// This portion of the data structure cannot change, it matches
// what the keyboard and mice drivers use and is used in a binary
// compare fashion.
//
ULONG AdapterType;
ULONG AdapterNumber;
ULONG ControllerType;
ULONG ControllerNumber;
ULONG PeripheralType;
ULONG PeripheralNumber;
//
// End of compatible portion of the data structure.
//
LPWSTR pszDeviceMapService;
} HWDESC_INFO, *PHWDESC_INFO;
//
// private prototypes
//
DWORD
ThreadProc_DeviceEvent(
LPDWORD lpParam
);
BOOL
ProcessNtPnPEvent(
IN DWORD dwEventID,
IN LPTSTR szDeviceID
);
DWORD
InitiateDeviceInstallation(
LPDWORD lpThreadParam
);
BOOL
GetSetupProcAddresses(
IN HINSTANCE hLib
);
BOOL
CheckforNewDevice(
IN LPWSTR pszPnpDeviceID,
IN LPWSTR pszInstance,
IN LPWSTR pszDeviceMapService,
IN LPWSTR pszInfFile,
IN LPWSTR pszClassGuid,
IN LPGUID ClassGuid
);
BOOL
CleanupOldInstances(
LPWSTR pszDevice
);
BOOL
IsDeviceDisabled(
HKEY hKey,
LPWSTR pszDeviceID
);
BOOL
SetProblemReinstall(
LPCWSTR pszDeviceID,
HKEY hDeviceKey
);
BOOL
GetKeyboardIDs(
OUT PHWDESC_INFO pHwDescInfo,
OUT PULONG pulNumDevices,
IN ULONG ulMaxDevices
);
BOOL
GetPointerIDs(
IN OUT PHWDESC_INFO pHwDescInfo,
OUT PULONG pulNumDevices,
IN ULONG ulMaxDevices
);
BOOL
FindPeripheralOnAdapter(
IN OUT PHWDESC_INFO pHwDescInfo,
IN LPWSTR pszAdapter,
IN LPWSTR pszController,
IN ULONG ControllerType,
IN LPWSTR pszPeripheral,
IN ULONG PeripheralType,
OUT PULONG pulNumDevices,
IN ULONG ulMaxDevices
);
BOOL
GetMappedAdapterInfo(
IN HKEY hKey,
OUT PULONG pulAdapterType,
OUT PULONG pulAdapterNumber
);
BOOL
GetPnpID(
IN LPWSTR pszInfFile,
IN LPWSTR pszDeviceID,
OUT LPWSTR pszPnpDeviceID
);
BOOL
FixupHardwareID(
IN LPWSTR pszHardwareID
);
BOOL
MarkClassDevices(
IN PHWDESC_INFO pHwDescInfo,
IN ULONG ulDetectedDevices,
IN LPCWSTR pszEnumerator,
IN LPCWSTR pszClassGuid
);
CONFIGRET
GetClassDevices(
IN LPCWSTR pszOriginalDevice,
IN LPCWSTR pszEnumerator,
OUT LPWSTR *ppClassDeviceList,
IN LPCWSTR pszStringGuid
);
BOOL
GetDeviceMapServices(
IN LPWSTR pszPeripheralPort,
IN LPWSTR pszPeripheralDevice,
IN OUT LPWSTR pszControllingService,
OUT PULONG pulNumServices,
IN ULONG ulMaxDevices
);
BOOL
MatchDevicesAndServices(
IN LPWSTR pszPeripheralDevice,
IN PHWDESC_INFO pHwDescInfo,
IN ULONG ulNumDevices,
IN PWSTR pszDeviceMapServices,
IN ULONG ulNumDeviceMapServices
);
BOOL
GetServicePrivateValues(
IN LPWSTR pszPeripheralDevice,
IN LPWSTR pszService,
OUT PULONG *ppServiceData,
OUT PULONG pulValues
);
BOOL
RemoveClassDevices(
IN LPGUID ClassGuid,
IN LPCWSTR pszClassGuid,
IN LPCWSTR pszNewDeviceId,
IN LPCWSTR pszNewService
);
DWORD
DoFakePnPInstall(
IN LPCWSTR DeviceId,
IN LPCWSTR PnPXlateInfName,
IN LPCWSTR LegacyServiceName,
IN LPCWSTR PnPHardwareId
);
BOOL
SetControllingService(
IN LPCWSTR pszDeviceID,
IN LPCWSTR pszService
);
BOOL
CleanupLegacyDevInst(
IN LPCWSTR pszService,
IN LPCWSTR pszDeviceId
);
//-------------------------------------------------------------------
// function pointer types of setupapi.dll routines
//-------------------------------------------------------------------
typedef HINF (WINAPI *FP_SETUPOPENINFFILE)(IN PCWSTR, IN PCWSTR, IN DWORD, OUT PUINT);
typedef BOOL (WINAPI *FP_SETUPFINDFIRSTLINE)(IN HINF, IN PCWSTR, IN PCWSTR, OUT PINFCONTEXT);
typedef BOOL (WINAPI *FP_SETUPGETSTRINGFIELD)(IN PINFCONTEXT, IN DWORD, OUT PWSTR, IN DWORD, OUT PDWORD);
typedef BOOL (WINAPI *FP_SETUPCLOSEINFFILE)(IN HINF);
typedef HDEVINFO (WINAPI *FP_CREATEDEVICEINFOLIST)(LPGUID, HWND);
typedef BOOL (WINAPI *FP_OPENDEVICEINFO)(HDEVINFO, PCWSTR, HWND, DWORD, PSP_DEVINFO_DATA);
typedef BOOL (WINAPI *FP_GETDEVICEREGISTRYPROPERTY)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD);
typedef BOOL (WINAPI *FP_SETDEVICEREGISTRYPROPERTY)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, CONST BYTE *, DWORD);
typedef BOOL (WINAPI *FP_GETDEVICEINSTALLPARAMS)(HDEVINFO, PSP_DEVINFO_DATA, PSP_DEVINSTALL_PARAMS_W);
typedef BOOL (WINAPI *FP_SETDEVICEINSTALLPARAMS)(HDEVINFO, PSP_DEVINFO_DATA, PSP_DEVINSTALL_PARAMS_W);
typedef BOOL (WINAPI *FP_BUILDDRIVERINFOLIST)(HDEVINFO, PSP_DEVINFO_DATA, DWORD);
typedef BOOL (WINAPI *FP_ENUMDRIVERINFO)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, PSP_DRVINFO_DATA_W);
typedef BOOL (WINAPI *FP_GETDRIVERINFODETAIL)(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_W, PSP_DRVINFO_DETAIL_DATA_W, DWORD, PDWORD);
typedef BOOL (WINAPI *FP_GETDRIVERINSTALLPARAMS)(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_W, PSP_DRVINSTALL_PARAMS);
typedef BOOL (WINAPI *FP_SETSELECTEDRIVER)(HDEVINFO, PSP_DEVINFO_DATA, PSP_DRVINFO_DATA_W);
typedef HKEY (WINAPI *FP_OPENDEVREGKEY)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM);
typedef BOOL (WINAPI *FP_INSTALLDEVICE)(HDEVINFO, PSP_DEVINFO_DATA);
typedef BOOL (WINAPI *FP_DESTROYDEVICEINFOLIST)(HDEVINFO);
typedef HDEVINFO (WINAPI *FP_GETCLASSDEVS)(LPGUID, PCWSTR, HWND, DWORD);
typedef BOOL (WINAPI *FP_ENUMDEVICEINFO)(HDEVINFO, DWORD, PSP_DEVINFO_DATA);
typedef BOOL (WINAPI *FP_SETCLASSINSTALLPARAMS)(HDEVINFO, PSP_DEVINFO_DATA, PSP_CLASSINSTALL_HEADER, DWORD);
typedef BOOL (WINAPI *FP_GETDEVICEINSTANCEID)(HDEVINFO, PSP_DEVINFO_DATA, PWSTR, DWORD, PDWORD);
typedef BOOL (WINAPI *FP_REMOVEDEVICE)(HDEVINFO, PSP_DEVINFO_DATA);
typedef DWORD (WINAPI *FP_RETRIEVESERVICECONFIG)(SC_HANDLE, LPQUERY_SERVICE_CONFIG *);
typedef DWORD (WINAPI *FP_ADDTAGTOGROUPORDERLISTENTRY)(PCTSTR, DWORD, BOOL);
typedef VOID (WINAPI *FP_MYFREE)(IN CONST VOID *);
typedef BOOL (WINAPI *FP_CALLCLASSINSTALLER)(DI_FUNCTION, HDEVINFO, PSP_DEVINFO_DATA);
//
// global data
//
FP_SETUPOPENINFFILE fpSetupOpenInfFile = NULL;
FP_SETUPFINDFIRSTLINE fpSetupFindFirstLine = NULL;
FP_SETUPGETSTRINGFIELD fpSetupGetStringField = NULL;
FP_SETUPCLOSEINFFILE fpSetupCloseInfFile = NULL;
FP_CREATEDEVICEINFOLIST fpCreateDeviceInfoList = NULL;
FP_OPENDEVICEINFO fpOpenDeviceInfo = NULL;
FP_GETDEVICEREGISTRYPROPERTY fpGetDeviceRegistryProperty = NULL;
FP_SETDEVICEREGISTRYPROPERTY fpSetDeviceRegistryProperty = NULL;
FP_GETDEVICEINSTALLPARAMS fpGetDeviceInstallParams = NULL;
FP_SETDEVICEINSTALLPARAMS fpSetDeviceInstallParams = NULL;
FP_BUILDDRIVERINFOLIST fpBuildDriverInfoList = NULL;
FP_ENUMDRIVERINFO fpEnumDriverInfo = NULL;
FP_GETDRIVERINFODETAIL fpGetDriverInfoDetail = NULL;
FP_GETDRIVERINSTALLPARAMS fpGetDriverInstallParams = NULL;
FP_SETSELECTEDRIVER fpSetSelectedDriver = NULL;
FP_OPENDEVREGKEY fpOpenDevRegKey = NULL;
FP_INSTALLDEVICE fpInstallDevice = NULL;
FP_DESTROYDEVICEINFOLIST fpDestroyDeviceInfoList = NULL;
FP_GETCLASSDEVS fpGetClassDevs = NULL;
FP_ENUMDEVICEINFO fpEnumDeviceInfo = NULL;
FP_SETCLASSINSTALLPARAMS fpSetClassInstallParams = NULL;
FP_GETDEVICEINSTANCEID fpGetDeviceInstanceId = NULL;
FP_REMOVEDEVICE fpRemoveDevice = NULL;
FP_RETRIEVESERVICECONFIG fpRetrieveServiceConfig = NULL;
FP_ADDTAGTOGROUPORDERLISTENTRY fpAddTagToGroupOrderListEntry = NULL;
FP_MYFREE fpMyFree = NULL;
FP_CALLCLASSINSTALLER fpCallClassInstaller = NULL;
extern HANDLE hInst;
extern HKEY ghEnumKey; // Key to HKLM\CCC\System\Enum - DO NOT MODIFY
extern HKEY ghServicesKey; // Key to HKLM\CCC\System\Services - DO NOT MODIFY
HANDLE hInitMutex = NULL;
//---------------------------------------------------------------------------
// Debugging interface - initiate detection through private debug interface
//---------------------------------------------------------------------------
CONFIGRET
PNP_InitDetection(
handle_t hBinding
)
{
#if DBG
HANDLE hThread = NULL;
DWORD ThreadID;
UNREFERENCED_PARAMETER(hBinding);
hThread = CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)InitializePnPManager,
NULL,
0,
&ThreadID);
if (hThread != NULL) {
CloseHandle(hThread);
}
#endif // DBG
return CR_SUCCESS;
} // PNP_InitDetection
DWORD
InitializePnPManager(
LPDWORD lpParam
)
/*++
Routine Description:
This thread routine is created from srventry.c when services.exe
attempts to start the plug and play service. The init routine in
srventry.c does critical initialize then creates this thread to
do pnp initialization so that it can return back to the service
controller before pnp init completes.
Arguments:
lpParam Not used.
Return Value:
Currently returns TRUE/FALSE.
--*/
{
DWORD dwStatus = TRUE;
WCHAR szPnpDeviceID[MAX_DEVICE_ID_LEN],
szClassGuid[MAX_GUID_STRING_LEN],
szInstance[MAX_PATH];
LPWSTR pszClassGuid = NULL, pszDeviceMapServices = NULL;
ULONG ulNumDevices = 0, ulNumDeviceMapServices = 0, i = 0;
HINSTANCE hLib = NULL;
DWORD ThreadID = 0;
HANDLE hThread = NULL;
PHWDESC_INFO pHwDescInfo = NULL, pData = NULL;
HKEY hKey = NULL;
UNREFERENCED_PARAMETER(lpParam);
//
// acquire a mutex now to make sure I get through this
// initialization task before getting pinged by a logon
//
hInitMutex = CreateMutex(NULL, TRUE, PNP_INIT_MUTEX);
if (hInitMutex == NULL) {
return FALSE;
}
try {
//
// First thing, remove PlugPlayServiceType value that may have
// been added to the default keyboard service key (i8042), this
// helps prevent the scenario where a user is stuck without a
// keyboard driver running and can't logon to install it. The
// PlugPlayServiceType value was being set for SUR Beta 2 and
// SUR RC1 versions of NT 4.0.
//
if (RegOpenKeyEx(ghServicesKey, DEFAULT_KBD_DRIVER, 0, KEY_WRITE,
&hKey) == ERROR_SUCCESS) {
RegDeleteValue(hKey, pszRegValuePlugPlayServiceType);
RegCloseKey(hKey);
hKey = NULL;
}
//
// start listening for new device events
//
#if 0
hThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)ThreadProc_DeviceEvent,
NULL,
0,
&ThreadID);
if (hThread != NULL) {
CloseHandle(hThread);
}
#endif
//
// dynamically load setupapi.dll for later use
//
hLib = LoadLibrary(SETUPAPI_DLL);
if (hLib == NULL) {
dwStatus = FALSE;
goto Clean0;
}
//
// retreive procedure addresses of setup routines for later use
//
if (!GetSetupProcAddresses(hLib)) {
dwStatus = FALSE;
goto Clean0;
}
//----------------------------------------------------------------
// retrieve the current keyboard id detected by firmware/bios
//----------------------------------------------------------------
pszDeviceMapServices = malloc(MAX_KEYBOARDS *
MAX_SERVICE_NAME_LEN *
sizeof(WCHAR));
if (pszDeviceMapServices == NULL) {
dwStatus = FALSE;
goto Clean0;
}
pHwDescInfo = malloc(MAX_KEYBOARDS * sizeof(HWDESC_INFO));
if (pHwDescInfo == NULL) {
dwStatus = FALSE;
goto Clean0;
}
if (GetKeyboardIDs(pHwDescInfo, &ulNumDevices, MAX_KEYBOARDS)) {
//
// retrive all devicemap services listed for this peripheral
//
GetDeviceMapServices(KBD_PORT,
KBD_DEVICE,
pszDeviceMapServices,
&ulNumDeviceMapServices,
MAX_KEYBOARDS);
MatchDevicesAndServices(KBD_DEVICE,
pHwDescInfo,
ulNumDevices,
pszDeviceMapServices,
ulNumDeviceMapServices);
//
// get the string form of the class guid for easy comparison
//
UuidToString((LPGUID)&GUID_DEVCLASS_KEYBOARD, &pszClassGuid);
wsprintf(szClassGuid, TEXT("{%s}"), pszClassGuid);
RpcStringFree(&pszClassGuid);
pszClassGuid = NULL;
//
// Process each detected mouse device
//
pData = pHwDescInfo;
for (i=0; i < ulNumDevices; i++) {
//
// Retrieve pnp hardware id from inf files
//
if (GetPnpID(KBD_INF_FILE,
(LPWSTR)pData->szDescription,
szPnpDeviceID)) {
//
// form a unique device instance based on device path
//
wsprintf(szInstance, TEXT("%d_%d_%d_%d_%d_%d"),
pData->AdapterType,
pData->AdapterNumber,
pData->ControllerType,
pData->ControllerNumber,
pData->PeripheralType,
pData->PeripheralNumber);
wsprintf(pData->szDeviceID, TEXT("%s\\%s\\%s"),
pszRegKeyRootEnum, // Root
szPnpDeviceID,
szInstance);
dwStatus = (DWORD)CheckforNewDevice(szPnpDeviceID,
szInstance,
pData->pszDeviceMapService,
KBD_INF_FILE,
szClassGuid,
(LPGUID)&GUID_DEVCLASS_KEYBOARD);
}
pData++; // increment by sizeof HWDESC_INFO struct
}
}
//
// Set all keyboards that weren't detected to "not present"
//
MarkClassDevices(pHwDescInfo, ulNumDevices, pszRegKeyRootEnum,
szClassGuid);
if (pHwDescInfo) {
free(pHwDescInfo);
pHwDescInfo = NULL;
}
if (pszDeviceMapServices) {
free(pszDeviceMapServices);
pszDeviceMapServices = NULL;
}
//----------------------------------------------------------------
// retrieve all pointer devices detected by firmware/bios
//----------------------------------------------------------------
pszDeviceMapServices = malloc(MAX_POINTERS *
MAX_SERVICE_NAME_LEN *
sizeof(WCHAR));
if (pszDeviceMapServices == NULL) {
dwStatus = FALSE;
goto Clean0;
}
pHwDescInfo = malloc(MAX_POINTERS * sizeof(HWDESC_INFO));
if (pHwDescInfo == NULL) {
dwStatus = FALSE;
goto Clean0;
}
//
// Build up a list of all the detected mice
//
ulNumDevices = 0;
ulNumDeviceMapServices = 0;
if (GetPointerIDs(pHwDescInfo, &ulNumDevices, MAX_POINTERS)) {
//
// retrive all devicemap services listed for this peripheral
//
GetDeviceMapServices(POINTER_PORT,
POINTER_DEVICE,
pszDeviceMapServices,
&ulNumDeviceMapServices,
MAX_POINTERS);
MatchDevicesAndServices(POINTER_DEVICE,
pHwDescInfo,
ulNumDevices,
pszDeviceMapServices,
ulNumDeviceMapServices);
//
// get the string form of the class guid for easy comparison
//
UuidToString((LPGUID)&GUID_DEVCLASS_MOUSE, &pszClassGuid);
wsprintf(szClassGuid, TEXT("{%s}"), pszClassGuid);
RpcStringFree(&pszClassGuid);
pszClassGuid = NULL;
//
// Process each detected mouse device
//
pData = pHwDescInfo;
for (i=0; i < ulNumDevices; i++) {
//
// Retrieve pnp hardware id from inf files
//
if (GetPnpID(POINTER_INF_FILE,
(LPWSTR)pData->szDescription,
szPnpDeviceID)) {
//
// form a unique device instance based on device path
//
wsprintf(szInstance, TEXT("%d_%d_%d_%d_%d_%d"),
pData->AdapterType,
pData->AdapterNumber,
pData->ControllerType,
pData->ControllerNumber,
pData->PeripheralType,
pData->PeripheralNumber);
wsprintf(pData->szDeviceID, TEXT("%s\\%s\\%s"),
pszRegKeyRootEnum, // Root
szPnpDeviceID,
szInstance);
dwStatus = (DWORD)CheckforNewDevice(szPnpDeviceID,
szInstance,
pData->pszDeviceMapService,
POINTER_INF_FILE,
szClassGuid,
(LPGUID)&GUID_DEVCLASS_MOUSE);
}
pData++; // increment by sizeof HWDESC_INFO struct
}
//
// Set all mice that weren't detected to "not present"
//
MarkClassDevices(pHwDescInfo, ulNumDevices, pszRegKeyRootEnum,
szClassGuid);
}
Clean0:
;
} except(EXCEPTION_EXECUTE_HANDLER) {
OutputDebugString(TEXT("Exception in InitializePnPManager\n"));
dwStatus = FALSE;
}
if (pHwDescInfo) {
free(pHwDescInfo);
}
if (pszDeviceMapServices) {
free(pszDeviceMapServices);
}
if (pszClassGuid != NULL) {
RpcStringFree(&pszClassGuid);
}
if (hLib != NULL) {
FreeLibrary(hLib);
}
//
// signal the init mutex so that logon init activity can procede
//
ReleaseMutex(hInitMutex);
return dwStatus;
} // InitializePnPManager
DWORD
ThreadProc_DeviceEvent(
LPDWORD lpParam
)
{
DWORD Status = TRUE;
DWORD dwBytesRead = 0, dwBytesRequired = 0, dwNumRecords = 0;
HANDLE hEvent = NULL, hEventLog = NULL;
ULONG BufferSize = 1024;
LPWSTR pszDeviceID = NULL;
EVENTLOGRECORD *pEventLogRecord = NULL, *p = NULL;
try {
//
// Create an auto-reset (after it's signaled only one waiting thread
// will be released, then it will automatically be set back to
// non-signalled) event that is initially not signalled.
//
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent == NULL) {
Status = FALSE;
goto Clean0;
}
//
// Open a handle to the "system" event log.
//
hEventLog = OpenEventLog(NULL, TEXT("System"));
if (hEventLog == NULL) {
Status = FALSE;
goto Clean0;
}
//
// Register for notification whenever an event is written to this
// (system) event log.
//
if (!NotifyChangeEventLog(hEventLog, hEvent)) {
Status = FALSE;
goto Clean0;
}
//
// Allocate a buffer to hold a single event log record.
//
pEventLogRecord = (EVENTLOGRECORD *)malloc(BufferSize);
if (pEventLogRecord == NULL) {
Status = FALSE;
goto Clean0;
}
//
// Continually wait for any new device events - which I'm notified
// about by a new event log entry.
//
while (TRUE) {
if (WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) {
OutputDebugString(TEXT("Device Event!\n"));
//
// Get the current total number of event log records
//
if (GetNumberOfEventLogRecords(hEventLog, &dwNumRecords)) {
//
// Read the newest (most recently added) event.
//
if (!ReadEventLog(hEventLog,
EVENTLOG_FORWARDS_READ |
EVENTLOG_SEEK_READ,
dwNumRecords,
pEventLogRecord,
BufferSize,
&dwBytesRead,
&dwBytesRequired)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
//
// Recoverable error - realloc a bigger buffer
// and attempt to read the event again.
//
p = realloc(pEventLogRecord, dwBytesRequired);
if (p == NULL) {
Status = FALSE;
goto Clean0;
}
pEventLogRecord = p;
BufferSize = dwBytesRequired;
if (!ReadEventLog(hEventLog,
EVENTLOG_FORWARDS_READ |
EVENTLOG_SEEK_READ,
dwNumRecords,
pEventLogRecord,
BufferSize,
&dwBytesRead,
&dwBytesRequired)) {
goto NextEvent; // try again on next event
}
} else {
goto NextEvent; // try again on next event
}
}
//
// Filter the event - only process the event if the source
// is ntpnp.
//
if (lstrcmpi((LPTSTR)((LPBYTE)pEventLogRecord +
sizeof(EVENTLOGRECORD)),
TEXT("Service Control Manager")) == 0) {
//BUGBUG -test code!!!
if (pEventLogRecord->DataOffset == 0) {
goto NextEvent;
}
pszDeviceID = (LPTSTR)(((LPBYTE)pEventLogRecord +
pEventLogRecord->DataOffset));
if (*pszDeviceID == 0x0) {
goto NextEvent;
}
ProcessNtPnPEvent(pEventLogRecord->EventID,
pszDeviceID);
}
}
}
NextEvent:
;
}
Clean0:
;
} except(EXCEPTION_EXECUTE_HANDLER) {
OutputDebugString(TEXT("Exception in ThreadProc_DeviceEvent\n"));
Status = FALSE;
}
if (hEventLog != NULL) {
CloseHandle(hEvent);
}
if (hEventLog != NULL) {
CloseEventLog(hEventLog);
}
if (pEventLogRecord != NULL) {
free(pEventLogRecord);
}
return Status;
} // ThreadProc_DeviceEvent
BOOL
ProcessNtPnPEvent(
IN DWORD dwEventID,
IN LPTSTR szDeviceID
)
{
WCHAR szDbg[MAX_PATH];
//
// Process the device arrival event
//
wsprintf(szDbg, TEXT("Device Arrival : EventID=%x"), dwEventID);
OutputDebugString(szDbg);
return TRUE;
} // ProcessNtPnPEvent
BOOL
GetSetupProcAddresses(
IN HINSTANCE hLib
)
{
//
// Get the procedure addresses for the setup inf file routines
//
fpSetupOpenInfFile = (FP_SETUPOPENINFFILE)GetProcAddress(
hLib, "SetupOpenInfFileW");
fpSetupFindFirstLine = (FP_SETUPFINDFIRSTLINE)GetProcAddress(
hLib, "SetupFindFirstLineW");
fpSetupGetStringField = (FP_SETUPGETSTRINGFIELD)GetProcAddress(
hLib, "SetupGetStringFieldW");
fpSetupCloseInfFile = (FP_SETUPCLOSEINFFILE)GetProcAddress(
hLib, "SetupCloseInfFile");
fpCreateDeviceInfoList = (FP_CREATEDEVICEINFOLIST)GetProcAddress(
hLib, "SetupDiCreateDeviceInfoList");
fpOpenDeviceInfo = (FP_OPENDEVICEINFO)GetProcAddress(
hLib, "SetupDiOpenDeviceInfoW");
fpGetDeviceRegistryProperty = (FP_GETDEVICEREGISTRYPROPERTY)GetProcAddress(
hLib, "SetupDiGetDeviceRegistryPropertyW");
fpSetDeviceRegistryProperty = (FP_SETDEVICEREGISTRYPROPERTY)GetProcAddress(
hLib, "SetupDiSetDeviceRegistryPropertyW");
fpGetDeviceInstallParams = (FP_GETDEVICEINSTALLPARAMS)GetProcAddress(
hLib, "SetupDiGetDeviceInstallParamsW");
fpSetDeviceInstallParams = (FP_SETDEVICEINSTALLPARAMS)GetProcAddress(
hLib, "SetupDiSetDeviceInstallParamsW");
fpBuildDriverInfoList = (FP_BUILDDRIVERINFOLIST)GetProcAddress(
hLib, "SetupDiBuildDriverInfoList");
fpEnumDriverInfo = (FP_ENUMDRIVERINFO)GetProcAddress(
hLib, "SetupDiEnumDriverInfoW");
fpGetDriverInfoDetail = (FP_GETDRIVERINFODETAIL)GetProcAddress(
hLib, "SetupDiGetDriverInfoDetailW");
fpGetDriverInstallParams = (FP_GETDRIVERINSTALLPARAMS)GetProcAddress(
hLib, "SetupDiGetDriverInstallParamsW");
fpSetSelectedDriver = (FP_SETSELECTEDRIVER)GetProcAddress(
hLib, "SetupDiSetSelectedDriverW");
fpOpenDevRegKey = (FP_OPENDEVREGKEY)GetProcAddress(
hLib, "SetupDiOpenDevRegKey");
fpInstallDevice = (FP_INSTALLDEVICE)GetProcAddress(
hLib, "SetupDiInstallDevice");
fpDestroyDeviceInfoList = (FP_DESTROYDEVICEINFOLIST)GetProcAddress(
hLib, "SetupDiDestroyDeviceInfoList");
fpGetClassDevs = (FP_GETCLASSDEVS)GetProcAddress(
hLib, "SetupDiGetClassDevsW");
fpEnumDeviceInfo = (FP_ENUMDEVICEINFO)GetProcAddress(
hLib, "SetupDiEnumDeviceInfo");
fpSetClassInstallParams = (FP_SETCLASSINSTALLPARAMS)GetProcAddress(
hLib, "SetupDiSetClassInstallParamsW");
fpGetDeviceInstanceId = (FP_GETDEVICEINSTANCEID)GetProcAddress(
hLib, "SetupDiGetDeviceInstanceIdW");
fpRemoveDevice = (FP_REMOVEDEVICE)GetProcAddress(
hLib, "SetupDiRemoveDevice");
fpRetrieveServiceConfig = (FP_RETRIEVESERVICECONFIG)GetProcAddress(
hLib, "RetrieveServiceConfig");
fpAddTagToGroupOrderListEntry = (FP_ADDTAGTOGROUPORDERLISTENTRY)GetProcAddress(
hLib, "AddTagToGroupOrderListEntry");
fpMyFree = (FP_MYFREE)GetProcAddress(
hLib, "MyFree");
fpCallClassInstaller = (FP_CALLCLASSINSTALLER)GetProcAddress(
hLib, "SetupDiCallClassInstaller");
if (fpSetupOpenInfFile == NULL ||
fpSetupFindFirstLine == NULL ||
fpSetupGetStringField == NULL ||
fpSetupCloseInfFile == NULL ||
fpCreateDeviceInfoList == NULL ||
fpOpenDeviceInfo == NULL ||
fpGetDeviceRegistryProperty == NULL ||
fpSetDeviceRegistryProperty == NULL ||
fpGetDeviceInstallParams == NULL ||
fpBuildDriverInfoList == NULL ||
fpEnumDriverInfo == NULL ||
fpGetDriverInfoDetail == NULL ||
fpGetDriverInstallParams == NULL ||
fpSetSelectedDriver == NULL ||
fpOpenDevRegKey == NULL ||
fpInstallDevice == NULL ||
fpDestroyDeviceInfoList == NULL ||
fpGetClassDevs == NULL ||
fpEnumDeviceInfo == NULL ||
fpSetClassInstallParams == NULL ||
fpGetDeviceInstanceId == NULL ||
fpRemoveDevice == NULL ||
fpRetrieveServiceConfig == NULL ||
fpAddTagToGroupOrderListEntry == NULL ||
fpMyFree == NULL ||
fpCallClassInstaller == NULL) {
return FALSE;
}
return TRUE;
} // GetSetupProcAddresses
BOOL
CheckforNewDevice(
IN LPWSTR pszPnpDeviceID,
IN LPWSTR pszInstance,
IN LPWSTR pszDeviceMapService,
IN LPWSTR pszInfFile,
IN LPWSTR pszClassGuid,
IN LPGUID ClassGuid
)
{
WCHAR RegStr[MAX_PATH],
szDevice[MAX_PATH],
szServiceProperty[MAX_PATH];
HKEY hKey = NULL;
ULONG ulDisposition, ulValue, ulSize;
//
// form the device instance string for this device
//
wsprintf(szDevice, TEXT("%s\\%s\\%s"),
pszRegKeyRootEnum, // Root
pszPnpDeviceID,
pszInstance);
wsprintf(RegStr, TEXT("%s\\%s"),
pszRegPathEnum,
szDevice);
//
// Create/open the device instance key
//
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, RegStr, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&hKey, &ulDisposition) == ERROR_SUCCESS) {
if (ulDisposition == REG_OPENED_EXISTING_KEY) {
//
// pnp device instance key already exists
//
if (IsDeviceDisabled(hKey, szDevice)) {
SetProblemReinstall(szDevice, hKey);
goto Clean0; // done
}
#if 0 // NT 4.0 SP1 - this is taken care of later
//
// If NULL driver installed for this device, then ignore
// it (test for this case by checking for ConfigFlags == 0).
//
ulSize = sizeof(DWORD);
if (RegQueryValueEx(hKey, pszRegValueConfigFlags, NULL, NULL,
(LPBYTE)&ulValue, &ulSize) == ERROR_SUCCESS) {
if (ulValue == 0) {
goto Clean0; // done
}
} else {
//
// assume ConfigFlags is zero if couldn't query it
//
goto Clean0; // done
}
#endif // NT 4.0 SP1
} else if (ulDisposition == REG_CREATED_NEW_KEY) {
//
// if the key didn't exist before, set base properties
// no matter what else we do
//
RegSetValueEx(hKey, pszRegValueHardwareID, 0,
REG_MULTI_SZ,
(LPBYTE)pszPnpDeviceID,
(lstrlen(pszPnpDeviceID)+1) * sizeof(WCHAR));
RegSetValueEx(hKey, pszRegValueBaseDevicePath, 0,
REG_SZ,
(LPBYTE)pszRegKeyRoot,
(lstrlen(pszRegKeyRoot)+1) * sizeof(WCHAR));
AddAttachedComponent(pszRegKeyRoot, szDevice);
ulValue = TRUE;
RegSetValueEx(hKey, pszRegValueFoundAtEnum, 0, REG_DWORD,
(LPBYTE)&ulValue, sizeof(ULONG));
}
if (pszDeviceMapService == NULL || *pszDeviceMapService == 0x0) {
//
// No device map value in the hardware tree for this
// device. If there is a service listed for this
// device then it has probably been successfully
// installed already but the mouse may not be physically
// present (note: on some MIPS systems, the description
// may list a mouse even if it's not physically present;
// in this case the device map would not contain a mouse
// entry). In this case do nothing.
//
if (ulDisposition == REG_OPENED_EXISTING_KEY) {
#if 0 // NT 4.0 SP1
//
// can safely ignore this check now - if a null driver was
// installed then the reinstall flag was cleared so don't
// need to do anything. Likewise, if user just cancelled
// then the reinstall flag is still set so do nothing.
//
ULONG ulValue = 0;
ULONG ulSize = MAX_PATH * sizeof(WCHAR);
if ((PNP_GetDeviceRegProp(NULL, szDevice, CM_DRP_SERVICE,
&ulValue, (LPBYTE)szServiceProperty,
&ulSize, &ulSize, 0) == CR_SUCCESS)
&& (*szServiceProperty != 0x0)) {
//
// service name exists - do nothing
//
} else {
//
// Device is physically present but no controlling service
// for this device yet, requires installation.
//
SetProblemReinstall(szDevice, hKey);
}
#endif // NT 4.0 SP1
} else {
//
// Device is physically present but no controlling service
// for this device yet, requires installation.
//
SetProblemReinstall(szDevice, hKey);
}
} else {
//
// a controlling service was found, so we should be
// able to do a fake install if necessary
//
//
// if the key already existed, retrieve the service property
//
if (ulDisposition == REG_OPENED_EXISTING_KEY) {
ULONG ulValue = 0;
ULONG ulSize = MAX_PATH * sizeof(WCHAR);
PNP_GetDeviceRegProp(NULL,
szDevice,
CM_DRP_SERVICE,
&ulValue,
(LPBYTE)szServiceProperty,
&ulSize,
&ulSize,
0);
}
//
// In the case where the device map service was different
// than the installed service, cleanup the service's enum
// key to reflect the real information. (the devicemap
// service is actually controlling the device)
//
if (lstrcmpi(pszDeviceMapService, szServiceProperty) != 0) {
PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
RtlInitUnicodeString(&ControlData.DeviceInstance,
szDevice);
NtPlugPlayControl(PlugPlayControlDeregisterDevice,
&ControlData,
sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
NULL);
}
//
// If the device didn't already exist or the service property
// doesn't match the actual controlling service, do a fake
// install (otherwise, no action is necessary)
//
if (ulDisposition == REG_CREATED_NEW_KEY ||
lstrcmpi(pszDeviceMapService, szServiceProperty) != 0) {
if(DoFakePnPInstall(szDevice,
pszInfFile,
pszDeviceMapService,
pszPnpDeviceID) != NO_ERROR) {
//
// cleanup registry key
//
wsprintf(RegStr, TEXT("%s\\%s\\%s"),
pszRegPathEnum, // ...Enum
pszRegKeyRootEnum, // Root
pszPnpDeviceID); // Device
RemoveAttachedComponent(pszRegKeyRoot, szDevice);
RegDeleteNode(HKEY_LOCAL_MACHINE, RegStr);
goto Clean0;
}
//
// Cleanup obsolete instance key method (from NT 4.0 Beta 2)
//
CleanupOldInstances(pszPnpDeviceID);
#if 0
//
// Enable the device in this profile and disable it in all
// other devices of the same class in this profile.
//
RemoveClassDevices(ClassGuid,
pszClassGuid,
szDevice,
pszDeviceMapService);
#endif
}
}
}
Clean0:
if (hKey != NULL) {
RegCloseKey(hKey);
}
return TRUE;
} // CheckForNewDevice
BOOL
CleanupOldInstances(
LPWSTR pszDevice
)
{
WCHAR RegStr[MAX_PATH];
HKEY hKey = NULL;
ULONG ulLength = 0;
PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
//
// Cleanup up any old "0000" instances of this device
//
wsprintf(RegStr, TEXT("%s\\%s"),
pszRegKeyRootEnum, // Root
pszDevice);
if (RegOpenKeyEx(ghEnumKey, RegStr, 0, KEY_ALL_ACCESS,
&hKey) == ERROR_SUCCESS) {
lstrcat(RegStr, TEXT("\\0000")); // full device instance
RtlInitUnicodeString(&ControlData.DeviceInstance, RegStr);
NtPlugPlayControl(PlugPlayControlDeregisterDevice,
&ControlData,
sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
&ulLength);
RemoveAttachedComponent(pszRegKeyRoot, RegStr);
RegDeleteNode(hKey, TEXT("0000"));
RegCloseKey(hKey);
}
return TRUE;
}
BOOL
IsDeviceDisabled(
HKEY hKey,
LPWSTR pszDeviceID
)
{
CONFIGRET Status = CR_SUCCESS;
ULONG ulFlag = 0, ulSize = 0;
HKEY hServiceKey = NULL;
WCHAR RegStr[MAX_PATH], szService[MAX_PATH];
SC_HANDLE hSCManager = NULL, hService = NULL;
//
// If Service is not a plug play service, then return FALSE. WHY?!
//
ulSize = MAX_PATH * sizeof(WCHAR);
if (RegQueryValueEx(hKey, pszRegValueService, NULL, NULL,
(LPBYTE)szService, &ulSize) == ERROR_SUCCESS) {
return FALSE; // has an installed service, not disabled
}
wsprintf(RegStr, TEXT("%s\\%s"),
pszRegPathServices,
szService);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegStr, 0, KEY_READ,
&hServiceKey) != ERROR_SUCCESS) {
return FALSE; // no controlling service, not disabled
}
ulSize = sizeof(ULONG);
if (RegQueryValueEx(hServiceKey, pszRegValuePlugPlayServiceType,
NULL, NULL, (LPBYTE)&ulFlag,
&ulSize) != ERROR_SUCCESS) {
RegCloseKey(hServiceKey);
return FALSE; // PlugPlayService value exists, not disabled
}
RegCloseKey(hServiceKey);
if (ulFlag != 0x2) {
return FALSE; // not a plug play service
}
//
// Is device disabled (set to "do not create") in this profile?
//
Status = PNP_HwProfFlags(NULL, PNP_GET_HWPROFFLAGS,
pszDeviceID, 0, &ulFlag, 0);
if (Status == CR_SUCCESS &&
ulFlag == CSCONFIGFLAG_DO_NOT_CREATE) {
return TRUE; // is disabled in this profile
}
//
// Is service explicitly set to disabled?
//
ulSize = MAX_PATH * sizeof(WCHAR);
if ((hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))
!= NULL) {
if ((hService = OpenService(hSCManager, szService,
SERVICE_ALL_ACCESS)) != NULL) {
QUERY_SERVICE_CONFIG Config;
if (QueryServiceConfig(hService, &Config,
sizeof(QUERY_SERVICE_CONFIG), &ulSize)) {
if (Config.dwStartType == SERVICE_DISABLED) {
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return TRUE; // explicitly disabled service
}
}
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCManager);
}
return FALSE;
} // IsDeviceDisabled
BOOL
SetProblemReinstall(
LPCWSTR pszDeviceID,
HKEY hDeviceKey
)
{
DWORD ConfigFlags = 0, dwValue = 0;
ULONG ConfigFlagsSize = sizeof(ConfigFlags);
if (PNP_GetDeviceRegProp(NULL,
pszDeviceID,
CM_DRP_CONFIGFLAGS,
&dwValue,
(LPBYTE)&ConfigFlags,
&ConfigFlagsSize,
&ConfigFlagsSize,
0) != CR_SUCCESS) {
ConfigFlags = 0;
}
ConfigFlagsSize = sizeof(ConfigFlags);
ConfigFlags |= CONFIGFLAG_REINSTALL;
PNP_SetDeviceRegProp(NULL,
pszDeviceID,
CM_DRP_CONFIGFLAGS,
REG_DWORD,
(LPBYTE)&ConfigFlags,
ConfigFlagsSize,
0);
//
// set problem CM_PROB_REINSTALL
//
dwValue = DN_HAS_PROBLEM;
RegSetValueEx(hDeviceKey, pszRegValueStatusFlags, 0, REG_DWORD,
(LPBYTE)&dwValue, sizeof(DWORD));
dwValue = CM_PROB_REINSTALL;
RegSetValueEx(hDeviceKey, pszRegValueProblem, 0, REG_DWORD,
(LPBYTE)&dwValue, sizeof(DWORD));
return TRUE;
} // SetProblemReinstall
BOOL
GetKeyboardIDs(
IN OUT PHWDESC_INFO pHwDescInfo,
OUT PULONG pulNumDevices,
IN ULONG ulMaxDevices
)
/*++
Routine Description:
Find the keyboard id from the registry hardware detection information.
Ported from setup\legacy\dll\hardware.c
Arguments:
Return Value:
--*/
{
PHWDESC_INFO pData = pHwDescInfo;
ULONG i = 0;
*pulNumDevices = 0;
//
// Find all keyboard devices on MultifunctionAdatper/KeyboardController
//
if (FindPeripheralOnAdapter(pData, MULTI_ADAPTER,
KBD_CONTROLLER, 22, // KeyboardController
KBD_PERIPHERAL, 32, // KeyboardPeripheral
&i, ulMaxDevices)) {
*pulNumDevices += i;
pData += i; // increment by i number of structs
}
//
// Find all keyboard devices on EisAdatper/KeyboardController
//
if (FindPeripheralOnAdapter(pData, EISA_ADAPTER,
KBD_CONTROLLER, 22, // KeyboardController
KBD_PERIPHERAL, 32, // KeyboardPeripheral
&i, ulMaxDevices)) {
*pulNumDevices += i;
pData += i; // increment by i number of structs
}
if (*pulNumDevices > 0) {
return TRUE;
} else {
return FALSE;
}
} // GetKeyboardIDs
BOOL
GetPointerIDs(
IN OUT PHWDESC_INFO pHwDescInfo,
OUT PULONG pulNumDevices,
IN ULONG ulMaxDevices
)
{
PHWDESC_INFO pData = pHwDescInfo;
ULONG i = 0;
*pulNumDevices = 0;
//
// Find all pointer devices on MultifunctionAdatper/PointerController
//
if (FindPeripheralOnAdapter(pData, MULTI_ADAPTER,
POINTER_CONTROLLER, 21, // PointerController
POINTER_PERIPHERAL, 31, // PointerPeripheral
&i, ulMaxDevices)) {
*pulNumDevices += i;
pData += i; // increment by i number of structs
}
//
// Find all pointer devices on a MultifunctionAdapter/KeyboardController
//
if (FindPeripheralOnAdapter(pData, MULTI_ADAPTER,
KBD_CONTROLLER, 22, // KeyboardController
POINTER_PERIPHERAL, 31, // PointerPeripheral
&i, ulMaxDevices)) {
*pulNumDevices += i;
pData += i; // increment by i number of structs
}
//
// Find all pointer devices on a MultifunctionAdapter/SerialController
//
if (FindPeripheralOnAdapter(pData, MULTI_ADAPTER,
SERIAL_CONTROLLER, 17, // SerialController
POINTER_PERIPHERAL, 31, // PointerPeripheral
&i, ulMaxDevices)) {
*pulNumDevices += i;
pData += i; // increment by i number of structs
}
//
// Find all pointer devices on a EisaAdapter/PointerController
//
if (FindPeripheralOnAdapter(pData, EISA_ADAPTER,
POINTER_CONTROLLER, 21, // PointerController
POINTER_PERIPHERAL, 31, // PointerPeripheral
&i, ulMaxDevices)) {
*pulNumDevices += i;
pData += i; // increment by i number of structs
}
//
// Find all pointer devices on a EisaAdapter/KeyboardController
//
if (FindPeripheralOnAdapter(pData, EISA_ADAPTER,
KBD_CONTROLLER, 22, // KeyboardController
POINTER_PERIPHERAL, 31, // PointerPeripheral
&i, ulMaxDevices)) {
*pulNumDevices += i;
pData += i; // increment by i number of structs
}
//
// Find all pointer devices on a EisaAdapter/SerialController
//
if (FindPeripheralOnAdapter(pData, EISA_ADAPTER,
SERIAL_CONTROLLER, 17, // KeyboardController
POINTER_PERIPHERAL, 31, // PointerPeripheral
&i, ulMaxDevices)) {
*pulNumDevices += i;
pData += i; // increment by i number of structs
}
if (*pulNumDevices > 0) {
return TRUE;
} else {
return FALSE;
}
} // GetPointerIDs
BOOL
FindPeripheralOnAdapter(
IN OUT PHWDESC_INFO pHwDescInfo,
IN LPWSTR pszAdapter,
IN LPWSTR pszController,
IN ULONG ControllerType,
IN LPWSTR pszPeripheral,
IN ULONG PeripheralType,
OUT PULONG pulNumDevices,
IN ULONG ulMaxDevices
)
{
LONG RegStatus = ERROR_SUCCESS, RegStatus1 = ERROR_SUCCESS,
RegStatus2 = ERROR_SUCCESS;
WCHAR RegStr[MAX_PATH];
HKEY hAdapterKey = NULL, hAdapterInstanceKey = NULL,
hControllerKey = NULL, hControllerInstanceKey = NULL,
hPeripheralKey = NULL, hPeripheralInstanceKey = NULL;
ULONG ulAdapter = 0, ulController = 0, ulPeripheral = 0, ulSize = 0;
PHWDESC_INFO pData = pHwDescInfo;
*pulNumDevices = 0;
//
// The adapter is always searched for under hardware\description\system
//
lstrcpy(RegStr, ADAPTER_PATH);
lstrcat(RegStr, pszAdapter);
//
// Open a key to the adapter
//
RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegStr, 0,
KEY_READ, &hAdapterKey);
if (RegStatus != ERROR_SUCCESS) {
return FALSE;
}
//
// Look at each adapter ordinal instance
//
while (RegStatus == ERROR_SUCCESS) {
wsprintf(RegStr, TEXT("%d"), ulAdapter);
if ((RegStatus = RegOpenKeyEx(hAdapterKey, RegStr, 0, KEY_READ,
&hAdapterInstanceKey)) == ERROR_SUCCESS) {
//
// attempt to open the specified controller key
//
if (RegOpenKeyEx(hAdapterInstanceKey, pszController,
0, KEY_READ, &hControllerKey) == ERROR_SUCCESS) {
//
// Look at each controller ordinal instance
//
ulController = 0;
RegStatus1 = ERROR_SUCCESS;
while (RegStatus1 == ERROR_SUCCESS) {
wsprintf(RegStr, TEXT("%d"), ulController);
if ((RegStatus1 = RegOpenKeyEx(hControllerKey, RegStr, 0,
KEY_READ, &hControllerInstanceKey))
== ERROR_SUCCESS) {
//
// Attempt to open the specified peripheral key
//
if (RegOpenKeyEx(hControllerInstanceKey,
pszPeripheral, 0, KEY_READ,
&hPeripheralKey) == ERROR_SUCCESS) {
//
// Look at each peripheral ordinal instance
//
ulPeripheral = 0;
RegStatus2 = ERROR_SUCCESS;
while (RegStatus2 == ERROR_SUCCESS) {
wsprintf(RegStr, TEXT("%d"), ulPeripheral);
if ((RegStatus2 = RegOpenKeyEx(hPeripheralKey,
RegStr, 0, KEY_READ,
&hPeripheralInstanceKey))
== ERROR_SUCCESS) {
//
// Found a device, query the Identifier value
//
ulSize = MAX_DESCRIPTION_LEN * sizeof(WCHAR);
if (RegQueryValueEx(hPeripheralInstanceKey,
IDENTIFIER,
NULL, NULL,
(LPBYTE)pData->szDescription,
&ulSize) == ERROR_SUCCESS) {
FixupHardwareID((LPWSTR)pData->szDescription);
GetMappedAdapterInfo(hPeripheralInstanceKey,
&pData->AdapterType,
&pData->AdapterNumber);
pData->ControllerType = ControllerType;
pData->ControllerNumber = ulController;
pData->PeripheralType = PeripheralType;
pData->PeripheralNumber = ulPeripheral;
pData->pszDeviceMapService = NULL; // init
pData++; // incrment by size of struct
(*pulNumDevices)++;
RegCloseKey(hPeripheralInstanceKey);
ulPeripheral++;
if (*pulNumDevices >= ulMaxDevices) {
RegCloseKey(hPeripheralKey);
RegCloseKey(hControllerInstanceKey);
RegCloseKey(hControllerKey);
RegCloseKey(hAdapterInstanceKey);
RegCloseKey(hAdapterKey);
return TRUE;
}
}
}
}
RegCloseKey(hPeripheralKey);
}
RegCloseKey(hControllerInstanceKey);
ulController++;
}
}
RegCloseKey(hControllerKey);
}
RegCloseKey(hAdapterInstanceKey);
ulAdapter++;
}
}
RegCloseKey(hAdapterKey);
return TRUE;
} // FindPeripheralOnAdapter
BOOL
GetMappedAdapterInfo(
IN HKEY hKey,
OUT PULONG pulAdapterType,
OUT PULONG pulAdapterNumber
)
{
//
// Must retrieve the corresponding InterfaceType and number for this
// device by looking at the ConfigurationData value
//
ULONG ulSize = 0, ulAdapterType = 0;
PCM_FULL_RESOURCE_DESCRIPTOR pRes = NULL;
*pulAdapterType = 0; // Internal (default)
*pulAdapterNumber = 0; // default
if (RegQueryValueEx(hKey, CONFIGURATION_DATA, NULL, NULL, NULL,
&ulSize) != ERROR_SUCCESS) {
return FALSE; // use default adapter values
}
pRes = (PCM_FULL_RESOURCE_DESCRIPTOR)malloc(ulSize);
if (pRes == NULL) {
return FALSE; // use default adapter values
}
if (RegQueryValueEx(hKey, CONFIGURATION_DATA, NULL, NULL,
(LPBYTE)pRes, &ulSize) != ERROR_SUCCESS) {
free(pRes);
return FALSE; // use default adapter values
}
*pulAdapterType = pRes->InterfaceType;
*pulAdapterNumber = pRes->BusNumber;
free(pRes);
return TRUE;
} // GetMappedAdapterInfo
BOOL
GetPnpID(
IN LPWSTR pszInfFile,
IN LPWSTR pszDeviceID,
OUT LPWSTR pszPnpDeviceID
)
{
HINF hInf = NULL;
INFCONTEXT InfContext;
ULONG ulSize = 0;
//
// if no PNP id is found for this, I'll use the same id
//
lstrcpy(pszPnpDeviceID, pszDeviceID);
//
// use Setup API routines to find corresponding pnp id
//
hInf = (fpSetupOpenInfFile)(pszInfFile,
NULL,
INF_STYLE_WIN4,
NULL);
if (hInf != INVALID_HANDLE_VALUE) {
if ((fpSetupFindFirstLine)(hInf,
INF_LEGACY_DEV_SECT,
pszDeviceID,
&InfContext)) {
(fpSetupGetStringField)(&InfContext,
1,
pszPnpDeviceID,
MAX_DEVICE_ID_LEN,
&ulSize);
}
(fpSetupCloseInfFile)(hInf);
}
return TRUE;
} // GetPnpID
BOOL
FixupHardwareID(
IN LPWSTR pszHardwareID
)
{
LPWSTR p = NULL;
if (pszHardwareID == NULL) {
return FALSE;
}
for (p = pszHardwareID; *p; p++) {
if (*p == TEXT(' ')) {
*p = TEXT('_');
}
}
return TRUE;
} // FixupHardwareID
BOOL
MarkClassDevices(
IN PHWDESC_INFO pHwDescInfo,
IN ULONG ulDetectedDevices,
IN LPCWSTR pszEnumerator,
IN LPCWSTR pszClassGuid
)
{
CONFIGRET Status = CR_SUCCESS;
LPWSTR pDeviceList = NULL, pszDevice = NULL;
ULONG ulSize = 0, i = 0;
WCHAR szClass[MAX_GUID_STRING_LEN];
BOOL bMatch = FALSE;
HKEY hKey = NULL;
PHWDESC_INFO pData = NULL;
PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
//-------------------------------------------------------------------------
// First pass - Retreive the list of devices for the specified enumerator
//-------------------------------------------------------------------------
Status = PNP_GetDeviceListSize(NULL, pszEnumerator, &ulSize,
CM_GETIDLIST_FILTER_ENUMERATOR);
if (Status != CR_SUCCESS) {
return FALSE;
}
pDeviceList = malloc(ulSize * sizeof(WCHAR));
if (pDeviceList == NULL) {
return FALSE;
}
Status = PNP_GetDeviceList(NULL, pszEnumerator, pDeviceList, &ulSize,
CM_GETIDLIST_FILTER_ENUMERATOR);
if (Status != CR_SUCCESS) {
free(pDeviceList);
return FALSE;
}
//-------------------------------------------------------------------------
// Second pass - process only devices of the specified class
//-------------------------------------------------------------------------
for (pszDevice = pDeviceList;
*pszDevice;
pszDevice += lstrlen(pszDevice) + 1) {
ulSize = MAX_GUID_STRING_LEN * sizeof(WCHAR);
Status = PNP_GetDeviceRegProp(NULL, pszDevice, CM_DRP_CLASSGUID, NULL,
(LPBYTE)szClass, &ulSize, &ulSize, 0);
if (Status == CR_SUCCESS) {
//-----------------------------------------------------------------
// third pass - filter out any devices that I detected
//-----------------------------------------------------------------
if (lstrcmpi(szClass, pszClassGuid) == 0) {
//
// GUID matches, is it a detected (present) device?
//
pData = pHwDescInfo;
bMatch = FALSE;
for (i = 0; i < ulDetectedDevices; i++) {
if (lstrcmpi(pszDevice, pData->szDeviceID) == 0) {
bMatch = TRUE;
goto DoneChecking;
}
pData++;
}
DoneChecking:
if (!bMatch) {
//
// this device was not detected and thus is not present
// at this boot, set private disabled flag and mark as not
// present
//
if (RegOpenKeyEx(ghEnumKey, pszDevice, 0, KEY_ALL_ACCESS,
&hKey) == ERROR_SUCCESS) {
ULONG ulValue = FALSE;
RegSetValueEx(hKey, pszRegValueFoundAtEnum, 0,
REG_DWORD, (LPBYTE)&ulValue,
sizeof(ULONG));
if (RegQueryValueEx(hKey, pszRegValueStatusFlags,
NULL, NULL, (LPBYTE)&ulValue,
&ulSize) != ERROR_SUCCESS) {
ulValue = 0;
}
ulValue |= DN_CSDISABLED; // borrow this flag
RegSetValueEx(hKey, pszRegValueStatusFlags, 0,
REG_DWORD, (LPBYTE)&ulValue,
sizeof(ULONG));
RegCloseKey(hKey);
//
// Also deregister the device so it doesn't show
// up under the service's enum list.
//
RtlInitUnicodeString(&ControlData.DeviceInstance, pszDevice);
NtPlugPlayControl(PlugPlayControlDeregisterDevice,
&ControlData,
sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
&ulSize);
}
}
}
}
}
free(pDeviceList);
return TRUE;
} // MarkClassDevices
CONFIGRET
GetClassDevices(
IN LPCWSTR pszOriginalDevice,
IN LPCWSTR pszEnumerator,
OUT LPWSTR *ppClassDeviceList,
IN LPCWSTR pszStringGuid
)
{
CONFIGRET Status = CR_SUCCESS;
LPWSTR pDeviceList = NULL, pszDevice = NULL,
pClassDeviceList = NULL, pszClassDevice = NULL;
ULONG ulSize = 0;
WCHAR szClassGuid[MAX_GUID_STRING_LEN];
//
// Retreive the list of root enumerated devices.
//
Status = PNP_GetDeviceListSize(NULL, pszEnumerator, &ulSize,
CM_GETIDLIST_FILTER_ENUMERATOR);
if (Status != CR_SUCCESS) {
goto Clean0;
}
pDeviceList = malloc(ulSize * sizeof(WCHAR));
if (pDeviceList == NULL) {
Status = CR_OUT_OF_MEMORY;
goto Clean0;
}
Status = PNP_GetDeviceList(NULL, pszEnumerator, pDeviceList, &ulSize,
CM_GETIDLIST_FILTER_ENUMERATOR);
if (Status != CR_SUCCESS) {
goto Clean0;
}
//
// Allocate a second buffer of equal size to hold matching devices
//
*ppClassDeviceList = malloc(ulSize * sizeof(WCHAR));
if (*ppClassDeviceList == NULL) {
Status = CR_OUT_OF_MEMORY;
goto Clean0;
}
memset(*ppClassDeviceList, 0, ulSize);
pszClassDevice = *ppClassDeviceList;
//
// Check the class guid for each device in the list, save any matches
// in the new list
//
for (pszDevice = pDeviceList;
*pszDevice;
pszDevice += lstrlen(pszDevice) + 1) {
ulSize = MAX_GUID_STRING_LEN * sizeof(WCHAR);
Status = PNP_GetDeviceRegProp(
NULL, pszDevice, CM_DRP_CLASSGUID, NULL,
(LPBYTE)szClassGuid, &ulSize, &ulSize, 0);
if (Status == CR_SUCCESS) {
if (lstrcmpi(szClassGuid, pszStringGuid) == 0) {
//
// GUID matches, if doesn't match the original
// then add it to list
//
if (lstrcmpi(pszDevice, pszOriginalDevice) != 0) {
lstrcpy(pszClassDevice, pszDevice);
pszClassDevice += lstrlen(pszDevice) + 1;
}
}
}
}
Clean0:
if (pDeviceList != NULL) {
free(pDeviceList);
}
return Status;
} // GetClassDevices
BOOL
GetDeviceMapServices(
IN LPWSTR pszPeripheralPort,
IN LPWSTR pszPeripheralDevice,
IN OUT LPWSTR pszControllingService,
OUT PULONG pulNumServices,
IN ULONG ulMaxDevices
)
{
HKEY hKey = NULL;
WCHAR RegStr[MAX_PATH], szDeviceString[MAX_PATH];
ULONG ulSize1, ulSize2;
LONG RegStatus = ERROR_SUCCESS;
LPTSTR pszService = NULL;
*pszControllingService = 0x0;
//
// Open the devicemap key for the hardware indicated
//
lstrcpy(RegStr, HARDWARE_DEVICEMAP);
lstrcat(RegStr, pszPeripheralPort);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegStr, 0, KEY_READ,
&hKey) != ERROR_SUCCESS) {
return FALSE;
}
//
// pszControllingService will be filled with a multisz list
// of each service listed on this peripheral port
//
// NT 4.0 SP1 FIX - This code was assuming that the ports listed
// in the hardware devicemap are always sequential, but we've
// now seen cases where that is not true. In order to be sure
// I'm getting all listed values under the XxxPort key, I will
// enumerate the values instead of query specific named values.
//
pszService = pszControllingService;
*pulNumServices = 0;
while (RegStatus == ERROR_SUCCESS) {
ulSize1 = ulSize2 = MAX_PATH;
RegStatus = RegEnumValue(hKey, *pulNumServices, szDeviceString,
&ulSize1, NULL, NULL, (LPBYTE)RegStr, &ulSize2);
if (RegStatus == ERROR_SUCCESS) {
LPWSTR pEntry;
if ((pEntry = wcsstr(RegStr, TEXT("Services\\"))) != NULL
&& (pEntry = wcschr(pEntry, TEXT('\\'))) != NULL
&& *++pEntry != TEXT('\0')) {
LPWSTR pEndOfEntry;
if((pEndOfEntry = wcschr(pEntry, TEXT('\\'))) != NULL) {
*pEndOfEntry = TEXT('\0');
}
}
else {
pEntry = RegStr;
}
lstrcpy(pszService, pEntry);
pszService += lstrlen(pszService) + 1;
*pszService = 0x0; // double-null terminator
(*pulNumServices)++;
if (*pulNumServices >= ulMaxDevices) {
RegCloseKey(hKey);
return TRUE;
}
}
}
RegCloseKey(hKey);
return TRUE;
} // GetDeviceMapServices
BOOL
MatchDevicesAndServices(
IN LPWSTR pszPeripheralDevice,
IN PHWDESC_INFO pHwDescInfo,
IN ULONG ulNumDevices,
IN PWSTR pszDeviceMapServices,
IN ULONG ulNumDeviceMapServices
)
{
PULONG pServiceData = NULL, pSrvData = NULL;
ULONG ulSize = 6 * sizeof(ULONG), ServiceIndex, DeviceIndex,
ulNumData, ulNumUnknownDevices = 0, ulNumOemServices = 0;
LPWSTR pszService = NULL, pszOemService = NULL;
PHWDESC_INFO pData = NULL, pUnknownDevice = NULL;
//
// give a list of detected devices and a list of controlling services,
// match them up based on available info. This will fill in the
// pszDeviceMapService field of each HWDESC_INFO struct in the list.
//
//
// exactly one device and one device map service
//
if (ulNumDeviceMapServices == 1 &&
ulNumDevices == 1) {
//
// assume a one-to-one correspondence
//
pHwDescInfo->pszDeviceMapService = pszDeviceMapServices;
return TRUE;
}
//
// no device map services found
//
if (ulNumDeviceMapServices < 1) {
return TRUE; // nothing more to do
}
//
// First Pass
//
// Attempt to match the known device map services to the list
// of detected devices - since only MS internal drivers will
// store the private data, there may be devices that we can't
// match up to a device map service.
//
for (pszService = pszDeviceMapServices;
*pszService;
pszService += lstrlen(pszService) + 1) {
if (GetServicePrivateValues(pszPeripheralDevice, pszService,
&pServiceData, &ulNumData)) {
pSrvData = pServiceData;
for (ServiceIndex = 0; ServiceIndex < ulNumData; ServiceIndex++) {
pData = pHwDescInfo;
for (DeviceIndex = 0; DeviceIndex < ulNumDevices; DeviceIndex++) {
if (memcmp(pSrvData, (LPBYTE)&pData->AdapterType, ulSize) == 0) {
pData->pszDeviceMapService = pszService;
goto NextService;
}
pData++; // increment by sizeof HWDESC_INFO struct
}
pSrvData += 6; // increment by 6 ulongs
}
if (pServiceData != NULL) {
free(pServiceData);
}
} else {
//
// this service didn't have private values, might still be
// able to handle it if it's the only service that doesn't
// have private values and there is only one unknown detected
// device left after the matching is done.
//
ulNumOemServices++;
if (ulNumOemServices == 1) {
pszOemService = pszService;
}
}
NextService:
;
}
//
// Second Pass
//
// If there is only one OEM Service and only one device left with a
// controlling service, then we can assume they are a match
//
if (ulNumOemServices == 1) {
pData = pHwDescInfo;
ulNumUnknownDevices = 0;
for (DeviceIndex = 0; DeviceIndex < ulNumDevices; DeviceIndex++) {
if (pData->pszDeviceMapService == NULL) {
ulNumUnknownDevices++;
pUnknownDevice = pData;
}
pData++; // increment by sizeof HWDESC_INFO struct
}
if (ulNumUnknownDevices == 1) {
pUnknownDevice->pszDeviceMapService = pszOemService;
}
}
return TRUE;
} // MatchDevicesAndServices
BOOL
GetServicePrivateValues(
IN LPWSTR pszPeripheralDevice,
IN LPWSTR pszService,
OUT PULONG *ppServiceData,
OUT PULONG pulValues
)
{
HKEY hKey = NULL;
WCHAR RegStr[MAX_PATH], szValue[MAX_PATH];
ULONG i, ulSize, ulValues = 0;
LPBYTE pData = NULL;
*pulValues = 0;
wsprintf(RegStr, TEXT("%s\\Description"), pszService);
if (RegOpenKeyEx(ghServicesKey, RegStr, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
&ulValues, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
*ppServiceData = malloc(sizeof(ULONG) * 6 * ulValues);
if (*ppServiceData == NULL) {
RegCloseKey(hKey);
return FALSE;
}
pData = (LPBYTE)*ppServiceData;
for (i = 0; i < ulValues; i++) {
ulSize = sizeof(ULONG) * 6;
wsprintf(szValue, pszPeripheralDevice, i);
if (RegQueryValueEx(hKey, szValue, NULL, NULL,
pData, &ulSize) == ERROR_SUCCESS) {
pData += sizeof(ULONG) * 6;
(*pulValues)++;
}
}
}
RegCloseKey(hKey);
return TRUE;
}
return FALSE;
} // GetServicePrivateValues
BOOL
RemoveClassDevices(
IN LPGUID ClassGuid,
IN LPCWSTR pszClassGuid,
IN LPCWSTR pszNewDeviceId,
IN LPCWSTR pszNewService
)
{
WCHAR RegStr[MAX_PATH];
HKEY hKey = NULL;
DWORD dwNumProfileKeys = 0;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
SP_REMOVEDEVICE_PARAMS RemoveDeviceParams;
DWORD i;
WCHAR szDeviceId[MAX_DEVICE_ID_LEN],
szService[MAX_PATH];
//---------------------------------------------------------------
// Current thinking - If there is only one hardware profile,
// then don't disable any other class devices in this one
// profile. This prevents a docking station user from having
// reboot an extra time each time they dock or undock.
//---------------------------------------------------------------
//
// open a key to the Hardware Profiles brank
//
wsprintf(RegStr, TEXT("%s\\%s"),
pszRegPathIDConfigDB,
pszRegKeyKnownDockingStates);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegStr, 0,
KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) {
return FALSE;
}
RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwNumProfileKeys, NULL,
NULL, NULL, NULL, NULL, NULL, NULL);
RegCloseKey(hKey);
#if 0
//
// If only one hardware profile exists, then just manually collect
// a list of any other devices of this same class and disable each
// of those devices in this (current) profile. By "disable" I mean
// that CSConfigFlag should be set to CSCONFIG_FLAG_NO_NOT_CREATE.
//
if (dwNumProfileKeys <= 1) {
CONFIGRET Status = CR_SUCCESS;
LPWSTR pDeviceList = NULL, pszDevice = NULL;
ULONG ulCSConfigFlags = 0;
//
// retrieve a list of all other devices (under the same enumerator)
// of the same class
//
Status = GetClassDevices(pszNewDeviceId,
TEXT("Root"),
&pDeviceList,
pszClassGuid);
ulCSConfigFlags = 0; // reset to enable
Status = PNP_HwProfFlags(NULL, PNP_SET_HWPROFFLAGS,
pszNewDeviceId, 0, &ulCSConfigFlags, 0);
ulCSConfigFlags = CSCONFIGFLAG_DO_NOT_CREATE;
for (pszDevice = pDeviceList;
*pszDevice;
pszDevice += lstrlen(pszDevice) + 1) {
Status = PNP_HwProfFlags(NULL, PNP_SET_HWPROFFLAGS,
pszDevice, 0, &ulCSConfigFlags, 0);
}
free(pDeviceList);
}
#endif
//
// Get all devices of the specified class that are present in the current
// hardware profile (i.e., aren't marked as CSCONFIGFLAG_DO_NOT_CREATE
// for this profile).
//
hDevInfo = (fpGetClassDevs)(ClassGuid,
NULL,
NULL,
DIGCF_PROFILE
);
//
// Initialize our class install parameters structure for DIF_REMOVE
//
RemoveDeviceParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
RemoveDeviceParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
RemoveDeviceParams.Scope = DI_REMOVEDEVICE_CONFIGSPECIFIC; // do profile-specific removal
RemoveDeviceParams.HwProfile = 0; // use current hardware profile
//
// Enumerate these devices, and remove each one from the current hardware
// profile.
//
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for(i = 0; (fpEnumDeviceInfo)(hDevInfo, i, &DeviceInfoData); i++) {
//
// Set the class install parameters for the profile-specific removal.
//
(fpSetClassInstallParams)(hDevInfo,
&DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&RemoveDeviceParams,
sizeof(SP_REMOVEDEVICE_PARAMS)
);
(fpGetDeviceInstanceId)(hDevInfo,
&DeviceInfoData,
szDeviceId,
MAX_DEVICE_ID_LEN,
NULL);
if (dwNumProfileKeys > 1) {
//
// If multiple hardware profiles, then remove the device
// (as long as it's not the new device).
//
if (lstrcmpi(pszNewDeviceId, szDeviceId) != 0) {
(fpRemoveDevice)(hDevInfo, &DeviceInfoData);
}
} else {
//
// Only one hardware profile, remove the device only if it's
// controlled by the same service as the newly enumerated
// device.
if (GetActiveService(szDeviceId, szService)) {
if (lstrcmpi(szService, pszNewService) == 0) {
(fpRemoveDevice)(hDevInfo, &DeviceInfoData);
}
}
}
}
//
// At this point, all devices of class <ClassGuid> have been removed--
// our hDevInfo handle is now simply a collection of invalid devices.
// Close the handle.
//
(fpDestroyDeviceInfoList)(hDevInfo);
return TRUE;
} // RemoveClassDevices
DWORD
DoFakePnPInstall(
IN LPCWSTR DeviceId,
IN LPCWSTR PnPXlateInfName,
IN LPCWSTR LegacyServiceName,
IN LPCWSTR PnPHardwareId
)
/*++
Routine Description:
This function is used to 'work backwards' from an already-installed legacy device
and generate a Plug&Play-installed device instance for it.
Arguments:
DeviceId - supplies the Plug&Play device ID that's been generated for this device.
PnPXlateInfName - supplies the INF name containing the legacy translations for this
driver.
LegacyServiceName - supplies the name of the legacy service currently controlling
this device.
Return Value:
If the function succeeds, the return value is NO_ERROR, otherwise, it is the Win32
error code (with setupapi extensions) indicating the cause of failure.
--*/
{
DWORD Err, RequiredSize, i, Rank;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVINSTALL_PARAMS DeviceInstallParams;
HINF hInf;
INFCONTEXT InfContext;
TCHAR CharBuffer[255]; // holds either section name or devID--section name is longer.
DWORD dwValue, HwIdLen;
BOOL KnownDriver, bFound;
SP_DRVINFO_DATA DriverInfoData;
SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
SP_DRVINSTALL_PARAMS DriverInstallParams;
HKEY hKey = NULL;
PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
SC_HANDLE hSCManager = NULL, hService = NULL;
LPQUERY_SERVICE_CONFIG pServiceConfig = NULL;
//
// First, open up the specified INF to see whether the legacy driver controlling
// this device is of a known type. If it's not, then we need to retrieve the
// made-up ID that matches the unknown driver installation section, so that building
// the compatible driver list will do the right thing.
//
if((hInf = (fpSetupOpenInfFile)(PnPXlateInfName,
NULL,
INF_STYLE_WIN4,
NULL)) == INVALID_HANDLE_VALUE) {
return GetLastError();
}
if((fpSetupFindFirstLine)(hInf,
TEXT("LegacyXlate.Driver"),
LegacyServiceName,
&InfContext)) {
//
// This is a service name that we know about. Store the associated installation
// section away for later use.
//
(fpSetupGetStringField)(&InfContext,
1,
CharBuffer,
sizeof(CharBuffer) / sizeof(TCHAR),
&RequiredSize
);
KnownDriver = TRUE;
} else {
//
// We don't have any information about this driver. Fetch the 'unknown' ID
// from the [ControlFlags] section, so that we can replace the device's HardwareID
// registry property with this special value.
//
if((fpSetupFindFirstLine)(hInf,
TEXT("ControlFlags"),
TEXT("UnknownLegacyDriverId"), &InfContext)) {
(fpSetupGetStringField)(&InfContext,
1,
CharBuffer,
sizeof(CharBuffer) / sizeof(TCHAR),
&RequiredSize
);
KnownDriver = FALSE;
} else {
Err = GetLastError();
(fpSetupCloseInfFile)(hInf);
return Err;
}
}
//
// We're done with the INF.
//
(fpSetupCloseInfFile)(hInf);
//
// Create a device information set to house our made-up device instance.
//
if((hDevInfo = (fpCreateDeviceInfoList)(NULL, NULL)) == INVALID_HANDLE_VALUE) {
return GetLastError();
}
Err = NO_ERROR; // assume success
//
// Now attempt to open the device instance.
//
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if(!(fpOpenDeviceInfo)(hDevInfo,
DeviceId,
NULL,
0,
&DeviceInfoData)) {
Err = GetLastError();
goto clean0;
}
//
// Set the device registry property indicating the legacy service controlling this
// device.
//
(fpSetDeviceRegistryProperty)(hDevInfo,
&DeviceInfoData,
SPDRP_SERVICE,
(PBYTE)LegacyServiceName,
(lstrlen(LegacyServiceName) + 1) * sizeof(TCHAR)
);
SetControllingService(DeviceId, LegacyServiceName);
//
// If this device is controlled by an unknown legacy driver, then write out the
// special HardwareID we retrieved above.
//
if(!KnownDriver) {
//
// This must be a double-NULL terminated buffer.
//
HwIdLen = lstrlen(CharBuffer) + 1;
CharBuffer[HwIdLen++] = TEXT('\0');
(fpSetDeviceRegistryProperty)(hDevInfo,
&DeviceInfoData,
SPDRP_HARDWAREID,
(LPBYTE)CharBuffer,
HwIdLen * sizeof(TCHAR)
);
}
//
// Now retrieve the device installation parameters for this device information
// element, so that we can customize the way the compatible driver list is built.
//
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
if(!(fpGetDeviceInstallParams)(hDevInfo,
&DeviceInfoData,
&DeviceInstallParams)) {
Err = GetLastError();
goto clean0;
}
DeviceInstallParams.Flags |= (DI_ENUMSINGLEINF | DI_NOFILECOPY | DI_DONOTCALLCONFIGMG | DI_QUIETINSTALL);
lstrcpy(DeviceInstallParams.DriverPath, PnPXlateInfName);
(fpSetDeviceInstallParams)(hDevInfo,
&DeviceInfoData,
&DeviceInstallParams
);
//
// Next, build a compatible driver list for this device. Since the device's
// hardware ID was retrieved from this INF, we are assured that we'll have at
// least one compatible driver node (and at least one rank-0 match).
//
if(!(fpBuildDriverInfoList)(hDevInfo,
&DeviceInfoData,
SPDIT_COMPATDRIVER)) {
Err = GetLastError();
goto clean0;
}
DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
bFound = FALSE;
for(i = 0;
(fpEnumDriverInfo)(hDevInfo,
&DeviceInfoData,
SPDIT_COMPATDRIVER,
i,
&DriverInfoData
);
i++)
{
if(!KnownDriver) {
//
// If the driver is unknown, then automatically pick the first driver node, since
// it's guaranteed to be the unknown driver install section.
//
bFound = TRUE;
break;
}
//
// We have a driver node for our known driver--check to see whether its install section
// matches the one we retrieved from the INF earlier.
//
(fpGetDriverInfoDetail)(hDevInfo,
&DeviceInfoData,
&DriverInfoData,
&DriverInfoDetailData,
sizeof(DriverInfoDetailData),
NULL
);
if(!lstrcmpi(DriverInfoDetailData.SectionName, CharBuffer)) {
//
// We have a driver node we can use--find out the rank of
// this driver, and break out of the loop.
//
DriverInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
if((fpGetDriverInstallParams)(hDevInfo,
&DeviceInfoData,
&DriverInfoData,
&DriverInstallParams)) {
Rank = DriverInstallParams.Rank;
} else {
//
// For some reason, we couldn't retrieve this information--
// just assume rank 0.
//
Rank = 0;
}
bFound = TRUE;
break;
}
}
//
// If no driver node was picked in the above scenario, then try again to find
// a match from the list of all class drivers this time. Note: this case
// currently happens when detection incorrectly picks the wrong device type
// but the user has overwridden so that the correct driver is controlling the
// device. In this case, we have to go with the what detect has told us for
// the device name but make sure we stick with the correct driver that the
// user has picked.
//
if (!bFound) {
if(!(fpBuildDriverInfoList)(hDevInfo,
&DeviceInfoData,
SPDIT_CLASSDRIVER)) {
Err = GetLastError();
goto clean0;
}
for(i = 0;
(fpEnumDriverInfo)(hDevInfo,
&DeviceInfoData,
SPDIT_CLASSDRIVER,
i,
&DriverInfoData
);
i++)
{
//
// We have a driver node for our known driver--check to see whether its install section
// matches the one we retrieved from the INF earlier.
//
(fpGetDriverInfoDetail)(hDevInfo,
&DeviceInfoData,
&DriverInfoData,
&DriverInfoDetailData,
sizeof(DriverInfoDetailData),
NULL
);
if(!lstrcmpi(DriverInfoDetailData.SectionName, CharBuffer)) {
//
// We have a driver node we can use--find out the rank of
// this driver, and break out of the loop.
//
DriverInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
if((fpGetDriverInstallParams)(hDevInfo,
&DeviceInfoData,
&DriverInfoData,
&DriverInstallParams)) {
Rank = DriverInstallParams.Rank;
} else {
//
// For some reason, we couldn't retrieve this information--
// just assume rank 0.
//
Rank = 0;
}
break;
}
}
}
//
// Set the selected driver to be the one we chose above.
//
(fpSetSelectedDriver)(hDevInfo,
&DeviceInfoData,
&DriverInfoData
);
//
// Now, install the driver.
//
#if 0 // NT 4.0 SP1
//
// Instead of calling SetupDiInstallDevice directly, I will
// call the class installer, this will ensure that any special
// stuff the class installer needs to do will happen (such as
// cleaning up the friendly name which is the current problem
// we're trying to solve). The class installer will call
// SetupDiInstallDevice itself.
if(!(fpInstallDevice)(hDevInfo,
&DeviceInfoData)) {
Err = GetLastError();
goto clean0;
}
#endif // NT 4.0 SP1
if (!(fpCallClassInstaller)(DIF_INSTALLDEVICE,
hDevInfo,
&DeviceInfoData)) {
Err = GetLastError();
goto clean0;
}
//
// After installing the driver, make sure that this driver is first in
// the load order group for it's group
//
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCManager != NULL) {
hService = OpenService(hSCManager,LegacyServiceName, SERVICE_ALL_ACCESS);
if (hService != NULL) {
if ((fpRetrieveServiceConfig)(hService,
&pServiceConfig) == NO_ERROR) {
(fpAddTagToGroupOrderListEntry)(pServiceConfig->lpLoadOrderGroup,
pServiceConfig->dwTagId,
TRUE);
}
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCManager);
}
//
// NOTE - it is no longer necessary to mark the keyboard and mice drivers
// as PlugPlayServiceType values. This was originally done as part of the
// way of treating only one keyboard and mouse driver as pnp and disabling
// all others. Now that we support multiple devices of each type, this is
// no longer necessary. In fact, it is causing problems in the scenario
// where someone installs a new oem keyboard driver and disabled the default
// keyboard driver. Then the script for removing the oem driver and
// reverting back to the default driver just reenables the default driver.
// But since the default driver was marked with a PlugPlayServiceType value,
// no legacy device instance was created and so the driver did not load. The
// driver would be detected an installed after a subsequent boot but without
// the keyboard a user can't logon to allow that to happen (chicken-and-egg
// problem).
//
#if 0
//
// Write out a PlugPlayServiceType entry to the service key, so that
// the kernel-mode PnP Mgr won't try to generate a new legacy devinst
// at next boot.
//
//if(!KnownDriver) {
wsprintf(CharBuffer, TEXT("%s\\%s"),
pszRegPathServices,
LegacyServiceName);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, CharBuffer, 0,
KEY_WRITE, &hKey) == ERROR_SUCCESS) {
dwValue = 0x2; // Hardcode PNP value for a peripheral
RegSetValueEx(hKey, TEXT("PlugPlayServiceType"), 0, REG_DWORD,
(LPBYTE)&dwValue, sizeof(DWORD));
RegCloseKey(hKey);
}
//}
#endif
//
// If we installed the unknown driver, or a non-rank-0 one, then we
// set the 'need reinstall' configflag, so that the user will get a
// chance to install a better driver at next login.
//
#if 0
if(!KnownDriver || Rank) {
DWORD ConfigFlags;
ULONG ConfigFlagsSize = sizeof(ConfigFlags);
if (PNP_GetDeviceRegProp(NULL,
DeviceId,
CM_DRP_CONFIGFLAGS,
&dwValue,
(LPBYTE)&ConfigFlags,
&ConfigFlagsSize,
&ConfigFlagsSize,
0) != CR_SUCCESS) {
ConfigFlags = 0;
}
ConfigFlags |= CONFIGFLAG_REINSTALL;
PNP_SetDeviceRegProp(NULL,
DeviceId,
CM_DRP_CONFIGFLAGS,
REG_DWORD,
(LPBYTE)&ConfigFlags,
ConfigFlagsSize,
0);
//
// set problem CM_PROB_REINSTALL
//
wsprintf(CharBuffer, TEXT("%s\\%s"),
pszRegPathEnum, // ...\Enum
DeviceId);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, CharBuffer, 0,
KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS) {
dwValue = DN_HAS_PROBLEM;
RegSetValueEx(hKey, pszRegValueStatusFlags, 0, REG_DWORD,
(LPBYTE)&dwValue, sizeof(DWORD));
dwValue = CM_PROB_REINSTALL;
RegSetValueEx(hKey, pszRegValueProblem, 0, REG_DWORD,
(LPBYTE)&dwValue, sizeof(DWORD));
RegCloseKey(hKey);
}
}
#endif
//
// If we installed an unknown device, then write out the driver name as the DriverDesc
// value in the device's driver key.
//
if(!KnownDriver && ((hKey = (fpOpenDevRegKey)(hDevInfo,
&DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DRV,
KEY_WRITE)) != INVALID_HANDLE_VALUE)) {
RegSetValueEx(hKey,
TEXT("DriverDesc"),
0,
REG_SZ,
(PBYTE)LegacyServiceName,
(lstrlen(LegacyServiceName) + 1) * sizeof(TCHAR)
);
RegCloseKey(hKey);
}
// _REVIEW_
if (!KnownDriver) {
WCHAR szDeviceDesc[MAX_PATH];
//
// If we intalled an unknown device, restore the real device id back
// over the generic unknown device id that was stored there earlier
//
PNP_SetDeviceRegProp(NULL,
DeviceId,
CM_DRP_HARDWAREID,
REG_MULTI_SZ,
(LPBYTE)PnPHardwareId,
(lstrlen(PnPHardwareId) + 1) * sizeof(TCHAR),
0);
//
// Also for unknown drivers, fill out the friendly name
//
i = MAX_PATH * sizeof(TCHAR);
if (PNP_GetDeviceRegProp(NULL,
DeviceId,
CM_DRP_DEVICEDESC,
&dwValue,
(LPBYTE)szDeviceDesc,
&i,
&i,
0) == CR_SUCCESS) {
WCHAR szFormat[MAX_PATH];
WCHAR szFriendlyName[MAX_PATH];
//
// if service config info available and display name exists, use it
// with format1 version of friendly name: "%s using %s"
//
if (pServiceConfig && pServiceConfig->lpDisplayName) {
LoadString(hInst, IDS_FRIENDLYNAME_FORMAT1, szFormat, MAX_PATH);
wsprintf(szFriendlyName, szFormat,
szDeviceDesc,
pServiceConfig->lpDisplayName);
} else {
//
// No service display name was available so use format2
// version of the friendly name with the service name:
// "%s using %s driver"
//
LoadString(hInst, IDS_FRIENDLYNAME_FORMAT2, szFormat, MAX_PATH);
wsprintf(szFriendlyName, szFormat,
szDeviceDesc,
LegacyServiceName);
}
PNP_SetDeviceRegProp(NULL,
DeviceId,
CM_DRP_FRIENDLYNAME,
REG_SZ,
(LPBYTE)szFriendlyName,
(lstrlen(szFriendlyName) + 1) * sizeof(TCHAR),
0);
}
}
#if 0
// The code to set the device as present has been moved to CheckForNewDevice
//
// We installed successfully so set device as present
//
wsprintf(CharBuffer, TEXT("%s\\%s"),
pszRegPathEnum, // ...\Enum
DeviceId);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, CharBuffer, 0,
KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS) {
dwValue = TRUE;
RegSetValueEx(hKey, pszRegValueFoundAtEnum, 0, REG_DWORD,
(LPBYTE)&dwValue, sizeof(DWORD));
RegCloseKey(hKey);
}
#endif
CleanupLegacyDevInst(LegacyServiceName,
DeviceId);
//
// Register the new device instance
//
RtlInitUnicodeString(&ControlData.DeviceInstance,
DeviceId);
NtPlugPlayControl(PlugPlayControlRegisterNewDevice,
&ControlData,
sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA),
NULL);
clean0:
(fpDestroyDeviceInfoList)(hDevInfo);
if (pServiceConfig != NULL) {
(fpMyFree)(pServiceConfig);
}
return Err;
} // DoFakePnPInstall
BOOL
SetControllingService(
IN LPCWSTR pszDeviceID,
IN LPCWSTR pszService
)
{
HKEY hKey = NULL, hControlKey = NULL;
if (RegOpenKeyEx(ghEnumKey, pszDeviceID, 0, KEY_ALL_ACCESS,
&hKey) == ERROR_SUCCESS) {
if (RegCreateKeyEx(hKey, pszRegKeyDeviceControl, 0, NULL,
REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
&hControlKey, NULL) == ERROR_SUCCESS) {
//
// set controlling service
//
RegSetValueEx(hControlKey, pszRegValueActiveService, 0, REG_SZ,
(PBYTE)pszService,
(lstrlen(pszService) + 1) * sizeof(WCHAR));
RegCloseKey(hControlKey);
}
RegCloseKey(hKey);
}
return TRUE;
} // SetControllingService
BOOL
CleanupLegacyDevInst(
IN LPCWSTR pszService,
IN LPCWSTR pszDeviceId
)
{
ULONG ulLength = 0, ulCount = 0, ulValue, i;
WCHAR RegStr[MAX_PATH],
szLegacyDeviceID[MAX_DEVICE_ID_LEN],
szUnknownClassGuid[MAX_GUID_STRING_LEN],
szClassGuid[MAX_GUID_STRING_LEN];
HKEY hKey = NULL;
LPWSTR pszUnknownClassGuid = NULL;
//
// NOTE: can't cleanup any user keys since running on server side and
// don't have access to user keys (actually, user keys aren't even
// setup at this point during initialization).
//
//
// open the service's volatile Enum key
//
wsprintf(RegStr, TEXT("%s\\%s\\%s"),
pszRegPathServices,
pszService,
pszRegKeyEnum);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegStr, 0,
KEY_READ, &hKey) == ERROR_SUCCESS) {
//
// how many device instances does this service control?
//
ulLength = sizeof(DWORD);
if (RegQueryValueEx(hKey, TEXT("Count"), NULL, NULL,
(LPBYTE)&ulCount, &ulLength) != ERROR_SUCCESS) {
goto Clean0;
}
//
// get the string form of the unknown class guid for easy comparison
//
UuidToString((LPGUID)&GUID_DEVCLASS_UNKNOWN, &pszUnknownClassGuid);
wsprintf(szUnknownClassGuid, TEXT("{%s}"), pszUnknownClassGuid);
RpcStringFree(&pszUnknownClassGuid);
//
// check each device instance controlled by this service, and remove
// and deregister any legacy device instances (distinguished by the
// fact that they have an unknown class type)
//
for (i = 0; i < ulCount; i++) {
ulLength = MAX_DEVICE_ID_LEN * sizeof(WCHAR);
wsprintf(RegStr, TEXT("%d"), i);
if (RegQueryValueEx(hKey, RegStr, NULL, NULL,
(LPBYTE)szLegacyDeviceID, &ulLength) == ERROR_SUCCESS) {
//
// make sure there was no mixup and this is not the
// current device
//
if (lstrcmpi(pszDeviceId, szLegacyDeviceID) != 0) {
//
// Retrieve the class guid for this device instance
//
ulLength = MAX_GUID_STRING_LEN * sizeof(WCHAR);
if (PNP_GetDeviceRegProp(NULL,
szLegacyDeviceID,
CM_DRP_CLASSGUID,
&ulValue,
(LPBYTE)szClassGuid,
&ulLength,
&ulLength,
0) == CR_SUCCESS) {
//
// if unknown class, then it's a legacy device instance
// so remove and deregister it
//
if (lstrcmpi(szClassGuid, szUnknownClassGuid) == 0) {
//
// This Server-side PNP routine does the following:
// - deregisters the device
// - deletes the Enum branch devinst key (HKLM)
// - deletes any profile specific entries from HKLM
// - removes the devinst from the parent's attached
// component list
//
// The PNP_PRIVATE flag tells PNP_UninstallDevInst
// to do a real uninstall even if it isn't a
// phantom (without bothering with the volatile
// key copying thing).
//
PNP_UninstallDevInst(NULL,
szLegacyDeviceID,
PNP_PRIVATE);
}
}
}
}
}
}
Clean0:
if (hKey != NULL) {
RegCloseKey(hKey);
}
return TRUE;
} // CleanupLegacyDevInst
//------------------------------------------------------------------------
// Post Log-On routines
//------------------------------------------------------------------------
CONFIGRET
PNP_ReportLogOn(
IN handle_t hBinding,
IN BOOL bAdmin
)
{
CONFIGRET Status = CR_SUCCESS;
HANDLE hThread = NULL;
DWORD ThreadID, dwWait;
UNREFERENCED_PARAMETER(hBinding);
//
// Wait for the init mutex - this ensures that the pnp init
// routine (called when the service starts) has had a chance
// to complete first.
//
if (hInitMutex != NULL) {
dwWait = WaitForSingleObject(hInitMutex, 180000); // 3 minutes
if (dwWait != WAIT_OBJECT_0) {
//
// mutex was abandoned or timed out during the wait,
// don't attempt any further init activity
//
return CR_FAILURE;
}
}
try {
//
// do this work in a separate thread so that this routine
// can return back to userinit and userinit can finish.
//
hThread = CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)InitiateDeviceInstallation,
(LPVOID)(BOOL)bAdmin,
0,
&ThreadID);
if (hThread == NULL) {
Status = CR_FAILURE;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = FALSE;
}
if (hInitMutex != NULL) {
ReleaseMutex(hInitMutex);
}
if (hThread != NULL) {
CloseHandle(hThread);
}
return Status; // log an event (BUGBUG)
} // PNP_ReportLogonInfo
DWORD
InitiateDeviceInstallation(
LPDWORD lpThreadParam
)
{
CONFIGRET Status = CR_SUCCESS;
LPWSTR pDeviceList = NULL, pszDevice = NULL;
ULONG ulSize = 0, ulProblem = 0;
HANDLE hPipe = NULL;
BOOL bAdmin;
try {
//
// open the client side of the named pipe to the hidden
// server process
//
if (!WaitNamedPipe(PNP_NEW_HW_PIPE, PNP_PIPE_TIMEOUT)) {
OutputDebugString(TEXT("UPNPPROC - WaitNamedPipe failed\n"));
Status = CR_FAILURE;
goto Clean0;
}
hPipe = CreateFile(PNP_NEW_HW_PIPE,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hPipe == INVALID_HANDLE_VALUE) {
// Log event - CreateFile on named pipe failed
Status = CR_FAILURE;
goto Clean0;
}
bAdmin = (BOOL)(lpThreadParam);
//
// Retreive the list of root enumerated devices
//
Status = PNP_GetDeviceListSize(NULL,
NULL, //TEXT("Root"),
&ulSize,
0); //CM_GETIDLIST_FILTER_ENUMERATOR);
if (Status != CR_SUCCESS) {
goto Clean0;
}
pDeviceList = malloc(ulSize * sizeof(WCHAR));
if (pDeviceList == NULL) {
Status = CR_OUT_OF_MEMORY;
goto Clean0;
}
Status = PNP_GetDeviceList(NULL,
NULL, //TEXT("Root"),
pDeviceList,
&ulSize,
0); //CM_GETIDLIST_FILTER_ENUMERATOR);
if (Status != CR_SUCCESS) {
goto Clean0;
}
//
// Get the problem value for each root enumerated device, if any
// need to be reinstalled, ask Device Manager to handle it
//
for (pszDevice = pDeviceList;
*pszDevice;
pszDevice += lstrlen(pszDevice) + 1) {
//
// Is device present?
//
if (IsDeviceIdPresent(pszDevice, NULL)) {
//
// If so, then check if it has a problem.
//
Status = PNP_GetDeviceStatus(NULL,
pszDevice,
NULL,
&ulProblem,
0);
if (Status == CR_SUCCESS) {
if (ulProblem == CM_PROB_REINSTALL ||
ulProblem == CM_PROB_NOT_CONFIGURED) {
//
// request for the hidden server process to
// continue with gui part of installation by
// writing the device id to the named pipe
//
if (!WriteFile(hPipe,
pszDevice,
(lstrlen(pszDevice)+1) * sizeof(WCHAR),
&ulSize,
NULL)) {
// log event
}
//
// if user is not admin, only bother them once
//
if (!bAdmin) {
goto Clean0;
}
}
}
}
}
Clean0:
;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
if (hPipe != INVALID_HANDLE_VALUE) {
CloseHandle(hPipe);
}
if (pDeviceList != NULL) {
free(pDeviceList);
}
return (DWORD)Status;
} // InitiateDeviceInstallation