247 lines
7.9 KiB
C
247 lines
7.9 KiB
C
|
#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;
|
||
|
}
|
||
|
|