/*++ Copyright (C) 1997-1999 Microsoft Corporation Module Name: devdrvpg.cpp Abstract: This module implements CDeviceDriverPage -- device driver property page Author: William Hsieh (williamh) created Revision History: --*/ // devdrvpg.cpp : implementation file // #include "devmgr.h" #include "devdrvpg.h" #include "cdriver.h" #include "tswizard.h" #include "devrmdlg.h" // // help topic ids // // BUGBUG: JasonC 3/23/2000 // Add context help for driver rollback button. // const DWORD g_a106HelpIDs[]= { IDC_DEVDRV_ICON, IDH_DISABLEHELP, // Driver: "" (Static) IDC_DEVDRV_DESC, IDH_DISABLEHELP, // Driver: "" (Static) IDC_DEVDRV_TITLE_DRIVERPROVIDER, idh_devmgr_driver_provider_main, IDC_DEVDRV_DRIVERPROVIDER, idh_devmgr_driver_provider_main, IDC_DEVDRV_TITLE_DRIVERDATE, idh_devmgr_driver_date_main, IDC_DEVDRV_DRIVERDATE, idh_devmgr_driver_date_main, IDC_DEVDRV_TITLE_DRIVERVERSION, idh_devmgr_driver_version_main, IDC_DEVDRV_DRIVERVERSION, idh_devmgr_driver_version_main, IDC_DEVDRV_TITLE_DRIVERSIGNER, idh_devmgr_digital_signer, IDC_DEVDRV_DRIVERSIGNER, idh_devmgr_digital_signer, IDC_DEVDRV_DETAILS, idh_devmgr_devdrv_details, // Driver: "Driver Details" (Button) IDC_DEVDRV_DETAILS_TEXT, idh_devmgr_devdrv_details, // Driver: "Driver Details" (Button) IDC_DEVDRV_UNINSTALL, idh_devmgr_devdrv_uninstall, // Driver: "Uninstall" (Button) IDC_DEVDRV_UNINSTALL_TEXT, idh_devmgr_devdrv_uninstall, // Driver: "Uninstall" (Button) IDC_DEVDRV_CHANGEDRIVER, idh_devmgr_driver_change_driver, // Driver: "&Change Driver..." (Button) IDC_DEVDRV_CHANGEDRIVER_TEXT, idh_devmgr_driver_change_driver, // Driver: "&Change Driver..." (Button) IDC_DEVDRV_ROLLBACK, idh_devmgr_rollback_button, // Driver: "Roll Back Driver..." (Button) IDC_DEVDRV_ROLLBACK_TEXT, idh_devmgr_rollback_button, // Driver: "Roll Back Driver..." (Button) 0, 0 }; CDeviceDriverPage::~CDeviceDriverPage() { if (m_pDriver) { delete m_pDriver; } } BOOL CDeviceDriverPage::OnCommand( WPARAM wParam, LPARAM lParam ) { if (BN_CLICKED == HIWORD(wParam)) { switch (LOWORD(wParam)) { case IDC_DEVDRV_DETAILS: { // // We first need to call CDriver::BuildDriverList to build up a list // of drivers for this device. This can take some time so we will put // up the busy cursor. // HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT)); CDriver* pDriver; pDriver = m_pDevice->CreateDriver(); if (pDriver) { pDriver->BuildDriverList(NULL); SetCursor(hCursorOld); // // Show driver file details // if (pDriver->GetCount() > 0) { if (pDriver) { CDriverFilesDlg DriverFilesDlg(m_pDevice, pDriver); DriverFilesDlg.DoModal(m_hDlg, (LPARAM)&DriverFilesDlg); } } else { // // No driver files are loaded for this device // String strNoDrivers; strNoDrivers.LoadString(g_hInstance, IDS_DEVDRV_NODRIVERFILE); MessageBox(m_hDlg, strNoDrivers, m_pDevice->GetDisplayName(), MB_OK); return FALSE; } delete pDriver; pDriver = NULL; } break; } case IDC_DEVDRV_UNINSTALL: { BOOL fChanged; BOOL Refresh = (m_pDevice->IsPhantom() || m_pDevice->HasProblem() || !m_pDevice->IsStarted()); if (UninstallDrivers(m_pDevice, m_hDlg, &fChanged) && fChanged) { // // Enable refresh since we disabled it in the beginning. // // We only need to force a refresh here if the device that // was removed was a Phantom device. This is because Phantom // devices don't have kernel mode devnodes and so they won't // generate a WM_DEVICECHANGE like live devnodes will. // if (Refresh) { m_pDevice->m_pMachine->ScheduleRefresh(); } ::DestroyWindow(GetParent(m_hDlg)); } break; } case IDC_DEVDRV_CHANGEDRIVER: { BOOL fChanged; DWORD Reboot = 0; if (UpdateDriver(m_pDevice, m_hDlg, &fChanged, &Reboot) && fChanged) { // // ISSUE: JasonC 2/7/00 // // A refresh on m_pDevice->m_pMachine is necessary here. // Since we are running on a different thread and each // property page may have cached the HDEVINFO and the // SP_DEVINFO_DATA, refresh on the CMachine object can not // be done here. The problem is worsen by the fact that // user can go back to the device tree and work on the tree // while this property sheet is still up. // It would be nice if MMC would support modal dialog boxes! // m_pDevice->PropertyChanged(); m_pDevice->GetClass()->PropertyChanged(); m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_PROPERTIES_CHANGE); UpdateControls(); PropSheet_SetTitle(GetParent(m_hDlg), PSH_PROPTITLE, m_pDevice->GetDisplayName()); PropSheet_CancelToClose(GetParent(m_hDlg)); if (Reboot & (DI_NEEDRESTART | DI_NEEDREBOOT)) { m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_NEEDREBOOT); } } break; } case IDC_DEVDRV_ROLLBACK: { BOOL fChanged; DWORD Reboot = 0; if (RollbackDriver(m_pDevice, m_hDlg, &fChanged, &Reboot) && fChanged) { // // ISSUE: JasonC 2/7/00 // // A refresh on m_pDevice->m_pMachine is necessary here. // Since we are running on a different thread and each // property page may have cached the HDEVINFO and the // SP_DEVINFO_DATA, refresh on the CMachine object can not // be done here. The problem is worsen by the fact that // user can go back to the device tree and work on the tree // while this property sheet is still up. // It would be nice if MMC would support modal dialog boxes! // m_pDevice->PropertyChanged(); m_pDevice->GetClass()->PropertyChanged(); m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_PROPERTIES_CHANGE); UpdateControls(); PropSheet_SetTitle(GetParent(m_hDlg), PSH_PROPTITLE, m_pDevice->GetDisplayName()); PropSheet_CancelToClose(GetParent(m_hDlg)); if (Reboot & (DI_NEEDRESTART | DI_NEEDREBOOT)) { m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_NEEDREBOOT); } } break; } default: break; } } return FALSE; } // // This function uninstalls the drivers for the given device // INPUT: // pDevice -- the object represent the device // hDlg -- the property page window handle // pfChanged -- optional buffer to receive if drivers // were uninstalled. // OUTPUT: // TRUE -- function succeeded. // FALSE -- function failed. // BOOL CDeviceDriverPage::UninstallDrivers( CDevice* pDevice, HWND hDlg, BOOL *pfUninstalled ) { BOOL Return = FALSE; int MsgBoxResult; TCHAR szText[MAX_PATH]; CMachine *pMachine; if (pDevice->m_pMachine->m_ParentMachine) { pMachine = pDevice->m_pMachine->m_ParentMachine; } else { pMachine = pDevice->m_pMachine; } if(!pDevice->m_pMachine->IsLocal() || !g_HasLoadDriverNamePrivilege) { // // Must be an admin and on the local machine to remove a device. // return FALSE; } BOOL Refresh = (pDevice->IsPhantom() || pDevice->HasProblem() || !pDevice->IsStarted()); pMachine->EnableRefresh(FALSE); CRemoveDevDlg TheDlg(pDevice); if (IDOK == TheDlg.DoModal(hDlg, (LPARAM) &TheDlg)) { DWORD DiFlags; DiFlags = pDevice->m_pMachine->DiGetFlags(*pDevice); // // We don't check to see if the device manager is connected to the local // machine because if it wasn't we would not have allowed the user to // get this far since we don't allow them to remove a device if it // is not connected to the local machine. // if (PromptForRestart(hDlg, DiFlags, IDS_REMOVEDEV_RESTART) == IDNO) { Refresh = TRUE; } if (Refresh) { pMachine->ScheduleRefresh(); } Return = TRUE; } pMachine->EnableRefresh(TRUE); return Return; } BOOL CDeviceDriverPage::LaunchTroubleShooter( CDevice* pDevice, HWND hDlg, BOOL *pfChanged ) { BOOL fChanged = FALSE; DWORD Status, Problem = 0; CProblemAgent* ProblemAgent; if (pDevice->GetStatus(&Status, &Problem) || pDevice->IsPhantom()) { // // if the device is a phantom device, use the CM_PROB_DEVICE_NOT_THERE // if (pDevice->IsPhantom()) { Problem = CM_PROB_DEVICE_NOT_THERE; Status = DN_HAS_PROBLEM; } // // if the device is not started and no problem is assigned to it // fake the problem number to be failed start. // if (!(Status & DN_STARTED) && !Problem && pDevice->IsRAW()) { Problem = CM_PROB_FAILED_START; } } ProblemAgent = new CProblemAgent(pDevice, Problem, FALSE); if (ProblemAgent) { fChanged = ProblemAgent->FixIt(GetParent(hDlg)); delete ProblemAgent; } if (pfChanged) { *pfChanged = fChanged; } return TRUE; } // // This function updates drivers for the given device // INPUT: // pDevice -- the object represent the device // hDlg -- the property page window handle // pfChanged -- optional buffer to receive if driver changes // have occured. // OUTPUT: // TRUE -- function succeeded. // FALSE -- function failed. // BOOL CDeviceDriverPage::RollbackDriver( CDevice* pDevice, HWND hDlg, BOOL *pfChanged, DWORD *pdwReboot ) { HCURSOR hCursorOld; BOOL RollbackSuccessful = FALSE; DWORD RollbackError = ERROR_CANCELLED; DWORD Status = 0, Problem = 0; // // Verify that the process has Admin credentials and that we are running on the local // machine. // if (!pDevice || !pDevice->m_pMachine->IsLocal() || !g_HasLoadDriverNamePrivilege) { ASSERT(FALSE); return FALSE; } hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT)); // // If the device has the DN_WILL_BE_REMOVED flag set and the user is // attempting to roll back the driver then we will prompt them for a // reboot and include text in the prompt that explains this device // is in the process of being removed. // if (pDevice->GetStatus(&Status, &Problem) && (Status & DN_WILL_BE_REMOVED)) { if (PromptForRestart(m_hDlg, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_ROLLBACK_DRIVER) == IDYES) { ::DestroyWindow(GetParent(m_hDlg)); } return FALSE; } // // First check to see if there are any drivers to Rollback // CSafeRegistry regRollback; TCHAR RollbackSubkeyName[MAX_PATH + 1]; TCHAR ReinstallString[MAX_PATH]; BOOL bFoundMatch = FALSE; int index = 0; ReinstallString[0] = TEXT('\0'); RollbackSubkeyName[0] = TEXT('\0'); if (regRollback.Open(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Reinstall"))) { DWORD SubkeySize = ARRAYLEN(RollbackSubkeyName); while (!bFoundMatch && regRollback.EnumerateSubkey(index, RollbackSubkeyName, &SubkeySize)) { CSafeRegistry regRollbackSubkey; if (regRollbackSubkey.Open(regRollback, RollbackSubkeyName)) { DWORD regType, cbSize; LPTSTR DeviceInstanceIds; cbSize = 0; if (regRollbackSubkey.GetValue(TEXT("DeviceInstanceIds"), ®Type, NULL, &cbSize)) { // // Allocate memory to hold the DeviceInstanceIds // DeviceInstanceIds = (LPTSTR)LocalAlloc(LPTR, cbSize); if (DeviceInstanceIds) { ZeroMemory(DeviceInstanceIds, cbSize); if (regRollbackSubkey.GetValue(TEXT("DeviceInstanceIds"), ®Type, (PBYTE)DeviceInstanceIds, &cbSize)) { // // Compare the list of DeviceInstanceIds in this registry key with this // devices DeviceInstanceId // for (LPTSTR p = DeviceInstanceIds; *p; p += (lstrlen(p) + 1)) { if (!lstrcmpi(p, pDevice->GetDeviceID())) { bFoundMatch = TRUE; cbSize = sizeof(ReinstallString); regRollbackSubkey.GetValue(TEXT("ReinstallString"), ®Type, (PBYTE)ReinstallString, &cbSize); break; } } } LocalFree(DeviceInstanceIds); } } } SubkeySize = ARRAYLEN(RollbackSubkeyName); index++; } } if (bFoundMatch) { // // Check the ReinstallString path to verify that a backup directory actually exists. // We first need to strip the INF name off of the end of the path. // PTSTR p; // // Assume that the directory does NOT exist // bFoundMatch = FALSE; if (ReinstallString[0] != TEXT('\0')) { p = StrRChr(ReinstallString, NULL, TEXT('\\')); if (p) { *p = 0; WIN32_FIND_DATA findData; HANDLE FindHandle; UINT OldMode; OldMode = SetErrorMode(SEM_FAILCRITICALERRORS); FindHandle = FindFirstFile(ReinstallString, &findData); if(FindHandle != INVALID_HANDLE_VALUE) { FindClose(FindHandle); bFoundMatch = TRUE; } else { // // The directory does not exist. Make sure we clean out the registry key // regRollback.DeleteSubkey(RollbackSubkeyName); } SetErrorMode(OldMode); } } } if (bFoundMatch) { // // We found a match, lets ask the user if they want to rollback the drivers // String strYesRollback; strYesRollback.LoadString(g_hInstance, IDS_DEVDRV_YESROLLBACK); if (MessageBox(hDlg, strYesRollback, pDevice->GetDisplayName(), MB_YESNO) == IDYES) { RollbackSuccessful = pDevice->m_pMachine->RollbackDriver(hDlg, RollbackSubkeyName, 0x3, pdwReboot); if (!RollbackSuccessful) { RollbackError = GetLastError(); } } } else { // // We could not find a drivers backup for this device. Lets ask the user if they want // to start the troubleshooter. // String strNoRollback; strNoRollback.LoadString(g_hInstance, IDS_DEVDRV_NOROLLBACK); if (MessageBox(hDlg, strNoRollback, pDevice->GetDisplayName(), MB_YESNO) == IDYES) { LaunchTroubleShooter(pDevice, hDlg, pfChanged); } } if (hCursorOld) { SetCursor(hCursorOld); } // // We will assume that something changed when we called InstallDevInst() // unless it returned FALSE and GetLastError() == ERROR_CANCELLED // if (pfChanged) { *pfChanged = TRUE; if (!bFoundMatch || (!RollbackSuccessful && (ERROR_CANCELLED == RollbackError))) { *pfChanged = FALSE; } } return TRUE; } // // This function updates drivers for the given device // INPUT: // pDevice -- the object represent the device // hDlg -- the property page window handle // pfChanged -- optional buffer to receive if driver changes // have occured. // OUTPUT: // TRUE -- function succeeded. // FALSE -- function failed. // BOOL CDeviceDriverPage::UpdateDriver( CDevice* pDevice, HWND hDlg, BOOL *pfChanged, DWORD *pdwReboot ) { BOOL Installed = FALSE; DWORD InstallError = ERROR_SUCCESS; DWORD Status = 0, Problem = 0; // // Must be an admin and on the local machine to update a device. // if (!pDevice || !pDevice->m_pMachine->IsLocal() || !g_HasLoadDriverNamePrivilege) { ASSERT(FALSE); return FALSE; } // // If the device has the DN_WILL_BE_REMOVED flag set and the user is // attempting to update the driver then we will prompt them for a // reboot and include text in the prompt that explains this device // is in the process of being removed. // if (pDevice->GetStatus(&Status, &Problem) && (Status & DN_WILL_BE_REMOVED)) { if (PromptForRestart(m_hDlg, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_UPDATE_DRIVER) == IDYES) { ::DestroyWindow(GetParent(m_hDlg)); } return FALSE; } Installed = pDevice->m_pMachine->InstallDevInst(hDlg, pDevice->GetDeviceID(), TRUE, pdwReboot); if (!Installed) { InstallError = GetLastError(); } // // We will assume that something changed when we called InstallDevInst() // unless it returned FALSE and GetLastError() == ERROR_CANCELLED // if (pfChanged) { *pfChanged = TRUE; if (!Installed && (ERROR_CANCELLED == InstallError)) { *pfChanged = FALSE; } } return TRUE; } void CDeviceDriverPage::InitializeDriver() { if (m_pDriver) { delete m_pDriver; m_pDriver = NULL; } m_pDriver = m_pDevice->CreateDriver(); } void CDeviceDriverPage::UpdateControls( LPARAM lParam ) { if (lParam) { m_pDevice = (CDevice*) lParam; } try { // // Calling PropertyChanged() will update the display name for the device. We need // to do this in case a 3rd party property sheet did something that could change // the device's display name. // m_pDevice->PropertyChanged(); // // If we are not running locally then don't bother showing the driver // details since we can't get a list of the drivers and we can't get // any information about the driver. // if (!m_pDevice->m_pMachine->IsLocal()) { ::EnableWindow(GetControl(IDC_DEVDRV_DETAILS), FALSE); ::EnableWindow(GetControl(IDC_DEVDRV_DETAILS_TEXT), FALSE); } // // can not change driver on remote machine or the user // has no Administrator privilege. // if (!m_pDevice->m_pMachine->IsLocal() || !g_HasLoadDriverNamePrivilege) { ::EnableWindow(GetControl(IDC_DEVDRV_CHANGEDRIVER), FALSE); ::EnableWindow(GetControl(IDC_DEVDRV_CHANGEDRIVER_TEXT), FALSE); ::EnableWindow(GetControl(IDC_DEVDRV_ROLLBACK), FALSE); ::EnableWindow(GetControl(IDC_DEVDRV_ROLLBACK_TEXT), FALSE); ::EnableWindow(GetControl(IDC_DEVDRV_UNINSTALL), FALSE); ::EnableWindow(GetControl(IDC_DEVDRV_UNINSTALL_TEXT), FALSE); } // // Hide the uninstall button if the device cannot be uninstalled // else if (!m_pDevice->IsUninstallable()) { ::EnableWindow(GetControl(IDC_DEVDRV_UNINSTALL), FALSE); ::EnableWindow(GetControl(IDC_DEVDRV_UNINSTALL_TEXT), FALSE); } HICON hIconOld; m_IDCicon = IDC_DEVDRV_ICON; // Save for cleanup in OnDestroy. hIconOld = (HICON)SendDlgItemMessage(m_hDlg, IDC_DEVDRV_ICON, STM_SETICON, (WPARAM)(m_pDevice->LoadClassIcon()), 0 ); if (hIconOld) { DestroyIcon(hIconOld); } InitializeDriver(); SetDlgItemText(m_hDlg, IDC_DEVDRV_DESC, m_pDevice->GetDisplayName()); String strDriverProvider, strDriverDate, strDriverVersion, strDriverSigner; m_pDevice->GetProviderString(strDriverProvider); SetDlgItemText(m_hDlg, IDC_DEVDRV_DRIVERPROVIDER, strDriverProvider); m_pDevice->GetDriverDateString(strDriverDate); SetDlgItemText(m_hDlg, IDC_DEVDRV_DRIVERDATE, strDriverDate); m_pDevice->GetDriverVersionString(strDriverVersion); SetDlgItemText(m_hDlg, IDC_DEVDRV_DRIVERVERSION, strDriverVersion); if (m_pDriver) { m_pDriver->GetDriverSignerString(strDriverSigner); } // // If we could not get a digital signature string or then just display // Unknown for the Digital Signer. // if (strDriverSigner.IsEmpty()) { strDriverSigner.LoadString(g_hInstance, IDS_UNKNOWN); } SetDlgItemText(m_hDlg, IDC_DEVDRV_DRIVERSIGNER, strDriverSigner); AddToolTips(m_hDlg, IDC_DEVDRV_DRIVERSIGNER, (LPTSTR)strDriverSigner, &m_hwndDigitalSignerTip); } catch (CMemoryException* e) { e->Delete(); // report memory error MsgBoxParam(m_hDlg, 0, 0, 0); } } BOOL CDeviceDriverPage::OnHelp( LPHELPINFO pHelpInfo ) { WinHelp((HWND)pHelpInfo->hItemHandle, DEVMGR_HELP_FILE_NAME, HELP_WM_HELP, (ULONG_PTR)g_a106HelpIDs); return FALSE; } BOOL CDeviceDriverPage::OnContextMenu( HWND hWnd, WORD xPos, WORD yPos ) { WinHelp(hWnd, DEVMGR_HELP_FILE_NAME, HELP_CONTEXTMENU, (ULONG_PTR)g_a106HelpIDs); return FALSE; } ////////////////////////////////////////////////////////////////////////////////////////// // // Driver Files // const DWORD g_a110HelpIDs[]= { IDC_DRIVERFILES_ICON, IDH_DISABLEHELP, // Driver: "" (Icon) IDC_DRIVERFILES_DESC, IDH_DISABLEHELP, // Driver: "" (Static) IDC_DRIVERFILES_FILES, IDH_DISABLEHELP, // Driver: "Provider:" (Static) IDC_DRIVERFILES_FILELIST, idh_devmgr_driver_driver_files, // Driver: "" (ListBox) IDC_DRIVERFILES_TITLE_PROVIDER, idh_devmgr_driver_provider, // Driver: "Provider:" (Static) IDC_DRIVERFILES_PROVIDER, idh_devmgr_driver_provider, // Driver: "" (Static) IDC_DRIVERFILES_TITLE_COPYRIGHT,idh_devmgr_driver_copyright, // Driver: "Copyright:" (Static) IDC_DRIVERFILES_COPYRIGHT, idh_devmgr_driver_copyright, // Driver: "" (Static) IDC_DRIVERFILES_TITLE_DIGITALSIGNER, IDH_DISABLEHELP, IDC_DRIVERFILES_DIGITALSIGNER, IDH_DISABLEHELP, IDC_DRIVERFILES_TITLE_VERSION, idh_devmgr_driver_file_version, // Driver: "Version:" (Static) IDC_DRIVERFILES_VERSION, idh_devmgr_driver_file_version, // Driver: "File Version:" (Static) 0, 0 }; BOOL CDriverFilesDlg::OnInitDialog() { int SignedIndex = 0, BlankIndex = 0, DriverBlockIndex = 0; try { HICON hIcon; hIcon = (HICON)SendDlgItemMessage(m_hDlg, IDC_DRIVERFILES_ICON, STM_SETICON, (WPARAM)(m_pDevice->LoadClassIcon()), 0); if (hIcon) { DestroyIcon(hIcon); } SetDlgItemText(m_hDlg, IDC_DRIVERFILES_DESC, m_pDevice->GetDisplayName()); // // Create the ImageList that contains the signed and blank images. // // NOTE: On BiDi builds we need to set the ILC_MIRROR flag so that the // signed/unsigned icons are not mirrored. // m_ImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_MASK | (GetWindowLong(GetParent(m_hDlg), GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ? ILC_MIRROR : 0, 1, 1 ); if (m_ImageList) { ImageList_SetBkColor(m_ImageList, GetSysColor(COLOR_WINDOW)); if ((hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_BLANK))) != NULL) { BlankIndex = ImageList_AddIcon(m_ImageList, hIcon); DestroyIcon(hIcon); } if ((hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SIGNED))) != NULL) { SignedIndex = ImageList_AddIcon(m_ImageList, hIcon); DestroyIcon(hIcon); } if ((hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DRIVERBLOCK))) != NULL) { DriverBlockIndex = ImageList_AddIcon(m_ImageList, hIcon); DestroyIcon(hIcon); } } // //Initialize the list of drivers // LV_COLUMN lvcCol; LV_ITEM lviItem; CDriverFile* pDrvFile; PVOID Context; HWND hwndFileList = GetDlgItem(m_hDlg, IDC_DRIVERFILES_FILELIST); // // Insert a single column for this list. // lvcCol.mask = LVCF_FMT | LVCF_WIDTH; lvcCol.fmt = LVCFMT_LEFT; lvcCol.iSubItem = 0; ListView_InsertColumn(hwndFileList, 0, (LV_COLUMN FAR *)&lvcCol); ListView_SetExtendedListViewStyle(hwndFileList, LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP); if (m_ImageList) { ListView_SetImageList(hwndFileList, m_ImageList, LVSIL_SMALL); } ListView_DeleteAllItems(hwndFileList); if (m_pDriver && m_pDriver->GetFirstDriverFile(&pDrvFile, Context)) { do { ASSERT(pDrvFile); LPCTSTR pFullPathName; pFullPathName = pDrvFile->GetFullPathName(); if (pFullPathName) { lviItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; lviItem.iSubItem = 0; lviItem.lParam = (LPARAM)pDrvFile; lviItem.iItem = ListView_GetItemCount(hwndFileList); lviItem.pszText = (LPTSTR)pFullPathName; if (m_ImageList) { if (pDrvFile->IsDriverBlocked()) { // // If the driver is blocked then it gets a special // icon. // lviItem.iImage = DriverBlockIndex; } else { // // If the driver is not blocked then show an icon // if the driver is digitally signed. // lviItem.iImage = (pDrvFile->GetWin32Error() == NO_ERROR) ? SignedIndex : BlankIndex; } } ListView_InsertItem(hwndFileList, &lviItem); } } while (m_pDriver->GetNextDriverFile(&pDrvFile, Context)); if (ListView_GetItemCount(hwndFileList) >= 1) { ListView_SetItemState(hwndFileList, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED ); ListView_EnsureVisible(hwndFileList, 0, FALSE); ListView_SetColumnWidth(hwndFileList, 0, LVSCW_AUTOSIZE_USEHEADER); ShowCurDriverFileDetail(); } else { // // nothing on the driver file list, disable it // ::EnableWindow(GetControl(IDC_DRIVERFILES_FILELIST), FALSE); } } } catch (CMemoryException* e) { e->Delete(); return FALSE; } return TRUE; } void CDriverFilesDlg::OnCommand( WPARAM wParam, LPARAM lParam ) { if (BN_CLICKED == HIWORD(wParam)) { if (IDOK == LOWORD(wParam)) { EndDialog(m_hDlg, IDOK); } else if (IDCANCEL == LOWORD(wParam)) { EndDialog(m_hDlg, IDCANCEL); } } } BOOL CDriverFilesDlg::OnNotify( LPNMHDR pnmhdr ) { switch (pnmhdr->code) { case LVN_ITEMCHANGED: ShowCurDriverFileDetail(); break; case NM_RETURN: case NM_CLICK: if (pnmhdr->idFrom == IDS_DRIVERFILES_BLOCKDRIVERLINK) { LaunchHelpForBlockedDriver(); } break; } return FALSE; } BOOL CDriverFilesDlg::OnDestroy() { HICON hIcon; if(hIcon = (HICON)SendDlgItemMessage(m_hDlg, IDC_DRIVERFILES_ICON, STM_GETICON, 0, 0)) { DestroyIcon(hIcon); } if (m_ImageList) { ImageList_Destroy(m_ImageList); } return FALSE; } BOOL CDriverFilesDlg::OnHelp( LPHELPINFO pHelpInfo ) { WinHelp((HWND)pHelpInfo->hItemHandle, DEVMGR_HELP_FILE_NAME, HELP_WM_HELP, (ULONG_PTR)g_a110HelpIDs); return FALSE; } BOOL CDriverFilesDlg::OnContextMenu( HWND hWnd, WORD xPos, WORD yPos ) { WinHelp(hWnd, DEVMGR_HELP_FILE_NAME, HELP_CONTEXTMENU, (ULONG_PTR)g_a110HelpIDs); return FALSE; } void CDriverFilesDlg::ShowCurDriverFileDetail() { HWND hwndFileList = GetDlgItem(m_hDlg, IDC_DRIVERFILES_FILELIST); LVITEM lvItem; LPCTSTR pString; lvItem.mask = LVIF_PARAM; lvItem.iSubItem = 0; lvItem.iItem = ListView_GetNextItem(hwndFileList, -1, LVNI_SELECTED ); if (lvItem.iItem != -1) { try { ListView_GetItem(hwndFileList, &lvItem); CDriverFile* pDrvFile = (CDriverFile*)lvItem.lParam; ASSERT(pDrvFile); TCHAR TempString[LINE_LEN]; LPCTSTR pFullPathName; pFullPathName = pDrvFile->GetFullPathName(); if (!pFullPathName || (pDrvFile->GetAttributes() == 0xFFFFFFFF)) { // // This is the case when the file is not present on the system // LoadResourceString(IDS_NOT_PRESENT, TempString, ARRAYLEN(TempString)); SetDlgItemText(m_hDlg, IDC_DRIVERFILES_VERSION, TempString); SetDlgItemText(m_hDlg, IDC_DRIVERFILES_PROVIDER, TempString); SetDlgItemText(m_hDlg, IDC_DRIVERFILES_COPYRIGHT, TempString); SetDlgItemText(m_hDlg, IDC_DRIVERFILES_DIGITALSIGNER, TempString); ShowWindow(GetControl(IDS_DRIVERFILES_BLOCKDRIVERLINK), FALSE); } else { if (!pDrvFile->HasVersionInfo()) { // // This is the case when the file is present but it does not have // version information. // LoadResourceString(IDS_UNKNOWN, TempString, ARRAYLEN(TempString)); SetDlgItemText(m_hDlg, IDC_DRIVERFILES_VERSION, TempString); SetDlgItemText(m_hDlg, IDC_DRIVERFILES_PROVIDER, TempString); SetDlgItemText(m_hDlg, IDC_DRIVERFILES_COPYRIGHT, TempString); } else { // // Show the file version information. // TempString[0] = _T('\0'); pString = pDrvFile->GetVersion(); if (!pString && _T('\0') == TempString[0]) { LoadResourceString(IDS_NOT_AVAILABLE, TempString, ARRAYLEN(TempString)); pString = TempString; } SetDlgItemText(m_hDlg, IDC_DRIVERFILES_VERSION, (LPTSTR)pString); pString = pDrvFile->GetProvider(); if (!pString && _T('\0') == TempString[0]) { LoadResourceString(IDS_NOT_AVAILABLE, TempString, ARRAYLEN(TempString)); pString = TempString; } SetDlgItemText(m_hDlg, IDC_DRIVERFILES_PROVIDER, (LPTSTR)pString); pString = pDrvFile->GetCopyright(); if (!pString && _T('\0') == TempString[0]) { LoadResourceString(IDS_NOT_AVAILABLE, TempString, ARRAYLEN(TempString)); pString = TempString; } SetDlgItemText(m_hDlg, IDC_DRIVERFILES_COPYRIGHT, (LPTSTR)pString); } // // Show the digital signer if the file is signed. // pString = pDrvFile->GetDigitalSigner(); if (!pString) { TempString[0] = _T('\0'); LoadResourceString(((pDrvFile->GetWin32Error() != 0) && (pDrvFile->GetWin32Error() != 0xFFFFFFFF) && (pDrvFile->GetWin32Error() != ERROR_DRIVER_BLOCKED)) ? IDS_NO_DIGITALSIGNATURE : IDS_NOT_AVAILABLE, TempString, ARRAYLEN(TempString)); pString = TempString; } SetDlgItemText(m_hDlg, IDC_DRIVERFILES_DIGITALSIGNER, (LPTSTR)pString); // // Show the block driver link if this driver is blocked and it // has a block driver html help ID. // ShowWindow(GetControl(IDS_DRIVERFILES_BLOCKDRIVERLINK), pDrvFile->GetBlockedDriverHtmlHelpID() ? TRUE : FALSE); } } catch (CMemoryException* e) { e->Delete(); // report memory error MsgBoxParam(m_hDlg, 0, 0, 0); } } else { // no selection SetDlgItemText(m_hDlg, IDC_DRIVERFILES_VERSION, TEXT("")); SetDlgItemText(m_hDlg, IDC_DRIVERFILES_PROVIDER, TEXT("")); SetDlgItemText(m_hDlg, IDC_DRIVERFILES_COPYRIGHT, TEXT("")); SetDlgItemText(m_hDlg, IDC_DRIVERFILES_DIGITALSIGNER, TEXT("")); } } void CDriverFilesDlg::LaunchHelpForBlockedDriver() { HWND hwndFileList = GetDlgItem(m_hDlg, IDC_DRIVERFILES_FILELIST); LVITEM lvItem; LPCTSTR pHtmlHelpID; String strHcpLink; lvItem.mask = LVIF_PARAM; lvItem.iSubItem = 0; lvItem.iItem = ListView_GetNextItem(hwndFileList, -1, LVNI_SELECTED ); if (lvItem.iItem != -1) { try { ListView_GetItem(hwndFileList, &lvItem); CDriverFile* pDrvFile = (CDriverFile*)lvItem.lParam; ASSERT(pDrvFile); if ((pHtmlHelpID = pDrvFile->GetBlockedDriverHtmlHelpID()) != NULL) { strHcpLink.Format(TEXT("HELPCTR.EXE -url %s"), pHtmlHelpID); TRACE((TEXT("launching %s"), pHtmlHelpID)); ShellExecute(m_hDlg, TEXT("open"), TEXT("HELPCTR.EXE"), (LPTSTR)strHcpLink, NULL, SW_SHOWNORMAL); } } catch (CMemoryException* e) { e->Delete(); // report memory error MsgBoxParam(m_hDlg, 0, 0, 0); } } }