//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: finish.c // //-------------------------------------------------------------------------- #include "newdevp.h" #include typedef UINT (*PDEVICEPROBLEMTEXT)( HMACHINE hMachine, DEVNODE DevNode, ULONG ProblemNumber, LPTSTR Buffer, UINT BufferSize ); BOOL IsNullDriverInstalled( DEVNODE DevNode ) /*++ Routine Description: This routine determines whether a null driver, or no driver at all, is installed for this device instance. Currently the test is that I know a null driver was installed if the "Driver" value entry doesn't exist. Arguments: DevNode Return Value: Returns TRUE if a null driver was installed for this device, otherwise returns FALSE. --*/ { TCHAR Buffer[1]; DWORD dwSize, dwType; dwSize = SIZECHARS(Buffer); if (CM_Get_DevNode_Registry_Property(DevNode, CM_DRP_DRIVER, &dwType, (LPVOID)Buffer, &dwSize, 0) == CR_BUFFER_SMALL) { return FALSE; } else { return TRUE; } } PTCHAR DeviceProblemText( HMACHINE hMachine, DEVNODE DevNode, ULONG ProblemNumber ) { UINT LenChars, ReqLenChars; HMODULE hDevMgr=NULL; PTCHAR Buffer=NULL; PDEVICEPROBLEMTEXT pDeviceProblemText = NULL; hDevMgr = LoadLibrary(TEXT("devmgr.dll")); if (hDevMgr) { pDeviceProblemText = (PVOID) GetProcAddress(hDevMgr, "DeviceProblemTextW"); } if (pDeviceProblemText) { LenChars = (pDeviceProblemText)(hMachine, DevNode, ProblemNumber, Buffer, 0 ); if (!LenChars) { goto DPTExitCleanup; } LenChars++; // one extra for terminating NULL Buffer = LocalAlloc(LPTR, LenChars*sizeof(TCHAR)); if (!Buffer) { goto DPTExitCleanup; } ReqLenChars = (pDeviceProblemText)(hMachine, DevNode, ProblemNumber, Buffer, LenChars ); if (!ReqLenChars || ReqLenChars >= LenChars) { LocalFree(Buffer); Buffer = NULL; } } DPTExitCleanup: if (hDevMgr) { FreeLibrary(hDevMgr); } return Buffer; } 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; } BOOL GetClassGuidForInf( PTSTR InfFileName, LPGUID ClassGuid ) { TCHAR ClassName[MAX_CLASS_NAME_LEN]; DWORD NumGuids; if(!SetupDiGetINFClass(InfFileName, ClassGuid, ClassName, sizeof(ClassName)/sizeof(TCHAR), 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), // or if it matches with multiple GUIDs, then we abort. // if(!SetupDiClassGuidsFromName(ClassName, ClassGuid, 1, &NumGuids) || !NumGuids) { return FALSE; } } return TRUE; } BOOL IsInternetDriver( HDEVINFO hDeviceInfo, PSP_DEVINFO_DATA DeviceInfoData ) { BOOL InternetDriver = FALSE; SP_DRVINFO_DATA DriverInfoData; SP_DRVINSTALL_PARAMS DriverInstallParams; DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA); if(SetupDiGetSelectedDriver(hDeviceInfo, DeviceInfoData, &DriverInfoData)) { DriverInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS); if (SetupDiGetDriverInstallParams(hDeviceInfo, DeviceInfoData, &DriverInfoData, &DriverInstallParams ) && (DriverInstallParams.Flags & DNF_INET_DRIVER)) { InternetDriver = TRUE; } } return InternetDriver; } UINT QueueCallback( IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2 ) { PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ)Context; switch (Notification) { case SPFILENOTIFY_TARGETNEWER: // // When doing a driver rollback we expect that some of the files will // be older then the files currently on the system since most backups // will be of older driver packages. So when a user does a rollback we // will hide the older vs. newer file prompt and always copy the older // backed up file. // if (NewDevWiz->Flags & IDI_FLAG_ROLLBACK) { return TRUE; } break; case SPFILENOTIFY_STARTCOPY: if (NewDevWiz->hWnd) { SendMessage(NewDevWiz->hWnd, WUM_INSTALLPROGRESS, INSTALLOP_COPY, (WPARAM)((PFILEPATHS)Param1) ); } break; case SPFILENOTIFY_STARTRENAME: if (NewDevWiz->hWnd) { SendMessage(NewDevWiz->hWnd, WUM_INSTALLPROGRESS, INSTALLOP_RENAME, (WPARAM)((PFILEPATHS)Param1) ); } break; case SPFILENOTIFY_STARTDELETE: if (NewDevWiz->hWnd) { SendMessage(NewDevWiz->hWnd, WUM_INSTALLPROGRESS, INSTALLOP_DELETE, (WPARAM)((PFILEPATHS)Param1) ); } break; case SPFILENOTIFY_STARTBACKUP: if (NewDevWiz->hWnd) { SendMessage(NewDevWiz->hWnd, WUM_INSTALLPROGRESS, INSTALLOP_BACKUP, (WPARAM)((PFILEPATHS)Param1) ); } break; } return SetupDefaultQueueCallback(NewDevWiz->MessageHandlerContext, Notification, Param1, Param2 ); } LONG ClassInstallerInstalls( HWND hwndParent, PNEWDEVWIZ NewDevWiz, BOOL BackupOldDrivers, BOOL ReadOnlyInstall, BOOL DontCreateQueue ) { DWORD Err = ERROR_SUCCESS; HSPFILEQ FileQueue = INVALID_HANDLE_VALUE; SP_DEVINSTALL_PARAMS DeviceInstallParams; DWORD ScanResult = 0; int FileQueueNeedsReboot = 0; NewDevWiz->MessageHandlerContext = NULL; // // If we can't create our own queue and we are doing a read-only install // then fail with ERROR_ACCESS_DENIED. // if (DontCreateQueue && ReadOnlyInstall) { Err = ERROR_ACCESS_DENIED; goto clean0; } // // 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, NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData ) && (GetLastError() != ERROR_DI_DO_DEFAULT)) { Err = GetLastError(); goto clean0; } // // Create our own queue. // if (!DontCreateQueue) { DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); if (!SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->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; // // Only set the DI_FLAGSEX_PREINSTALLBACKUP flag if we are doing a // backup...not in the read only install case. // if (BackupOldDrivers) { DeviceInstallParams.FlagsEx |= DI_FLAGSEX_PREINSTALLBACKUP; } SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DeviceInstallParams ); // // If the IDI_FLAG_SETRESTOREPOINT flag is set then we want to set the // SPQ_FLAG_ABORT_IF_UNSIGNED value on the file queue. With this flag // setup 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 flag. // #ifndef _WIN64 if (NewDevWiz->Flags & IDI_FLAG_SETRESTOREPOINT) { 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, NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData )) { Err = GetLastError(); goto clean0; } if (FileQueue != INVALID_HANDLE_VALUE) { // // If we created our own FileQueue then we need to // scan and possibly commit the queue // // If we are doing a read only install then we just queued up the files so // that we could do a presence check on them. We will throw away the queue // so that the files are not copied. // // Any other install, prune copies as needed // if (!SetupScanFileQueue(FileQueue, ReadOnlyInstall ? SPQ_SCAN_FILE_PRESENCE : (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 (ReadOnlyInstall && (ScanResult != 1)) { // // ReadOnlyInstall cannot perform copies, deletes or renames // bail now! // Err = ERROR_ACCESS_DENIED; goto clean0; } // // We will always commit the file queue, even if we pruned all of the // files. The reason for this is that backing up of drivers, for // driver rollback, won't work unless the file queue is committed. // if(NewDevWiz->Flags & IDI_FLAG_ROLLBACK) { // // Prepare file queue for rollback // we need the directory of the INF // that's being used for the install // SP_DRVINFO_DATA DriverInfoData; SP_DRVINFO_DETAIL_DATA DriverInfoDetailData; DWORD RetVal; LPTSTR pFileName; TCHAR BackupPath[MAX_PATH]; DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA); if (SetupDiGetSelectedDriver(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DriverInfoData)) { DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); if (SetupDiGetDriverInfoDetail(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DriverInfoData, &DriverInfoDetailData, sizeof(SP_DRVINFO_DETAIL_DATA), NULL) || (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { // // we now have path of INF we're using for the restore // RetVal = GetFullPathName(DriverInfoDetailData.InfFileName, MAX_PATH, BackupPath, &pFileName); if(RetVal && pFileName && (pFileName != BackupPath)) { if(*CharPrev(BackupPath,pFileName)==TEXT('\\')) { pFileName--; } *pFileName = TEXT('\0'); // // Prepare queue for rollback // if this fails, carry on, it'll work in a degraded way // SetupPrepareQueueForRestore(FileQueue,BackupPath,0); } } } } NewDevWiz->MessageHandlerContext = SetupInitDefaultQueueCallbackEx( hwndParent, (DeviceInstallParams.Flags & DI_QUIETINSTALL) ? INVALID_HANDLE_VALUE : NewDevWiz->hWnd, WUM_INSTALLPROGRESS, 0, NULL ); if (NewDevWiz->MessageHandlerContext) { // // Commit the file queue. // if (!SetupCommitFileQueue(hwndParent, FileQueue, QueueCallback, (PVOID)NewDevWiz )) { Err = GetLastError(); if (Err == ERROR_SET_SYSTEM_RESTORE_POINT) { UINT RestorePointResourceId; // // If we get back ERROR_SET_SYSTEM_RESTORE_POINT then // we better have the IDI_FLAG_SETRESTOREPOINT flag // set. // ASSERT(NewDevWiz->Flags & IDI_FLAG_SETRESTOREPOINT); if (!(DeviceInstallParams.Flags & DI_QUIETINSTALL) && NewDevWiz->hWnd) { PostMessage(NewDevWiz->hWnd, WUM_INSTALLPROGRESS, INSTALLOP_SETTEXT, (LPARAM)IDS_SYSTEMRESTORE_TEXT ); } SetupTermDefaultQueueCallback(NewDevWiz->MessageHandlerContext); NewDevWiz->MessageHandlerContext = SetupInitDefaultQueueCallbackEx( hwndParent, (DeviceInstallParams.Flags & DI_QUIETINSTALL) ? INVALID_HANDLE_VALUE : NewDevWiz->hWnd, WUM_INSTALLPROGRESS, 0, NULL ); if (NewDevWiz->MessageHandlerContext) { // // Set the system restore point. // if (NewDevWiz->Flags & IDI_FLAG_ROLLBACK) { RestorePointResourceId = IDS_ROLLBACK_SETRESTOREPOINT; } else if (NewDevWiz->InstallType == NDWTYPE_FOUNDNEW) { RestorePointResourceId = IDS_NEW_SETRESTOREPOINT; } else { RestorePointResourceId = IDS_UPDATE_SETRESTOREPOINT; } pSetSystemRestorePoint(TRUE, FALSE, RestorePointResourceId); NewDevWiz->SetRestorePoint = TRUE; if (!(DeviceInstallParams.Flags & DI_QUIETINSTALL) && NewDevWiz->hWnd) { PostMessage(NewDevWiz->hWnd, WUM_INSTALLPROGRESS, INSTALLOP_SETTEXT, (LPARAM)NULL ); } // // 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, QueueCallback, (PVOID)NewDevWiz )) { Err = GetLastError(); // // If the error we get is ERROR_CANCELLED then // the user has canceld out of the file copy. // This means that no changes have been made // to the system, so we will tell system // restore to cancel its restore point. // // Also clear the SetRestorePoint BOOL since // we didn't actually set a restore point. // if (Err == ERROR_CANCELLED) { pSetSystemRestorePoint(FALSE, TRUE, 0); NewDevWiz->SetRestorePoint = FALSE; } 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 (BackupOldDrivers) { // // If the backup succeeded and we have a UpdateDriverInfo structure // then we need to call SetupGetBackupInformation so we can get the // registry key that the backup was saved into. // SP_BACKUP_QUEUE_PARAMS BackupQueueParams; BackupQueueParams.cbSize = sizeof(SP_BACKUP_QUEUE_PARAMS); if (NewDevWiz->UpdateDriverInfo && SetupGetBackupInformation(FileQueue, &BackupQueueParams)) { lstrcpy(NewDevWiz->UpdateDriverInfo->BackupRegistryKey, REGSTR_PATH_REINSTALL); lstrcat(NewDevWiz->UpdateDriverInfo->BackupRegistryKey, TEXT("\\")); lstrcat(NewDevWiz->UpdateDriverInfo->BackupRegistryKey, BackupQueueParams.ReinstallInstance); } } } DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->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 ((FileQueue != INVALID_HANDLE_VALUE) && 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(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DeviceInstallParams ); } // // Register any device-specific co-installers for this device, // if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData )) { Err = GetLastError(); goto clean0; } // // install any INF/class installer-specified interfaces. // and then finally the real "InstallDevice"! // if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData ) || !SetupDiCallClassInstaller(DIF_INSTALLDEVICE, NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData )) { Err = GetLastError(); goto clean0; } Err = ERROR_SUCCESS; clean0: if (NewDevWiz->MessageHandlerContext) { SetupTermDefaultQueueCallback(NewDevWiz->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(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DeviceInstallParams )) { DeviceInstallParams.Flags |= DI_NEEDRESTART; SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->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(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DeviceInstallParams )) { DeviceInstallParams.Flags &= ~DI_NOVCP; DeviceInstallParams.FileQueue = INVALID_HANDLE_VALUE; SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DeviceInstallParams ); } SetupCloseFileQueue(FileQueue); } return Err; } // // invokable only from finish page! // DWORD InstallDev( HWND hwndParent, PNEWDEVWIZ NewDevWiz ) { 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*2]; PVOID pvBuffer = Buffer; ULONG DevNodeStatus = 0, Problem = 0; DWORD ClassGuidListSize, i; BOOL Backup = FALSE; BOOL DontCreateQueue = FALSE; if (!NewDevWiz->ClassGuidSelected) { NewDevWiz->ClassGuidSelected = (LPGUID)&GUID_NULL; } DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA); if (SetupDiGetSelectedDriver(NewDevWiz->hDeviceInfo, &NewDevWiz->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(NewDevWiz->hDeviceInfo, &NewDevWiz->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. // NdwBuildClassInfoList(NewDevWiz, 0); // // fetch classguid from inf, (It may be different than what we already // have in class guid selected). // if (!GetClassGuidForInf(DriverInfoDetailData.InfFileName, &ClassGuidInf)) { ClassGuidInf = *NewDevWiz->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 = NewDevWiz->ClassGuidList; ClassGuidNum = NewDevWiz->ClassGuidNum; while (ClassGuidNum--) { if (IsEqualGUID(ClassGuid, &ClassGuidInf)) { break; } ClassGuid++; } if (ClassGuidNum < 0 && !SetupDiInstallClass(hwndParent, DriverInfoDetailData.InfFileName, NewDevWiz->SilentMode ? DI_QUIETINSTALL : 0, NULL )) { Error = GetLastError(); goto clean0; } } // // 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, NewDevWiz->DeviceInfoData.DevInst, 0) == CR_SUCCESS) { if (!SetupDiGetDeviceRegistryProperty(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, SPDRP_SERVICE, NULL, // regdatatype pvBuffer, sizeof(Buffer), NULL )) { *Buffer = TEXT('\0'); } if((DevNodeStatus & DN_STARTED) && (*Buffer == TEXT('\0'))) { IgnoreRebootFlags = TRUE; } } if (IsEqualGUID(NewDevWiz->ClassGuidSelected, &GUID_NULL)) { pSetupStringFromGuid(&GUID_DEVCLASS_UNKNOWN, ClassGuidString, sizeof(ClassGuidString)/sizeof(TCHAR) ); SetupDiSetDeviceRegistryProperty(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, SPDRP_CLASSGUID, (PBYTE)ClassGuidString, sizeof(ClassGuidString) ); } ClassGuidInf = *NewDevWiz->ClassGuidSelected; } // // We will backup the current drivers in all cases except if any of the following are true: // // 1) The device is a printer // 2) The selected driver is the currently installed driver // 3) The DontBackupCurrentDrivers NEWDEVWIZ BOOL is TRUE // 4) The device has a problem // if (IsEqualGUID(&ClassGuidInf, &GUID_DEVCLASS_PRINTER) || IsInstalledDriver(NewDevWiz, NULL) || (NewDevWiz->Flags & IDI_FLAG_NOBACKUP) || ((CM_Get_DevNode_Status(&DevNodeStatus, &Problem, NewDevWiz->DeviceInfoData.DevInst, 0) == CR_SUCCESS) && ((DevNodeStatus & DN_HAS_PROBLEM) || (DevNodeStatus & DN_PRIVATE_PROBLEM)))) { Backup = FALSE; } else { Backup = TRUE; } // // We will always create our own queue during device install, except in the // following specific cases. // // 1) The device is a printer // // Note that if we can't create our own queue then we cannot do any of the // operations that need a queue, like backup, rollback, read-only install, // or setting a restore point. // DontCreateQueue = IsEqualGUID(&ClassGuidInf, & GUID_DEVCLASS_PRINTER); Error = ClassInstallerInstalls(hwndParent, NewDevWiz, Backup, (NewDevWiz->Flags & IDI_FLAG_READONLY_INSTALL), DontCreateQueue ); // // If this is a WU/CDM install and it was successful then set // the DriverWasUpgraded to TRUE // if (NewDevWiz->UpdateDriverInfo && (Error == ERROR_SUCCESS)) { NewDevWiz->UpdateDriverInfo->DriverWasUpgraded = TRUE; } // // If this is a new device (currently no drivers are installed) and we encounter // an error that is not ERROR_CANCELLED then we will install the NULL driver for // this device and set the FAILED INSTALL flag. // if ((Error != ERROR_SUCCESS) && (Error != ERROR_CANCELLED)) { if (IsNullDriverInstalled(NewDevWiz->DeviceInfoData.DevInst)) { if (SetupDiSetSelectedDriver(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, NULL )) { DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DeviceInstallParams )) { DeviceInstallParams.FlagsEx |= DI_FLAGSEX_SETFAILEDINSTALL; SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DeviceInstallParams ); } SetupDiInstallDevice(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData); } } goto clean0; } // // See if the device needs to the system to be restarted before it will work. // if(!IgnoreRebootFlags) { DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DeviceInstallParams ) && (DeviceInstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))) { // // If either the DI_NEEDRESTART or the DI_NEEDREBOOT DeviceInstallParams // flag is set, then a restart is needed. // NewDevWiz->Reboot |= DI_NEEDREBOOT; } else if ((CM_Get_DevNode_Status(&DevNodeStatus, &Problem, NewDevWiz->DeviceInfoData.DevInst, 0) == CR_SUCCESS) && (DevNodeStatus & DN_NEED_RESTART) || (Problem == CM_PROB_NEED_RESTART)) { // // If the DN_NEED_RESTART devnode status flag is set, then a restart // is needed. // NewDevWiz->Reboot |= DI_NEEDREBOOT; } } clean0: return Error; } DWORD InstallNullDriver( HWND hDlg, PNEWDEVWIZ NewDevWiz, BOOL FailedInstall ) { SP_DEVINSTALL_PARAMS DevInstallParams; DWORD Err = ERROR_SUCCESS; DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); // // Set the DI_FLAGSEX_SETFAILEDINSTALL flag if this is a failed // install. // if (FailedInstall) { if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DevInstallParams )) { DevInstallParams.FlagsEx |= DI_FLAGSEX_SETFAILEDINSTALL; SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DevInstallParams ); } } // // Set the selected driver to NULL // if (SetupDiSetSelectedDriver(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, NULL )) { // // 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, NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData ) || (GetLastError() == ERROR_DI_DO_DEFAULT)) { // // If the class/co-installers gave the OK then call DIF_INSTALLDEVICE. // if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData )) { Err = GetLastError(); } } else { Err = GetLastError(); } } return Err; } // InstallNullDriver BOOL CALLBACK AddPropSheetPageProc( IN HPROPSHEETPAGE hpage, IN LPARAM lParam ) { *((HPROPSHEETPAGE *)lParam) = hpage; return TRUE; } void DisplayResource( PNEWDEVWIZ NewDevWiz, HWND hWndParent ) { HINSTANCE hLib; PROPSHEETHEADER psh; HPROPSHEETPAGE hpsPages[1]; SP_PROPSHEETPAGE_REQUEST PropPageRequest; LPFNADDPROPSHEETPAGES ExtensionPropSheetPage = NULL; LPTSTR Title; SP_DEVINSTALL_PARAMS DevInstallParams; // // Now get the resource selection page from setupapi.dll // hLib = GetModuleHandle(TEXT("setupapi.dll")); if (hLib) { ExtensionPropSheetPage = (PVOID)GetProcAddress(hLib, "ExtensionPropSheetPageProc"); } if (!ExtensionPropSheetPage) { return; } PropPageRequest.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST); PropPageRequest.PageRequested = SPPSR_SELECT_DEVICE_RESOURCES; PropPageRequest.DeviceInfoSet = NewDevWiz->hDeviceInfo; PropPageRequest.DeviceInfoData = &NewDevWiz->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 = hNewDev; psh.pszIcon = NULL; switch (NewDevWiz->InstallType) { case NDWTYPE_FOUNDNEW: Title = (LPTSTR)IDS_FOUNDDEVICE; break; case NDWTYPE_UPDATE: Title = (LPTSTR)IDS_UPDATEDEVICE; break; default: Title = TEXT(""); // unknown } psh.pszCaption = Title; 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(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DevInstallParams )) { DevInstallParams.FlagsEx &= ~DI_FLAGSEX_PROPCHANGE_PENDING; SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, &DevInstallParams ); } if (PropertySheet(&psh) == -1) { DestroyPropertySheetPage(hpsPages[0]); } // // If a PropChange occurred invoke the DIF_PROPERTYCHANGE // if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->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(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, (PSP_CLASSINSTALL_HEADER)&PropChangeParams, sizeof(PropChangeParams) )) { SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData ); } // // Clear the class install parameters. // SetupDiSetClassInstallParams(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData, NULL, 0 ); } } return; } DWORD WINAPI InstallDevThreadProc( LPVOID lpVoid ) /*++ Description: In the Wizard, we will do the driver installation in a separate thread so that the user will see the driver instal wizard page. --*/ { PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ)lpVoid; // // Do the device install // NewDevWiz->LastError = InstallDev(NewDevWiz->hWnd, NewDevWiz); // // Post a message to the window to let it know that we are finished with the install // PostMessage(NewDevWiz->hWnd, WUM_INSTALLCOMPLETE, TRUE, GetLastError()); return GetLastError(); } INT_PTR CALLBACK NDW_InstallDevDlgProc( HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam ) { HWND hwndParentDlg = GetParent(hDlg); PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ)GetWindowLongPtr(hDlg, DWLP_USER); LONG Error; ULONG DevNodeStatus, Problem; static HANDLE DeviceInstallThread = NULL; TCHAR Text1[MAX_PATH], Text2[MAX_PATH], Target[MAX_PATH], Format[MAX_PATH]; PTSTR p; switch (wMsg) { case WM_INITDIALOG: { LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam; NewDevWiz = (PNEWDEVWIZ)lppsp->lParam; SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)NewDevWiz); break; } case WM_DESTROY: break; case WUM_INSTALLCOMPLETE: // // This message is posted to the window when the device installation is complete. // WaitForSingleObject(DeviceInstallThread, INFINITE); Animate_Stop(GetDlgItem(hDlg, IDC_ANIMATE_INSTALL)); NewDevWiz->CurrCursor = NULL; PropSheet_PressButton(hwndParentDlg, PSBTN_NEXT); break; case WUM_INSTALLPROGRESS: Text1[0] = Text2[0] = TEXT('\0'); // // This is the message that is sent from setupapi so we can display our // own copy progress. // // If wParam is 0 then the lParam is the number of files that will be // copied. // If wParam is 1 then that is a tick for a single file being copied, // so the progress bar should be advanced. // switch (wParam) { case 0: ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), SW_SHOW); ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT1), SW_SHOW); ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT2), SW_SHOW); ShowWindow(GetDlgItem(hDlg, IDC_STATUS_TEXT), SW_HIDE); SetDlgItemText(hDlg, IDC_FILECOPY_TEXT1, TEXT("")); SetDlgItemText(hDlg, IDC_FILECOPY_TEXT2, TEXT("")); SendMessage(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), PBM_SETRANGE,0,MAKELPARAM(0,lParam)); SendMessage(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), PBM_SETSTEP,1,0); SendMessage(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), PBM_SETPOS,0,0); break; case 1: SendMessage(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), PBM_STEPIT,0,0); break; case INSTALLOP_COPY: lstrcpyn(Target, ((PFILEPATHS)lParam)->Target, MAX_PATH); if (p = _tcsrchr(Target,TEXT('\\'))) { *p++ = 0; lstrcpyn(Text1, p, MAX_PATH); if (LoadString(hNewDev, IDS_FILEOP_TO, Format, SIZECHARS(Format))) { _snwprintf(Text2, MAX_PATH, Format, Target); } } else { lstrcpyn(Text1, ((PFILEPATHS)lParam)->Target, MAX_PATH); lstrcpy(Text2, TEXT("")); } break; case INSTALLOP_RENAME: lstrcpyn(Text1, ((PFILEPATHS)lParam)->Source, MAX_PATH); if (p = _tcsrchr(((PFILEPATHS)lParam)->Target, TEXT('\\'))) { p++; } else { p = (PTSTR)((PFILEPATHS)lParam)->Target; } if (LoadString(hNewDev, IDS_FILEOP_TO, Format, SIZECHARS(Format))) { _snwprintf(Text2, MAX_PATH, Format, p); } break; case INSTALLOP_DELETE: lstrcpyn(Target, ((PFILEPATHS)lParam)->Target, MAX_PATH); if (p = _tcsrchr(Target,TEXT('\\'))) { *p++ = 0; lstrcpyn(Text1, p, MAX_PATH); if (LoadString(hNewDev, IDS_FILEOP_FROM, Format, SIZECHARS(Format))) { _snwprintf(Text2, MAX_PATH, Format, Target); } } else { lstrcpyn(Text1, ((PFILEPATHS)lParam)->Target, MAX_PATH); lstrcpy(Text2, TEXT("")); } break; case INSTALLOP_BACKUP: lstrcpyn(Target, ((PFILEPATHS)lParam)->Source, MAX_PATH); if (p = _tcsrchr(Target,TEXT('\\'))) { *p++ = 0; if (((PFILEPATHS)lParam)->Target == NULL) { if (LoadString(hNewDev, IDS_FILEOP_BACKUP, Format, SIZECHARS(Format))) { _snwprintf(Text1, MAX_PATH, Format, p); } } else { lstrcpyn(Text1, p, MAX_PATH); } lstrcpyn(Text2, Target, MAX_PATH); } else { if (LoadString(hNewDev, IDS_FILEOP_BACKUP, Format, SIZECHARS(Format))) { _snwprintf(Text1, MAX_PATH, Format, Target); } lstrcpy(Text2, TEXT("")); } break; case INSTALLOP_SETTEXT: ShowWindow(GetDlgItem(hDlg, IDC_STATUS_TEXT), SW_SHOW); ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT1), SW_HIDE); if (lParam) { if (LoadString(hNewDev, (UINT)lParam, Text2, SIZECHARS(Text2))) { ShowWindow(GetDlgItem(hDlg, IDC_STATUS_TEXT), SW_SHOW); SetDlgItemText(hDlg, IDC_STATUS_TEXT, Text2); } } else { SetDlgItemText(hDlg, IDC_STATUS_TEXT, TEXT("")); } Text1[0] = TEXT('\0'); Text2[0] = TEXT('\0'); break; } if ((Text1[0] != TEXT('\0')) && (Text2[0] != TEXT('\0'))) { ShowWindow(GetDlgItem(hDlg, IDC_STATUS_TEXT), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT1), SW_SHOW); ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT2), SW_SHOW); SetDlgItemText(hDlg, IDC_FILECOPY_TEXT1, Text1); SetDlgItemText(hDlg, IDC_FILECOPY_TEXT2, Text2); } break; case WM_NOTIFY: switch (((NMHDR FAR *)lParam)->code) { case PSN_SETACTIVE: { HICON hicon; SP_DRVINFO_DATA DriverInfoData; NewDevWiz->PrevPage = IDD_NEWDEVWIZ_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); ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT1), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT2), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_STATUS_TEXT), SW_HIDE); SetDriverDescription(hDlg, IDC_NDW_DESCRIPTION, NewDevWiz); if (SetupDiLoadClassIcon(NewDevWiz->ClassGuidSelected, &hicon, NULL)) { hicon = (HICON)SendDlgItemMessage(hDlg, IDC_CLASSICON, STM_SETICON, (WPARAM)hicon, 0L); if (hicon) { DestroyIcon(hicon); } } NewDevWiz->CurrCursor = NewDevWiz->IdcWait; SetCursor(NewDevWiz->CurrCursor); // // If we are doing a silent install then do the actual install here in the PSN_SETACTIVE. // Doing the install here means that this wizard page will never be displayed. When we // are finished calling InstallDev() then we will jump to any FinishInstall pages that // the class/co-installers have added, or we will jump to our finish page. // if (NewDevWiz->SilentMode) { // // do the Install immediately and move to the next page // to prevent any UI from showing. // NewDevWiz->hWnd = NULL; NewDevWiz->LastError =InstallDev(hDlg, NewDevWiz); NewDevWiz->CurrCursor = NULL; // // Add the FinishInstall Page and jump to it if the install was successful // if (NewDevWiz->LastError == ERROR_SUCCESS) { NewDevWiz->WizExtFinishInstall.hPropSheet = CreateWizExtPage(IDD_WIZARDEXT_FINISHINSTALL, WizExtFinishInstallDlgProc, NewDevWiz ); if (NewDevWiz->WizExtFinishInstall.hPropSheet) { PropSheet_AddPage(hwndParentDlg, NewDevWiz->WizExtFinishInstall.hPropSheet); } SetDlgMsgResult(hDlg, wMsg, IDD_WIZARDEXT_FINISHINSTALL); } else { // // There was an error during the install so just jump to our finish page // SetDlgMsgResult(hDlg, wMsg, -1); } } // // Post ourselves a msg, to do the actual install, this allows this // page to show itself while the install is actually occuring. // else { DWORD ThreadId; NewDevWiz->hWnd = hDlg; ShowWindow(GetDlgItem(hDlg, IDC_ANIMATE_INSTALL), SW_SHOW); Animate_Open(GetDlgItem(hDlg, IDC_ANIMATE_INSTALL), MAKEINTRESOURCE(IDA_INSTALLING)); Animate_Play(GetDlgItem(hDlg, IDC_ANIMATE_INSTALL), 0, -1, -1); // // Start up a separate thread to do the device installation on. // When the driver installation is complete the InstallDevThreadProc // will post us a WUM_INSTALLCOMPLETE message. // DeviceInstallThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)InstallDevThreadProc, (LPVOID)NewDevWiz, 0, &ThreadId ); // // If the CreateThread fails then we will just call InstallDev() ourselves. // if (!DeviceInstallThread) { NewDevWiz->hWnd = NULL; // // Do the device install // NewDevWiz->LastError = InstallDev(NewDevWiz->hWnd, NewDevWiz); // // Post a message to the window to let it know that we are finished with the install // PostMessage(hDlg, WUM_INSTALLCOMPLETE, TRUE, GetLastError()); } } break; } case PSN_WIZNEXT: Animate_Stop(GetDlgItem(hDlg, IDC_ANIMATE_INSTALL)); // // Add the FinishInstall Page and jump to it if the installation succeded. // if (NewDevWiz->LastError == ERROR_SUCCESS) { NewDevWiz->WizExtFinishInstall.hPropSheet = CreateWizExtPage(IDD_WIZARDEXT_FINISHINSTALL, WizExtFinishInstallDlgProc, NewDevWiz ); if (NewDevWiz->WizExtFinishInstall.hPropSheet) { PropSheet_AddPage(hwndParentDlg, NewDevWiz->WizExtFinishInstall.hPropSheet); } SetDlgMsgResult(hDlg, wMsg, IDD_WIZARDEXT_FINISHINSTALL); } else { // // There was an error during the install so just jump to our finish page // SetDlgMsgResult(hDlg, wMsg, IDD_NEWDEVWIZ_FINISH); } break; } break; case WM_SETCURSOR: if (NewDevWiz->CurrCursor) { SetCursor(NewDevWiz->CurrCursor); break; } // fall thru to return(FALSE); default: return(FALSE); } return(TRUE); } void ShowInstallSummary( HWND hDlg, PNEWDEVWIZ NewDevWiz ) { LONG Error; CONFIGRET ConfigRet; ULONG Len, Problem, DevNodeStatus; BOOL HasResources; HWND hwndParentDlg = GetParent(hDlg); PTCHAR ErrorMsg, ProblemText; TCHAR TextBuffer[MAX_PATH*4]; Problem = 0; *TextBuffer = TEXT('\0'); Error = NewDevWiz->LastError; // // On Windows Update installs we don't want to show any UI at all, even // if there was an error during the installation. // We can tell a WU install from a CDM install because only a WU install // has a UpdateDriverInfo structure and is SilentMode. // We also never want to show the finish page if this is a NonInteractive // install. // if ((NewDevWiz->SilentMode && NewDevWiz->UpdateDriverInfo) || NewDevWiz->Flags & IDI_FLAG_NONINTERACTIVE) { HideWindowByMove(hwndParentDlg); PropSheet_PressButton(hwndParentDlg, PSBTN_FINISH); return; } if (NewDevWiz->hfontTextBigBold) { SetWindowFont(GetDlgItem(hDlg, IDC_FINISH_MSG1), NewDevWiz->hfontTextBigBold, TRUE); } if (NDWTYPE_UPDATE == NewDevWiz->InstallType) { SetDlgText(hDlg, IDC_FINISH_MSG1, IDS_FINISH_MSG1_UPGRADE, IDS_FINISH_MSG1_UPGRADE); } else { SetDlgText(hDlg, IDC_FINISH_MSG1, IDS_FINISH_MSG1_NEW, IDS_FINISH_MSG1_NEW); } // // Installation failed // if (Error != ERROR_SUCCESS) { NewDevWiz->Installed = FALSE; SetDlgText(hDlg, IDC_FINISH_MSG1, IDS_FINISH_MSG1_INSTALL_PROBLEM, IDS_FINISH_MSG1_INSTALL_PROBLEM); SetDlgText(hDlg, IDC_FINISH_MSG2, IDS_FINISH_PROB_MSG2, IDS_FINISH_PROB_MSG2); #if DBG DbgPrint("InstallDev Error =%x\n", Error); #endif // // Display failure message for installation // // We will special case the following error codes so we can give a more // friendly description of the problem to the user: // // TRUST_E_SUBJECT_FORM_UNKNOWN // ERROR_NO_ASSOCIATED_SERVICE // TYPE_E_ELEMENTNOTFOUND // ERROR_NOT_FOUND // if ((Error == TRUST_E_SUBJECT_FORM_UNKNOWN) || (Error == CERT_E_EXPIRED) || (Error == TYPE_E_ELEMENTNOTFOUND) || (Error == ERROR_NOT_FOUND)) { LoadText(TextBuffer, sizeof(TextBuffer), IDS_FINISH_PROB_TRUST_E_SUBJECT_FORM_UNKNOWN, IDS_FINISH_PROB_TRUST_E_SUBJECT_FORM_UNKNOWN); } else if (Error == ERROR_NO_ASSOCIATED_SERVICE) { LoadText(TextBuffer, sizeof(TextBuffer), IDS_FINISH_PROB_ERROR_NO_ASSOCIATED_SERVICE, IDS_FINISH_PROB_ERROR_NO_ASSOCIATED_SERVICE); } else { LoadText(TextBuffer, sizeof(TextBuffer), IDS_NDW_ERRORFIN1_PNP, IDS_NDW_ERRORFIN1_PNP); if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, HRESULT_FROM_SETUPAPI(Error), 0, (LPTSTR)&ErrorMsg, 0, NULL )) { lstrcat(TextBuffer, TEXT("\n\n")); lstrcat(TextBuffer, ErrorMsg); LocalFree(ErrorMsg); } } SetDlgItemText(hDlg, IDC_FINISH_MSG3, 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, NewDevWiz->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 (NewDevWiz->Reboot || Problem == CM_PROB_NEED_RESTART) { if (Problem != CM_PROB_PARTIAL_LOG_CONF) { Problem = CM_PROB_NEED_RESTART; } NewDevWiz->Reboot |= DI_NEEDREBOOT; } NewDevWiz->Installed = TRUE; HasResources = DeviceHasResources(NewDevWiz->DeviceInfoData.DevInst); // // The device has a problem // if ((Error != CR_SUCCESS) || Problem) { // // If we are going to launch the troubleshooter then change the finish text. // // We currently launch the troubleshooter if the device has some type of problem, // unless the problem is CM_PROB_NEED_RESTART. // if (Problem && (Problem != CM_PROB_NEED_RESTART)) { SetDlgText(hDlg, IDC_FINISH_MSG1, IDS_FINISH_MSG1_DEVICE_PROBLEM, IDS_FINISH_MSG1_DEVICE_PROBLEM); SetDlgText(hDlg, IDC_FINISH_MSG2, IDS_FINISH_PROB_MSG2, IDS_FINISH_PROB_MSG2); NewDevWiz->LaunchTroubleShooter = TRUE; SetDlgText(hDlg, IDC_FINISH_MSG4, IDS_FINISH_PROB_MSG4, IDS_FINISH_PROB_MSG4); } // // Show the resource button if the device has resources and it // has the problem CM_PROB_PARTIAL_LOG_CONF // if (HasResources && (Problem == CM_PROB_PARTIAL_LOG_CONF)) { ShowWindow(GetDlgItem(hDlg, IDC_NDW_DISPLAYRESOURCE), SW_SHOW); } if (Problem == CM_PROB_NEED_RESTART) { LoadText(TextBuffer, sizeof(TextBuffer), IDS_NEEDREBOOT, IDS_NEEDREBOOT); } else if (Problem) { ProblemText = DeviceProblemText(NULL, NewDevWiz->DeviceInfoData.DevInst, Problem ); if (ProblemText) { lstrcat(TextBuffer, TEXT("\n\n")); lstrcat(TextBuffer, ProblemText); LocalFree(ProblemText); } } #if DBG DbgPrint("InstallDev CM_Get_DevNode_Status()=%x DevNodeStatus=%x Problem=%x\n", Error, DevNodeStatus, Problem ); #endif } // // Installation was sucessful and the device does not have any problems // else { // // If this was a silent install (a Rank 0 match for example) then don't show the finish // page. // if (NewDevWiz->SilentMode) { HideWindowByMove(hwndParentDlg); PropSheet_PressButton(hwndParentDlg, PSBTN_FINISH); return; } } SetDlgItemText(hDlg, IDC_FINISH_MSG3, TextBuffer); } } INT_PTR CALLBACK NDW_FinishDlgProc( HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam ) { PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ)GetWindowLongPtr(hDlg, DWLP_USER); switch (wMsg) { case WM_INITDIALOG: { LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam; NewDevWiz = (PNEWDEVWIZ)lppsp->lParam; SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)NewDevWiz); break; } case WM_DESTROY: break; case WM_COMMAND: switch (wParam) { case IDC_NDW_DISPLAYRESOURCE: DisplayResource(NewDevWiz, GetParent(hDlg)); break; } break; case WM_NOTIFY: switch (((NMHDR FAR *)lParam)->code) { case PSN_SETACTIVE: { HICON hicon; SP_DRVINFO_DATA DriverInfoData; // // 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); EnableWindow(GetDlgItem(GetParent(hDlg), IDCANCEL), FALSE); ShowWindow(GetDlgItem(hDlg, IDC_NDW_DISPLAYRESOURCE), SW_HIDE); if (NewDevWiz->LastError == ERROR_CANCELLED) { if (NewDevWiz->SilentMode) { HideWindowByMove(GetParent(hDlg)); } PropSheet_PressButton(GetParent(hDlg), PSBTN_CANCEL); } else { SetDriverDescription(hDlg, IDC_NDW_DESCRIPTION, NewDevWiz); if (SetupDiLoadClassIcon(NewDevWiz->ClassGuidSelected, &hicon, NULL)) { hicon = (HICON)SendDlgItemMessage(hDlg, IDC_CLASSICON, STM_SETICON, (WPARAM)hicon, 0L); if (hicon) { DestroyIcon(hicon); } } ShowInstallSummary(hDlg, NewDevWiz); } break; } case PSN_RESET: break; case PSN_WIZFINISH: if (NewDevWiz->LaunchTroubleShooter) { // // The command line that we will run is: // rundll32 devmgr.dll, DeviceProblenWizard_RunDLL /deviceid %s // where %s is the device instance id. // TCHAR szCmdLine[512]; TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN]; if (CM_Get_Device_ID(NewDevWiz->DeviceInfoData.DevInst, DeviceInstanceId, sizeof(DeviceInstanceId)/sizeof(TCHAR), 0 ) == CR_SUCCESS) { wsprintf(szCmdLine, TEXT("devmgr.dll,DeviceProblenWizard_RunDLL /deviceid %s"), DeviceInstanceId); ShellExecute(NULL, TEXT("open"), TEXT("RUNDLL32.EXE"), szCmdLine, NULL, SW_SHOWNORMAL ); } } break; } break; default: return(FALSE); } return(TRUE); } INT_PTR CALLBACK WizExtFinishInstallDlgProc( HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam ) { HWND hwndParentDlg = GetParent(hDlg); PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ )GetWindowLongPtr(hDlg, DWLP_USER); int PrevPageId; switch (wMsg) { case WM_INITDIALOG: { LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam; NewDevWiz = (PNEWDEVWIZ )lppsp->lParam; SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)NewDevWiz); break; } case WM_DESTROY: break; case WM_NOTIFY: switch (((NMHDR FAR *)lParam)->code) { case PSN_SETACTIVE: PrevPageId = NewDevWiz->PrevPage; NewDevWiz->PrevPage = IDD_WIZARDEXT_FINISHINSTALL; if (PrevPageId == IDD_NEWDEVWIZ_INSTALLDEV) { PROPSHEETPAGE psp; HPROPSHEETPAGE hPage = NULL; // // Moving forward on first page // // // If this was a silent install and NOT a NonInteractive install // then we need to create the FinishInstallIntro page at this // point so we can add it to the wizard. We do this so the wizard // has a proper intro and finish page with the FinishInstall // pages inbetween. // if (NewDevWiz->SilentMode && !(NewDevWiz->Flags & IDI_FLAG_NONINTERACTIVE)) { ZeroMemory(&psp, sizeof(PROPSHEETPAGE)); psp.dwSize = sizeof(PROPSHEETPAGE); psp.hInstance = hNewDev; psp.dwFlags = PSP_DEFAULT | PSP_USETITLE | PSP_HIDEHEADER; psp.pszTemplate = MAKEINTRESOURCE(IDD_NEWDEVWIZ_FINISHINSTALL_INTRO); psp.pfnDlgProc = FinishInstallIntroDlgProc; psp.lParam = (LPARAM)NewDevWiz; hPage = CreatePropertySheetPage(&psp); } // // Add ClassWizard Extension pages for FinishInstall // if (AddClassWizExtPages(hwndParentDlg, NewDevWiz, &NewDevWiz->WizExtFinishInstall.DeviceWizardData, DIF_NEWDEVICEWIZARD_FINISHINSTALL, hPage )) { // // If this is a NonInteractive install then we need to set the last // error at this point so the error is propagated back to the original // caller. // if (NewDevWiz->Flags & IDI_FLAG_NONINTERACTIVE) { NewDevWiz->LastError = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION; } else { // // If we have finish install pages then we should also show the finish // page. // NewDevWiz->SilentMode = FALSE; } } // // Add the end page, which is FinishInstall end // NewDevWiz->WizExtFinishInstall.hPropSheetEnd = CreateWizExtPage(IDD_WIZARDEXT_FINISHINSTALL_END, WizExtFinishInstallEndDlgProc, NewDevWiz ); if (NewDevWiz->WizExtFinishInstall.hPropSheetEnd) { PropSheet_AddPage(hwndParentDlg, NewDevWiz->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 ) { HWND hwndParentDlg = GetParent(hDlg); PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ )GetWindowLongPtr(hDlg, DWLP_USER); int PrevPageId; switch (wMsg) { case WM_INITDIALOG: { LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam; NewDevWiz = (PNEWDEVWIZ )lppsp->lParam; SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)NewDevWiz); break; } case WM_DESTROY: break; case WM_NOTIFY: switch (((NMHDR FAR *)lParam)->code) { case PSN_SETACTIVE: PrevPageId = NewDevWiz->PrevPage; NewDevWiz->PrevPage = IDD_WIZARDEXT_FINISHINSTALL_END; // // We can't go backwards, so always go forward // SetDlgMsgResult(hDlg, wMsg, IDD_NEWDEVWIZ_FINISH); break; case PSN_WIZBACK: case PSN_WIZNEXT: SetDlgMsgResult(hDlg, wMsg, 0); break; } break; default: return(FALSE); } return(TRUE); }