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.
1436 lines
49 KiB
1436 lines
49 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation
|
|
//
|
|
// File: finish.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "hdwwiz.h"
|
|
#include <help.h>
|
|
|
|
typedef
|
|
BOOL
|
|
(*SRSETRESTOREPOINT)(
|
|
PRESTOREPOINTINFO pRestorePtSpec,
|
|
PSTATEMGRSTATUS pSMgrStatus
|
|
);
|
|
|
|
BOOL
|
|
DeviceHasResources(
|
|
DEVINST DeviceInst
|
|
)
|
|
{
|
|
CONFIGRET ConfigRet;
|
|
ULONG lcType = NUM_LOG_CONF;
|
|
|
|
while (lcType--) {
|
|
|
|
ConfigRet = CM_Get_First_Log_Conf_Ex(NULL, DeviceInst, lcType, NULL);
|
|
|
|
if (ConfigRet == CR_SUCCESS) {
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD
|
|
HdwRemoveDevice(
|
|
PHARDWAREWIZ HardwareWiz
|
|
)
|
|
{
|
|
SP_REMOVEDEVICE_PARAMS RemoveDeviceParams;
|
|
LONG Error = ERROR_SUCCESS;
|
|
|
|
RemoveDeviceParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
RemoveDeviceParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
|
|
RemoveDeviceParams.Scope = DI_REMOVEDEVICE_GLOBAL;
|
|
RemoveDeviceParams.HwProfile = 0;
|
|
|
|
if (!SetupDiSetClassInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
(PSP_CLASSINSTALL_HEADER)&RemoveDeviceParams,
|
|
sizeof(RemoveDeviceParams)
|
|
)
|
|
||
|
|
!SetupDiCallClassInstaller(DIF_REMOVE,
|
|
HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData
|
|
)) {
|
|
Error = GetLastError();
|
|
}
|
|
|
|
|
|
//
|
|
// Clear the class install parameters.
|
|
//
|
|
SetupDiSetClassInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
return Error;
|
|
}
|
|
|
|
BOOL
|
|
GetClassGuidForInf(
|
|
PTSTR InfFileName,
|
|
LPGUID ClassGuid
|
|
)
|
|
{
|
|
TCHAR ClassName[MAX_CLASS_NAME_LEN];
|
|
DWORD NumGuids;
|
|
|
|
if (!SetupDiGetINFClass(InfFileName,
|
|
ClassGuid,
|
|
ClassName,
|
|
SIZECHARS(ClassName),
|
|
NULL)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (IsEqualGUID(ClassGuid, &GUID_NULL)) {
|
|
//
|
|
// Then we need to retrieve the GUID associated with the INF's class name.
|
|
// (If this class name isn't installed (i.e., has no corresponding GUID),
|
|
// of if it matches with multiple GUIDs, then we abort.
|
|
//
|
|
if (!SetupDiClassGuidsFromName(ClassName, ClassGuid, 1, &NumGuids) ||
|
|
!NumGuids) {
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LONG
|
|
ClassInstallerInstalls(
|
|
HWND hwndParent,
|
|
PHARDWAREWIZ HardwareWiz,
|
|
HDEVINFO hDeviceInfo,
|
|
PSP_DEVINFO_DATA DeviceInfoData,
|
|
BOOL InstallFilesOnly
|
|
)
|
|
{
|
|
DWORD Err = ERROR_SUCCESS;
|
|
HSPFILEQ FileQueue = INVALID_HANDLE_VALUE;
|
|
PVOID MessageHandlerContext = NULL;
|
|
SP_DEVINSTALL_PARAMS DeviceInstallParams;
|
|
DWORD ScanResult = 0;
|
|
RESTOREPOINTINFO RestorePointInfo;
|
|
STATEMGRSTATUS SMgrStatus;
|
|
int FileQueueNeedsReboot = 0;
|
|
|
|
//
|
|
// verify with class installer, and class-specific coinstallers
|
|
// that the driver is not blacklisted. For DIF_ALLOW_INSTALL we
|
|
// accept ERROR_SUCCESS or ERROR_DI_DO_DEFAULT as good return codes.
|
|
//
|
|
if (!SetupDiCallClassInstaller(DIF_ALLOW_INSTALL,
|
|
hDeviceInfo,
|
|
DeviceInfoData
|
|
) &&
|
|
(GetLastError() != ERROR_DI_DO_DEFAULT)) {
|
|
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if (!SetupDiGetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DeviceInstallParams
|
|
)) {
|
|
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
FileQueue = SetupOpenFileQueue();
|
|
|
|
if (FileQueue == INVALID_HANDLE_VALUE) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
DeviceInstallParams.Flags |= DI_NOVCP;
|
|
DeviceInstallParams.FileQueue = FileQueue;
|
|
|
|
SetupDiSetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DeviceInstallParams
|
|
);
|
|
|
|
//
|
|
// Set the SPQ_FLAG_ABORT_IF_UNSIGNED value on the file queue. With this
|
|
// flag set setupapi will bail out of the copy if it encounters an unsigned
|
|
// file. At that point we will set a system restore point and then
|
|
// do the copy. This way the user can back out of an unsigned driver
|
|
// install using system restore.
|
|
//
|
|
// Note that system restore is currently not supported on 64-bit so don't
|
|
// bother setting the SPQ_FLAG_ABORT_IF_UNSIGNED.
|
|
//
|
|
#ifndef _WIN64
|
|
SetupSetFileQueueFlags(FileQueue,
|
|
SPQ_FLAG_ABORT_IF_UNSIGNED,
|
|
SPQ_FLAG_ABORT_IF_UNSIGNED
|
|
);
|
|
#endif
|
|
|
|
//
|
|
// Install the files first in one shot.
|
|
// This allows new coinstallers to run during the install.
|
|
//
|
|
if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
|
|
hDeviceInfo,
|
|
DeviceInfoData
|
|
)) {
|
|
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Since we created our own FileQueue then we need to
|
|
// scan and possibly commit the queue and prune copies as needed.
|
|
//
|
|
if (!SetupScanFileQueue(FileQueue,
|
|
SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
|
|
hwndParent,
|
|
NULL,
|
|
NULL,
|
|
&ScanResult
|
|
)) {
|
|
|
|
//
|
|
// If the API failed then set the ScanResult to 0 (failure).
|
|
//
|
|
ScanResult = 0;
|
|
}
|
|
|
|
//
|
|
// If the ScanResult is 1 then that means that all of the files are present
|
|
// and that there are no rename or delete operations are left in the copy
|
|
// queue. This means we can skip the file queue commit.
|
|
//
|
|
// If the ScanResult is 0 then there are file copy operations that are needed.
|
|
// If the ScanResult is 2 then there are delete, rename or backup operations
|
|
// that are needed.
|
|
//
|
|
if (ScanResult != 1) {
|
|
MessageHandlerContext = SetupInitDefaultQueueCallbackEx(
|
|
hwndParent,
|
|
(DeviceInstallParams.Flags & DI_QUIETINSTALL)
|
|
? INVALID_HANDLE_VALUE : NULL,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (MessageHandlerContext) {
|
|
//
|
|
// Commit the file queue.
|
|
//
|
|
if (!SetupCommitFileQueue(hwndParent,
|
|
FileQueue,
|
|
SetupDefaultQueueCallback,
|
|
MessageHandlerContext
|
|
)) {
|
|
|
|
Err = GetLastError();
|
|
|
|
if (Err == ERROR_SET_SYSTEM_RESTORE_POINT) {
|
|
SetupTermDefaultQueueCallback(MessageHandlerContext);
|
|
|
|
MessageHandlerContext = SetupInitDefaultQueueCallbackEx(
|
|
hwndParent,
|
|
(DeviceInstallParams.Flags & DI_QUIETINSTALL)
|
|
? INVALID_HANDLE_VALUE : NULL,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (MessageHandlerContext) {
|
|
HMODULE hSrClientDll = NULL;
|
|
SRSETRESTOREPOINT pfnSrSetRestorePoint = NULL;
|
|
|
|
if ((hSrClientDll = LoadLibrary(TEXT("srclient.dll"))) != NULL) {
|
|
|
|
if ((pfnSrSetRestorePoint = (SRSETRESTOREPOINT)GetProcAddress(hSrClientDll,
|
|
"SRSetRestorePointW"
|
|
)) != NULL) {
|
|
//
|
|
// Set the system restore point.
|
|
//
|
|
RestorePointInfo.dwEventType = BEGIN_SYSTEM_CHANGE;
|
|
RestorePointInfo.dwRestorePtType = DEVICE_DRIVER_INSTALL;
|
|
RestorePointInfo.llSequenceNumber = 0;
|
|
|
|
if (!LoadString(hHdwWiz,
|
|
IDS_NEW_SETRESTOREPOINT,
|
|
(LPWSTR)RestorePointInfo.szDescription,
|
|
SIZECHARS(RestorePointInfo.szDescription)
|
|
)) {
|
|
RestorePointInfo.szDescription[0] = TEXT('\0');
|
|
}
|
|
|
|
pfnSrSetRestorePoint(&RestorePointInfo, &SMgrStatus);
|
|
}
|
|
|
|
FreeLibrary(hSrClientDll);
|
|
}
|
|
|
|
//
|
|
// Clear the SPQ_FLAG_ABORT_IF_UNSIGNED flag so the file
|
|
// queue will be commited the next time.
|
|
//
|
|
SetupSetFileQueueFlags(FileQueue,
|
|
SPQ_FLAG_ABORT_IF_UNSIGNED,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Now that we have set the restore point and cleared the
|
|
// SPQ_FLAG_ABORT_IF_UNSIGNED flag from the file queue we
|
|
// can commit the queue again.
|
|
//
|
|
if (!SetupCommitFileQueue(hwndParent,
|
|
FileQueue,
|
|
SetupDefaultQueueCallback,
|
|
MessageHandlerContext
|
|
)) {
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
} else {
|
|
//
|
|
// We were successful in commiting the file queue, so check
|
|
// to see whether a reboot is required as a result of committing
|
|
// the queue (i.e. because files were in use, or the INF requested
|
|
// a reboot).
|
|
//
|
|
FileQueueNeedsReboot = SetupPromptReboot(FileQueue, NULL, TRUE);
|
|
}
|
|
}
|
|
} else {
|
|
goto clean0;
|
|
}
|
|
} else {
|
|
//
|
|
// We were successful in commiting the file queue, so check
|
|
// to see whether a reboot is required as a result of committing
|
|
// the queue (i.e. because files were in use, or the INF requested
|
|
// a reboot).
|
|
//
|
|
FileQueueNeedsReboot = SetupPromptReboot(FileQueue, NULL, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we were only copiny files then we are done!
|
|
//
|
|
if (InstallFilesOnly) {
|
|
Err = ERROR_SUCCESS;
|
|
goto clean0;
|
|
}
|
|
|
|
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if (SetupDiGetDeviceInstallParams(hDeviceInfo,
|
|
DeviceInfoData,
|
|
&DeviceInstallParams
|
|
)) {
|
|
DWORD FileQueueFlags;
|
|
|
|
//
|
|
// If we didn't copy any files when commiting the file queue then the
|
|
// SPQ_FLAG_FILES_MODIFIED flag will NOT be set. In this case set
|
|
// the DI_FLAGSEX_RESTART_DEVICE_ONLY flag so that we only stop/start
|
|
// this single device. By default setupapi will stop/start this device
|
|
// as well as any other device that was using the same driver/filter
|
|
// that this device is using.
|
|
//
|
|
if (SetupGetFileQueueFlags(FileQueue, &FileQueueFlags) &&
|
|
!(FileQueueFlags & SPQ_FLAG_FILES_MODIFIED)) {
|
|
|
|
DeviceInstallParams.FlagsEx |= DI_FLAGSEX_RESTART_DEVICE_ONLY;
|
|
}
|
|
|
|
//
|
|
// Set the DI_NOFILECOPY flag since we already copied the files during
|
|
// the DIF_INSTALLDEVICEFILES, so we don't need to copy them again during
|
|
// the DIF_INSTALLDEVICE.
|
|
//
|
|
DeviceInstallParams.Flags |= DI_NOFILECOPY;
|
|
SetupDiSetDeviceInstallParams(hDeviceInfo,
|
|
DeviceInfoData,
|
|
&DeviceInstallParams
|
|
);
|
|
}
|
|
|
|
|
|
//
|
|
// Register any device-specific co-installers for this device,
|
|
//
|
|
if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS,
|
|
hDeviceInfo,
|
|
DeviceInfoData
|
|
)) {
|
|
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// install any INF/class installer-specified interfaces.
|
|
// and then finally the real "InstallDevice"!
|
|
//
|
|
if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES,
|
|
hDeviceInfo,
|
|
DeviceInfoData
|
|
)
|
|
||
|
|
!SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
|
|
hDeviceInfo,
|
|
DeviceInfoData
|
|
)) {
|
|
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
Err = ERROR_SUCCESS;
|
|
|
|
clean0:
|
|
|
|
if (MessageHandlerContext) {
|
|
SetupTermDefaultQueueCallback(MessageHandlerContext);
|
|
}
|
|
|
|
//
|
|
// If the file queue said that a reboot was needed then set the
|
|
// DI_NEEDRESTART flag.
|
|
//
|
|
if (FileQueueNeedsReboot) {
|
|
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if (SetupDiGetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DeviceInstallParams
|
|
)) {
|
|
|
|
DeviceInstallParams.Flags |= DI_NEEDRESTART;
|
|
|
|
SetupDiSetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DeviceInstallParams
|
|
);
|
|
}
|
|
}
|
|
|
|
if (FileQueue != INVALID_HANDLE_VALUE) {
|
|
//
|
|
// If we have a valid file queue handle and there was an error during
|
|
// the device install then we want to delete any new INFs that were
|
|
// copied into the INF directory. We do this under the assumption that
|
|
// since there was an error during the install these INFs must be bad.
|
|
//
|
|
if (Err != ERROR_SUCCESS) {
|
|
SetupUninstallNewlyCopiedInfs(FileQueue,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// Clear out our file queue from the device install params. We need
|
|
// to do this or else SetupCloseFileQueue will fail because it will
|
|
// still have a ref count.
|
|
//
|
|
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if (SetupDiGetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DeviceInstallParams
|
|
)) {
|
|
|
|
DeviceInstallParams.Flags &= ~DI_NOVCP;
|
|
DeviceInstallParams.FileQueue = INVALID_HANDLE_VALUE;
|
|
|
|
SetupDiSetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DeviceInstallParams
|
|
);
|
|
}
|
|
|
|
SetupCloseFileQueue(FileQueue);
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
//
|
|
// invokable only from finish page!
|
|
//
|
|
DWORD
|
|
InstallDev(
|
|
HWND hwndParent,
|
|
PHARDWAREWIZ HardwareWiz
|
|
)
|
|
{
|
|
SP_DRVINFO_DATA DriverInfoData;
|
|
SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
|
|
SP_DEVINSTALL_PARAMS DeviceInstallParams;
|
|
TCHAR ClassGuidString[MAX_GUID_STRING_LEN];
|
|
GUID ClassGuidInf;
|
|
LPGUID ClassGuid;
|
|
int ClassGuidNum;
|
|
DWORD Error = ERROR_SUCCESS;
|
|
BOOL IgnoreRebootFlags = FALSE;
|
|
TCHAR Buffer[MAX_PATH];
|
|
ULONG DevNodeStatus = 0, Problem = 0;
|
|
|
|
|
|
if (!HardwareWiz->ClassGuidSelected) {
|
|
HardwareWiz->ClassGuidSelected = (LPGUID)&GUID_NULL;
|
|
}
|
|
|
|
|
|
DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
|
|
if (SetupDiGetSelectedDriver(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DriverInfoData
|
|
)) {
|
|
//
|
|
// Get details on this driver node, so that we can examine the INF that this
|
|
// node came from.
|
|
//
|
|
DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
|
|
if (!SetupDiGetDriverInfoDetail(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DriverInfoData,
|
|
&DriverInfoDetailData,
|
|
sizeof(DriverInfoDetailData),
|
|
NULL
|
|
)) {
|
|
Error = GetLastError();
|
|
if (Error != ERROR_INSUFFICIENT_BUFFER) {
|
|
goto clean0;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Verif that the class is installed, if its not then
|
|
// attempt to install it.
|
|
//
|
|
HdwBuildClassInfoList(HardwareWiz,
|
|
0
|
|
);
|
|
|
|
|
|
//
|
|
// fetch classguid from inf, (It may be different than what we already
|
|
// have in class guid selected).
|
|
//
|
|
if (!GetClassGuidForInf(DriverInfoDetailData.InfFileName, &ClassGuidInf)) {
|
|
|
|
ClassGuidInf = *HardwareWiz->ClassGuidSelected;
|
|
}
|
|
|
|
if (IsEqualGUID(&ClassGuidInf, &GUID_NULL)) {
|
|
|
|
ClassGuidInf = GUID_DEVCLASS_UNKNOWN;
|
|
}
|
|
|
|
//
|
|
// if the ClassGuidInf wasn't found then this class hasn't been installed yet.
|
|
// -install the class installer now.
|
|
//
|
|
ClassGuid = HardwareWiz->ClassGuidList;
|
|
ClassGuidNum = HardwareWiz->ClassGuidNum;
|
|
while (ClassGuidNum--) {
|
|
if (IsEqualGUID(ClassGuid, &ClassGuidInf)) {
|
|
break;
|
|
}
|
|
|
|
ClassGuid++;
|
|
}
|
|
|
|
if (ClassGuidNum < 0 &&
|
|
!SetupDiInstallClass(hwndParent,
|
|
DriverInfoDetailData.InfFileName,
|
|
0,
|
|
NULL
|
|
)) {
|
|
Error = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
|
|
//
|
|
// Now make sure that the class of this device is the same as the class
|
|
// of the selected driver node.
|
|
//
|
|
if (!IsEqualGUID(&ClassGuidInf, HardwareWiz->ClassGuidSelected)) {
|
|
pSetupStringFromGuid(&ClassGuidInf,
|
|
ClassGuidString,
|
|
SIZECHARS(ClassGuidString)
|
|
);
|
|
|
|
SetupDiSetDeviceRegistryProperty(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
SPDRP_CLASSGUID,
|
|
(PBYTE)ClassGuidString,
|
|
sizeof(ClassGuidString)
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// No selected driver, and no associated class--use "Unknown" class.
|
|
//
|
|
else {
|
|
|
|
//
|
|
// If the devnode is currently running 'raw', then remember this
|
|
// fact so that we don't require a reboot later (NULL driver installation
|
|
// isn't going to change anything).
|
|
//
|
|
if (CM_Get_DevNode_Status(&DevNodeStatus,
|
|
&Problem,
|
|
HardwareWiz->DeviceInfoData.DevInst,
|
|
0) == CR_SUCCESS) {
|
|
if (!SetupDiGetDeviceRegistryProperty(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
SPDRP_SERVICE,
|
|
NULL, // regdatatype
|
|
(PVOID)Buffer,
|
|
sizeof(Buffer),
|
|
NULL
|
|
)) {
|
|
*Buffer = TEXT('\0');
|
|
}
|
|
|
|
if ((DevNodeStatus & DN_STARTED) && (*Buffer == TEXT('\0'))) {
|
|
IgnoreRebootFlags = TRUE;
|
|
}
|
|
}
|
|
|
|
if (IsEqualGUID(HardwareWiz->ClassGuidSelected, &GUID_NULL)) {
|
|
|
|
pSetupStringFromGuid(&GUID_DEVCLASS_UNKNOWN,
|
|
ClassGuidString,
|
|
SIZECHARS(ClassGuidString)
|
|
);
|
|
|
|
|
|
SetupDiSetDeviceRegistryProperty(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
SPDRP_CLASSGUID,
|
|
(PBYTE)ClassGuidString,
|
|
sizeof(ClassGuidString)
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// since this is a legacy install, set the manually installed bit if the
|
|
// driver that was selected was not a CopyFilesOnly (PnP) driver.
|
|
//
|
|
if (!HardwareWiz->CopyFilesOnly) {
|
|
ULONG Len;
|
|
CONFIGRET ConfigRet;
|
|
ULONG ConfigFlag;
|
|
|
|
Len = sizeof(ConfigFlag);
|
|
ConfigRet = CM_Get_DevNode_Registry_Property_Ex(HardwareWiz->DeviceInfoData.DevInst,
|
|
CM_DRP_CONFIGFLAGS,
|
|
NULL,
|
|
(PVOID)&ConfigFlag,
|
|
&Len,
|
|
0,
|
|
NULL
|
|
);
|
|
if (ConfigRet != CR_SUCCESS) {
|
|
ConfigFlag = 0;
|
|
}
|
|
|
|
ConfigFlag |= CONFIGFLAG_MANUAL_INSTALL;
|
|
CM_Set_DevNode_Registry_Property_Ex(HardwareWiz->DeviceInfoData.DevInst,
|
|
CM_DRP_CONFIGFLAGS,
|
|
(PVOID)&ConfigFlag,
|
|
sizeof(ConfigFlag),
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
Error = ClassInstallerInstalls(hwndParent,
|
|
HardwareWiz,
|
|
HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
HardwareWiz->CopyFilesOnly
|
|
);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
//
|
|
// we Have an install error, including a user cancel.
|
|
// Install the null driver.
|
|
//
|
|
if (SetupDiSetSelectedDriver(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
NULL
|
|
)) {
|
|
|
|
if (SetupDiGetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DeviceInstallParams
|
|
)) {
|
|
DeviceInstallParams.FlagsEx |= DI_FLAGSEX_SETFAILEDINSTALL;
|
|
SetupDiSetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DeviceInstallParams
|
|
);
|
|
}
|
|
|
|
SetupDiInstallDevice(HardwareWiz->hDeviceInfo, &HardwareWiz->DeviceInfoData);
|
|
}
|
|
|
|
goto clean0;
|
|
}
|
|
|
|
|
|
//
|
|
// Fetch the latest DeviceInstallParams for the restart bits.
|
|
//
|
|
if (!IgnoreRebootFlags) {
|
|
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if (SetupDiGetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DeviceInstallParams
|
|
)) {
|
|
if (DeviceInstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) {
|
|
HardwareWiz->Reboot |= DI_NEEDREBOOT;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
clean0:
|
|
|
|
return Error;
|
|
}
|
|
|
|
BOOL
|
|
CALLBACK
|
|
AddPropSheetPageProc(
|
|
IN HPROPSHEETPAGE hpage,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
*((HPROPSHEETPAGE *)lParam) = hpage;
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DisplayResource(
|
|
PHARDWAREWIZ HardwareWiz,
|
|
HWND hWndParent,
|
|
BOOL NeedsForcedConfig
|
|
)
|
|
{
|
|
HINSTANCE hLib;
|
|
PROPSHEETHEADER psh;
|
|
HPROPSHEETPAGE hpsPages[1];
|
|
SP_PROPSHEETPAGE_REQUEST PropPageRequest;
|
|
LPFNADDPROPSHEETPAGES ExtensionPropSheetPage = NULL;
|
|
SP_DEVINSTALL_PARAMS DevInstallParams;
|
|
|
|
//
|
|
// Now get the resource selection page from setupapi.dll
|
|
//
|
|
hLib = GetModuleHandle(TEXT("setupapi.dll"));
|
|
if (hLib) {
|
|
ExtensionPropSheetPage = (LPFNADDPROPSHEETPAGES)GetProcAddress(hLib, "ExtensionPropSheetPageProc");
|
|
}
|
|
|
|
if (!ExtensionPropSheetPage) {
|
|
return;
|
|
}
|
|
|
|
PropPageRequest.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
|
|
PropPageRequest.PageRequested = SPPSR_SELECT_DEVICE_RESOURCES;
|
|
PropPageRequest.DeviceInfoSet = HardwareWiz->hDeviceInfo;
|
|
PropPageRequest.DeviceInfoData = &HardwareWiz->DeviceInfoData;
|
|
|
|
if (!ExtensionPropSheetPage(&PropPageRequest,
|
|
AddPropSheetPageProc,
|
|
(LONG_PTR)hpsPages
|
|
)) {
|
|
// warning ?
|
|
return;
|
|
}
|
|
|
|
//
|
|
// create the property sheet
|
|
//
|
|
psh.dwSize = sizeof(PROPSHEETHEADER);
|
|
psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
|
|
psh.hwndParent = hWndParent;
|
|
psh.hInstance = hHdwWiz;
|
|
psh.pszIcon = NULL;
|
|
|
|
psh.pszCaption = (LPTSTR)IDS_ADDNEWDEVICE;
|
|
|
|
psh.nPages = 1;
|
|
psh.phpage = hpsPages;
|
|
psh.nStartPage = 0;
|
|
psh.pfnCallback = NULL;
|
|
|
|
|
|
//
|
|
// Clear the Propchange pending bit in the DeviceInstall params.
|
|
//
|
|
DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if (SetupDiGetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DevInstallParams
|
|
)) {
|
|
DevInstallParams.FlagsEx &= ~DI_FLAGSEX_PROPCHANGE_PENDING;
|
|
SetupDiSetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DevInstallParams
|
|
);
|
|
}
|
|
|
|
//
|
|
// Set the CONFIGFLAG_NEEDS_FORCED_CONFIG if this device needs a forced config.
|
|
//
|
|
if (NeedsForcedConfig) {
|
|
|
|
DWORD ConfigFlags = 0;
|
|
ULONG ulSize = sizeof(ConfigFlags);
|
|
|
|
if (CM_Get_DevInst_Registry_Property(HardwareWiz->DeviceInfoData.DevInst,
|
|
CM_DRP_CONFIGFLAGS,
|
|
NULL,
|
|
(LPBYTE)&ConfigFlags,
|
|
&ulSize,
|
|
0) != CR_SUCCESS) {
|
|
ConfigFlags = 0;
|
|
}
|
|
|
|
ConfigFlags |= CONFIGFLAG_NEEDS_FORCED_CONFIG;
|
|
|
|
CM_Set_DevInst_Registry_Property(HardwareWiz->DeviceInfoData.DevInst,
|
|
CM_DRP_CONFIGFLAGS,
|
|
(LPBYTE)&ConfigFlags,
|
|
sizeof(ConfigFlags),
|
|
0
|
|
);
|
|
}
|
|
|
|
if (PropertySheet(&psh) == -1) {
|
|
DestroyPropertySheetPage(hpsPages[0]);
|
|
}
|
|
|
|
//
|
|
// If a PropChange occurred invoke the DIF_PROPERTYCHANGE
|
|
//
|
|
if (SetupDiGetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DevInstallParams
|
|
)) {
|
|
if (DevInstallParams.FlagsEx & DI_FLAGSEX_PROPCHANGE_PENDING) {
|
|
SP_PROPCHANGE_PARAMS PropChangeParams;
|
|
|
|
PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
|
|
PropChangeParams.Scope = DICS_FLAG_GLOBAL;
|
|
PropChangeParams.HwProfile = 0;
|
|
|
|
if (SetupDiSetClassInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
(PSP_CLASSINSTALL_HEADER)&PropChangeParams,
|
|
sizeof(PropChangeParams)
|
|
)) {
|
|
SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
|
|
HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData
|
|
);
|
|
}
|
|
|
|
//
|
|
// Clear the class install parameters.
|
|
//
|
|
SetupDiSetClassInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
NULL,
|
|
0
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if we need to reboot
|
|
//
|
|
if (SetupDiGetDeviceInstallParams(HardwareWiz->hDeviceInfo,
|
|
&HardwareWiz->DeviceInfoData,
|
|
&DevInstallParams
|
|
)) {
|
|
if (DevInstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) {
|
|
HardwareWiz->Reboot |= DI_NEEDREBOOT;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Clear the CONFIGFLAG_NEEDS_FORCED_CONFIG if this device needs a forced config.
|
|
//
|
|
if (NeedsForcedConfig) {
|
|
|
|
DWORD ConfigFlags = 0;
|
|
ULONG ulSize = sizeof(ConfigFlags);
|
|
|
|
if (CM_Get_DevInst_Registry_Property(HardwareWiz->DeviceInfoData.DevInst,
|
|
CM_DRP_CONFIGFLAGS,
|
|
NULL,
|
|
(LPBYTE)&ConfigFlags,
|
|
&ulSize,
|
|
0) == CR_SUCCESS) {
|
|
|
|
ConfigFlags &= ~CONFIGFLAG_NEEDS_FORCED_CONFIG;
|
|
|
|
CM_Set_DevInst_Registry_Property(HardwareWiz->DeviceInfoData.DevInst,
|
|
CM_DRP_CONFIGFLAGS,
|
|
(LPBYTE)&ConfigFlags,
|
|
sizeof(ConfigFlags),
|
|
0
|
|
);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
INT_PTR CALLBACK
|
|
HdwInstallDevDlgProc(
|
|
HWND hDlg,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
HWND hwndParentDlg = GetParent(hDlg);
|
|
PHARDWAREWIZ HardwareWiz = (PHARDWAREWIZ)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
HICON hicon;
|
|
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
|
|
switch (wMsg) {
|
|
case WM_INITDIALOG: {
|
|
LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
|
|
HardwareWiz = (PHARDWAREWIZ)lppsp->lParam;
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)HardwareWiz);
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
hicon = (HICON)SendDlgItemMessage(hDlg,IDC_CLASSICON,STM_GETICON,0,0);
|
|
if (hicon) {
|
|
DestroyIcon(hicon);
|
|
}
|
|
break;
|
|
|
|
case WUM_DOINSTALL:
|
|
|
|
// do the Install
|
|
HardwareWiz->LastError = InstallDev(hDlg, HardwareWiz);
|
|
HardwareWiz->InstallPending = FALSE;
|
|
HardwareWiz->CurrCursor = NULL;
|
|
PropSheet_PressButton(hwndParentDlg, PSBTN_NEXT);
|
|
break;
|
|
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR FAR *)lParam)->code) {
|
|
case PSN_SETACTIVE: {
|
|
HardwareWiz->PrevPage = IDD_ADDDEVICE_INSTALLDEV;
|
|
|
|
//
|
|
// This is an intermediary status page, no buttons needed.
|
|
// Set the device description
|
|
// Set the class Icon
|
|
//
|
|
PropSheet_SetWizButtons(hwndParentDlg, 0);
|
|
EnableWindow(GetDlgItem(GetParent(hDlg), IDCANCEL), FALSE);
|
|
|
|
SetDriverDescription(hDlg, IDC_HDW_DESCRIPTION, HardwareWiz);
|
|
|
|
if (SetupDiLoadClassIcon(HardwareWiz->ClassGuidSelected, &hicon, NULL)) {
|
|
hicon = (HICON)SendDlgItemMessage(hDlg, IDC_CLASSICON, STM_SETICON, (WPARAM)hicon, 0L);
|
|
if (hicon) {
|
|
DestroyIcon(hicon);
|
|
}
|
|
}
|
|
|
|
HardwareWiz->CurrCursor = HardwareWiz->IdcWait;
|
|
SetCursor(HardwareWiz->CurrCursor);
|
|
|
|
//
|
|
// Post ourselves a msg, to do the actual install, this allows this
|
|
// page to show itself while the install is actually occuring.
|
|
//
|
|
HardwareWiz->InstallPending = TRUE;
|
|
|
|
PostMessage(hDlg, WUM_DOINSTALL, 0, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case PSN_WIZNEXT:
|
|
|
|
//
|
|
// Add the FinishInstall Page and jump to it if the installation succeded.
|
|
//
|
|
if (HardwareWiz->LastError == ERROR_SUCCESS) {
|
|
|
|
HardwareWiz->WizExtFinishInstall.hPropSheet = CreateWizExtPage(IDD_WIZARDEXT_FINISHINSTALL,
|
|
WizExtFinishInstallDlgProc,
|
|
HardwareWiz
|
|
);
|
|
|
|
if (HardwareWiz->WizExtFinishInstall.hPropSheet) {
|
|
PropSheet_AddPage(hwndParentDlg, HardwareWiz->WizExtFinishInstall.hPropSheet);
|
|
}
|
|
|
|
SetDlgMsgResult(hDlg, wMsg, IDD_WIZARDEXT_FINISHINSTALL);
|
|
|
|
//
|
|
// There was an error during the installation so just jump to our finish page.
|
|
//
|
|
} else {
|
|
|
|
SetDlgMsgResult(hDlg, wMsg, IDD_ADDDEVICE_FINISH);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case WM_SETCURSOR:
|
|
if (HardwareWiz->CurrCursor) {
|
|
SetCursor(HardwareWiz->CurrCursor);
|
|
break;
|
|
}
|
|
|
|
// fall thru to return(FALSE);
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
ShowInstallSummary(
|
|
HWND hDlg,
|
|
PHARDWAREWIZ HardwareWiz
|
|
)
|
|
{
|
|
LONG Error;
|
|
ULONG Problem, DevNodeStatus;
|
|
BOOL HasResources;
|
|
HWND hwndParentDlg = GetParent(hDlg);
|
|
PTCHAR ErrorMsg, ProblemText;
|
|
TCHAR TextBuffer[MAX_PATH*4];
|
|
|
|
|
|
Problem = 0;
|
|
*TextBuffer = TEXT('\0');
|
|
|
|
Error = HardwareWiz->LastError;
|
|
|
|
//
|
|
// Installation was canceled
|
|
//
|
|
if (Error == ERROR_CANCELLED) {
|
|
PropSheet_PressButton(hwndParentDlg, PSBTN_CANCEL);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Installation failed
|
|
//
|
|
if (Error != ERROR_SUCCESS) {
|
|
|
|
HardwareWiz->Installed = FALSE;
|
|
|
|
LoadText(TextBuffer, SIZECHARS(TextBuffer), IDS_HDW_ERRORFIN1, IDS_HDW_ERRORFIN1);
|
|
|
|
//
|
|
// Add on a description of the error to the end of the text buffer.
|
|
// NOTE: if the description of the error does not fit in our huge text
|
|
// buffer then it also won't fit in the dialog, however we should display
|
|
// as much as we can to the user. The full error will be logged in
|
|
// setupapi.log so PSS can still figure out what happened.
|
|
//
|
|
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
HRESULT_FROM_SETUPAPI(Error),
|
|
0,
|
|
(LPTSTR)&ErrorMsg,
|
|
0,
|
|
NULL)) {
|
|
|
|
StringCchCat(TextBuffer, SIZECHARS(TextBuffer), TEXT("\n\n"));
|
|
StringCchCat(TextBuffer, SIZECHARS(TextBuffer), ErrorMsg);
|
|
LocalFree(ErrorMsg);
|
|
}
|
|
|
|
SetDlgItemText(hDlg, IDC_HDW_TEXT, TextBuffer);
|
|
}
|
|
|
|
//
|
|
// No errors installing the drivers for this device
|
|
//
|
|
else {
|
|
//
|
|
// Check to see if the device itself has any problems
|
|
//
|
|
Error = CM_Get_DevNode_Status(&DevNodeStatus,
|
|
&Problem,
|
|
HardwareWiz->DeviceInfoData.DevInst,
|
|
0
|
|
);
|
|
if (Error != CR_SUCCESS) {
|
|
|
|
//
|
|
// For some reason, we couldn't retrieve the devnode's status.
|
|
// Default status and problem values to zero.
|
|
//
|
|
DevNodeStatus = Problem = 0;
|
|
}
|
|
|
|
//
|
|
// make sure the reboot flags\Problem are set correctly
|
|
//
|
|
if (HardwareWiz->CopyFilesOnly || HardwareWiz->Reboot || Problem == CM_PROB_NEED_RESTART) {
|
|
|
|
if (Problem != CM_PROB_PARTIAL_LOG_CONF) {
|
|
Problem = CM_PROB_NEED_RESTART;
|
|
}
|
|
|
|
HardwareWiz->Reboot |= DI_NEEDREBOOT;
|
|
}
|
|
|
|
|
|
HardwareWiz->Installed = TRUE;
|
|
HasResources = DeviceHasResources(HardwareWiz->DeviceInfoData.DevInst);
|
|
|
|
//
|
|
// The device has a problem
|
|
//
|
|
if ((Error != CR_SUCCESS) || Problem) {
|
|
if (Problem == CM_PROB_NEED_RESTART) {
|
|
if (HasResources &&
|
|
!HardwareWiz->CopyFilesOnly) {
|
|
LoadText(TextBuffer, SIZECHARS(TextBuffer), IDS_HDW_NORMAL_LEGACY_FINISH1, IDS_HDW_NORMAL_LEGACY_FINISH1);
|
|
} else {
|
|
LoadText(TextBuffer, SIZECHARS(TextBuffer), IDS_HDW_NORMALFINISH1, IDS_HDW_NORMALFINISH1);
|
|
}
|
|
|
|
LoadText(TextBuffer, SIZECHARS(TextBuffer), IDS_NEEDREBOOT, IDS_NEEDREBOOT);
|
|
}
|
|
|
|
else {
|
|
LoadText(TextBuffer, SIZECHARS(TextBuffer), IDS_INSTALL_PROBLEM, IDS_INSTALL_PROBLEM);
|
|
|
|
//
|
|
// If the device has a problem then get the problem text from
|
|
// device manager. It the TextBuffer is too small then the
|
|
// user will just see a truncated error message, so it is
|
|
// OK if StringCchCat fails.
|
|
//
|
|
if (Problem) {
|
|
ProblemText = DeviceProblemText(HardwareWiz->DeviceInfoData.DevInst,
|
|
0,
|
|
Problem
|
|
);
|
|
|
|
if (ProblemText) {
|
|
StringCchCat(TextBuffer, SIZECHARS(TextBuffer), TEXT("\n\n"));
|
|
StringCchCat(TextBuffer, SIZECHARS(TextBuffer), ProblemText);
|
|
LocalFree(ProblemText);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Show the resource button if the device has resources and it has a problem
|
|
//
|
|
if (HasResources ||
|
|
(Problem && !(HardwareWiz->Reboot && (DevNodeStatus & DN_STARTED))) ||
|
|
(Problem == CM_PROB_PARTIAL_LOG_CONF)) {
|
|
ShowWindow(GetDlgItem(hDlg, IDC_HDW_DISPLAYRESOURCE), SW_SHOW);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Installation was sucessful and the device does not have any problems
|
|
//
|
|
else {
|
|
LoadText(TextBuffer, SIZECHARS(TextBuffer), IDS_HDW_NORMALFINISH1, IDS_HDW_NORMALFINISH1);
|
|
}
|
|
|
|
SetDlgItemText(hDlg, IDC_HDW_TEXT, TextBuffer);
|
|
}
|
|
}
|
|
|
|
INT_PTR CALLBACK
|
|
HdwAddDeviceFinishDlgProc(
|
|
HWND hDlg,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
HICON hicon;
|
|
PHARDWAREWIZ HardwareWiz = (PHARDWAREWIZ)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
|
|
switch (wMsg) {
|
|
case WM_INITDIALOG:
|
|
{
|
|
LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
|
|
HardwareWiz = (PHARDWAREWIZ)lppsp->lParam;
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)HardwareWiz);
|
|
SetWindowFont(GetDlgItem(hDlg, IDC_HDWNAME), HardwareWiz->hfontTextBigBold, TRUE);
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
hicon = (HICON)SendDlgItemMessage(hDlg,IDC_CLASSICON,STM_GETICON,0,0);
|
|
if (hicon) {
|
|
|
|
DestroyIcon(hicon);
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR FAR *)lParam)->code) {
|
|
case PSN_SETACTIVE:
|
|
//
|
|
// No back button since install is already done.
|
|
// set the device description
|
|
// Hide Resources button until we know if resources exist or not.
|
|
// Set the class Icon
|
|
//
|
|
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH);
|
|
|
|
SetDriverDescription(hDlg, IDC_HDW_DESCRIPTION, HardwareWiz);
|
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_HDW_DISPLAYRESOURCE), SW_HIDE);
|
|
|
|
//
|
|
// Set the class Icon
|
|
//
|
|
if (SetupDiLoadClassIcon(&HardwareWiz->DeviceInfoData.ClassGuid, &hicon, NULL)) {
|
|
|
|
hicon = (HICON)SendDlgItemMessage(hDlg, IDC_CLASSICON, STM_SETICON, (WPARAM)hicon, 0L);
|
|
if (hicon) {
|
|
|
|
DestroyIcon(hicon);
|
|
}
|
|
}
|
|
|
|
ShowInstallSummary(hDlg, HardwareWiz);
|
|
break;
|
|
|
|
case PSN_RESET:
|
|
//
|
|
// Cancel the install
|
|
//
|
|
if (HardwareWiz->Registered) {
|
|
HardwareWiz->Installed = FALSE;
|
|
}
|
|
break;
|
|
|
|
case PSN_WIZFINISH:
|
|
//
|
|
// Pnp Device install only consists of copying files
|
|
// when the system does the real install, it will create
|
|
// the proper devnode, so remove our temporary devnode.
|
|
//
|
|
if (HardwareWiz->CopyFilesOnly && HardwareWiz->Registered) {
|
|
HardwareWiz->Installed = FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NM_RETURN:
|
|
case NM_CLICK:
|
|
DisplayResource(HardwareWiz, GetParent(hDlg), FALSE);
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
INT_PTR CALLBACK
|
|
WizExtFinishInstallDlgProc(
|
|
HWND hDlg,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
HWND hwndParentDlg = GetParent(hDlg);
|
|
PHARDWAREWIZ HardwareWiz = (PHARDWAREWIZ)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
int PrevPageId;
|
|
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
|
|
|
|
switch (wMsg) {
|
|
case WM_INITDIALOG: {
|
|
LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
|
|
HardwareWiz = (PHARDWAREWIZ)lppsp->lParam;
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)HardwareWiz);
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
break;
|
|
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR FAR *)lParam)->code) {
|
|
case PSN_SETACTIVE:
|
|
|
|
PrevPageId = HardwareWiz->PrevPage;
|
|
HardwareWiz->PrevPage = IDD_WIZARDEXT_FINISHINSTALL;
|
|
|
|
if (PrevPageId == IDD_ADDDEVICE_INSTALLDEV) {
|
|
|
|
//
|
|
// Moving forward on first page
|
|
//
|
|
|
|
//
|
|
// Add ClassWizard Extension pages for FinishInstall
|
|
//
|
|
AddClassWizExtPages(hwndParentDlg,
|
|
HardwareWiz,
|
|
&HardwareWiz->WizExtFinishInstall.DeviceWizardData,
|
|
DIF_NEWDEVICEWIZARD_FINISHINSTALL
|
|
);
|
|
|
|
//
|
|
// Add the end page, which is FinishInstall end
|
|
//
|
|
HardwareWiz->WizExtFinishInstall.hPropSheetEnd = CreateWizExtPage(IDD_WIZARDEXT_FINISHINSTALL_END,
|
|
WizExtFinishInstallEndDlgProc,
|
|
HardwareWiz
|
|
);
|
|
|
|
if (HardwareWiz->WizExtFinishInstall.hPropSheetEnd) {
|
|
PropSheet_AddPage(hwndParentDlg, HardwareWiz->WizExtFinishInstall.hPropSheetEnd);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// We can't go backwards, so always go forward
|
|
//
|
|
SetDlgMsgResult(hDlg, wMsg, -1);
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
SetDlgMsgResult(hDlg, wMsg, 0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
INT_PTR CALLBACK
|
|
WizExtFinishInstallEndDlgProc(
|
|
HWND hDlg,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
PHARDWAREWIZ HardwareWiz = (PHARDWAREWIZ)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
int PrevPageId;
|
|
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
|
|
switch (wMsg) {
|
|
case WM_INITDIALOG: {
|
|
LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
|
|
HardwareWiz = (PHARDWAREWIZ)lppsp->lParam;
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)HardwareWiz);
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
break;
|
|
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR FAR *)lParam)->code) {
|
|
case PSN_SETACTIVE:
|
|
|
|
PrevPageId = HardwareWiz->PrevPage;
|
|
HardwareWiz->PrevPage = IDD_WIZARDEXT_FINISHINSTALL_END;
|
|
|
|
//
|
|
// We can't go backwards, so always go forward
|
|
//
|
|
SetDlgMsgResult(hDlg, wMsg, IDD_ADDDEVICE_FINISH);
|
|
break;
|
|
|
|
case PSN_WIZBACK:
|
|
case PSN_WIZNEXT:
|
|
SetDlgMsgResult(hDlg, wMsg, 0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|