#include "precomp.h" #pragma hdrstop typedef enum { ACPIAPIC_UP, MPS_UP, HAL_TYPE_OTHER } HalType; typedef BOOL (WINAPI *UPDATE_DRIVER_FOR_PLUG_AND_PLAY_DEVICES_PROC) ( HWND hwndParent, LPCTSTR HardwareId, LPCTSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired ); DWORD GetCurrentlyInstalledHal( HDEVINFO hDeviceInfo, PSP_DEVINFO_DATA DeviceInfoData ) /*++ Routine Description: This routine will determine if the currently installed HAL on this machine. Arguments: hDeviceInfo - handle to the device information set that contains the HAL for this machine. DeviceInfoData - pointer to the SP_DEVINFO_DATA structure that contains the specific HAL devnode for this machine. Return Value: The return value will be one of the HalType enums: ACPIAPIC_UP MPS_UP HAL_TYPE_OTHER We only care about the ACPIAPIC_UP and the MPS_UP case since those are the only ones we can currently update to MP Hals. --*/ { DWORD CurrentlyInstalledHalType = HAL_TYPE_OTHER; HKEY hKey = INVALID_HANDLE_VALUE; TCHAR InfSection[LINE_LEN]; DWORD RegDataType, RegDataLength; // // The "InfSection" is stored in the devnodes driver key // hKey = SetupDiOpenDevRegKey(hDeviceInfo, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ ); if (hKey != INVALID_HANDLE_VALUE) { RegDataLength = sizeof(InfSection); if (RegQueryValueEx(hKey, REGSTR_VAL_INFSECTION, NULL, &RegDataType, (PBYTE)InfSection, &RegDataLength ) == ERROR_SUCCESS) { printf("Current HAL is using InfSection %ws\n", InfSection); // // Compare the InfSection to see if it is one of the two that // we can change from UP to MP. // if (!lstrcmpi(InfSection, TEXT("ACPIAPIC_UP_HAL"))) { CurrentlyInstalledHalType = ACPIAPIC_UP; } if (!lstrcmpi(InfSection, TEXT("MPS_UP_HAL"))) { CurrentlyInstalledHalType = MPS_UP; } } RegCloseKey(hKey); } return CurrentlyInstalledHalType; } int __cdecl main( IN int argc, IN char *argv[] ) { HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE; SP_DEVINFO_DATA DeviceInfoData; DWORD CurrentlyInstalledHalType = HAL_TYPE_OTHER; TCHAR HardwareId[MAX_DEVICE_ID_LEN]; TCHAR FullInfPath[MAX_PATH]; HMODULE hNewDev; UPDATE_DRIVER_FOR_PLUG_AND_PLAY_DEVICES_PROC pfnUpdateDriverForPlugAndPlayDevices; // // Ask setupapi to build up a list of all the COMPUTER class devnodes // on this machine. // hDeviceInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_COMPUTER, NULL, NULL, DIGCF_PRESENT ); if (hDeviceInfo == INVALID_HANDLE_VALUE) { printf("ERROR could not find a HAL devnode on this machine!\n"); return 0; } // // There is only one HAL per machine, so we will just grab the 1st device // information data element in the list. // DeviceInfoData.cbSize = sizeof(DeviceInfoData); if (!SetupDiEnumDeviceInfo(hDeviceInfo, 0, &DeviceInfoData )) { goto clean0; } // // Get the currently installed Hal Type. // The currently installed Hal must be ACPIAPIC_UP or MPS_UP in order for us // to upgrade it to an MP Hal. // CurrentlyInstalledHalType = GetCurrentlyInstalledHal(hDeviceInfo, &DeviceInfoData); if (CurrentlyInstalledHalType == HAL_TYPE_OTHER) { printf("The currently installed HAL is not upgradable to MP!\n"); goto clean0; } // // At this point we know what the currently installed Hal is and we know that it // has a corresponding MP Hal that it can be upgraded to. In order to upgrade // the Hal we will replace the Hals Hardware Id registry key with the appropriate // MP Hardware Id and then call the newdev.dll API UpdateDriverForPlugAndPlayDevices // which will do the rest of the work. // memset(HardwareId, 0, sizeof(HardwareId)); if (CurrentlyInstalledHalType == ACPIAPIC_UP) { lstrcpy(HardwareId, TEXT("ACPIAPIC_MP")); } else { lstrcpy(HardwareId, TEXT("MPS_MP")); } if (SetupDiSetDeviceRegistryProperty(hDeviceInfo, &DeviceInfoData, SPDRP_HARDWAREID, (CONST BYTE*)HardwareId, (sizeof(HardwareId) + 2) * sizeof(TCHAR) )) { // // The Hardware Id has now been changed so call UpdateDriverForPlugAndPlayDevices // to upate the driver on this device. // // UpdateDriverForPlugAndPlayDevices needs to have a full path to the INF file. // For this sample code we will always be using the hal.inf in the %windir%\inf // directory. // if (GetWindowsDirectory(FullInfPath, sizeof(FullInfPath)/sizeof(TCHAR))) { lstrcat(FullInfPath, TEXT("\\INF\\HAL.INF")); hNewDev = LoadLibrary(TEXT("newdev.dll")); if (hNewDev) { pfnUpdateDriverForPlugAndPlayDevices = (UPDATE_DRIVER_FOR_PLUG_AND_PLAY_DEVICES_PROC)GetProcAddress(hNewDev, "UpdateDriverForPlugAndPlayDevicesW" ); if (pfnUpdateDriverForPlugAndPlayDevices) { BOOL bRet; // // Call UpdateDriverForPlugAndPlayDevices with the appropriate HardwareId and // FullInfPath. We will pass in 0 for the flags and NULL for the bRebootRequired // pointer. By passing in NULL for bRebootRequired this will tell newdev.dll to // prompt for a reboot if one is needed. Since we are replacing a Hal a reboot // will always be needed. If the caller of this program wants to handle the reboot // logic themselves then just pass a PBOOL as the last parameter to // UpdateDriverForPlugAndPlayDevices and then handle the reboot yourself // if this value is TRUE. // bRet = pfnUpdateDriverForPlugAndPlayDevices(NULL, HardwareId, FullInfPath, 0, NULL ); printf("UpdateDriverForPlugAndPlayDevices(%ws, %ws) returned 0x%X, 0x%X\n", HardwareId, FullInfPath, bRet, GetLastError()); } else { printf("ERROR GetProcAddress() failed with 0x%X\n", GetLastError()); } FreeLibrary(hNewDev); } } } clean0: if (hDeviceInfo != INVALID_HANDLE_VALUE) { SetupDiDestroyDeviceInfoList(hDeviceInfo); } return 0; }