/****************************************************************************** Source File: deskmon.cpp Main code for the advanced desktop Monitor page Copyright (c) 1997-1998 by Microsoft Corporation Change History: 12-16-97 AndreVa - Created It ******************************************************************************/ #include "deskmon.h" #define DECL_CRTFREE #include // // The function DeviceProperties() is implemented in DevMgr.dll; Since we don't have a devmgr.h, we // explicitly declare it here. // typedef int (WINAPI *DEVPROPERTIES)( HWND hwndParent, LPCTSTR MachineName, LPCTSTR DeviceID, BOOL ShowDeviceTree ); // OLE-Registry magic number // 42071713-76d4-11d1-8b24-00a0c9068ff3 // GUID g_CLSID_CplExt = { 0x42071713, 0x76d4, 0x11d1, { 0x8b, 0x24, 0x00, 0xa0, 0xc9, 0x06, 0x8f, 0xf3} }; DESK_EXTENSION_INTERFACE DeskInterface; static const DWORD sc_MonitorHelpIds[] = { IDC_MONITOR_GRP, IDH_DISPLAY_SETTINGS_ADVANCED_MONITOR_TYPE, IDI_MONITOR, IDH_DISPLAY_SETTINGS_ADVANCED_MONITOR_TYPE, IDC_MONITORDESC, IDH_DISPLAY_SETTINGS_ADVANCED_MONITOR_TYPE, IDC_MONITORS_LIST, IDH_DISPLAY_SETTINGS_ADVANCED_MONITOR_MONITORTYPE_LISTBOX, IDC_PROPERTIES, IDH_DISPLAY_SETTINGS_ADVANCED_MONITOR_PROPERTIES, IDC_MONSET_GRP, IDH_NOHELP, IDC_MONSET_FREQSTR, IDH_DISPLAY_SETTINGS_ADVANCED_MONITOR_REFRESH, IDC_MONSET_FREQ, IDH_DISPLAY_SETTINGS_ADVANCED_MONITOR_REFRESH, IDC_MONSET_PRUNNING_MODE, IDH_DISPLAY_SETTINGS_ADVANCED_MONITOR_HIDEMODE_CHECKBOX, IDC_MONSET_PRUNNING_MODE_DESC, IDH_DISPLAY_SETTINGS_ADVANCED_MONITOR_HIDEMODE_CHECKBOX, 0, 0 }; /////////////////////////////////////////////////////////////////////////////// // // Messagebox wrapper // /////////////////////////////////////////////////////////////////////////////// int FmtMessageBox( HWND hwnd, UINT fuStyle, DWORD dwTitleID, DWORD dwTextID) { TCHAR Title[256]; TCHAR Text[1700]; LoadString(g_hInst, dwTextID, Text, ARRAYSIZE(Text)); LoadString(g_hInst, dwTitleID, Title, ARRAYSIZE(Title)); return (MessageBox(hwnd, Text, Title, fuStyle)); } // Constructors / destructor CMonitorPage::CMonitorPage(HWND hDlg) : m_hDlg(hDlg) , m_lpdmPrevious(NULL) , m_bCanBePruned(FALSE) , m_bIsPruningReadOnly(TRUE) , m_bIsPruningOn(FALSE) , m_cMonitors(0) , m_hMonitorsList(NULL) , m_lpdmOnCancel(NULL) , m_bOnCancelIsPruningOn(FALSE) { } void CMonitorPage::OnApply() { long lRet = PSNRET_INVALID_NOCHANGEPAGE; HINSTANCE hInst; LPDISPLAY_SAVE_SETTINGS lpfnDisplaySaveSettings = NULL; hInst = LoadLibrary(TEXT("desk.cpl")); if (hInst) { lpfnDisplaySaveSettings = (LPDISPLAY_SAVE_SETTINGS) GetProcAddress(hInst, "DisplaySaveSettings"); if (lpfnDisplaySaveSettings) { long lSave = lpfnDisplaySaveSettings(DeskInterface.pContext, m_hDlg); LPDEVMODEW lpdmCurrent = DeskInterface.lpfnGetSelectedMode(DeskInterface.pContext); if (lSave == DISP_CHANGE_SUCCESSFUL) { // // Save the current mode - to restore it in case the user cancels the p. sheet // m_lpdmOnCancel = m_lpdmPrevious = lpdmCurrent; m_bOnCancelIsPruningOn = m_bIsPruningOn; lRet = PSNRET_NOERROR; } else if (lSave == DISP_CHANGE_RESTART) { // // User wants to reboot system. // PropSheet_RestartWindows(GetParent(m_hDlg)); lRet = PSNRET_NOERROR; } else { // // Keep the apply button active // lRet = PSNRET_INVALID_NOCHANGEPAGE; RefreshFrequenciesList(); BOOL bCanBePruned, bIsPruningReadOnly, bIsPruningOn; DeskInterface.lpfnGetPruningMode(DeskInterface.pContext, &bCanBePruned, &bIsPruningReadOnly, &bIsPruningOn); if(m_bIsPruningOn != bIsPruningOn) InitPruningMode(); } } FreeLibrary(hInst); } SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, lRet); } void CMonitorPage::OnCancel() { if (m_bCanBePruned && !m_bIsPruningReadOnly && ((m_bOnCancelIsPruningOn != 0) != (m_bIsPruningOn != 0))) DeskInterface.lpfnSetPruningMode(DeskInterface.pContext, m_bOnCancelIsPruningOn); DeskInterface.lpfnSetSelectedMode(DeskInterface.pContext, m_lpdmOnCancel); }; void CMonitorPage::OnInitDialog() { m_hMonitorsList = GetDlgItem(m_hDlg, IDC_MONITORS_LIST); HWND hSingleMonitor = GetDlgItem(m_hDlg, IDC_MONITORDESC); ListBox_ResetContent(m_hMonitorsList); // // Get the CPL extension interfaces from IDataObject. // STGMEDIUM stgmExt; FORMATETC fmteExt = {(CLIPFORMAT)RegisterClipboardFormat(DESKCPLEXT_INTERFACE), (DVTARGETDEVICE FAR *) NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; HRESULT hres = g_lpdoTarget->GetData(&fmteExt, &stgmExt); if (SUCCEEDED(hres) && stgmExt.hGlobal) { // // The storage now contains Display device path (\\.\DisplayX) in UNICODE. // PDESK_EXTENSION_INTERFACE pInterface = (PDESK_EXTENSION_INTERFACE) GlobalLock(stgmExt.hGlobal); RtlCopyMemory(&DeskInterface, pInterface, min(pInterface->cbSize, sizeof(DESK_EXTENSION_INTERFACE))); GlobalUnlock(stgmExt.hGlobal); ReleaseStgMedium(&stgmExt); } // // Get the adapter devnode. // The adapter is the parent of all monitors in the device tree. // DEVINST devInstAdapter; BOOL bDevInstAdapter = FALSE; STGMEDIUM stgmAdpId; FORMATETC fmteAdpId = {(CLIPFORMAT)RegisterClipboardFormat(DESKCPLEXT_DISPLAY_ID), (DVTARGETDEVICE FAR *) NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; hres = g_lpdoTarget->GetData(&fmteAdpId, &stgmAdpId); if(SUCCEEDED(hres) && stgmAdpId.hGlobal) { LPWSTR pwDeviceID = (LPWSTR) GlobalLock(stgmAdpId.hGlobal); bDevInstAdapter = (CM_Locate_DevNodeW(&devInstAdapter, pwDeviceID, 0) == CR_SUCCESS); GlobalUnlock(stgmAdpId.hGlobal); ReleaseStgMedium(&stgmAdpId); } // // Get the adapter device and enum all monitors // STGMEDIUM stgmAdpDev; FORMATETC fmteAdpDev = {(CLIPFORMAT)RegisterClipboardFormat(DESKCPLEXT_DISPLAY_DEVICE), (DVTARGETDEVICE FAR *) NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; hres = g_lpdoTarget->GetData(&fmteAdpDev, &stgmAdpDev); if (SUCCEEDED(hres) && stgmAdpDev.hGlobal) { LPWSTR pwDisplayDevice = (LPWSTR)GlobalLock(stgmAdpDev.hGlobal); LPTSTR pBuffer = pwDisplayDevice; if(NULL != pBuffer) { DISPLAY_DEVICE ddMon; BOOL bSuccess = FALSE; int cMonitors = 0; do { ZeroMemory(&ddMon, sizeof(ddMon)); ddMon.cb = sizeof(ddMon); bSuccess = EnumDisplayDevices(pBuffer, cMonitors, &ddMon, 0); if (bSuccess) { ++cMonitors; if (ddMon.StateFlags & DISPLAY_DEVICE_ATTACHED) { if(0 == m_cMonitors) SendDlgItemMessage(m_hDlg, IDC_MONITORDESC, WM_SETTEXT, 0, (LPARAM)ddMon.DeviceString); int nNewItem = ListBox_AddString(m_hMonitorsList, (LPTSTR)ddMon.DeviceString); if(nNewItem >= 0) { ++m_cMonitors; ListBox_SetItemData(m_hMonitorsList, nNewItem, NULL); if(bDevInstAdapter) SaveMonitorInstancePath(devInstAdapter, ddMon.DeviceID, nNewItem); } } } } while (bSuccess); } GlobalUnlock(stgmAdpDev.hGlobal); ReleaseStgMedium(&stgmAdpDev); } if(m_cMonitors <= 0) { TCHAR szDefaultMonitor[MAX_PATH]; LoadString(g_hInst, IDS_DEFAULT_MONITOR, szDefaultMonitor, ARRAYSIZE(szDefaultMonitor)); SendDlgItemMessage(m_hDlg, IDC_MONITORDESC, WM_SETTEXT, 0, (LPARAM)szDefaultMonitor); EnableWindow(GetDlgItem(m_hDlg, IDC_PROPERTIES), FALSE); } else if(m_cMonitors == 1) { BOOL bEnable = ((ListBox_GetCount(m_hMonitorsList) >= 1) && (NULL != (LPTSTR)ListBox_GetItemData(m_hMonitorsList, 0))); EnableWindow(GetDlgItem(m_hDlg, IDC_PROPERTIES), bEnable); } else { ListBox_SetCurSel(m_hMonitorsList, 0); OnSelMonitorChanged(); } ShowWindow(((m_cMonitors <= 1) ? m_hMonitorsList : hSingleMonitor), SW_HIDE); // // Init the pruning mode check box // InitPruningMode(); m_bOnCancelIsPruningOn = m_bIsPruningOn; // // Save the current mode - in case the user cancels the p. sheet // m_lpdmOnCancel = DeskInterface.lpfnGetSelectedMode(DeskInterface.pContext); } void CMonitorPage::OnDestroy() { int cMonitors = ListBox_GetCount(m_hMonitorsList); for(int nMonitor = 0; nMonitor < cMonitors; ++nMonitor) { LPTSTR pMonitorInstancePath = (LPTSTR)ListBox_GetItemData(m_hMonitorsList, nMonitor); if(NULL != pMonitorInstancePath) LocalFree(pMonitorInstancePath); } } void CMonitorPage::SaveMonitorInstancePath(DEVINST devInstAdapter, LPCTSTR pMonitorID, int nNewItem) { DEVINST devInstChild, devInstPrevChild; TCHAR szBuff[256]; // buffer used to concatenate: HARDWAREID, "\" and DRIVER // this is what EnumDisplayDevice returns in DeviceID in case of a monitor ULONG lenBuff; // size of the buffer, in bytes if (CM_Get_Child(&devInstChild, devInstAdapter, 0) != CR_SUCCESS) return; do { devInstPrevChild = devInstChild; //CM_DRP_HARDWAREID lenBuff = ARRAYSIZE(szBuff) - 2 ; // make sure we have place to append "\" if (CM_Get_DevNode_Registry_Property(devInstChild, CM_DRP_HARDWAREID, NULL, szBuff, &lenBuff, 0) != CR_SUCCESS) continue; // "\" StringCchCat(szBuff, ARRAYSIZE(szBuff), TEXT("\\")); //CM_DRP_DRIVER lenBuff = sizeof(szBuff) - lstrlen(szBuff) * sizeof(TCHAR); if (CM_Get_DevNode_Registry_Property(devInstChild, CM_DRP_DRIVER, NULL, szBuff + lstrlen(szBuff), &lenBuff, 0) != CR_SUCCESS) continue; if (lstrcmpi(szBuff, pMonitorID) == 0) { LPTSTR pMonitorInstancePath = (LPTSTR)LocalAlloc(LPTR, MAX_PATH * sizeof(TCHAR)); if((NULL != pMonitorInstancePath) && (CM_Get_Device_ID(devInstChild, pMonitorInstancePath, MAX_PATH, 0) == CR_SUCCESS)) ListBox_SetItemData(m_hMonitorsList, nNewItem, (LPARAM)pMonitorInstancePath); break; } } while(CM_Get_Sibling(&devInstChild, devInstPrevChild, 0) == CR_SUCCESS); } void CMonitorPage::OnSelMonitorChanged() { // // Enable / Disable the Properties button // BOOL bEnable = FALSE; if(ListBox_GetCount(m_hMonitorsList) >= 1) { int nCurSel = ListBox_GetCurSel(m_hMonitorsList); if(nCurSel >= 0) bEnable = (NULL != (LPTSTR)ListBox_GetItemData(m_hMonitorsList, nCurSel)); } EnableWindow(GetDlgItem(m_hDlg, IDC_PROPERTIES), bEnable); } void CMonitorPage::OnProperties() { int nSelMonitor; if(m_cMonitors <= 0) nSelMonitor = -1; else if(m_cMonitors == 1) nSelMonitor = ((ListBox_GetCount(m_hMonitorsList) >= 1) ? 0 : -1); else nSelMonitor = ListBox_GetCurSel(m_hMonitorsList); if(nSelMonitor < 0) return; LPTSTR pMonitorInstancePath = (LPTSTR)ListBox_GetItemData(m_hMonitorsList, nSelMonitor); if(NULL != pMonitorInstancePath) { HINSTANCE hinstDevMgr = LoadLibrary(TEXT("DEVMGR.DLL")); if (hinstDevMgr) { DEVPROPERTIES pfnDevProp = (DEVPROPERTIES)GetProcAddress(hinstDevMgr, "DevicePropertiesW"); if (pfnDevProp) { //Display the property sheets for this device. (*pfnDevProp)(m_hDlg, NULL, pMonitorInstancePath, FALSE); } FreeLibrary(hinstDevMgr); } } } BOOL CMonitorPage::OnSetActive() { LPDEVMODEW lpdm; DWORD item; LPDEVMODEW lpdmCurrent, lpdmPrevious; LPDEVMODEW lpdmTmp; DWORD i = 0; TCHAR achFre[50]; TCHAR achText[80]; DWORD pos; HWND hFreq; InitPruningMode(); // // Build the list of refresh rates for the currently selected mode. // lpdmCurrent = DeskInterface.lpfnGetSelectedMode(DeskInterface.pContext); hFreq = GetDlgItem(m_hDlg, IDC_MONSET_FREQ); if (lpdmCurrent == NULL) return -1; if (m_lpdmPrevious) { if (lpdmCurrent->dmBitsPerPel != m_lpdmPrevious->dmBitsPerPel || lpdmCurrent->dmPelsWidth != m_lpdmPrevious->dmPelsWidth || lpdmCurrent->dmPelsHeight != m_lpdmPrevious->dmPelsHeight) { ComboBox_ResetContent(hFreq); } } m_lpdmPrevious = lpdmCurrent; while (lpdm = DeskInterface.lpfnEnumAllModes(DeskInterface.pContext, i++)) { // // Only show refresh frequencies for current modes. // if ((lpdmCurrent->dmBitsPerPel != lpdm->dmBitsPerPel) || (lpdmCurrent->dmPelsWidth != lpdm->dmPelsWidth) || (lpdmCurrent->dmPelsHeight != lpdm->dmPelsHeight)) continue; // // convert bit count to number of colors and make it a string // // WARNING should this be 0 ? if (lpdm->dmDisplayFrequency == 1) { LoadString(g_hInst, IDS_DEFFREQ, achText, ARRAYSIZE(achText)); } else { DWORD idFreq = IDS_FREQ; if (lpdm->dmDisplayFrequency < 50) { idFreq = IDS_INTERLACED; } LoadString(g_hInst, idFreq, achFre, ARRAYSIZE(achFre)); StringCchPrintf(achText, ARRAYSIZE(achText), TEXT("%d %s"), lpdm->dmDisplayFrequency, achFre); } // // Insert the string in the right place // pos = 0; while (lpdmTmp = (LPDEVMODEW) ComboBox_GetItemData(hFreq, pos)) { if ((ULONG_PTR)lpdmTmp != CB_ERR) { if (lpdmTmp->dmDisplayFrequency == lpdm->dmDisplayFrequency) { break; } if (lpdmTmp->dmDisplayFrequency < lpdm->dmDisplayFrequency) { pos++; continue; } } // // Insert it here // item = ComboBox_InsertString(hFreq, pos, achText); ComboBox_SetItemData(hFreq, item, lpdm); break; } } // // Finally, set the right selection // pos = 0; while (lpdmTmp = (LPDEVMODEW) ComboBox_GetItemData(hFreq, pos)) { if ((ULONG_PTR)lpdmTmp == CB_ERR) { FmtMessageBox(m_hDlg, MB_OK | MB_ICONINFORMATION, IDS_BAD_REFRESH, IDS_BAD_REFRESH); return -1; } if (lpdmTmp->dmDisplayFrequency == lpdmCurrent->dmDisplayFrequency) { ComboBox_SetCurSel(hFreq, pos); break; } pos++; } return 0; } void CMonitorPage::OnFrequencyChanged() { DWORD item; HWND hFreq; LPDEVMODEW lpdmSelected = NULL, lpdmCurrent = NULL; // // Save the mode back // hFreq = GetDlgItem(m_hDlg, IDC_MONSET_FREQ); item = ComboBox_GetCurSel(hFreq); if (item == LB_ERR) return; lpdmCurrent = DeskInterface.lpfnGetSelectedMode(DeskInterface.pContext); lpdmSelected = (LPDEVMODEW) ComboBox_GetItemData(hFreq, item); if (lpdmSelected && (lpdmSelected != lpdmCurrent)) DeskInterface.lpfnSetSelectedMode(DeskInterface.pContext, lpdmSelected); } void CMonitorPage::OnPruningModeChanged() { if (m_bCanBePruned && !m_bIsPruningReadOnly) { BOOL bNewIsPruningOn = (BST_UNCHECKED != IsDlgButtonChecked(m_hDlg, IDC_MONSET_PRUNNING_MODE)); if((m_bIsPruningOn != 0) != bNewIsPruningOn) { m_bIsPruningOn = bNewIsPruningOn; DeskInterface.lpfnSetPruningMode(DeskInterface.pContext, m_bIsPruningOn); RefreshFrequenciesList(); } } } void CMonitorPage::InitPruningMode() { m_bCanBePruned = FALSE; m_bIsPruningReadOnly = TRUE; m_bIsPruningOn = FALSE; DeskInterface.lpfnGetPruningMode(DeskInterface.pContext, &m_bCanBePruned, &m_bIsPruningReadOnly, &m_bIsPruningOn); BOOL bEnable = (m_bCanBePruned && !m_bIsPruningReadOnly); EnableWindow(GetDlgItem(m_hDlg, IDC_MONSET_PRUNNING_MODE), bEnable); EnableWindow(GetDlgItem(m_hDlg, IDC_MONSET_PRUNNING_MODE_DESC), bEnable); BOOL bChecked = (m_bCanBePruned && m_bIsPruningOn); CheckDlgButton(m_hDlg, IDC_MONSET_PRUNNING_MODE, bChecked); } void CMonitorPage::RefreshFrequenciesList() { LPDEVMODEW lpdm; DWORD item; LPDEVMODEW lpdmCurrent, lpdmPrevious; LPDEVMODEW lpdmTmp; DWORD i = 0; TCHAR achFre[50]; TCHAR achText[80]; DWORD pos; HWND hFreq; HWND hwndCurr = GetFocus(); // // Build the list of refresh rates for the currently selected mode. // lpdmCurrent = DeskInterface.lpfnGetSelectedMode(DeskInterface.pContext); if (lpdmCurrent == NULL) return; hFreq = GetDlgItem(m_hDlg, IDC_MONSET_FREQ); ComboBox_ResetContent(hFreq); while (lpdm = DeskInterface.lpfnEnumAllModes(DeskInterface.pContext, i++)) { // // Only show refresh frequencies for current modes. // if ((lpdmCurrent->dmBitsPerPel != lpdm->dmBitsPerPel) || (lpdmCurrent->dmPelsWidth != lpdm->dmPelsWidth) || (lpdmCurrent->dmPelsHeight != lpdm->dmPelsHeight)) continue; // // convert bit count to number of colors and make it a string // // WARNING should this be 0 ? if (lpdm->dmDisplayFrequency == 1) { LoadString(g_hInst, IDS_DEFFREQ, achText, ARRAYSIZE(achText)); } else { DWORD idFreq = IDS_FREQ; if (lpdm->dmDisplayFrequency < 50) { idFreq = IDS_INTERLACED; } LoadString(g_hInst, idFreq, achFre, ARRAYSIZE(achFre)); StringCchPrintf(achText, ARRAYSIZE(achText), TEXT("%d %s"), lpdm->dmDisplayFrequency, achFre); } // // Insert the string in the right place // pos = 0; while (lpdmTmp = (LPDEVMODEW) ComboBox_GetItemData(hFreq, pos)) { if ((ULONG_PTR)lpdmTmp != CB_ERR) { if (lpdmTmp->dmDisplayFrequency == lpdm->dmDisplayFrequency) { break; } if (lpdmTmp->dmDisplayFrequency < lpdm->dmDisplayFrequency) { pos++; continue; } } // // Insert it here // item = ComboBox_InsertString(hFreq, pos, achText); ComboBox_SetItemData(hFreq, item, lpdm); break; } } // // Finally, set the right selection // pos = 0; while (lpdmTmp = (LPDEVMODEW) ComboBox_GetItemData(hFreq, pos)) { if ((ULONG_PTR)lpdmTmp == CB_ERR) { FmtMessageBox(m_hDlg, MB_OK | MB_ICONINFORMATION, IDS_BAD_REFRESH, IDS_BAD_REFRESH); break; } if (lpdmTmp->dmDisplayFrequency == lpdmCurrent->dmDisplayFrequency) { ComboBox_SetCurSel(hFreq, pos); break; } pos++; } if (hwndCurr) SetFocus(hwndCurr); return; } //--------------------------------------------------------------------------- // // PropertySheeDlgProc() // // The dialog procedure for the "Monitor" property sheet page. // //--------------------------------------------------------------------------- INT_PTR CALLBACK PropertySheeDlgProc( HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam ) { NMHDR FAR *lpnm; CMonitorPage * pMonitorPage = (CMonitorPage*)GetWindowLongPtr(hDlg, DWLP_USER); switch (uMessage) { case WM_INITDIALOG: if (!g_lpdoTarget) { return FALSE; } else { pMonitorPage = new CMonitorPage(hDlg); if(!pMonitorPage) return FALSE; SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)pMonitorPage); pMonitorPage->OnInitDialog(); } break; case WM_DESTROY: if (pMonitorPage) { pMonitorPage->OnDestroy(); SetWindowLongPtr(hDlg, DWLP_USER, NULL); delete pMonitorPage; } break; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_MONSET_FREQ: switch(GET_WM_COMMAND_CMD(wParam, lParam)) { case CBN_SELCHANGE: PropSheet_Changed(GetParent(hDlg), hDlg); if(pMonitorPage) pMonitorPage->OnFrequencyChanged(); break; default: break; } break; case IDC_PROPERTIES: if(pMonitorPage) pMonitorPage->OnProperties(); break; case IDC_MONSET_PRUNNING_MODE: PropSheet_Changed(GetParent(hDlg), hDlg); if(pMonitorPage) pMonitorPage->OnPruningModeChanged(); break; case IDC_MONITORS_LIST: switch(GET_WM_COMMAND_CMD(wParam, lParam)) { case LBN_SELCHANGE: if(pMonitorPage) pMonitorPage->OnSelMonitorChanged(); break; default: return FALSE; } break; default: return FALSE; } break; case WM_NOTIFY: switch (((NMHDR FAR *)lParam)->code) { case PSN_SETACTIVE: return (pMonitorPage && pMonitorPage->OnSetActive()); case PSN_APPLY: if(pMonitorPage) pMonitorPage->OnApply(); break; case PSN_RESET: if(pMonitorPage) pMonitorPage->OnCancel(); break; default: return FALSE; } break; case WM_HELP: WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, TEXT("display.hlp"), HELP_WM_HELP, (DWORD_PTR)(LPTSTR)sc_MonitorHelpIds); break; case WM_CONTEXTMENU: WinHelp((HWND)wParam, TEXT("display.hlp"), HELP_CONTEXTMENU, (DWORD_PTR)(LPTSTR)sc_MonitorHelpIds); break; default: return FALSE; } return TRUE; }