windows-nt/Source/XPSP1/NT/base/pnp/tools/chnghal/chnghal.c
2020-09-26 16:20:57 +08:00

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;
}