|
|
/*++
Copyright (C) Microsoft Corporation
Module Name:
devgenpg.cpp
Abstract:
This module implements CDeviceGeneralPage -- device general property page
Author:
William Hsieh (williamh) created
Revision History:
--*/ // devgenpg.cpp : implementation file
//
#include "devmgr.h"
#include "hwprof.h"
#include "devgenpg.h"
#include "tswizard.h"
#include "utils.h"
//
// help topic ids
//
const DWORD g_a103HelpIDs[]= { IDC_DEVGEN_TITLE_TYPE, idh_devmgr_general_devicetype, IDC_DEVGEN_TITLE_MFG, idh_devmgr_general_manufacturer, IDC_DEVGEN_STATUSGROUP, IDH_DISABLEHELP, IDC_DEVGEN_ICON, IDH_DISABLEHELP, // General: "" (Static)
IDC_DEVGEN_DESC, IDH_DISABLEHELP, // General: "" (Static)
IDC_DEVGEN_USAGETEXT, IDH_DISABLEHELP, // General: "Place a check mark next to the configuration(s) where this device should be used." (Static)
IDC_DEVGEN_TYPE, idh_devmgr_general_devicetype, // General: "" (Static)
IDC_DEVGEN_MFG, idh_devmgr_general_manufacturer, // General: "" (Static)
IDC_DEVGEN_STATUS, idh_devmgr_general_device_status, // General: "" (Static)
IDC_DEVGEN_PROFILELIST, idh_devmgr_general_device_usage, // General: "Dropdown Combo" (SysListView32)
IDC_DEVGEN_TITLE_LOCATION, idh_devmgr_general_location, // General: location
IDC_DEVGEN_LOCATION, idh_devmgr_general_location, // General: location
IDC_DEVGEN_TROUBLESHOOTING, idh_devmgr_general_trouble, // General: troubleshooting
0, 0 };
CDeviceGeneralPage::~CDeviceGeneralPage() { if (m_pHwProfileList) {
delete m_pHwProfileList; }
if (m_pProblemAgent) {
delete m_pProblemAgent; } }
HPROPSHEETPAGE CDeviceGeneralPage::Create( CDevice* pDevice ) { ASSERT(pDevice);
if (pDevice) { m_pDevice = pDevice; // override PROPSHEETPAGE structure here...
m_psp.lParam = (LPARAM)this; pDevice->m_pMachine->DiTurnOffDiExFlags(*pDevice, DI_FLAGSEX_PROPCHANGE_PENDING); return CreatePage(); } return NULL; }
BOOL CDeviceGeneralPage::OnInitDialog( LPPROPSHEETPAGE ppsp ) { m_pDevice->m_pMachine->AttachPropertySheet(m_hDlg);
// notify property sheet data that the property sheet is up
m_pDevice->m_psd.PageCreateNotify(m_hDlg);
return CPropSheetPage::OnInitDialog(ppsp); }
BOOL CDeviceGeneralPage::OnApply() { try { HWND hwndCB = GetControl(IDC_DEVGEN_PROFILELIST); m_SelectedDeviceUsage = ComboBox_GetCurSel(hwndCB);
if ((-1 != m_SelectedDeviceUsage) && (m_SelectedDeviceUsage != m_CurrentDeviceUsage)) {
//
// User is changing the device usage
//
UpdateHwProfileStates(); SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, PSNRET_NOERROR); return TRUE; } }
catch(CMemoryException* e) { e->Delete(); MsgBoxParam(m_hDlg, 0, 0, 0); } return FALSE; }
void CDeviceGeneralPage::UpdateHwProfileStates() { // first decide what to do: enabling or disabling
BOOL Canceled; Canceled = FALSE;
if (m_SelectedDeviceUsage == m_CurrentDeviceUsage) { return; }
m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_NODI_DEFAULTACTION);
SP_PROPCHANGE_PARAMS pcp; pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
//
// specific enabling/disabling
//
pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; CHwProfile* phwpf;
if (m_pHwProfileList->GetCurrentHwProfile(&phwpf)) { if (DEVICE_ENABLE == m_SelectedDeviceUsage) { pcp.StateChange = DICS_ENABLE; } else { pcp.StateChange = DICS_DISABLE; }
pcp.HwProfile = phwpf->GetHwProfile(); m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice, &pcp.ClassInstallHeader, sizeof(pcp) ); m_pDevice->m_pMachine->DiCallClassInstaller(DIF_PROPERTYCHANGE, *m_pDevice); Canceled = (ERROR_CANCELLED == GetLastError()); }
//
// class installer has not objection of our enabling/disabling,
// do real enabling/disabling.
//
if (!Canceled) { if (m_pHwProfileList->GetCurrentHwProfile(&phwpf)) { if (DEVICE_ENABLE == m_SelectedDeviceUsage) { //
// we are enabling the device,
// do a specific enabling then a globally enabling.
// the globally enabling will start the device
// The implementation here is different from
// Win9x which does a global enabling, a config
// specific enabling and then a start.
//
pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; pcp.HwProfile = phwpf->GetHwProfile(); m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice, &pcp.ClassInstallHeader, sizeof(pcp) ); m_pDevice->m_pMachine->DiChangeState(*m_pDevice); //
// this call will start the device is it not started.
//
pcp.Scope = DICS_FLAG_GLOBAL; m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice, &pcp.ClassInstallHeader, sizeof(pcp) ); m_pDevice->m_pMachine->DiChangeState(*m_pDevice); } else { //
// Do either a global disable or a configspecific disable
//
if (DEVICE_DISABLE == m_SelectedDeviceUsage) { pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; } else {
pcp.Scope = DICS_FLAG_GLOBAL; }
pcp.StateChange = DICS_DISABLE; pcp.HwProfile = phwpf->GetHwProfile(); m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice, &pcp.ClassInstallHeader, sizeof(pcp) ); m_pDevice->m_pMachine->DiChangeState(*m_pDevice); } }
// signal that the property of the device is changed.
m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_PROPERTIES_CHANGE); m_RestartFlags |= (m_pDevice->m_pMachine->DiGetFlags(*m_pDevice)) & (DI_NEEDRESTART | DI_NEEDREBOOT); }
// remove class install parameters, this also reset
// DI_CLASSINATLLPARAMS
m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice, NULL, 0);
m_pDevice->m_pMachine->DiTurnOffDiFlags(*m_pDevice, DI_NODI_DEFAULTACTION); }
BOOL CDeviceGeneralPage::OnLastChanceApply() { //
// The last chance apply message is sent in reverse order page n to page 0.
//
// Since we are the first page in the set of property sheets we can gaurentee
// that the last PSN_LASTCHANCEAPPLY message will be the last message for all
// the pages.
//
// The property sheet is going away, consolidate the changes on the device. We
// do this during the PSN_LASTCHANCEAPPLY message so that the property sheet is
// still displayed while we do the DIF_PROPERTYCHANGE. There are some cases where
// the DIF_PROPERTYCHANGE can take quite a long time so we want the property sheet
// to still be shown while this is happening. If we do this during the DestroyCallback
// the property sheet UI has already been torn down and so the user won't realize
// we are still saving the changes.
//
try { ASSERT(m_pDevice);
if (m_pDevice->m_pMachine->DiGetExFlags(*m_pDevice) & DI_FLAGSEX_PROPCHANGE_PENDING) { DWORD Status = 0, Problem = 0;
//
// If the device has the DN_WILL_BE_REMOVED flag set and the user is
// attempting to change settings on 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 (m_pDevice->GetStatus(&Status, &Problem) && (Status & DN_WILL_BE_REMOVED)) {
//
// First try and send a MMCPropertyChangeNotify message to our
// CComponent so that it can prompt for a reboot inside the
// device manager thread instead of our thread. If this is not
// done then the property sheet will hang around after device
// manager has gone away...which will cause a "hung app" dialog
// to appear.
//
CNotifyRebootRequest* pNRR = new CNotifyRebootRequest(NULL, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_CHANGE_SETTINGS);
if (pNRR) { if (!m_pDevice->m_psd.PropertyChangeNotify(reinterpret_cast<LONG_PTR>(pNRR))) { //
// There isn't a CComponent around, so this is just a property
// sheet running outside of MMC.
//
pNRR->Release(); PromptForRestart(m_hDlg, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_CHANGE_SETTINGS); } } else { //
// We couldn't allocate memory to create our CNotifyRebootRequest
// instance, so just prompt for a reboot in this thread.
//
PromptForRestart(m_hDlg, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_CHANGE_SETTINGS); }
} else { //
// property change pending, issue a DICS_PROPERTYCHANGE to the
// class installer. A DICS_PROPCHANGE would basically stop the
// device and restart it. If each property page issues
// its own DICS_PROPCHANGE command, the device would
// be stopped/started several times even though one is enough.
// A property page sets DI_FLAGEX_PROPCHANGE_PENDING when it needs
// a DICS_PROPCHANGE command to be issued.
//
SP_PROPCHANGE_PARAMS pcp; pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT)); pcp.Scope = DICS_FLAG_GLOBAL; pcp.StateChange = DICS_PROPCHANGE; m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice, &pcp.ClassInstallHeader, sizeof(pcp) ); m_pDevice->m_pMachine->DiCallClassInstaller(DIF_PROPERTYCHANGE, *m_pDevice); m_pDevice->m_pMachine->DiTurnOnDiFlags(*m_pDevice, DI_PROPERTIES_CHANGE); m_pDevice->m_pMachine->DiTurnOffDiExFlags(*m_pDevice, DI_FLAGSEX_PROPCHANGE_PENDING); if (hCursorOld) { SetCursor(hCursorOld); } } } }
catch(CMemoryException* e) { e->Delete(); MsgBoxParam(m_hDlg, 0, 0, 0); } return FALSE; }
UINT CDeviceGeneralPage::DestroyCallback() { //
// We do this because this is the page we are sure will be created --
// this page is ALWAYS the first page.
//
ASSERT(m_pDevice);
//
// We don't want to prompt for a reboot if the device has the problem
// DN_WILL_BE_REMOVED, because we have already prompted for a reboot
// before we get to this destroy callback.
//
DWORD Status = 0, Problem = 0; if (m_pDevice->GetStatus(&Status, &Problem) && !(Status & DN_WILL_BE_REMOVED)) { m_RestartFlags |= m_pDevice->m_pMachine->DiGetFlags(*m_pDevice); if (m_RestartFlags & (DI_NEEDRESTART | DI_NEEDREBOOT)) { //
// Do not use our window handle(or its parent) as the parent
// to the newly create dialog because they are in "detroyed state".
// WM_CLOSE does not help either.
// NULL window handle(Desktop) should be okay here.
//
// We only want to prompt for a restart if device manager is connected
// to the local machine.
//
if (m_pDevice->m_pMachine->IsLocal()) { //
// First try and send a MMCPropertyChangeNotify message to our
// CComponent so that it can prompt for a reboot inside the
// device manager thread instead of our thread. If this is not
// done then the property sheet will hang around after device
// manager has gone away...which will cause a "hung app" dialog
// to appear.
//
CNotifyRebootRequest* pNRR = new CNotifyRebootRequest(NULL, m_RestartFlags, 0); if (pNRR) { if (!m_pDevice->m_psd.PropertyChangeNotify(reinterpret_cast<LONG_PTR>(pNRR))) { //
// There isn't a CComponent around, so this is just a property
// sheet running outside of MMC.
//
pNRR->Release(); PromptForRestart(NULL, m_RestartFlags); } } else { //
// We couldn't allocate memory to create our CNotifyRebootRequest
// instance, so just prompt for a reboot in this thread.
//
PromptForRestart(NULL, m_RestartFlags); } } } }
// notify CPropSheetData that the property sheet is going away
m_pDevice->m_psd.PageDestroyNotify(m_hDlg); if (m_RestartFlags & DI_PROPERTIES_CHANGE) { // Device properties changed. We need to refresh the machine.
// Since we are running in a separate thread, we can not
// call the refresh function, instead, we schedule it.
// This should be done before enabling the refresh
if (m_pDevice->m_pMachine->m_ParentMachine) {
m_pDevice->m_pMachine->m_ParentMachine->ScheduleRefresh();
} else {
m_pDevice->m_pMachine->ScheduleRefresh(); } }
//
// Detach this property page from the CMachine so that the CMachine can be
// destroyed now if it needs to be.
//
m_pDevice->m_pMachine->DetachPropertySheet(m_hDlg); ASSERT(!::IsWindow(m_hwndLocationTip));
//
// Destory the CMachine.
//
CMachine* pMachine; pMachine = m_pDevice->m_pMachine; if (pMachine->ShouldPropertySheetDestroy()) { delete pMachine; } return CPropSheetPage::DestroyCallback(); }
void CDeviceGeneralPage::UpdateControls( LPARAM lParam ) { if (lParam) m_pDevice = (CDevice*)lParam;
m_RestartFlags = 0;
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();
SetDlgItemText(m_hDlg, IDC_DEVGEN_DESC, m_pDevice->GetDisplayName()); TCHAR TempString[512]; String str; m_pDevice->GetMFGString(str); SetDlgItemText(m_hDlg, IDC_DEVGEN_MFG, str); SetDlgItemText(m_hDlg, IDC_DEVGEN_TYPE, m_pDevice->GetClassDisplayName());
HICON hIconNew; hIconNew = m_pDevice->LoadClassIcon(); if (hIconNew) { HICON hIconOld; m_IDCicon = IDC_DEVGEN_ICON; // Save for cleanup in OnDestroy.
hIconOld = (HICON)SendDlgItemMessage(m_hDlg, IDC_DEVGEN_ICON, STM_SETICON, (WPARAM)hIconNew, 0); if (hIconOld) DestroyIcon(hIconOld); }
//
// get the device location information
//
if (::GetLocationInformation(m_pDevice->GetDevNode(), TempString, ARRAYLEN(TempString), m_pDevice->m_pMachine->GetHMachine()) != CR_SUCCESS) { // if the devnode does not have location information,
// use the word "unknown"
LoadString(g_hInstance, IDS_UNKNOWN, TempString, ARRAYLEN(TempString)); }
SetDlgItemText(m_hDlg, IDC_DEVGEN_LOCATION, TempString);
AddToolTips(m_hDlg, IDC_DEVGEN_LOCATION, TempString, &m_hwndLocationTip);
ShowWindow(GetControl(IDC_DEVGEN_TROUBLESHOOTING), SW_HIDE);
DWORD Problem, Status; if (m_pDevice->GetStatus(&Status, &Problem) || m_pDevice->IsPhantom()) { //
// if the device is a phantom device, use the CM_PROB_PHANTOM
//
if (m_pDevice->IsPhantom()) { Problem = CM_PROB_PHANTOM; 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 && m_pDevice->IsRAW()) { Problem = CM_PROB_FAILED_START; }
//
// if a device has a private problem then give it special text telling
// the user to contact the manufacturer of this driver.
//
if (Status & DN_PRIVATE_PROBLEM) { str.LoadString(g_hInstance, IDS_SPECIALPROB_PRIVATEPROB); }
//
// if a device is not started and still does not have a problem
// then give it special problem text saying that this device
// does not have a driver.
//
else if (!(Status & DN_STARTED) && !(Status & DN_HAS_PROBLEM)) { if (::GetSystemMetrics(SM_CLEANBOOT) == 0) { str.LoadString(g_hInstance, IDS_SPECIALPROB_NODRIVERS);
} else {
str.LoadString(g_hInstance, IDS_SPECIALPROB_SAFEMODE); } }
//
// Display normal problem text
//
else { UINT len = GetDeviceProblemText(Problem, TempString, ARRAYLEN(TempString)); if (len) { if (len < ARRAYLEN(TempString)) { SetDlgItemText(m_hDlg, IDC_DEVGEN_STATUS, TempString); str = TempString; } else { BufferPtr<TCHAR> TextPtr(len + 1); GetDeviceProblemText(Problem, TextPtr, len + 1);
str = (LPTSTR)TextPtr; } }
else { str.LoadString(g_hInstance, IDS_PROB_UNKNOWN); } }
//
// Add the 'related driver blocked' text if the device has the devnode
// flag DN_DRIVER_BLOCKED set and it does not have the problem
// CM_PROB_DRIVER_BLOCKED.
//
if ((Status & DN_DRIVER_BLOCKED) && (Problem != CM_PROB_DRIVER_BLOCKED)) { LoadString(g_hInstance, IDS_DRIVER_BLOCKED, TempString, ARRAYLEN(TempString)); str += TempString; }
//
// Add the 'child device with invalid Id' text if the device has
// the devnode flag DN_CHILD_WITH_INVALID_ID set.
//
if (Status & DN_CHILD_WITH_INVALID_ID) { LoadString(g_hInstance, IDS_CHILD_WITH_INVALID_ID, TempString, ARRAYLEN(TempString)); str += TempString; }
//
// Add the 'will be removed' text if the device is going to be removed
// on the next restart.
//
if (Status & DN_WILL_BE_REMOVED) {
LoadString(g_hInstance, IDS_WILL_BE_REMOVED, TempString, ARRAYLEN(TempString)); str += TempString; }
//
// Add the restart text if the device needs to be restarted
//
if (Status & DN_NEED_RESTART) {
LoadString(g_hInstance, IDS_NEED_RESTART, TempString, ARRAYLEN(TempString)); str += TempString;
m_RestartFlags |= DI_NEEDRESTART; }
//
// Create the problem agent and update the control text
//
if (!(Status & DN_PRIVATE_PROBLEM)) { if (m_pProblemAgent) { delete m_pProblemAgent; } m_pProblemAgent = new CProblemAgent(m_pDevice, Problem, FALSE); DWORD Len; Len = m_pProblemAgent->InstructionText(TempString, ARRAYLEN(TempString)); if (Len) { str += TempString; } Len = m_pProblemAgent->FixitText(TempString, ARRAYLEN(TempString)); if (Len) { ::ShowWindow(GetControl(IDC_DEVGEN_TROUBLESHOOTING), SW_SHOW); SetDlgItemText(m_hDlg, IDC_DEVGEN_TROUBLESHOOTING, TempString); } } }
else { TRACE((TEXT("%s has not status, devnode =%lx, cr = %lx\n"), m_pDevice->GetDisplayName(), m_pDevice->GetDevNode(), m_pDevice->m_pMachine->GetLastCR())); str.LoadString(g_hInstance, IDS_PROB_UNKNOWN); ::ShowWindow(GetControl(IDC_DEVGEN_TROUBLESHOOTING), SW_HIDE); }
SetDlgItemText(m_hDlg, IDC_DEVGEN_STATUS, str);
if (m_pDevice->NoChangeUsage() || !m_pDevice->IsDisableable() || (CM_PROB_HARDWARE_DISABLED == Problem)) { // the device disallows any changes on hw profile.
// disable all profile related controls.
::EnableWindow(GetControl(IDC_DEVGEN_PROFILELIST), FALSE); ::EnableWindow(GetControl(IDC_DEVGEN_USAGETEXT), FALSE); }
else { HWND hwndCB = GetControl(IDC_DEVGEN_PROFILELIST);
DWORD ConfigFlags; if (!m_pDevice->GetConfigFlags(&ConfigFlags)) { ConfigFlags = 0; }
//
// only want the disabled bit
//
ConfigFlags &= CONFIGFLAG_DISABLED;
//
// rebuild the profile list.
//
if (m_pHwProfileList) { delete m_pHwProfileList; }
m_pHwProfileList = new CHwProfileList();
if (m_pHwProfileList->Create(m_pDevice, ConfigFlags)) { ComboBox_ResetContent(hwndCB);
//
// Get the current device usage
//
if (m_pDevice->IsStateDisabled()) {
if ((m_pHwProfileList->GetCount() > 1) && ConfigFlags) {
m_CurrentDeviceUsage = DEVICE_DISABLE_GLOBAL; } else {
m_CurrentDeviceUsage = DEVICE_DISABLE; }
} else {
m_CurrentDeviceUsage = DEVICE_ENABLE; }
//
// Always add the Enable item
//
String Enable; Enable.LoadString(g_hInstance, IDS_ENABLE_CURRENT); ComboBox_AddString(hwndCB, Enable);
//
// Add the disable items. There will either be one disable
// item if there is only one hardware profile or two if there
// are more than one hardware profile.
//
if (m_pHwProfileList->GetCount() > 1) {
String DisableInCurrent; DisableInCurrent.LoadString(g_hInstance, IDS_DISABLE_IN_PROFILE); ComboBox_AddString(hwndCB, DisableInCurrent);
String DisableGlobal; DisableGlobal.LoadString(g_hInstance, IDS_DISABLE_GLOBAL); ComboBox_AddString(hwndCB, DisableGlobal);
} else {
String Disable; Disable.LoadString(g_hInstance, IDS_DISABLE_CURRENT); ComboBox_AddString(hwndCB, Disable); }
ComboBox_SetCurSel(hwndCB, m_CurrentDeviceUsage); } }
//
// If this is a remote computer or the user is not an administrator
// then disable the enable/disable drop down list along with the
// TroubleShooter button.
//
if (!m_pDevice->m_pMachine->IsLocal() || !g_IsAdmin) { ::EnableWindow(GetControl(IDC_DEVGEN_PROFILELIST), FALSE); ::EnableWindow(GetControl(IDC_DEVGEN_TROUBLESHOOTING), FALSE); }
//
// Check if we need to autolauch the troubleshooter
//
if (m_pDevice->m_pMachine->IsLocal() && g_IsAdmin && m_pDevice->m_bLaunchTroubleShooter) {
m_pDevice->m_bLaunchTroubleShooter = FALSE; ::PostMessage(m_hDlg, WM_COMMAND, MAKELONG(IDC_DEVGEN_TROUBLESHOOTING, BN_CLICKED), 0); }
} catch (CMemoryException* e) { e->Delete(); MsgBoxParam(m_hDlg, 0, 0, 0); } }
BOOL CDeviceGeneralPage::OnQuerySiblings( WPARAM wParam, LPARAM lParam ) { DMQUERYSIBLINGCODE Code = (DMQUERYSIBLINGCODE)wParam; if (QSC_TO_FOREGROUND == Code) { HWND hwndSheet; hwndSheet = m_pDevice->m_psd.GetWindowHandle(); if (GetForegroundWindow() != hwndSheet) { SetForegroundWindow(hwndSheet); } SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, 1); return TRUE; }
return CPropSheetPage::OnQuerySiblings(wParam, lParam); }
BOOL CDeviceGeneralPage::OnCommand( WPARAM wParam, LPARAM lParam ) { UNREFERENCED_PARAMETER(lParam);
if (BN_CLICKED == HIWORD(wParam) && IDC_DEVGEN_TROUBLESHOOTING == LOWORD(wParam)) {
BOOL fChanged = FALSE; if (m_pProblemAgent) {
fChanged = m_pProblemAgent->FixIt(GetParent(m_hDlg)); } if (fChanged) {
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));
//
// ISSUE: JasonC 2/7/2000
//
// 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.
//
} }
return FALSE; }
BOOL CDeviceGeneralPage::OnHelp( LPHELPINFO pHelpInfo ) { WinHelp((HWND)pHelpInfo->hItemHandle, DEVMGR_HELP_FILE_NAME, HELP_WM_HELP, (ULONG_PTR)g_a103HelpIDs); return FALSE; }
BOOL CDeviceGeneralPage::OnContextMenu( HWND hWnd, WORD xPos, WORD yPos ) { UNREFERENCED_PARAMETER(xPos); UNREFERENCED_PARAMETER(yPos);
WinHelp(hWnd, DEVMGR_HELP_FILE_NAME, HELP_CONTEXTMENU, (ULONG_PTR)g_a103HelpIDs); return FALSE; }
|