[PSDK][REACTOS] Fix definitions and usage of DWLP_MSGRESULT, DWLP_DLGPROC, and DWLP_USER
[reactos.git] / dll / shellext / deskmon / deskmon.c
1 #include "precomp.h"
2
3 #include <tchar.h>
4
5 #define NDEBUG
6 #include <debug.h>
7
8 #include "resource.h"
9
10 static HINSTANCE hInstance;
11
12 #ifdef UNICODE
13 typedef INT_PTR (WINAPI *PDEVICEPROPERTIES)(HWND,LPCWSTR,LPCWSTR,BOOL);
14 #define FUNC_DEVICEPROPERTIES "DevicePropertiesW"
15 #else
16 typedef INT_PTR (WINAPI *PDEVICEPROPERTIES)(HWND,LPCSTR,LPCSTR,BOOL);
17 #define FUNC_DEVICEPROPERTIES "DevicePropertiesA"
18 #endif
19
20 static LPTSTR
21 GetMonitorDevInstID(LPCTSTR lpDeviceID)
22 {
23 /* FIXME: Implement, allocate returned string with LocalAlloc! */
24 return NULL;
25 }
26
27 static VOID
28 ShowMonitorProperties(PDESKMONITOR This)
29 {
30 HMODULE hDevMgr;
31 PDEVICEPROPERTIES pDeviceProperties;
32 LPTSTR lpDevInstID;
33
34 if (This->SelMonitor != NULL)
35 {
36 lpDevInstID = GetMonitorDevInstID(This->SelMonitor->dd.DeviceID);
37 if (lpDevInstID != NULL)
38 {
39 hDevMgr = LoadLibrary(TEXT("devmgr.dll"));
40 if (hDevMgr != NULL)
41 {
42 pDeviceProperties = (PDEVICEPROPERTIES)GetProcAddress(hDevMgr,
43 FUNC_DEVICEPROPERTIES);
44 if (pDeviceProperties != NULL)
45 {
46 pDeviceProperties(This->hwndDlg,
47 NULL,
48 This->SelMonitor->dd.DeviceID,
49 FALSE);
50 }
51
52 FreeLibrary(hDevMgr);
53 }
54
55 LocalFree((HLOCAL)lpDevInstID);
56 }
57 }
58 }
59
60 static VOID
61 UpdateMonitorSelection(PDESKMONITOR This)
62 {
63 INT i;
64
65 if (This->dwMonitorCount > 1)
66 {
67 This->SelMonitor = NULL;
68
69 i = (INT)SendDlgItemMessage(This->hwndDlg,
70 IDC_MONITORLIST,
71 LB_GETCURSEL,
72 0,
73 0);
74 if (i >= 0)
75 {
76 This->SelMonitor = (PDESKMONINFO)SendDlgItemMessage(This->hwndDlg,
77 IDC_MONITORLIST,
78 LB_GETITEMDATA,
79 (WPARAM)i,
80 0);
81 }
82 }
83 else
84 This->SelMonitor = This->Monitors;
85
86 EnableWindow(GetDlgItem(This->hwndDlg,
87 IDC_MONITORPROPERTIES),
88 This->SelMonitor != NULL);
89 }
90
91 static VOID
92 UpdatePruningControls(PDESKMONITOR This)
93 {
94 EnableWindow(GetDlgItem(This->hwndDlg,
95 IDC_PRUNINGCHECK),
96 This->bModesPruned && !This->bKeyIsReadOnly);
97 CheckDlgButton(This->hwndDlg,
98 IDC_PRUNINGCHECK,
99 (This->bModesPruned && This->bPruningOn) ? BST_CHECKED : BST_UNCHECKED);
100 }
101
102 static VOID
103 GetPruningSettings(PDESKMONITOR This)
104 {
105 BOOL bModesPruned = FALSE, bKeyIsReadOnly = FALSE, bPruningOn = FALSE;
106
107 if (This->DeskExtInterface != NULL)
108 {
109 This->DeskExtInterface->GetPruningMode(This->DeskExtInterface->Context,
110 &bModesPruned,
111 &bKeyIsReadOnly,
112 &bPruningOn);
113 }
114
115 /* Check the boolean values against zero before assigning it to the bitfields! */
116 This->bModesPruned = (bModesPruned != FALSE);
117 This->bKeyIsReadOnly = (bKeyIsReadOnly != FALSE);
118 This->bPruningOn = (bPruningOn != FALSE);
119
120 UpdatePruningControls(This);
121 }
122
123 static VOID
124 UpdateRefreshFrequencyList(PDESKMONITOR This)
125 {
126 PDEVMODEW lpCurrentMode, lpMode;
127 TCHAR szBuffer[64];
128 DWORD dwIndex;
129 INT i;
130 BOOL bHasDef = FALSE;
131 BOOL bAdded = FALSE;
132
133 /* Fill the refresh rate combo box */
134 SendDlgItemMessage(This->hwndDlg,
135 IDC_REFRESHRATE,
136 CB_RESETCONTENT,
137 0,
138 0);
139
140 lpCurrentMode = This->DeskExtInterface->GetCurrentMode(This->DeskExtInterface->Context);
141 dwIndex = 0;
142
143 do
144 {
145 lpMode = This->DeskExtInterface->EnumAllModes(This->DeskExtInterface->Context,
146 dwIndex++);
147 if (lpMode != NULL &&
148 lpMode->dmBitsPerPel == lpCurrentMode->dmBitsPerPel &&
149 lpMode->dmPelsWidth == lpCurrentMode->dmPelsWidth &&
150 lpMode->dmPelsHeight == lpCurrentMode->dmPelsHeight)
151 {
152 /* We're only interested in refresh rates for the current resolution and color depth */
153
154 if (lpMode->dmDisplayFrequency <= 1)
155 {
156 /* Default hardware frequency */
157 if (bHasDef)
158 continue;
159
160 bHasDef = TRUE;
161
162 if (!LoadString(hInstance,
163 IDS_USEDEFFRQUENCY,
164 szBuffer,
165 sizeof(szBuffer) / sizeof(szBuffer[0])))
166 {
167 szBuffer[0] = TEXT('\0');
168 }
169 }
170 else
171 {
172 TCHAR szFmt[64];
173
174 if (!LoadString(hInstance,
175 IDS_FREQFMT,
176 szFmt,
177 sizeof(szFmt) / sizeof(szFmt[0])))
178 {
179 szFmt[0] = TEXT('\0');
180 }
181
182 _sntprintf(szBuffer,
183 sizeof(szBuffer) / sizeof(szBuffer[0]),
184 szFmt,
185 lpMode->dmDisplayFrequency);
186 }
187
188 i = (INT)SendDlgItemMessage(This->hwndDlg,
189 IDC_REFRESHRATE,
190 CB_ADDSTRING,
191 0,
192 (LPARAM)szBuffer);
193 if (i >= 0)
194 {
195 bAdded = TRUE;
196
197 SendDlgItemMessage(This->hwndDlg,
198 IDC_REFRESHRATE,
199 CB_SETITEMDATA,
200 (WPARAM)i,
201 (LPARAM)lpMode);
202
203 if (lpMode->dmDisplayFrequency == lpCurrentMode->dmDisplayFrequency)
204 {
205 SendDlgItemMessage(This->hwndDlg,
206 IDC_REFRESHRATE,
207 CB_SETCURSEL,
208 (WPARAM)i,
209 0);
210 }
211 }
212 }
213
214 } while (lpMode != NULL);
215
216 EnableWindow(GetDlgItem(This->hwndDlg,
217 IDS_MONITORSETTINGSGROUP),
218 bAdded);
219 EnableWindow(GetDlgItem(This->hwndDlg,
220 IDS_REFRESHRATELABEL),
221 bAdded);
222 EnableWindow(GetDlgItem(This->hwndDlg,
223 IDC_REFRESHRATE),
224 bAdded);
225
226 GetPruningSettings(This);
227 }
228
229 static VOID
230 InitMonitorDialog(PDESKMONITOR This)
231 {
232 PDESKMONINFO pmi, pminext, *pmilink;
233 DISPLAY_DEVICE dd;
234 BOOL bRet;
235 INT i;
236 DWORD dwIndex;
237
238 /* Free all allocated monitors */
239 pmi = This->Monitors;
240 This->Monitors = NULL;
241 while (pmi != NULL)
242 {
243 pminext = pmi->Next;
244 LocalFree((HLOCAL)pmi);
245 pmi = pminext;
246 }
247
248 This->SelMonitor = NULL;
249 This->dwMonitorCount = 0;
250
251 if (This->lpDisplayDevice != NULL)
252 LocalFree((HLOCAL)This->lpDisplayDevice);
253
254 This->lpDisplayDevice = QueryDeskCplString(This->pdtobj,
255 RegisterClipboardFormat(DESK_EXT_DISPLAYDEVICE));
256
257 if (This->DeskExtInterface != NULL)
258 {
259 if (This->lpDisplayDevice != NULL)
260 {
261 /* Enumerate all monitors */
262 dwIndex = 0;
263 pmilink = &This->Monitors;
264
265 do
266 {
267 dd.cb = sizeof(dd);
268 bRet = EnumDisplayDevices(This->lpDisplayDevice,
269 dwIndex++,
270 &dd,
271 0);
272 if (bRet)
273 {
274 pmi = LocalAlloc(LMEM_FIXED,
275 sizeof(*pmi));
276 if (pmi != NULL)
277 {
278 CopyMemory(&pmi->dd,
279 &dd,
280 sizeof(dd));
281 pmi->Next = NULL;
282 *pmilink = pmi;
283 pmilink = &pmi->Next;
284
285 This->dwMonitorCount++;
286 }
287 }
288 } while (bRet);
289 }
290
291 This->lpDevModeOnInit = This->DeskExtInterface->GetCurrentMode(This->DeskExtInterface->Context);
292 }
293 else
294 This->lpDevModeOnInit = NULL;
295
296 This->lpSelDevMode = This->lpDevModeOnInit;
297
298 /* Setup the UI depending on how many monitors are attached */
299 if (This->dwMonitorCount == 0)
300 {
301 LPTSTR lpMonitorName;
302
303 /* This is a fallback, let's hope that desk.cpl can provide us with a monitor name */
304 lpMonitorName = QueryDeskCplString(This->pdtobj,
305 RegisterClipboardFormat(DESK_EXT_MONITORNAME));
306
307 SetDlgItemText(This->hwndDlg,
308 IDC_MONITORNAME,
309 lpMonitorName);
310
311 if (lpMonitorName != NULL)
312 LocalFree((HLOCAL)lpMonitorName);
313 }
314 else if (This->dwMonitorCount == 1)
315 {
316 This->SelMonitor = This->Monitors;
317 SetDlgItemText(This->hwndDlg,
318 IDC_MONITORNAME,
319 This->Monitors->dd.DeviceString);
320 }
321 else
322 {
323 SendDlgItemMessage(This->hwndDlg,
324 IDC_MONITORLIST,
325 LB_RESETCONTENT,
326 0,
327 0);
328
329 pmi = This->Monitors;
330 while (pmi != NULL)
331 {
332 i = (INT)SendDlgItemMessage(This->hwndDlg,
333 IDC_MONITORLIST,
334 LB_ADDSTRING,
335 0,
336 (LPARAM)pmi->dd.DeviceString);
337 if (i >= 0)
338 {
339 SendDlgItemMessage(This->hwndDlg,
340 IDC_MONITORLIST,
341 LB_SETITEMDATA,
342 (WPARAM)i,
343 (LPARAM)pmi);
344
345 if (This->SelMonitor == NULL)
346 {
347 SendDlgItemMessage(This->hwndDlg,
348 IDC_MONITORLIST,
349 LB_SETCURSEL,
350 (WPARAM)i,
351 0);
352
353 This->SelMonitor = pmi;
354 }
355 }
356
357 pmi = pmi->Next;
358 }
359 }
360
361 /* Show/Hide controls */
362 ShowWindow(GetDlgItem(This->hwndDlg,
363 IDC_MONITORNAME),
364 (This->dwMonitorCount <= 1 ? SW_SHOW : SW_HIDE));
365 ShowWindow(GetDlgItem(This->hwndDlg,
366 IDC_MONITORLIST),
367 (This->dwMonitorCount > 1 ? SW_SHOW : SW_HIDE));
368
369 UpdateRefreshFrequencyList(This);
370 UpdateMonitorSelection(This);
371 }
372
373 static VOID
374 UpdatePruningSelection(PDESKMONITOR This)
375 {
376 BOOL bPruningOn;
377
378 if (This->DeskExtInterface != NULL && This->bModesPruned && !This->bKeyIsReadOnly)
379 {
380 bPruningOn = IsDlgButtonChecked(This->hwndDlg,
381 IDC_PRUNINGCHECK) != BST_UNCHECKED;
382
383 if (bPruningOn != This->bPruningOn)
384 {
385 /* Tell desk.cpl to turn on/off pruning mode */
386 This->bPruningOn = bPruningOn;
387 This->DeskExtInterface->SetPruningMode(This->DeskExtInterface->Context,
388 bPruningOn);
389
390 /* Fill the refresh rate combobox again, we now receive a filtered
391 or unfiltered device mode list from desk.cpl (depending on whether
392 pruning is active or not) */
393 UpdateRefreshFrequencyList(This);
394
395 (void)PropSheet_Changed(GetParent(This->hwndDlg),
396 This->hwndDlg);
397 }
398 }
399 }
400
401 static VOID
402 UpdateRefreshRateSelection(PDESKMONITOR This)
403 {
404 PDEVMODEW lpCurrentDevMode;
405 INT i;
406
407 if (This->DeskExtInterface != NULL)
408 {
409 i = (INT)SendDlgItemMessage(This->hwndDlg,
410 IDC_REFRESHRATE,
411 CB_GETCURSEL,
412 0,
413 0);
414 if (i >= 0)
415 {
416 lpCurrentDevMode = This->lpSelDevMode;
417 This->lpSelDevMode = (PDEVMODEW)SendDlgItemMessage(This->hwndDlg,
418 IDC_REFRESHRATE,
419 CB_GETITEMDATA,
420 (WPARAM)i,
421 0);
422
423 if (This->lpSelDevMode != NULL && This->lpSelDevMode != lpCurrentDevMode)
424 {
425 This->DeskExtInterface->SetCurrentMode(This->DeskExtInterface->Context,
426 This->lpSelDevMode);
427
428 UpdateRefreshFrequencyList(This);
429
430 (void)PropSheet_Changed(GetParent(This->hwndDlg),
431 This->hwndDlg);
432 }
433 }
434 }
435 }
436
437 static LONG
438 ApplyMonitorChanges(PDESKMONITOR This)
439 {
440 LONG lChangeRet;
441
442 if (This->DeskExtInterface != NULL)
443 {
444 /* Change the display settings through desk.cpl */
445 lChangeRet = DeskCplExtDisplaySaveSettings(This->DeskExtInterface,
446 This->hwndDlg);
447 if (lChangeRet == DISP_CHANGE_SUCCESSFUL)
448 {
449 /* Save the new mode */
450 This->lpDevModeOnInit = This->DeskExtInterface->GetCurrentMode(This->DeskExtInterface->Context);
451 This->lpSelDevMode = This->lpDevModeOnInit;
452 return PSNRET_NOERROR;
453 }
454 else if (lChangeRet == DISP_CHANGE_RESTART)
455 {
456 /* Notify desk.cpl that the user needs to reboot */
457 PropSheet_RestartWindows(GetParent(This->hwndDlg));
458 return PSNRET_NOERROR;
459 }
460 }
461
462 InitMonitorDialog(This);
463
464 return PSNRET_INVALID_NOCHANGEPAGE;
465 }
466
467 static VOID
468 ResetMonitorChanges(PDESKMONITOR This)
469 {
470 if (This->DeskExtInterface != NULL && This->lpDevModeOnInit != NULL)
471 {
472 This->DeskExtInterface->SetCurrentMode(This->DeskExtInterface->Context,
473 This->lpDevModeOnInit);
474 }
475 }
476
477 static INT_PTR CALLBACK
478 MonitorDlgProc(HWND hwndDlg,
479 UINT uMsg,
480 WPARAM wParam,
481 LPARAM lParam)
482 {
483 PDESKMONITOR This;
484 INT_PTR Ret = 0;
485
486 if (uMsg != WM_INITDIALOG)
487 {
488 This = (PDESKMONITOR)GetWindowLongPtr(hwndDlg, DWLP_USER);
489 }
490
491 switch (uMsg)
492 {
493 case WM_INITDIALOG:
494 This = (PDESKMONITOR)((LPCPROPSHEETPAGE)lParam)->lParam;
495 This->hwndDlg = hwndDlg;
496 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)This);
497
498 InitMonitorDialog(This);
499 Ret = TRUE;
500 break;
501
502 case WM_COMMAND:
503 switch (LOWORD(wParam))
504 {
505 case IDC_MONITORPROPERTIES:
506 ShowMonitorProperties(This);
507 break;
508
509 case IDC_MONITORLIST:
510 if (HIWORD(wParam) == LBN_SELCHANGE)
511 UpdateMonitorSelection(This);
512 break;
513
514 case IDC_PRUNINGCHECK:
515 if (HIWORD(wParam) == BN_CLICKED)
516 UpdatePruningSelection(This);
517 break;
518
519 case IDC_REFRESHRATE:
520 if (HIWORD(wParam) == CBN_SELCHANGE)
521 UpdateRefreshRateSelection(This);
522 break;
523 }
524 break;
525
526 case WM_NOTIFY:
527 {
528 NMHDR *nmh = (NMHDR *)lParam;
529
530 switch (nmh->code)
531 {
532 case PSN_APPLY:
533 {
534 SetWindowLongPtr(hwndDlg,
535 DWLP_MSGRESULT,
536 ApplyMonitorChanges(This));
537 break;
538 }
539
540 case PSN_RESET:
541 ResetMonitorChanges(This);
542 break;
543
544 case PSN_SETACTIVE:
545 UpdateRefreshFrequencyList(This);
546 break;
547 }
548 break;
549 }
550 }
551
552 return Ret;
553 }
554
555 static VOID
556 IDeskMonitor_Destroy(PDESKMONITOR This)
557 {
558 PDESKMONINFO pmi, pminext;
559
560 if (This->pdtobj != NULL)
561 {
562 IDataObject_Release(This->pdtobj);
563 This->pdtobj = NULL;
564 }
565
566 if (This->DeskExtInterface != NULL)
567 {
568 LocalFree((HLOCAL)This->DeskExtInterface);
569 This->DeskExtInterface = NULL;
570 }
571
572 if (This->lpDisplayDevice != NULL)
573 {
574 LocalFree((HLOCAL)This->lpDisplayDevice);
575 This->lpDisplayDevice = NULL;
576 }
577
578 /* Free all monitors */
579 pmi = This->Monitors;
580 This->Monitors = NULL;
581 while (pmi != NULL)
582 {
583 pminext = pmi->Next;
584 LocalFree((HLOCAL)pmi);
585 pmi = pminext;
586 }
587 }
588
589 ULONG
590 IDeskMonitor_AddRef(PDESKMONITOR This)
591 {
592 ULONG ret;
593
594 ret = InterlockedIncrement((PLONG)&This->ref);
595 if (ret == 1)
596 InterlockedIncrement(&dll_refs);
597
598 return ret;
599 }
600
601 ULONG
602 IDeskMonitor_Release(PDESKMONITOR This)
603 {
604 ULONG ret;
605
606 ret = InterlockedDecrement((PLONG)&This->ref);
607 if (ret == 0)
608 {
609 IDeskMonitor_Destroy(This);
610 InterlockedDecrement(&dll_refs);
611
612 HeapFree(GetProcessHeap(),
613 0,
614 This);
615 }
616
617 return ret;
618 }
619
620 HRESULT STDMETHODCALLTYPE
621 IDeskMonitor_QueryInterface(PDESKMONITOR This,
622 REFIID iid,
623 PVOID *pvObject)
624 {
625 *pvObject = NULL;
626
627 if (IsEqualIID(iid,
628 &IID_IShellPropSheetExt) ||
629 IsEqualIID(iid,
630 &IID_IUnknown))
631 {
632 *pvObject = impl_to_interface(This, IShellPropSheetExt);
633 }
634 else if (IsEqualIID(iid,
635 &IID_IShellExtInit))
636 {
637 *pvObject = impl_to_interface(This, IShellExtInit);
638 }
639 else if (IsEqualIID(iid,
640 &IID_IClassFactory))
641 {
642 *pvObject = impl_to_interface(This, IClassFactory);
643 }
644 else
645 {
646 DPRINT1("IDeskMonitor::QueryInterface(%p,%p): E_NOINTERFACE\n", iid, pvObject);
647 return E_NOINTERFACE;
648 }
649
650 IDeskMonitor_AddRef(This);
651 return S_OK;
652 }
653
654 HRESULT
655 IDeskMonitor_Initialize(PDESKMONITOR This,
656 LPCITEMIDLIST pidlFolder,
657 IDataObject *pdtobj,
658 HKEY hkeyProgID)
659 {
660 DPRINT1("IDeskMonitor::Initialize(%p,%p,%p)\n", pidlFolder, pdtobj, hkeyProgID);
661
662 if (pdtobj != NULL)
663 {
664 IDataObject_AddRef(pdtobj);
665 This->pdtobj = pdtobj;
666
667 /* Get a copy of the desk.cpl extension interface */
668 This->DeskExtInterface = QueryDeskCplExtInterface(This->pdtobj);
669 if (This->DeskExtInterface != NULL)
670 return S_OK;
671 }
672
673 return S_FALSE;
674 }
675
676 HRESULT
677 IDeskMonitor_AddPages(PDESKMONITOR This,
678 LPFNADDPROPSHEETPAGE pfnAddPage,
679 LPARAM lParam)
680 {
681 HPROPSHEETPAGE hpsp;
682 PROPSHEETPAGE psp;
683
684 DPRINT1("IDeskMonitor::AddPages(%p,%p)\n", pfnAddPage, lParam);
685
686 psp.dwSize = sizeof(psp);
687 psp.dwFlags = PSP_DEFAULT;
688 psp.hInstance = hInstance;
689 psp.pszTemplate = MAKEINTRESOURCE(IDD_MONITOR);
690 psp.pfnDlgProc = MonitorDlgProc;
691 psp.lParam = (LPARAM)This;
692
693 hpsp = CreatePropertySheetPage(&psp);
694 if (hpsp != NULL && pfnAddPage(hpsp, lParam))
695 return S_OK;
696
697 return S_FALSE;
698 }
699
700 HRESULT
701 IDeskMonitor_ReplacePage(PDESKMONITOR This,
702 EXPPS uPageID,
703 LPFNADDPROPSHEETPAGE pfnReplacePage,
704 LPARAM lParam)
705 {
706 DPRINT1("IDeskMonitor::ReplacePage(%u,%p,%p)\n", uPageID, pfnReplacePage, lParam);
707 return E_NOTIMPL;
708 }
709
710 HRESULT
711 IDeskMonitor_Constructor(REFIID riid,
712 LPVOID *ppv)
713 {
714 PDESKMONITOR This;
715 HRESULT hRet = E_OUTOFMEMORY;
716
717 DPRINT1("IDeskMonitor::Constructor(%p,%p)\n", riid, ppv);
718
719 This = HeapAlloc(GetProcessHeap(),
720 0,
721 sizeof(*This));
722 if (This != NULL)
723 {
724 ZeroMemory(This,
725 sizeof(*This));
726
727 IDeskMonitor_InitIface(This);
728
729 hRet = IDeskMonitor_QueryInterface(This,
730 riid,
731 ppv);
732 if (!SUCCEEDED(hRet))
733 IDeskMonitor_Release(This);
734 }
735
736 return hRet;
737 }
738
739 BOOL WINAPI
740 DllMain(HINSTANCE hinstDLL,
741 DWORD dwReason,
742 LPVOID lpvReserved)
743 {
744 switch (dwReason)
745 {
746 case DLL_PROCESS_ATTACH:
747 hInstance = hinstDLL;
748 DisableThreadLibraryCalls(hInstance);
749 break;
750 }
751
752 return TRUE;
753 }