12 static HINSTANCE hInstance
;
13 static BOOL bFoundAdapter
;
14 static DEVINST diAdapter
;
17 typedef INT_PTR (WINAPI
*PDEVICEPROPERTIES
)(HWND
,LPCWSTR
,LPCWSTR
,BOOL
);
18 #define FUNC_DEVICEPROPERTIES "DevicePropertiesW"
20 typedef INT_PTR (WINAPI
*PDEVICEPROPERTIES
)(HWND
,LPCSTR
,LPCSTR
,BOOL
);
21 #define FUNC_DEVICEPROPERTIES "DevicePropertiesA"
26 * Converts a Hardware ID (DeviceID from EnumDisplayDevices)
27 * to an unique Device Instance ID.
29 * @param[in] lpDeviceID
30 * A pointer to a null-terminated string
31 * containing a Hardware ID concatenated with driver key.
32 * e.g. "Monitor\Default_Monitor\{4D36E96E-E325-11CE-BFC1-08002BE10318}\0000"
35 * A pointer to a null-terminated string
36 * containing an unique Device Instance ID
37 * or NULL in case of error.
38 * e.g. "DISPLAY\DEFAULT_MONITOR\4&2ABFAA30&0&00000001&00&02"
41 * The caller must free the returned string with LocalFree.
44 GetMonitorDevInstID(LPCTSTR lpDeviceID
)
48 TCHAR szProperty
[256];
50 LPTSTR lpDevInstId
= NULL
;
55 /* Look for child monitor devices of selected video adapter */
56 cr
= CM_Get_Child(&diChild
, diAdapter
, 0);
59 DPRINT1("CM_Get_Child failed: %d\n", cr
);
65 /* Get Hardware ID for each of them */
66 dwSize
= sizeof(szProperty
) - sizeof(TCHAR
);
68 cr
= CM_Get_DevNode_Registry_Property(diChild
,
76 DPRINT1("CM_Get_DevNode_Registry_Property failed: %d\n", cr
);
80 /* Concatenate with driver key */
81 _tcscat(szProperty
, TEXT("\\"));
82 dwSize
= sizeof(szProperty
) - sizeof(TCHAR
);
83 dwSize
-= _tcslen(szProperty
) * sizeof(TCHAR
);
85 cr
= CM_Get_DevNode_Registry_Property(diChild
,
88 szProperty
+ _tcslen(szProperty
),
93 DPRINT1("CM_Get_DevNode_Registry_Property failed: %d\n", cr
);
97 /* If the strings match, this is our monitor device node */
98 if (_tcscmp(szProperty
, lpDeviceID
) == 0)
100 cr
= CM_Get_Device_ID_Size(&dwSize
,
103 if (cr
!= CR_SUCCESS
)
105 DPRINT1("CM_Get_Device_ID_Size failed: %d\n", cr
);
109 lpDevInstId
= LocalAlloc(LMEM_FIXED
,
110 (dwSize
+ 1) * sizeof(TCHAR
));
111 if (lpDevInstId
== NULL
)
113 DPRINT1("LocalAlloc failed\n");
117 cr
= CM_Get_Device_ID(diChild
,
121 if (cr
!= CR_SUCCESS
)
123 DPRINT1("CM_Get_Device_ID failed: %d\n", cr
);
124 LocalFree((HLOCAL
)lpDevInstId
);
130 } while (CM_Get_Sibling(&diChild
, diChild
, 0) == CR_SUCCESS
);
136 ShowMonitorProperties(PDESKMONITOR This
)
139 PDEVICEPROPERTIES pDeviceProperties
;
142 if (This
->SelMonitor
!= NULL
)
144 lpDevInstID
= GetMonitorDevInstID(This
->SelMonitor
->dd
.DeviceID
);
145 if (lpDevInstID
!= NULL
)
147 hDevMgr
= LoadLibrary(TEXT("devmgr.dll"));
150 pDeviceProperties
= (PDEVICEPROPERTIES
)GetProcAddress(hDevMgr
,
151 FUNC_DEVICEPROPERTIES
);
152 if (pDeviceProperties
!= NULL
)
154 pDeviceProperties(This
->hwndDlg
,
160 FreeLibrary(hDevMgr
);
163 LocalFree((HLOCAL
)lpDevInstID
);
169 UpdateMonitorSelection(PDESKMONITOR This
)
172 LPTSTR lpDevInstID
= NULL
;
174 if (This
->dwMonitorCount
> 1)
176 This
->SelMonitor
= NULL
;
178 i
= (INT
)SendDlgItemMessage(This
->hwndDlg
,
185 This
->SelMonitor
= (PDESKMONINFO
)SendDlgItemMessage(This
->hwndDlg
,
193 This
->SelMonitor
= This
->Monitors
;
195 if (This
->SelMonitor
!= NULL
)
196 lpDevInstID
= GetMonitorDevInstID(This
->SelMonitor
->dd
.DeviceID
);
198 EnableWindow(GetDlgItem(This
->hwndDlg
,
199 IDC_MONITORPROPERTIES
),
200 lpDevInstID
!= NULL
&& lpDevInstID
[0] != TEXT('\0'));
202 if (lpDevInstID
!= NULL
)
203 LocalFree((HLOCAL
)lpDevInstID
);
207 UpdatePruningControls(PDESKMONITOR This
)
209 EnableWindow(GetDlgItem(This
->hwndDlg
,
211 This
->bModesPruned
&& !This
->bKeyIsReadOnly
);
212 CheckDlgButton(This
->hwndDlg
,
214 (This
->bModesPruned
&& This
->bPruningOn
) ? BST_CHECKED
: BST_UNCHECKED
);
218 GetPruningSettings(PDESKMONITOR This
)
220 BOOL bModesPruned
= FALSE
, bKeyIsReadOnly
= FALSE
, bPruningOn
= FALSE
;
222 if (This
->DeskExtInterface
!= NULL
)
224 This
->DeskExtInterface
->GetPruningMode(This
->DeskExtInterface
->Context
,
230 /* Check the boolean values against zero before assigning it to the bitfields! */
231 This
->bModesPruned
= (bModesPruned
!= FALSE
);
232 This
->bKeyIsReadOnly
= (bKeyIsReadOnly
!= FALSE
);
233 This
->bPruningOn
= (bPruningOn
!= FALSE
);
235 UpdatePruningControls(This
);
239 UpdateRefreshFrequencyList(PDESKMONITOR This
)
241 PDEVMODEW lpCurrentMode
, lpMode
;
245 BOOL bHasDef
= FALSE
;
248 /* Fill the refresh rate combo box */
249 SendDlgItemMessage(This
->hwndDlg
,
255 lpCurrentMode
= This
->DeskExtInterface
->GetCurrentMode(This
->DeskExtInterface
->Context
);
260 lpMode
= This
->DeskExtInterface
->EnumAllModes(This
->DeskExtInterface
->Context
,
262 if (lpMode
!= NULL
&&
263 lpMode
->dmBitsPerPel
== lpCurrentMode
->dmBitsPerPel
&&
264 lpMode
->dmPelsWidth
== lpCurrentMode
->dmPelsWidth
&&
265 lpMode
->dmPelsHeight
== lpCurrentMode
->dmPelsHeight
)
267 /* We're only interested in refresh rates for the current resolution and color depth */
269 if (lpMode
->dmDisplayFrequency
<= 1)
271 /* Default hardware frequency */
277 if (!LoadString(hInstance
,
280 sizeof(szBuffer
) / sizeof(szBuffer
[0])))
282 szBuffer
[0] = TEXT('\0');
289 if (!LoadString(hInstance
,
292 sizeof(szFmt
) / sizeof(szFmt
[0])))
294 szFmt
[0] = TEXT('\0');
298 sizeof(szBuffer
) / sizeof(szBuffer
[0]),
300 lpMode
->dmDisplayFrequency
);
303 i
= (INT
)SendDlgItemMessage(This
->hwndDlg
,
312 SendDlgItemMessage(This
->hwndDlg
,
318 if (lpMode
->dmDisplayFrequency
== lpCurrentMode
->dmDisplayFrequency
)
320 SendDlgItemMessage(This
->hwndDlg
,
329 } while (lpMode
!= NULL
);
331 EnableWindow(GetDlgItem(This
->hwndDlg
,
332 IDS_MONITORSETTINGSGROUP
),
334 EnableWindow(GetDlgItem(This
->hwndDlg
,
335 IDS_REFRESHRATELABEL
),
337 EnableWindow(GetDlgItem(This
->hwndDlg
,
341 GetPruningSettings(This
);
345 InitMonitorDialog(PDESKMONITOR This
)
347 PDESKMONINFO pmi
, pminext
, *pmilink
;
355 /* Free all allocated monitors */
356 pmi
= This
->Monitors
;
357 This
->Monitors
= NULL
;
361 LocalFree((HLOCAL
)pmi
);
365 This
->SelMonitor
= NULL
;
366 This
->dwMonitorCount
= 0;
368 bFoundAdapter
= FALSE
;
369 lpDeviceId
= QueryDeskCplString(This
->pdtobj
,
370 RegisterClipboardFormat(DESK_EXT_DISPLAYID
));
372 if (lpDeviceId
!= NULL
&& lpDeviceId
[0] != TEXT('\0'))
374 cr
= CM_Locate_DevNode(&diAdapter
,
376 CM_LOCATE_DEVNODE_NORMAL
);
377 bFoundAdapter
= (cr
== CR_SUCCESS
);
380 DPRINT1("CM_Locate_DevNode failed: %d\n", cr
);
383 if (This
->lpDisplayDevice
!= NULL
)
384 LocalFree((HLOCAL
)This
->lpDisplayDevice
);
386 This
->lpDisplayDevice
= QueryDeskCplString(This
->pdtobj
,
387 RegisterClipboardFormat(DESK_EXT_DISPLAYDEVICE
));
389 if (This
->DeskExtInterface
!= NULL
)
391 if (This
->lpDisplayDevice
!= NULL
)
393 /* Enumerate all monitors */
395 pmilink
= &This
->Monitors
;
400 bRet
= EnumDisplayDevices(This
->lpDisplayDevice
,
406 pmi
= LocalAlloc(LMEM_FIXED
,
415 pmilink
= &pmi
->Next
;
417 This
->dwMonitorCount
++;
423 This
->lpDevModeOnInit
= This
->DeskExtInterface
->GetCurrentMode(This
->DeskExtInterface
->Context
);
426 This
->lpDevModeOnInit
= NULL
;
428 This
->lpSelDevMode
= This
->lpDevModeOnInit
;
430 /* Setup the UI depending on how many monitors are attached */
431 if (This
->dwMonitorCount
== 0)
433 LPTSTR lpMonitorName
;
435 /* This is a fallback, let's hope that desk.cpl can provide us with a monitor name */
436 lpMonitorName
= QueryDeskCplString(This
->pdtobj
,
437 RegisterClipboardFormat(DESK_EXT_MONITORNAME
));
439 SetDlgItemText(This
->hwndDlg
,
443 if (lpMonitorName
!= NULL
)
444 LocalFree((HLOCAL
)lpMonitorName
);
446 else if (This
->dwMonitorCount
== 1)
448 This
->SelMonitor
= This
->Monitors
;
449 SetDlgItemText(This
->hwndDlg
,
451 This
->Monitors
->dd
.DeviceString
);
455 SendDlgItemMessage(This
->hwndDlg
,
461 pmi
= This
->Monitors
;
464 i
= (INT
)SendDlgItemMessage(This
->hwndDlg
,
468 (LPARAM
)pmi
->dd
.DeviceString
);
471 SendDlgItemMessage(This
->hwndDlg
,
477 if (This
->SelMonitor
== NULL
)
479 SendDlgItemMessage(This
->hwndDlg
,
485 This
->SelMonitor
= pmi
;
493 /* Show/Hide controls */
494 ShowWindow(GetDlgItem(This
->hwndDlg
,
496 (This
->dwMonitorCount
<= 1 ? SW_SHOW
: SW_HIDE
));
497 ShowWindow(GetDlgItem(This
->hwndDlg
,
499 (This
->dwMonitorCount
> 1 ? SW_SHOW
: SW_HIDE
));
501 UpdateRefreshFrequencyList(This
);
502 UpdateMonitorSelection(This
);
506 UpdatePruningSelection(PDESKMONITOR This
)
510 if (This
->DeskExtInterface
!= NULL
&& This
->bModesPruned
&& !This
->bKeyIsReadOnly
)
512 bPruningOn
= IsDlgButtonChecked(This
->hwndDlg
,
513 IDC_PRUNINGCHECK
) != BST_UNCHECKED
;
515 if (bPruningOn
!= This
->bPruningOn
)
517 /* Tell desk.cpl to turn on/off pruning mode */
518 This
->bPruningOn
= bPruningOn
;
519 This
->DeskExtInterface
->SetPruningMode(This
->DeskExtInterface
->Context
,
522 /* Fill the refresh rate combobox again, we now receive a filtered
523 or unfiltered device mode list from desk.cpl (depending on whether
524 pruning is active or not) */
525 UpdateRefreshFrequencyList(This
);
527 (void)PropSheet_Changed(GetParent(This
->hwndDlg
),
534 UpdateRefreshRateSelection(PDESKMONITOR This
)
536 PDEVMODEW lpCurrentDevMode
;
539 if (This
->DeskExtInterface
!= NULL
)
541 i
= (INT
)SendDlgItemMessage(This
->hwndDlg
,
548 lpCurrentDevMode
= This
->lpSelDevMode
;
549 This
->lpSelDevMode
= (PDEVMODEW
)SendDlgItemMessage(This
->hwndDlg
,
555 if (This
->lpSelDevMode
!= NULL
&& This
->lpSelDevMode
!= lpCurrentDevMode
)
557 This
->DeskExtInterface
->SetCurrentMode(This
->DeskExtInterface
->Context
,
560 UpdateRefreshFrequencyList(This
);
562 (void)PropSheet_Changed(GetParent(This
->hwndDlg
),
570 ApplyMonitorChanges(PDESKMONITOR This
)
574 if (This
->DeskExtInterface
!= NULL
)
576 /* Change the display settings through desk.cpl */
577 lChangeRet
= DeskCplExtDisplaySaveSettings(This
->DeskExtInterface
,
579 if (lChangeRet
== DISP_CHANGE_SUCCESSFUL
)
581 /* Save the new mode */
582 This
->lpDevModeOnInit
= This
->DeskExtInterface
->GetCurrentMode(This
->DeskExtInterface
->Context
);
583 This
->lpSelDevMode
= This
->lpDevModeOnInit
;
584 return PSNRET_NOERROR
;
586 else if (lChangeRet
== DISP_CHANGE_RESTART
)
588 /* Notify desk.cpl that the user needs to reboot */
589 PropSheet_RestartWindows(GetParent(This
->hwndDlg
));
590 return PSNRET_NOERROR
;
594 InitMonitorDialog(This
);
596 return PSNRET_INVALID_NOCHANGEPAGE
;
600 ResetMonitorChanges(PDESKMONITOR This
)
602 if (This
->DeskExtInterface
!= NULL
&& This
->lpDevModeOnInit
!= NULL
)
604 This
->DeskExtInterface
->SetCurrentMode(This
->DeskExtInterface
->Context
,
605 This
->lpDevModeOnInit
);
609 static INT_PTR CALLBACK
610 MonitorDlgProc(HWND hwndDlg
,
618 if (uMsg
!= WM_INITDIALOG
)
620 This
= (PDESKMONITOR
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
626 This
= (PDESKMONITOR
)((LPCPROPSHEETPAGE
)lParam
)->lParam
;
627 This
->hwndDlg
= hwndDlg
;
628 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)This
);
630 InitMonitorDialog(This
);
635 switch (LOWORD(wParam
))
637 case IDC_MONITORPROPERTIES
:
638 ShowMonitorProperties(This
);
641 case IDC_MONITORLIST
:
642 if (HIWORD(wParam
) == LBN_SELCHANGE
)
643 UpdateMonitorSelection(This
);
646 case IDC_PRUNINGCHECK
:
647 if (HIWORD(wParam
) == BN_CLICKED
)
648 UpdatePruningSelection(This
);
651 case IDC_REFRESHRATE
:
652 if (HIWORD(wParam
) == CBN_SELCHANGE
)
653 UpdateRefreshRateSelection(This
);
660 NMHDR
*nmh
= (NMHDR
*)lParam
;
666 SetWindowLongPtr(hwndDlg
,
668 ApplyMonitorChanges(This
));
674 ResetMonitorChanges(This
);
678 UpdateRefreshFrequencyList(This
);
689 IDeskMonitor_Destroy(PDESKMONITOR This
)
691 PDESKMONINFO pmi
, pminext
;
693 if (This
->pdtobj
!= NULL
)
695 IDataObject_Release(This
->pdtobj
);
699 if (This
->DeskExtInterface
!= NULL
)
701 LocalFree((HLOCAL
)This
->DeskExtInterface
);
702 This
->DeskExtInterface
= NULL
;
705 if (This
->lpDisplayDevice
!= NULL
)
707 LocalFree((HLOCAL
)This
->lpDisplayDevice
);
708 This
->lpDisplayDevice
= NULL
;
711 /* Free all monitors */
712 pmi
= This
->Monitors
;
713 This
->Monitors
= NULL
;
717 LocalFree((HLOCAL
)pmi
);
723 IDeskMonitor_AddRef(PDESKMONITOR This
)
727 ret
= InterlockedIncrement((PLONG
)&This
->ref
);
729 InterlockedIncrement(&dll_refs
);
735 IDeskMonitor_Release(PDESKMONITOR This
)
739 ret
= InterlockedDecrement((PLONG
)&This
->ref
);
742 IDeskMonitor_Destroy(This
);
743 InterlockedDecrement(&dll_refs
);
745 HeapFree(GetProcessHeap(),
753 HRESULT STDMETHODCALLTYPE
754 IDeskMonitor_QueryInterface(PDESKMONITOR This
,
761 &IID_IShellPropSheetExt
) ||
765 *pvObject
= impl_to_interface(This
, IShellPropSheetExt
);
767 else if (IsEqualIID(iid
,
770 *pvObject
= impl_to_interface(This
, IShellExtInit
);
772 else if (IsEqualIID(iid
,
775 *pvObject
= impl_to_interface(This
, IClassFactory
);
779 DPRINT1("IDeskMonitor::QueryInterface(%p,%p): E_NOINTERFACE\n", iid
, pvObject
);
780 return E_NOINTERFACE
;
783 IDeskMonitor_AddRef(This
);
788 IDeskMonitor_Initialize(PDESKMONITOR This
,
789 LPCITEMIDLIST pidlFolder
,
793 DPRINT1("IDeskMonitor::Initialize(%p,%p,%p)\n", pidlFolder
, pdtobj
, hkeyProgID
);
797 IDataObject_AddRef(pdtobj
);
798 This
->pdtobj
= pdtobj
;
800 /* Get a copy of the desk.cpl extension interface */
801 This
->DeskExtInterface
= QueryDeskCplExtInterface(This
->pdtobj
);
802 if (This
->DeskExtInterface
!= NULL
)
810 IDeskMonitor_AddPages(PDESKMONITOR This
,
811 LPFNADDPROPSHEETPAGE pfnAddPage
,
817 DPRINT1("IDeskMonitor::AddPages(%p,%p)\n", pfnAddPage
, lParam
);
819 psp
.dwSize
= sizeof(psp
);
820 psp
.dwFlags
= PSP_DEFAULT
;
821 psp
.hInstance
= hInstance
;
822 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_MONITOR
);
823 psp
.pfnDlgProc
= MonitorDlgProc
;
824 psp
.lParam
= (LPARAM
)This
;
826 hpsp
= CreatePropertySheetPage(&psp
);
827 if (hpsp
!= NULL
&& pfnAddPage(hpsp
, lParam
))
834 IDeskMonitor_ReplacePage(PDESKMONITOR This
,
836 LPFNADDPROPSHEETPAGE pfnReplacePage
,
839 DPRINT1("IDeskMonitor::ReplacePage(%u,%p,%p)\n", uPageID
, pfnReplacePage
, lParam
);
844 IDeskMonitor_Constructor(REFIID riid
,
848 HRESULT hRet
= E_OUTOFMEMORY
;
850 DPRINT1("IDeskMonitor::Constructor(%p,%p)\n", riid
, ppv
);
852 This
= HeapAlloc(GetProcessHeap(),
860 IDeskMonitor_InitIface(This
);
862 hRet
= IDeskMonitor_QueryInterface(This
,
865 if (!SUCCEEDED(hRet
))
866 IDeskMonitor_Release(This
);
873 DllMain(HINSTANCE hinstDLL
,
879 case DLL_PROCESS_ATTACH
:
880 hInstance
= hinstDLL
;
881 DisableThreadLibraryCalls(hInstance
);