1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS msgina.dll
4 * FILE: lib/msgina/shutdown.c
5 * PURPOSE: Shutdown Dialog Box (GUI only)
6 * PROGRAMMERS: Lee Schroeder (spaceseel at gmail dot com)
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 * Arnav Bhatt (arnavbhatt288 at gmail dot com)
9 */
10
11 #include "msgina.h"
12 #include <powrprof.h>
13 #include <wingdi.h>
14 #include <windowsx.h>
15 #include <commctrl.h>
16
17 /* Shutdown state flags */
18 #define WLX_SHUTDOWN_STATE_LOGOFF 0x01
19 #define WLX_SHUTDOWN_STATE_POWER_OFF 0x02
20 #define WLX_SHUTDOWN_STATE_REBOOT 0x04
21 // 0x08
22 #define WLX_SHUTDOWN_STATE_SLEEP 0x10
23 // 0x20
24 #define WLX_SHUTDOWN_STATE_HIBERNATE 0x40
25 // 0x80
26
27 /* Macros for fancy shut down dialog */
28 #define FONT_POINT_SIZE 13
29
30 #define DARK_GREY_COLOR RGB(244, 244, 244)
31 #define LIGHT_GREY_COLOR RGB(38, 38, 38)
32
33 /* Bitmap's size for buttons */
34 #define CX_BITMAP 33
35 #define CY_BITMAP 33
36
37 #define NUMBER_OF_BUTTONS 4
38
39 /* After determining the button as well as its state paint the image strip bitmap using these predefined positions */
40 #define BUTTON_SHUTDOWN 0
41 #define BUTTON_SHUTDOWN_PRESSED (CY_BITMAP + BUTTON_SHUTDOWN)
42 #define BUTTON_SHUTDOWN_FOCUSED (CY_BITMAP + BUTTON_SHUTDOWN_PRESSED)
43 #define BUTTON_REBOOT (CY_BITMAP + BUTTON_SHUTDOWN_FOCUSED)
44 #define BUTTON_REBOOT_PRESSED (CY_BITMAP + BUTTON_REBOOT)
45 #define BUTTON_REBOOT_FOCUSED (CY_BITMAP + BUTTON_REBOOT_PRESSED)
46 #define BUTTON_SLEEP (CY_BITMAP + BUTTON_REBOOT_FOCUSED)
47 #define BUTTON_SLEEP_PRESSED (CY_BITMAP + BUTTON_SLEEP)
48 #define BUTTON_SLEEP_FOCUSED (CY_BITMAP + BUTTON_SLEEP_PRESSED)
49 #define BUTTON_SLEEP_DISABLED (CY_BITMAP + BUTTON_SLEEP_FOCUSED)
50
51 /* For bIsButtonHot */
52 #define SHUTDOWN_BUTTON_HOT 0
53 #define REBOOT_BUTTON_HOT 1
54 #define SLEEP_BUTTON_HOT 2
55 #define HIBERNATE_BUTTON_HOT 3
56
57 typedef struct _SHUTDOWN_DLG_CONTEXT
58 {
59 PGINA_CONTEXT pgContext;
60 HBITMAP hBitmap;
61 HBITMAP hImageStrip;
62 DWORD ShutdownDialogId;
63 DWORD ShutdownOptions;
64 HBRUSH hBrush;
65 HFONT hfFont;
66 BOOL bCloseDlg;
67 BOOL bIsSleepButtonReplaced;
68 BOOL bReasonUI;
69 BOOL bFriendlyUI;
70 BOOL bIsButtonHot[NUMBER_OF_BUTTONS];
71 BOOL bTimer;
72 UINT_PTR iTimer;
73 WNDPROC OldButtonProc;
74 } SHUTDOWN_DLG_CONTEXT, *PSHUTDOWN_DLG_CONTEXT;
75
76 static
77 BOOL
GetShutdownReasonUI(VOID)78 GetShutdownReasonUI(VOID)
79 {
80 OSVERSIONINFOEX VersionInfo;
81 DWORD dwValue, dwSize;
82 HKEY hKey;
83 LONG lRet;
84
85 /* Query the policy value */
86 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
87 L"Software\\Policies\\Microsoft\\Windows NT\\Reliability",
88 0,
89 KEY_QUERY_VALUE,
90 &hKey);
91 if (lRet == ERROR_SUCCESS)
92 {
93 dwValue = 0;
94 dwSize = sizeof(dwValue);
95 RegQueryValueExW(hKey,
96 L"ShutdownReasonUI",
97 NULL,
98 NULL,
99 (LPBYTE)&dwValue,
100 &dwSize);
101 RegCloseKey(hKey);
102
103 return (dwValue != 0) ? TRUE : FALSE;
104 }
105
106 /* Query the machine value */
107 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
108 L"Software\\Microsoft\\Windows\\CurrentVersion\\Reliability",
109 0,
110 KEY_QUERY_VALUE,
111 &hKey);
112 if (lRet == ERROR_SUCCESS)
113 {
114 dwValue = 0;
115 dwSize = sizeof(dwValue);
116 RegQueryValueExW(hKey,
117 L"ShutdownReasonUI",
118 NULL,
119 NULL,
120 (LPBYTE)&dwValue,
121 &dwSize);
122 RegCloseKey(hKey);
123
124 return (dwValue != 0) ? TRUE : FALSE;
125 }
126
127 /* Return the default value */
128 VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
129 if (!GetVersionEx((POSVERSIONINFO)&VersionInfo))
130 return FALSE;
131
132 return FALSE;
133 // return (VersionInfo.wProductType == VER_NT_WORKSTATION) ? FALSE : TRUE;
134 }
135
136 static
137 BOOL
IsFriendlyUIActive(VOID)138 IsFriendlyUIActive(VOID)
139 {
140 DWORD dwType, dwValue, dwSize;
141 HKEY hKey;
142 LONG lRet;
143
144 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
145 L"SYSTEM\\CurrentControlSet\\Control\\Windows",
146 0,
147 KEY_QUERY_VALUE,
148 &hKey);
149 if (lRet != ERROR_SUCCESS)
150 return FALSE;
151
152 /* CORE-17282 First check an optional ReactOS specific override, that Windows does not check.
153 We use this to allow users pairing 'Server'-configuration with FriendlyShutdown.
154 Otherwise users would have to change CSDVersion or LogonType (side-effects AppCompat) */
155 dwValue = 0;
156 dwSize = sizeof(dwValue);
157 lRet = RegQueryValueExW(hKey,
158 L"EnforceFriendlyShutdown",
159 NULL,
160 &dwType,
161 (LPBYTE)&dwValue,
162 &dwSize);
163
164 if (lRet == ERROR_SUCCESS && dwType == REG_DWORD && dwValue == 0x1)
165 {
166 RegCloseKey(hKey);
167 return TRUE;
168 }
169
170 /* Check product version number */
171 dwValue = 0;
172 dwSize = sizeof(dwValue);
173 lRet = RegQueryValueExW(hKey,
174 L"CSDVersion",
175 NULL,
176 &dwType,
177 (LPBYTE)&dwValue,
178 &dwSize);
179 RegCloseKey(hKey);
180
181 if (lRet != ERROR_SUCCESS || dwType != REG_DWORD || dwValue != 0x300)
182 {
183 /* Allow Friendly UI only on Workstation */
184 return FALSE;
185 }
186
187 /* Check LogonType value */
188 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
189 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
190 0,
191 KEY_QUERY_VALUE,
192 &hKey);
193 if (lRet != ERROR_SUCCESS)
194 return FALSE;
195
196 dwValue = 0;
197 dwSize = sizeof(dwValue);
198 lRet = RegQueryValueExW(hKey,
199 L"LogonType",
200 NULL,
201 &dwType,
202 (LPBYTE)&dwValue,
203 &dwSize);
204 RegCloseKey(hKey);
205
206 if (lRet != ERROR_SUCCESS || dwType != REG_DWORD)
207 return FALSE;
208
209 return (dwValue != 0);
210 }
211
212 static
213 BOOL
IsDomainMember(VOID)214 IsDomainMember(VOID)
215 {
216 UNIMPLEMENTED;
217 return FALSE;
218 }
219
220 static
221 BOOL
IsNetwareActive(VOID)222 IsNetwareActive(VOID)
223 {
224 UNIMPLEMENTED;
225 return FALSE;
226 }
227
228 static
229 BOOL
IsShowHibernateButtonActive(VOID)230 IsShowHibernateButtonActive(VOID)
231 {
232 INT_PTR lRet;
233 HKEY hKey;
234 DWORD dwValue, dwSize;
235
236 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
237 L"SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Shutdown",
238 0, KEY_QUERY_VALUE, &hKey);
239 if (lRet == ERROR_SUCCESS)
240 {
241 dwValue = 0;
242 dwSize = sizeof(dwValue);
243
244 lRet = RegQueryValueExW(hKey,
245 L"ShowHibernateButton",
246 NULL, NULL,
247 (LPBYTE)&dwValue, &dwSize);
248 RegCloseKey(hKey);
249 if (lRet != ERROR_SUCCESS)
250 {
251 return FALSE;
252 }
253 return (dwValue != 0);
254 }
255 return FALSE;
256 }
257
258 static
259 BOOL
ForceFriendlyUI(VOID)260 ForceFriendlyUI(VOID)
261 {
262 DWORD dwType, dwValue, dwSize;
263 HKEY hKey;
264 LONG lRet;
265
266 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
267 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
268 0,
269 KEY_QUERY_VALUE,
270 &hKey);
271 if (lRet == ERROR_SUCCESS)
272 {
273 dwValue = 0;
274 dwSize = sizeof(dwValue);
275 lRet = RegQueryValueExW(hKey,
276 L"ForceFriendlyUI",
277 NULL,
278 &dwType,
279 (LPBYTE)&dwValue,
280 &dwSize);
281 RegCloseKey(hKey);
282
283 if (lRet == ERROR_SUCCESS && dwType == REG_DWORD)
284 return (dwValue != 0);
285 }
286
287 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
288 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
289 0,
290 KEY_QUERY_VALUE,
291 &hKey);
292 if (lRet == ERROR_SUCCESS)
293 {
294 dwValue = 0;
295 dwSize = sizeof(dwValue);
296 lRet = RegQueryValueExW(hKey,
297 L"ForceFriendlyUI",
298 NULL,
299 &dwType,
300 (LPBYTE)&dwValue,
301 &dwSize);
302
303 RegCloseKey(hKey);
304
305 if (lRet == ERROR_SUCCESS && dwType == REG_DWORD)
306 return (dwValue != 0);
307 }
308
309 return FALSE;
310 }
311
312 static
313 BOOL
DrawIconOnOwnerDrawnButtons(DRAWITEMSTRUCT * pdis,PSHUTDOWN_DLG_CONTEXT pContext)314 DrawIconOnOwnerDrawnButtons(
315 DRAWITEMSTRUCT* pdis,
316 PSHUTDOWN_DLG_CONTEXT pContext)
317 {
318 BOOL bRet;
319 HDC hdcMem;
320 HBITMAP hbmOld;
321 int y;
322 RECT rect;
323
324 hdcMem = CreateCompatibleDC(pdis->hDC);
325 hbmOld = SelectObject(hdcMem, pContext->hImageStrip);
326 rect = pdis->rcItem;
327
328 /* Check the button ID for revelant bitmap to be used */
329 switch (pdis->CtlID)
330 {
331 case IDC_BUTTON_SHUTDOWN:
332 {
333 switch (pdis->itemAction)
334 {
335 case ODA_DRAWENTIRE:
336 case ODA_FOCUS:
337 case ODA_SELECT:
338 {
339 y = BUTTON_SHUTDOWN;
340 if (pdis->itemState & ODS_SELECTED)
341 {
342 y = BUTTON_SHUTDOWN_PRESSED;
343 }
344 else if (pContext->bIsButtonHot[SHUTDOWN_BUTTON_HOT] || (pdis->itemState & ODS_FOCUS))
345 {
346 y = BUTTON_SHUTDOWN_FOCUSED;
347 }
348 break;
349 }
350 }
351 break;
352 }
353
354 case IDC_BUTTON_REBOOT:
355 {
356 switch (pdis->itemAction)
357 {
358 case ODA_DRAWENTIRE:
359 case ODA_FOCUS:
360 case ODA_SELECT:
361 {
362 y = BUTTON_REBOOT;
363 if (pdis->itemState & ODS_SELECTED)
364 {
365 y = BUTTON_REBOOT_PRESSED;
366 }
367 else if (pContext->bIsButtonHot[REBOOT_BUTTON_HOT] || (pdis->itemState & ODS_FOCUS))
368 {
369 y = BUTTON_REBOOT_FOCUSED;
370 }
371 break;
372 }
373 }
374 break;
375 }
376
377 case IDC_BUTTON_HIBERNATE:
378 case IDC_BUTTON_SLEEP:
379 {
380 switch (pdis->itemAction)
381 {
382 case ODA_DRAWENTIRE:
383 case ODA_FOCUS:
384 case ODA_SELECT:
385 {
386 y = BUTTON_SLEEP;
387 if (pdis->itemState & ODS_DISABLED)
388 {
389 y = BUTTON_SLEEP_DISABLED;
390 }
391 else if (pdis->itemState & ODS_SELECTED)
392 {
393 y = BUTTON_SLEEP_PRESSED;
394 }
395 else if ((pdis->CtlID == IDC_BUTTON_SLEEP && pContext->bIsButtonHot[SLEEP_BUTTON_HOT]) ||
396 (pdis->CtlID == IDC_BUTTON_HIBERNATE && pContext->bIsButtonHot[HIBERNATE_BUTTON_HOT]) ||
397 (pdis->itemState & ODS_FOCUS))
398 {
399 y = BUTTON_SLEEP_FOCUSED;
400 }
401 break;
402 }
403 }
404 break;
405 }
406 }
407
408 /* Draw it on the required button */
409 bRet = BitBlt(pdis->hDC,
410 (rect.right - rect.left - CX_BITMAP) / 2,
411 (rect.bottom - rect.top - CY_BITMAP) / 2,
412 CX_BITMAP, CY_BITMAP, hdcMem, 0, y, SRCCOPY);
413
414 SelectObject(hdcMem, hbmOld);
415 DeleteDC(hdcMem);
416
417 return bRet;
418 }
419
420 BOOL
421 WINAPI
ShellIsFriendlyUIActive(VOID)422 ShellIsFriendlyUIActive(VOID)
423 {
424 BOOL bActive;
425
426 bActive = IsFriendlyUIActive();
427
428 if ((IsDomainMember() || IsNetwareActive()) && !ForceFriendlyUI())
429 return FALSE;
430
431 return bActive;
432 }
433
434 DWORD
GetDefaultShutdownSelState(VOID)435 GetDefaultShutdownSelState(VOID)
436 {
437 return WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
438 }
439
440 DWORD
LoadShutdownSelState(VOID)441 LoadShutdownSelState(VOID)
442 {
443 LONG lRet;
444 HKEY hKeyCurrentUser, hKey;
445 DWORD dwValue, dwTemp, dwSize;
446
447 /* Default to shutdown */
448 dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
449
450 /* Open the current user HKCU key */
451 lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
452 if (lRet == ERROR_SUCCESS)
453 {
454 /* Open the subkey */
455 lRet = RegOpenKeyExW(hKeyCurrentUser,
456 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
457 0, KEY_QUERY_VALUE, &hKey);
458 RegCloseKey(hKeyCurrentUser);
459 }
460 if (lRet != ERROR_SUCCESS)
461 return dwValue;
462
463 /* Read the value */
464 dwSize = sizeof(dwTemp);
465 lRet = RegQueryValueExW(hKey,
466 L"Shutdown Setting",
467 NULL, NULL,
468 (LPBYTE)&dwTemp, &dwSize);
469 RegCloseKey(hKey);
470
471 if (lRet == ERROR_SUCCESS)
472 {
473 switch (dwTemp)
474 {
475 case WLX_SHUTDOWN_STATE_LOGOFF:
476 dwValue = WLX_SAS_ACTION_LOGOFF;
477 break;
478
479 case WLX_SHUTDOWN_STATE_POWER_OFF:
480 dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
481 break;
482
483 case WLX_SHUTDOWN_STATE_REBOOT:
484 dwValue = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
485 break;
486
487 // 0x08
488
489 case WLX_SHUTDOWN_STATE_SLEEP:
490 dwValue = WLX_SAS_ACTION_SHUTDOWN_SLEEP;
491 break;
492
493 // 0x20
494
495 case WLX_SHUTDOWN_STATE_HIBERNATE:
496 dwValue = WLX_SAS_ACTION_SHUTDOWN_HIBERNATE;
497 break;
498
499 // 0x80
500 }
501 }
502
503 return dwValue;
504 }
505
506 static INT_PTR
507 CALLBACK
OwnerDrawButtonSubclass(HWND hButton,UINT uMsg,WPARAM wParam,LPARAM lParam)508 OwnerDrawButtonSubclass(
509 HWND hButton,
510 UINT uMsg,
511 WPARAM wParam,
512 LPARAM lParam)
513 {
514 PSHUTDOWN_DLG_CONTEXT pContext;
515 pContext = (PSHUTDOWN_DLG_CONTEXT)GetWindowLongPtrW(GetParent(hButton), GWLP_USERDATA);
516 int buttonID = GetDlgCtrlID(hButton);
517
518 switch (uMsg)
519 {
520 case WM_MOUSEMOVE:
521 {
522 HWND hwndTarget;
523 POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
524
525 if (GetCapture() != hButton)
526 {
527 SetCapture(hButton);
528 if (buttonID == IDC_BUTTON_SHUTDOWN)
529 {
530 pContext->bIsButtonHot[SHUTDOWN_BUTTON_HOT] = TRUE;
531 }
532 else if (buttonID == IDC_BUTTON_REBOOT)
533 {
534 pContext->bIsButtonHot[REBOOT_BUTTON_HOT] = TRUE;
535 }
536 else if (buttonID == IDC_BUTTON_SLEEP)
537 {
538 pContext->bIsButtonHot[SLEEP_BUTTON_HOT] = TRUE;
539 }
540 else if (buttonID == IDC_BUTTON_HIBERNATE)
541 {
542 pContext->bIsButtonHot[HIBERNATE_BUTTON_HOT] = TRUE;
543 }
544 SetCursor(LoadCursorW(NULL, IDC_HAND));
545 }
546
547 ClientToScreen(hButton, &pt);
548 hwndTarget = WindowFromPoint(pt);
549
550 if (hwndTarget != hButton)
551 {
552 ReleaseCapture();
553 if (buttonID == IDC_BUTTON_SHUTDOWN)
554 {
555 pContext->bIsButtonHot[SHUTDOWN_BUTTON_HOT] = FALSE;
556 }
557 else if (buttonID == IDC_BUTTON_REBOOT)
558 {
559 pContext->bIsButtonHot[REBOOT_BUTTON_HOT] = FALSE;
560 }
561 else if (buttonID == IDC_BUTTON_SLEEP)
562 {
563 pContext->bIsButtonHot[SLEEP_BUTTON_HOT] = FALSE;
564 }
565 else if (buttonID == IDC_BUTTON_HIBERNATE)
566 {
567 pContext->bIsButtonHot[HIBERNATE_BUTTON_HOT] = FALSE;
568 }
569 }
570 InvalidateRect(hButton, NULL, FALSE);
571 break;
572 }
573
574 /* Whenever one of the buttons gets the keyboard focus, set it as default button */
575 case WM_SETFOCUS:
576 {
577 SendMessageW(GetParent(hButton), DM_SETDEFID, buttonID, 0);
578 break;
579 }
580
581 /* Otherwise, set IDCANCEL as default button */
582 case WM_KILLFOCUS:
583 {
584 SendMessageW(GetParent(hButton), DM_SETDEFID, IDCANCEL, 0);
585 break;
586 }
587 }
588 return CallWindowProcW(pContext->OldButtonProc, hButton, uMsg, wParam, lParam);
589 }
590
591 VOID
CreateToolTipForButtons(int controlID,int detailID,HWND hDlg,int titleID,HINSTANCE hInst)592 CreateToolTipForButtons(
593 int controlID,
594 int detailID,
595 HWND hDlg,
596 int titleID,
597 HINSTANCE hInst)
598 {
599 HWND hwndTool, hwndTip;
600 WCHAR szBuffer[256];
601 TTTOOLINFOW tool;
602
603 hwndTool = GetDlgItem(hDlg, controlID);
604
605 tool.cbSize = sizeof(tool);
606 tool.hwnd = hDlg;
607 tool.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
608 tool.uId = (UINT_PTR)hwndTool;
609
610 /* Create the tooltip */
611 hwndTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL,
612 WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON,
613 CW_USEDEFAULT, CW_USEDEFAULT,
614 CW_USEDEFAULT, CW_USEDEFAULT,
615 hDlg, NULL, hInst, NULL);
616
617 /* Associate the tooltip with the tool. */
618 LoadStringW(hInst, detailID, szBuffer, _countof(szBuffer));
619 tool.lpszText = szBuffer;
620 SendMessageW(hwndTip, TTM_ADDTOOLW, 0, (LPARAM)&tool);
621 LoadStringW(hInst, titleID, szBuffer, _countof(szBuffer));
622 SendMessageW(hwndTip, TTM_SETTITLEW, TTI_NONE, (LPARAM)szBuffer);
623 SendMessageW(hwndTip, TTM_SETMAXTIPWIDTH, 0, 250);
624 }
625
626 VOID
EndFriendlyDialog(HWND hDlg,PSHUTDOWN_DLG_CONTEXT pContext)627 EndFriendlyDialog(
628 HWND hDlg,
629 PSHUTDOWN_DLG_CONTEXT pContext)
630 {
631 if (pContext->bTimer)
632 {
633 KillTimer(hDlg, pContext->iTimer);
634 }
635
636 DeleteObject(pContext->hBitmap);
637 DeleteObject(pContext->hBrush);
638 DeleteObject(pContext->hImageStrip);
639 DeleteObject(pContext->hfFont);
640
641 /* Remove the subclass from the buttons */
642 for (int i = 0; i < NUMBER_OF_BUTTONS; i++)
643 {
644 SetWindowLongPtrW(GetDlgItem(hDlg, IDC_BUTTON_SHUTDOWN + i),
645 GWLP_WNDPROC,
646 (LONG_PTR)pContext->OldButtonProc);
647 }
648 }
649
650 VOID
ChangeRequiredButton(HWND hDlg,PSHUTDOWN_DLG_CONTEXT pContext)651 ChangeRequiredButton(
652 HWND hDlg,
653 PSHUTDOWN_DLG_CONTEXT pContext)
654 {
655 int destID = IDC_BUTTON_SLEEP;
656 int targetedID = IDC_BUTTON_HIBERNATE;
657 HWND hwndDest, hwndTarget;
658 RECT rect;
659 WCHAR szBuffer[30];
660
661 /* If the sleep button has been already replaced earlier, bring sleep button back to its original position */
662 if (pContext->bIsSleepButtonReplaced)
663 {
664 destID = IDC_BUTTON_HIBERNATE;
665 targetedID = IDC_BUTTON_SLEEP;
666 }
667
668 hwndDest = GetDlgItem(hDlg, destID);
669 hwndTarget = GetDlgItem(hDlg, targetedID);
670
671 /* Get the position of the destination button */
672 GetWindowRect(hwndDest, &rect);
673
674 /* Get the corrected translated coordinates which is relative to the client window */
675 MapWindowPoints(HWND_DESKTOP, hDlg, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
676
677 /* Set the position of targeted button and hide the destination button */
678 SetWindowPos(hwndTarget,
679 HWND_TOP,
680 rect.left, rect.top,
681 0, 0,
682 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
683
684 EnableWindow(hwndDest, FALSE);
685 ShowWindow(hwndDest, SW_HIDE);
686 EnableWindow(hwndTarget, TRUE);
687 ShowWindow(hwndTarget, SW_SHOW);
688 SetFocus(hwndTarget);
689
690 if (!pContext->bIsSleepButtonReplaced)
691 {
692 LoadStringW(pContext->pgContext->hDllInstance, IDS_SHUTDOWN_HIBERNATE, szBuffer, _countof(szBuffer));
693 SetDlgItemTextW(hDlg, IDC_SLEEP_STATIC, szBuffer);
694 }
695 else
696 {
697 LoadStringW(pContext->pgContext->hDllInstance, IDS_SHUTDOWN_SLEEP, szBuffer, _countof(szBuffer));
698 SetDlgItemTextW(hDlg, IDC_SLEEP_STATIC, szBuffer);
699 }
700
701 InvalidateRect(hDlg, NULL, FALSE);
702 }
703
OnTimer(HWND hDlg,PSHUTDOWN_DLG_CONTEXT pContext)704 VOID OnTimer(
705 HWND hDlg,
706 PSHUTDOWN_DLG_CONTEXT pContext)
707 {
708 BOOL ReplaceButton = !!(GetKeyState(VK_SHIFT) & 0x8000);
709
710 if (ReplaceButton && !pContext->bIsSleepButtonReplaced)
711 {
712 ChangeRequiredButton(hDlg, pContext);
713 pContext->bIsSleepButtonReplaced = TRUE;
714 }
715 else if (!ReplaceButton && pContext->bIsSleepButtonReplaced)
716 {
717 ChangeRequiredButton(hDlg, pContext);
718 pContext->bIsSleepButtonReplaced = FALSE;
719 }
720 }
721
722 VOID
SaveShutdownSelState(IN DWORD ShutdownCode)723 SaveShutdownSelState(
724 IN DWORD ShutdownCode)
725 {
726 LONG lRet;
727 HKEY hKeyCurrentUser, hKey;
728 DWORD dwValue = 0;
729
730 /* Open the current user HKCU key */
731 lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
732 if (lRet == ERROR_SUCCESS)
733 {
734 /* Create the subkey */
735 lRet = RegCreateKeyExW(hKeyCurrentUser,
736 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
737 0, NULL,
738 REG_OPTION_NON_VOLATILE,
739 KEY_SET_VALUE,
740 NULL, &hKey, NULL);
741 RegCloseKey(hKeyCurrentUser);
742 }
743 if (lRet != ERROR_SUCCESS)
744 return;
745
746 switch (ShutdownCode)
747 {
748 case WLX_SAS_ACTION_LOGOFF:
749 dwValue = WLX_SHUTDOWN_STATE_LOGOFF;
750 break;
751
752 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
753 dwValue = WLX_SHUTDOWN_STATE_POWER_OFF;
754 break;
755
756 case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
757 dwValue = WLX_SHUTDOWN_STATE_REBOOT;
758 break;
759
760 case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
761 dwValue = WLX_SHUTDOWN_STATE_SLEEP;
762 break;
763
764 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
765 dwValue = WLX_SHUTDOWN_STATE_HIBERNATE;
766 break;
767 }
768
769 RegSetValueExW(hKey,
770 L"Shutdown Setting",
771 0, REG_DWORD,
772 (LPBYTE)&dwValue, sizeof(dwValue));
773 RegCloseKey(hKey);
774 }
775
776 DWORD
GetDefaultShutdownOptions(VOID)777 GetDefaultShutdownOptions(VOID)
778 {
779 return WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
780 }
781
782 DWORD
GetAllowedShutdownOptions(VOID)783 GetAllowedShutdownOptions(VOID)
784 {
785 DWORD Options = 0;
786
787 // FIXME: Compute those options accordings to current user's rights!
788 Options |= WLX_SHUTDOWN_STATE_LOGOFF | WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
789
790 if (IsPwrSuspendAllowed())
791 Options |= WLX_SHUTDOWN_STATE_SLEEP;
792
793 if (IsPwrHibernateAllowed())
794 Options |= WLX_SHUTDOWN_STATE_HIBERNATE;
795
796 return Options;
797 }
798
799 static VOID
UpdateShutdownDesc(IN HWND hDlg,IN PSHUTDOWN_DLG_CONTEXT pContext)800 UpdateShutdownDesc(
801 IN HWND hDlg,
802 IN PSHUTDOWN_DLG_CONTEXT pContext) // HINSTANCE hInstance
803 {
804 UINT DescId = 0;
805 DWORD ShutdownCode;
806 WCHAR szBuffer[256];
807
808 ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_ACTION, CB_GETCURSEL, 0, 0);
809 if (ShutdownCode == CB_ERR) // Invalid selection
810 return;
811
812 ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_ACTION, CB_GETITEMDATA, ShutdownCode, 0);
813
814 switch (ShutdownCode)
815 {
816 case WLX_SAS_ACTION_LOGOFF:
817 DescId = IDS_SHUTDOWN_LOGOFF_DESC;
818 break;
819
820 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
821 DescId = IDS_SHUTDOWN_SHUTDOWN_DESC;
822 break;
823
824 case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
825 DescId = IDS_SHUTDOWN_RESTART_DESC;
826 break;
827
828 case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
829 DescId = IDS_SHUTDOWN_SLEEP_DESC;
830 break;
831
832 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
833 DescId = IDS_SHUTDOWN_HIBERNATE_DESC;
834 break;
835
836 default:
837 break;
838 }
839
840 LoadStringW(pContext->pgContext->hDllInstance, DescId, szBuffer, _countof(szBuffer));
841 SetDlgItemTextW(hDlg, IDC_SHUTDOWN_DESCRIPTION, szBuffer);
842
843 if (pContext->bReasonUI)
844 {
845 EnableWindow(GetDlgItem(hDlg, IDC_REASON_PLANNED), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
846 EnableWindow(GetDlgItem(hDlg, IDC_REASON_LIST), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
847 EnableWindow(GetDlgItem(hDlg, IDC_REASON_COMMENT), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
848 }
849 }
850
851 static VOID
ShutdownOnFriendlyInit(IN HWND hDlg,IN PSHUTDOWN_DLG_CONTEXT pContext)852 ShutdownOnFriendlyInit(
853 IN HWND hDlg,
854 IN PSHUTDOWN_DLG_CONTEXT pContext)
855 {
856 PGINA_CONTEXT pgContext = pContext->pgContext;
857 HDC hdc;
858 LONG lfHeight;
859
860 /* Create font for the IDC_TURN_OFF_STATIC static control */
861 hdc = GetDC(hDlg);
862 lfHeight = -MulDiv(FONT_POINT_SIZE, GetDeviceCaps(hdc, LOGPIXELSY), 72);
863 ReleaseDC(hDlg, hdc);
864 pContext->hfFont = CreateFontW(lfHeight, 0, 0, 0, FW_MEDIUM, FALSE, 0, 0, 0, 0, 0, 0, 0, L"MS Shell Dlg");
865 SendDlgItemMessageW(hDlg, IDC_TURN_OFF_STATIC, WM_SETFONT, (WPARAM)pContext->hfFont, TRUE);
866
867 /* Create a brush for static controls for fancy shut down dialog */
868 pContext->hBrush = CreateSolidBrush(DARK_GREY_COLOR);
869
870 /* Gather image strip */
871 pContext->hImageStrip = LoadBitmapW(pgContext->hDllInstance, MAKEINTRESOURCEW(IDB_IMAGE_STRIP));
872
873 /* Set the boolean flags to false */
874 pContext->bIsSleepButtonReplaced = FALSE;
875 pContext->bTimer = FALSE;
876
877 EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_HIBERNATE), FALSE);
878 EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SLEEP), IsPwrSuspendAllowed());
879
880 /* Gather old button func */
881 pContext->OldButtonProc = (WNDPROC)GetWindowLongPtrW(GetDlgItem(hDlg, IDC_BUTTON_HIBERNATE), GWLP_WNDPROC);
882
883 /* Set bIsButtonHot to false, create tooltips for each buttons, make buttons to remember pContext and subclass the buttons */
884 for (int i = 0; i < NUMBER_OF_BUTTONS; i++)
885 {
886 pContext->bIsButtonHot[i] = FALSE;
887 SetWindowLongPtrW(GetDlgItem(hDlg, IDC_BUTTON_SHUTDOWN + i),
888 GWLP_WNDPROC,
889 (LONG_PTR)OwnerDrawButtonSubclass);
890 CreateToolTipForButtons(IDC_BUTTON_SHUTDOWN + i,
891 IDS_SHUTDOWN_SHUTDOWN_DESC + i,
892 hDlg, IDS_SHUTDOWN_SHUTDOWN + i,
893 pContext->pgContext->hDllInstance);
894 }
895
896 if (pContext->ShutdownDialogId == IDD_SHUTDOWN_FANCY && IsPwrSuspendAllowed())
897 {
898 pContext->iTimer = SetTimer(hDlg, 0, 50, NULL);
899 pContext->bTimer = TRUE;
900 }
901 }
902
903 static VOID
ShutdownOnInit(IN HWND hDlg,IN PSHUTDOWN_DLG_CONTEXT pContext)904 ShutdownOnInit(
905 IN HWND hDlg,
906 IN PSHUTDOWN_DLG_CONTEXT pContext)
907 {
908 PGINA_CONTEXT pgContext = pContext->pgContext;
909 HWND hwndList;
910 INT idx, count, i;
911 WCHAR szBuffer[256];
912 WCHAR szBuffer2[256];
913
914 if (pContext->bFriendlyUI)
915 {
916 ShutdownOnFriendlyInit(hDlg, pContext);
917 return;
918 }
919
920 hwndList = GetDlgItem(hDlg, IDC_SHUTDOWN_ACTION);
921
922 /* Clear the content before it's used */
923 SendMessageW(hwndList, CB_RESETCONTENT, 0, 0);
924
925 /* Log off */
926 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_LOGOFF)
927 {
928 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_LOGOFF, szBuffer, _countof(szBuffer));
929 StringCchPrintfW(szBuffer2, _countof(szBuffer2), szBuffer, pgContext->UserName);
930 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer2);
931 if (idx != CB_ERR)
932 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_LOGOFF);
933 }
934
935 /* Shut down - DEFAULT */
936 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_POWER_OFF)
937 {
938 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SHUTDOWN, szBuffer, _countof(szBuffer));
939 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
940 if (idx != CB_ERR)
941 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
942 }
943
944 /* Restart */
945 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_REBOOT)
946 {
947 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_RESTART, szBuffer, _countof(szBuffer));
948 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
949 if (idx != CB_ERR)
950 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
951 }
952
953 // if (pContext->ShutdownOptions & 0x08) {}
954
955 /* Sleep */
956 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_SLEEP)
957 {
958 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SLEEP, szBuffer, _countof(szBuffer));
959 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
960 if (idx != CB_ERR)
961 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_SLEEP);
962 }
963
964 // if (pContext->ShutdownOptions & 0x20) {}
965
966 /* Hibernate */
967 if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_HIBERNATE)
968 {
969 LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_HIBERNATE, szBuffer, _countof(szBuffer));
970 idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
971 if (idx != CB_ERR)
972 SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_HIBERNATE);
973 }
974
975 // if (pContext->ShutdownOptions & 0x80) {}
976
977 /* Set the default shut down selection */
978 count = SendMessageW(hwndList, CB_GETCOUNT, 0, 0);
979 for (i = 0; i < count; i++)
980 {
981 if (SendMessageW(hwndList, CB_GETITEMDATA, i, 0) == pgContext->nShutdownAction)
982 {
983 SendMessageW(hwndList, CB_SETCURSEL, i, 0);
984 break;
985 }
986 }
987
988 /* Update the choice description based on the current selection */
989 UpdateShutdownDesc(hDlg, pContext);
990 }
991
992 static VOID
ShutdownOnOk(IN HWND hDlg,IN PGINA_CONTEXT pgContext)993 ShutdownOnOk(
994 IN HWND hDlg,
995 IN PGINA_CONTEXT pgContext)
996 {
997 INT idx;
998
999 idx = SendDlgItemMessageW(hDlg,
1000 IDC_SHUTDOWN_ACTION,
1001 CB_GETCURSEL,
1002 0,
1003 0);
1004 if (idx != CB_ERR)
1005 {
1006 pgContext->nShutdownAction =
1007 SendDlgItemMessageW(hDlg,
1008 IDC_SHUTDOWN_ACTION,
1009 CB_GETITEMDATA,
1010 idx,
1011 0);
1012 }
1013 }
1014
1015 static INT_PTR
1016 CALLBACK
ShutdownDialogProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)1017 ShutdownDialogProc(
1018 HWND hDlg,
1019 UINT uMsg,
1020 WPARAM wParam,
1021 LPARAM lParam)
1022 {
1023 PSHUTDOWN_DLG_CONTEXT pContext;
1024
1025 pContext = (PSHUTDOWN_DLG_CONTEXT)GetWindowLongPtrW(hDlg, GWLP_USERDATA);
1026
1027 switch (uMsg)
1028 {
1029 case WM_INITDIALOG:
1030 {
1031 pContext = (PSHUTDOWN_DLG_CONTEXT)lParam;
1032 SetWindowLongPtrW(hDlg, GWLP_USERDATA, (LONG_PTR)pContext);
1033
1034 ShutdownOnInit(hDlg, pContext);
1035 return TRUE;
1036 }
1037
1038 case WM_DESTROY:
1039 if (pContext->bFriendlyUI)
1040 {
1041 EndFriendlyDialog(hDlg, pContext);
1042 }
1043 return TRUE;
1044
1045 case WM_ACTIVATE:
1046 {
1047 /*
1048 * If the user deactivates the shutdown dialog (it loses its focus
1049 * while the dialog is not being closed), then destroy the dialog
1050 * and cancel shutdown.
1051 */
1052 if (LOWORD(wParam) == WA_INACTIVE)
1053 {
1054 if (!pContext->bCloseDlg)
1055 {
1056 pContext->bCloseDlg = TRUE;
1057 EndDialog(hDlg, IDCANCEL);
1058 }
1059 }
1060 return FALSE;
1061 }
1062
1063 case WM_CLOSE:
1064 pContext->bCloseDlg = TRUE;
1065 EndDialog(hDlg, IDCANCEL);
1066 break;
1067
1068 case WM_COMMAND:
1069 switch (LOWORD(wParam))
1070 {
1071 case IDC_BUTTON_SHUTDOWN:
1072 ExitWindowsEx(EWX_SHUTDOWN, SHTDN_REASON_MAJOR_OTHER);
1073 break;
1074
1075 case IDC_BUTTON_REBOOT:
1076 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_OTHER);
1077 break;
1078
1079 case IDC_BUTTON_SLEEP:
1080 SetSuspendState(TRUE, TRUE, TRUE);
1081 break;
1082
1083 case IDOK:
1084 ShutdownOnOk(hDlg, pContext->pgContext);
1085
1086 /* Fall back */
1087 case IDCANCEL:
1088 case IDHELP:
1089 pContext->bCloseDlg = TRUE;
1090 EndDialog(hDlg, LOWORD(wParam));
1091 break;
1092
1093 case IDC_SHUTDOWN_ACTION:
1094 UpdateShutdownDesc(hDlg, pContext);
1095 break;
1096 }
1097 break;
1098
1099 case WM_CTLCOLORSTATIC:
1100 {
1101 /* Either make background transparent or fill it with color for required static controls */
1102 HDC hdcStatic = (HDC)wParam;
1103 UINT StaticID = (UINT)GetWindowLongPtrW((HWND)lParam, GWL_ID);
1104
1105 switch (StaticID)
1106 {
1107 case IDC_TURN_OFF_STATIC:
1108 SetTextColor(hdcStatic, DARK_GREY_COLOR);
1109 SetBkMode(hdcStatic, TRANSPARENT);
1110 return (INT_PTR)GetStockObject(HOLLOW_BRUSH);
1111
1112 case IDC_HIBERNATE_STATIC:
1113 case IDC_SHUTDOWN_STATIC:
1114 case IDC_SLEEP_STATIC:
1115 case IDC_RESTART_STATIC:
1116 SetTextColor(hdcStatic, LIGHT_GREY_COLOR);
1117 SetBkMode(hdcStatic, TRANSPARENT);
1118 return (LONG_PTR)pContext->hBrush;
1119 }
1120 return FALSE;
1121 }
1122
1123 case WM_DRAWITEM:
1124 {
1125 /* Draw bitmaps on required buttons */
1126 DRAWITEMSTRUCT* pdis = (DRAWITEMSTRUCT*)lParam;
1127 switch (pdis->CtlID)
1128 {
1129 case IDC_BUTTON_SHUTDOWN:
1130 case IDC_BUTTON_REBOOT:
1131 case IDC_BUTTON_SLEEP:
1132 case IDC_BUTTON_HIBERNATE:
1133 return DrawIconOnOwnerDrawnButtons(pdis, pContext);
1134 }
1135 break;
1136 }
1137
1138 case WM_TIMER:
1139 OnTimer(hDlg, pContext);
1140 return TRUE;
1141
1142 default:
1143 return FALSE;
1144 }
1145 return TRUE;
1146 }
1147
1148 INT_PTR
ShutdownDialog(IN HWND hwndDlg,IN DWORD ShutdownOptions,IN PGINA_CONTEXT pgContext)1149 ShutdownDialog(
1150 IN HWND hwndDlg,
1151 IN DWORD ShutdownOptions,
1152 IN PGINA_CONTEXT pgContext)
1153 {
1154 INT_PTR ret;
1155 SHUTDOWN_DLG_CONTEXT Context;
1156
1157 #if 0
1158 DWORD ShutdownOptions;
1159
1160 // FIXME: User impersonation!!
1161 pgContext->nShutdownAction = LoadShutdownSelState();
1162 ShutdownOptions = GetAllowedShutdownOptions();
1163 #endif
1164
1165 Context.pgContext = pgContext;
1166 Context.ShutdownOptions = ShutdownOptions;
1167 Context.ShutdownDialogId = IDD_SHUTDOWN;
1168 Context.bCloseDlg = FALSE;
1169 Context.bReasonUI = GetShutdownReasonUI();
1170 Context.bFriendlyUI = ShellIsFriendlyUIActive();
1171
1172 if (pgContext->hWlx && pgContext->pWlxFuncs && !Context.bFriendlyUI)
1173 {
1174 ret = pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx,
1175 pgContext->hDllInstance,
1176 MAKEINTRESOURCEW(Context.bReasonUI ? IDD_SHUTDOWN_REASON : IDD_SHUTDOWN),
1177 hwndDlg,
1178 ShutdownDialogProc,
1179 (LPARAM)&Context);
1180 }
1181 else
1182 {
1183 if (Context.bFriendlyUI)
1184 {
1185 if (IsShowHibernateButtonActive())
1186 {
1187 Context.ShutdownDialogId = IDD_SHUTDOWN_FANCY_LONG;
1188 }
1189 else
1190 {
1191 Context.ShutdownDialogId = IDD_SHUTDOWN_FANCY;
1192 }
1193 }
1194
1195 ret = DialogBoxParamW(pgContext->hDllInstance,
1196 MAKEINTRESOURCEW(Context.bReasonUI ? IDD_SHUTDOWN_REASON : Context.ShutdownDialogId),
1197 hwndDlg,
1198 ShutdownDialogProc,
1199 (LPARAM)&Context);
1200 }
1201
1202 #if 0
1203 // FIXME: User impersonation!!
1204 if (ret == IDOK)
1205 SaveShutdownSelState(pgContext->nShutdownAction);
1206 #endif
1207
1208 return ret;
1209 }
1210
1211
1212 /*
1213 * NOTES:
1214 * - Based upon observations on the ShellShutdownDialog() function, the function doesn't actually
1215 * do anything except show a dialog box and returning a value based upon the value chosen. That
1216 * means that any code that calls the function has to execute the chosen action (shut down,
1217 * restart, etc.).
1218 * - When this function is called in Windows XP, it shows the classic dialog box regardless if
1219 * SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\LogonType is enabled or not.
1220 * - When the Help button is pushed, it sends the same return value as IDCANCEL (0x00), but
1221 * at the same time, it calls the help file directly from the dialog box.
1222 * - When the dialog is created, it doesn't disable all other input from the other windows.
1223 * This is done elsewhere. When running the function ShellShutdownDialog() from XP/2K3, if the user clicks
1224 * out of the window, it automatically closes itself.
1225 * - The parameter, lpUsername never seems to be used when calling the function from Windows XP. Either
1226 * it was a parameter that was never used in the final version before release, or it has a use that
1227 * is currently not known.
1228 */
1229 DWORD WINAPI
ShellShutdownDialog(HWND hParent,LPWSTR lpUsername,BOOL bHideLogoff)1230 ShellShutdownDialog(
1231 HWND hParent,
1232 LPWSTR lpUsername,
1233 BOOL bHideLogoff)
1234 {
1235 INT_PTR dlgValue;
1236 DWORD ShutdownOptions;
1237
1238 /*
1239 * As we are called by the shell itself, don't use
1240 * the cached GINA context but use a local copy here.
1241 */
1242 GINA_CONTEXT gContext = { 0 };
1243 DWORD BufferSize;
1244
1245 UNREFERENCED_PARAMETER(lpUsername);
1246
1247 ShutdownOptions = GetAllowedShutdownOptions();
1248 if (bHideLogoff)
1249 ShutdownOptions &= ~WLX_SHUTDOWN_STATE_LOGOFF;
1250
1251 /* Initialize our local GINA context */
1252 gContext.hDllInstance = hDllInstance;
1253 BufferSize = _countof(gContext.UserName);
1254 // NOTE: Only when this function is called, Win checks inside
1255 // HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
1256 // value "Logon User Name", and determines whether it will display
1257 // the user name.
1258 GetUserNameW(gContext.UserName, &BufferSize);
1259 gContext.nShutdownAction = LoadShutdownSelState();
1260
1261 /* Load the shutdown dialog box */
1262 dlgValue = ShutdownDialog(hParent, ShutdownOptions, &gContext);
1263
1264 /* Determine what to do based on user selection */
1265 if (dlgValue == IDOK)
1266 {
1267 SaveShutdownSelState(gContext.nShutdownAction);
1268
1269 switch (gContext.nShutdownAction)
1270 {
1271 case WLX_SAS_ACTION_LOGOFF:
1272 return WLX_SHUTDOWN_STATE_LOGOFF;
1273
1274 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
1275 return WLX_SHUTDOWN_STATE_POWER_OFF;
1276
1277 case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
1278 return WLX_SHUTDOWN_STATE_REBOOT;
1279
1280 // 0x08
1281
1282 case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
1283 return WLX_SHUTDOWN_STATE_SLEEP;
1284
1285 // 0x20
1286
1287 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
1288 return WLX_SHUTDOWN_STATE_HIBERNATE;
1289
1290 // 0x80
1291 }
1292 }
1293 /* Help file is called directly here */
1294 else if (dlgValue == IDHELP)
1295 {
1296 FIXME("Help is not implemented yet.\n");
1297 MessageBoxW(hParent, L"Help is not implemented yet.", L"Message", MB_OK | MB_ICONEXCLAMATION);
1298 }
1299 else if (dlgValue == -1)
1300 {
1301 ERR("Failed to create dialog\n");
1302 }
1303
1304 return 0;
1305 }
1306
1307 /*
1308 * NOTES:
1309 * - Undocumented, called from MS shell32.dll to show the turn off dialog.
1310 * - Seems to have the same purpose as ShellShutdownDialog.
1311 */
1312 DWORD WINAPI
ShellTurnOffDialog(HWND hWnd)1313 ShellTurnOffDialog(HWND hWnd)
1314 {
1315 return ShellShutdownDialog(hWnd, NULL, FALSE);
1316 }
1317