xref: /reactos/dll/win32/msgina/shutdown.c (revision 8a978a17)
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  */
9 
10 #include "msgina.h"
11 #include <powrprof.h>
12 #include <wingdi.h>
13 
14 /* Shutdown state flags */
15 #define WLX_SHUTDOWN_STATE_LOGOFF       0x01
16 #define WLX_SHUTDOWN_STATE_POWER_OFF    0x02
17 #define WLX_SHUTDOWN_STATE_REBOOT       0x04
18 // 0x08
19 #define WLX_SHUTDOWN_STATE_SLEEP        0x10
20 // 0x20
21 #define WLX_SHUTDOWN_STATE_HIBERNATE    0x40
22 // 0x80
23 
24 typedef struct _SHUTDOWN_DLG_CONTEXT
25 {
26     PGINA_CONTEXT pgContext;
27     HBITMAP hBitmap;
28     DWORD ShutdownOptions;
29     BOOL bCloseDlg;
30     BOOL bReasonUI;
31     BOOL bFriendlyUI;
32 } SHUTDOWN_DLG_CONTEXT, *PSHUTDOWN_DLG_CONTEXT;
33 
34 
35 static
36 BOOL
37 GetShutdownReasonUI(VOID)
38 {
39     OSVERSIONINFOEX VersionInfo;
40     DWORD dwValue, dwSize;
41     HKEY hKey;
42     LONG lRet;
43 
44     /* Query the policy value */
45     lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
46                          L"Software\\Policies\\Microsoft\\Windows NT\\Reliability",
47                          0,
48                          KEY_QUERY_VALUE,
49                          &hKey);
50     if (lRet == ERROR_SUCCESS)
51     {
52         dwValue = 0;
53         dwSize = sizeof(dwValue);
54         RegQueryValueExW(hKey,
55                          L"ShutdownReasonUI",
56                          NULL,
57                          NULL,
58                          (LPBYTE)&dwValue,
59                          &dwSize);
60         RegCloseKey(hKey);
61 
62         return (dwValue != 0) ? TRUE : FALSE;
63     }
64 
65     /* Query the machine value */
66     lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
67                          L"Software\\Microsoft\\Windows\\CurrentVersion\\Reliability",
68                          0,
69                          KEY_QUERY_VALUE,
70                          &hKey);
71     if (lRet == ERROR_SUCCESS)
72     {
73         dwValue = 0;
74         dwSize = sizeof(dwValue);
75         RegQueryValueExW(hKey,
76                          L"ShutdownReasonUI",
77                          NULL,
78                          NULL,
79                          (LPBYTE)&dwValue,
80                          &dwSize);
81         RegCloseKey(hKey);
82 
83         return (dwValue != 0) ? TRUE : FALSE;
84     }
85 
86     /* Return the default value */
87     VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
88     if (!GetVersionEx((POSVERSIONINFO)&VersionInfo))
89         return FALSE;
90 
91     return FALSE;
92 //    return (VersionInfo.wProductType == VER_NT_WORKSTATION) ? FALSE : TRUE;
93 }
94 
95 static
96 BOOL
97 IsFriendlyUIActive(VOID)
98 {
99     DWORD dwType, dwValue, dwSize;
100     HKEY hKey;
101     LONG lRet;
102 
103     lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
104                          L"SYSTEM\\CurrentControlSet\\Control\\Windows",
105                          0,
106                          KEY_QUERY_VALUE,
107                          &hKey);
108     if (lRet != ERROR_SUCCESS)
109         return FALSE;
110 
111     /* CORE-17282 First check an optional ReactOS specific override, that Windows does not check.
112        We use this to allow users pairing 'Server'-configuration with FriendlyShutdown.
113        Otherwise users would have to change CSDVersion or LogonType (side-effects AppCompat) */
114     dwValue = 0;
115     dwSize = sizeof(dwValue);
116     lRet = RegQueryValueExW(hKey,
117                             L"EnforceFriendlyShutdown",
118                             NULL,
119                             &dwType,
120                             (LPBYTE)&dwValue,
121                             &dwSize);
122 
123     if (lRet == ERROR_SUCCESS && dwType == REG_DWORD && dwValue == 0x1)
124     {
125         RegCloseKey(hKey);
126         return TRUE;
127     }
128 
129     /* Check product version number */
130     dwValue = 0;
131     dwSize = sizeof(dwValue);
132     lRet = RegQueryValueExW(hKey,
133                             L"CSDVersion",
134                             NULL,
135                             &dwType,
136                             (LPBYTE)&dwValue,
137                             &dwSize);
138     RegCloseKey(hKey);
139 
140     if (lRet != ERROR_SUCCESS || dwType != REG_DWORD || dwValue != 0x300)
141     {
142         /* Allow Friendly UI only on Workstation */
143         return FALSE;
144     }
145 
146     /* Check LogonType value */
147     lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
148                          L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
149                          0,
150                          KEY_QUERY_VALUE,
151                          &hKey);
152     if (lRet != ERROR_SUCCESS)
153         return FALSE;
154 
155     dwValue = 0;
156     dwSize = sizeof(dwValue);
157     lRet = RegQueryValueExW(hKey,
158                             L"LogonType",
159                             NULL,
160                             &dwType,
161                             (LPBYTE)&dwValue,
162                             &dwSize);
163     RegCloseKey(hKey);
164 
165     if (lRet != ERROR_SUCCESS || dwType != REG_DWORD)
166         return FALSE;
167 
168     return (dwValue != 0);
169 }
170 
171 static
172 BOOL
173 IsDomainMember(VOID)
174 {
175     UNIMPLEMENTED;
176     return FALSE;
177 }
178 
179 static
180 BOOL
181 IsNetwareActive(VOID)
182 {
183     UNIMPLEMENTED;
184     return FALSE;
185 }
186 
187 static
188 BOOL
189 ForceFriendlyUI(VOID)
190 {
191     DWORD dwType, dwValue, dwSize;
192     HKEY hKey;
193     LONG lRet;
194 
195     lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
196                          L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
197                          0,
198                          KEY_QUERY_VALUE,
199                          &hKey);
200     if (lRet == ERROR_SUCCESS)
201     {
202         dwValue = 0;
203         dwSize = sizeof(dwValue);
204         lRet = RegQueryValueExW(hKey,
205                                 L"ForceFriendlyUI",
206                                 NULL,
207                                 &dwType,
208                                 (LPBYTE)&dwValue,
209                                 &dwSize);
210         RegCloseKey(hKey);
211 
212         if (lRet == ERROR_SUCCESS && dwType == REG_DWORD)
213             return (dwValue != 0);
214     }
215 
216     lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
217                          L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
218                          0,
219                          KEY_QUERY_VALUE,
220                          &hKey);
221     if (lRet == ERROR_SUCCESS)
222     {
223         dwValue = 0;
224         dwSize = sizeof(dwValue);
225         lRet = RegQueryValueExW(hKey,
226                                 L"ForceFriendlyUI",
227                                 NULL,
228                                 &dwType,
229                                 (LPBYTE)&dwValue,
230                                 &dwSize);
231 
232         RegCloseKey(hKey);
233 
234         if (lRet == ERROR_SUCCESS && dwType == REG_DWORD)
235             return (dwValue != 0);
236     }
237 
238     return FALSE;
239 }
240 
241 BOOL
242 WINAPI
243 ShellIsFriendlyUIActive(VOID)
244 {
245     BOOL bActive;
246 
247     bActive = IsFriendlyUIActive();
248 
249     if ((IsDomainMember() || IsNetwareActive()) && !ForceFriendlyUI())
250         return FALSE;
251 
252     return bActive;
253 }
254 
255 DWORD
256 GetDefaultShutdownSelState(VOID)
257 {
258     return WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
259 }
260 
261 DWORD
262 LoadShutdownSelState(VOID)
263 {
264     LONG lRet;
265     HKEY hKeyCurrentUser, hKey;
266     DWORD dwValue, dwTemp, dwSize;
267 
268     /* Default to shutdown */
269     dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
270 
271     /* Open the current user HKCU key */
272     lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
273     if (lRet == ERROR_SUCCESS)
274     {
275         /* Open the subkey */
276         lRet = RegOpenKeyExW(hKeyCurrentUser,
277                              L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
278                              0, KEY_QUERY_VALUE, &hKey);
279         RegCloseKey(hKeyCurrentUser);
280     }
281     if (lRet != ERROR_SUCCESS)
282         return dwValue;
283 
284     /* Read the value */
285     dwSize = sizeof(dwTemp);
286     lRet = RegQueryValueExW(hKey,
287                             L"Shutdown Setting",
288                             NULL, NULL,
289                             (LPBYTE)&dwTemp, &dwSize);
290     RegCloseKey(hKey);
291 
292     if (lRet == ERROR_SUCCESS)
293     {
294         switch (dwTemp)
295         {
296             case WLX_SHUTDOWN_STATE_LOGOFF:
297                 dwValue = WLX_SAS_ACTION_LOGOFF;
298                 break;
299 
300             case WLX_SHUTDOWN_STATE_POWER_OFF:
301                 dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
302                 break;
303 
304             case WLX_SHUTDOWN_STATE_REBOOT:
305                 dwValue = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
306                 break;
307 
308             // 0x08
309 
310             case WLX_SHUTDOWN_STATE_SLEEP:
311                 dwValue = WLX_SAS_ACTION_SHUTDOWN_SLEEP;
312                 break;
313 
314             // 0x20
315 
316             case WLX_SHUTDOWN_STATE_HIBERNATE:
317                 dwValue = WLX_SAS_ACTION_SHUTDOWN_HIBERNATE;
318                 break;
319 
320             // 0x80
321         }
322     }
323 
324     return dwValue;
325 }
326 
327 VOID
328 SaveShutdownSelState(
329     IN DWORD ShutdownCode)
330 {
331     LONG lRet;
332     HKEY hKeyCurrentUser, hKey;
333     DWORD dwValue = 0;
334 
335     /* Open the current user HKCU key */
336     lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
337     if (lRet == ERROR_SUCCESS)
338     {
339         /* Create the subkey */
340         lRet = RegCreateKeyExW(hKeyCurrentUser,
341                                L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
342                                0, NULL,
343                                REG_OPTION_NON_VOLATILE,
344                                KEY_SET_VALUE,
345                                NULL, &hKey, NULL);
346         RegCloseKey(hKeyCurrentUser);
347     }
348     if (lRet != ERROR_SUCCESS)
349         return;
350 
351     switch (ShutdownCode)
352     {
353         case WLX_SAS_ACTION_LOGOFF:
354             dwValue = WLX_SHUTDOWN_STATE_LOGOFF;
355             break;
356 
357         case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
358             dwValue = WLX_SHUTDOWN_STATE_POWER_OFF;
359             break;
360 
361         case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
362             dwValue = WLX_SHUTDOWN_STATE_REBOOT;
363             break;
364 
365         case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
366             dwValue = WLX_SHUTDOWN_STATE_SLEEP;
367             break;
368 
369         case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
370             dwValue = WLX_SHUTDOWN_STATE_HIBERNATE;
371             break;
372     }
373 
374     RegSetValueExW(hKey,
375                    L"Shutdown Setting",
376                    0, REG_DWORD,
377                    (LPBYTE)&dwValue, sizeof(dwValue));
378     RegCloseKey(hKey);
379 }
380 
381 DWORD
382 GetDefaultShutdownOptions(VOID)
383 {
384     return WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
385 }
386 
387 DWORD
388 GetAllowedShutdownOptions(VOID)
389 {
390     DWORD Options = 0;
391 
392     // FIXME: Compute those options accordings to current user's rights!
393     Options |= WLX_SHUTDOWN_STATE_LOGOFF | WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
394 
395     if (IsPwrSuspendAllowed())
396         Options |= WLX_SHUTDOWN_STATE_SLEEP;
397 
398     if (IsPwrHibernateAllowed())
399         Options |= WLX_SHUTDOWN_STATE_HIBERNATE;
400 
401     return Options;
402 }
403 
404 static VOID
405 UpdateShutdownDesc(
406     IN HWND hDlg,
407     IN PSHUTDOWN_DLG_CONTEXT pContext) // HINSTANCE hInstance
408 {
409     UINT DescId = 0;
410     DWORD ShutdownCode;
411     WCHAR szBuffer[256];
412 
413     ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_ACTION, CB_GETCURSEL, 0, 0);
414     if (ShutdownCode == CB_ERR) // Invalid selection
415         return;
416 
417     ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_ACTION, CB_GETITEMDATA, ShutdownCode, 0);
418 
419     switch (ShutdownCode)
420     {
421         case WLX_SAS_ACTION_LOGOFF:
422             DescId = IDS_SHUTDOWN_LOGOFF_DESC;
423             break;
424 
425         case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
426             DescId = IDS_SHUTDOWN_SHUTDOWN_DESC;
427             break;
428 
429         case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
430             DescId = IDS_SHUTDOWN_RESTART_DESC;
431             break;
432 
433         case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
434             DescId = IDS_SHUTDOWN_SLEEP_DESC;
435             break;
436 
437         case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
438             DescId = IDS_SHUTDOWN_HIBERNATE_DESC;
439             break;
440 
441         default:
442             break;
443     }
444 
445     LoadStringW(pContext->pgContext->hDllInstance, DescId, szBuffer, _countof(szBuffer));
446     SetDlgItemTextW(hDlg, IDC_SHUTDOWN_DESCRIPTION, szBuffer);
447 
448     if (pContext->bReasonUI)
449     {
450         EnableWindow(GetDlgItem(hDlg, IDC_REASON_PLANNED), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
451         EnableWindow(GetDlgItem(hDlg, IDC_REASON_LIST), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
452         EnableWindow(GetDlgItem(hDlg, IDC_REASON_COMMENT), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
453     }
454 }
455 
456 static VOID
457 ShutdownOnInit(
458     IN HWND hDlg,
459     IN PSHUTDOWN_DLG_CONTEXT pContext)
460 {
461     PGINA_CONTEXT pgContext = pContext->pgContext;
462     HWND hwndList;
463     INT idx, count, i;
464     WCHAR szBuffer[256];
465     WCHAR szBuffer2[256];
466 
467     hwndList = GetDlgItem(hDlg, IDC_SHUTDOWN_ACTION);
468 
469     /* Clear the content before it's used */
470     SendMessageW(hwndList, CB_RESETCONTENT, 0, 0);
471 
472     /* Log off */
473     if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_LOGOFF)
474     {
475         LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_LOGOFF, szBuffer, _countof(szBuffer));
476         StringCchPrintfW(szBuffer2, _countof(szBuffer2), szBuffer, pgContext->UserName);
477         idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer2);
478         if (idx != CB_ERR)
479             SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_LOGOFF);
480     }
481 
482     /* Shut down - DEFAULT */
483     if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_POWER_OFF)
484     {
485         LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SHUTDOWN, szBuffer, _countof(szBuffer));
486         idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
487         if (idx != CB_ERR)
488             SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
489     }
490     else if (pContext->bFriendlyUI)
491     {
492         EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SHUTDOWN), FALSE);
493     }
494 
495     /* Restart */
496     if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_REBOOT)
497     {
498         LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_RESTART, szBuffer, _countof(szBuffer));
499         idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
500         if (idx != CB_ERR)
501             SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
502     }
503     else if (pContext->bFriendlyUI)
504     {
505         EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_REBOOT), FALSE);
506     }
507 
508     // if (pContext->ShutdownOptions & 0x08) {}
509 
510     /* Sleep */
511     if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_SLEEP)
512     {
513         LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SLEEP, szBuffer, _countof(szBuffer));
514         idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
515         if (idx != CB_ERR)
516             SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_SLEEP);
517     }
518     else if (pContext->bFriendlyUI)
519     {
520         EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SLEEP), FALSE);
521     }
522 
523     // if (pContext->ShutdownOptions & 0x20) {}
524 
525     /* Hibernate */
526     if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_HIBERNATE)
527     {
528         LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_HIBERNATE, szBuffer, _countof(szBuffer));
529         idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
530         if (idx != CB_ERR)
531             SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_HIBERNATE);
532     }
533 
534     // if (pContext->ShutdownOptions & 0x80) {}
535 
536     /* Set the default shut down selection */
537     count = SendMessageW(hwndList, CB_GETCOUNT, 0, 0);
538     for (i = 0; i < count; i++)
539     {
540         if (SendMessageW(hwndList, CB_GETITEMDATA, i, 0) == pgContext->nShutdownAction)
541         {
542             SendMessageW(hwndList, CB_SETCURSEL, i, 0);
543             break;
544         }
545     }
546 
547     /* Update the choice description based on the current selection */
548     UpdateShutdownDesc(hDlg, pContext);
549 }
550 
551 static VOID
552 ShutdownOnOk(
553     IN HWND hDlg,
554     IN PGINA_CONTEXT pgContext)
555 {
556     INT idx;
557 
558     idx = SendDlgItemMessageW(hDlg,
559                               IDC_SHUTDOWN_ACTION,
560                               CB_GETCURSEL,
561                               0,
562                               0);
563     if (idx != CB_ERR)
564     {
565         pgContext->nShutdownAction =
566             SendDlgItemMessageW(hDlg,
567                                 IDC_SHUTDOWN_ACTION,
568                                 CB_GETITEMDATA,
569                                 idx,
570                                 0);
571     }
572 }
573 
574 static INT_PTR
575 CALLBACK
576 ShutdownDialogProc(
577     HWND hDlg,
578     UINT uMsg,
579     WPARAM wParam,
580     LPARAM lParam)
581 {
582     PSHUTDOWN_DLG_CONTEXT pContext;
583 
584     pContext = (PSHUTDOWN_DLG_CONTEXT)GetWindowLongPtrW(hDlg, GWLP_USERDATA);
585 
586     switch (uMsg)
587     {
588         case WM_INITDIALOG:
589         {
590             pContext = (PSHUTDOWN_DLG_CONTEXT)lParam;
591             SetWindowLongPtrW(hDlg, GWLP_USERDATA, (LONG_PTR)pContext);
592 
593             ShutdownOnInit(hDlg, pContext);
594 
595             /* Draw the logo bitmap */
596             pContext->hBitmap =
597                 LoadImageW(pContext->pgContext->hDllInstance, MAKEINTRESOURCEW(IDI_ROSLOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
598             return TRUE;
599         }
600 
601         case WM_DESTROY:
602             DeleteObject(pContext->hBitmap);
603             return TRUE;
604 
605         case WM_ACTIVATE:
606         {
607             /*
608              * If the user deactivates the shutdown dialog (it loses its focus
609              * while the dialog is not being closed), then destroy the dialog
610              * and cancel shutdown.
611              */
612             if (LOWORD(wParam) == WA_INACTIVE)
613             {
614                 if (!pContext->bCloseDlg)
615                 {
616                     pContext->bCloseDlg = TRUE;
617                     EndDialog(hDlg, 0);
618                 }
619             }
620             return FALSE;
621         }
622 
623         case WM_PAINT:
624         {
625             PAINTSTRUCT ps;
626             if (pContext->hBitmap)
627             {
628                 BeginPaint(hDlg, &ps);
629                 DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pContext->hBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
630                 EndPaint(hDlg, &ps);
631             }
632             return TRUE;
633         }
634 
635         case WM_CLOSE:
636             pContext->bCloseDlg = TRUE;
637             EndDialog(hDlg, IDCANCEL);
638             break;
639 
640         case WM_COMMAND:
641             switch (LOWORD(wParam))
642             {
643                 case IDC_BUTTON_SHUTDOWN:
644                     ExitWindowsEx(EWX_SHUTDOWN, SHTDN_REASON_MAJOR_OTHER);
645                     break;
646 
647                 case IDC_BUTTON_REBOOT:
648                     ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_OTHER);
649                     break;
650 
651                 case IDC_BUTTON_SLEEP:
652                     SetSuspendState(TRUE, TRUE, TRUE);
653                     break;
654 
655                 case IDOK:
656                     ShutdownOnOk(hDlg, pContext->pgContext);
657 
658                 /* Fall back */
659                 case IDCANCEL:
660                 case IDHELP:
661                     pContext->bCloseDlg = TRUE;
662                     EndDialog(hDlg, LOWORD(wParam));
663                     break;
664 
665                 case IDC_SHUTDOWN_ACTION:
666                     UpdateShutdownDesc(hDlg, pContext);
667                     break;
668             }
669             break;
670 
671         default:
672             return FALSE;
673     }
674     return TRUE;
675 }
676 
677 INT_PTR
678 ShutdownDialog(
679     IN HWND hwndDlg,
680     IN DWORD ShutdownOptions,
681     IN PGINA_CONTEXT pgContext)
682 {
683     INT_PTR ret;
684     SHUTDOWN_DLG_CONTEXT Context;
685     DWORD ShutdownDialogId = IDD_SHUTDOWN;
686 
687 #if 0
688     DWORD ShutdownOptions;
689 
690     // FIXME: User impersonation!!
691     pgContext->nShutdownAction = LoadShutdownSelState();
692     ShutdownOptions = GetAllowedShutdownOptions();
693 #endif
694 
695     Context.pgContext = pgContext;
696     Context.ShutdownOptions = ShutdownOptions;
697     Context.bCloseDlg = FALSE;
698     Context.bReasonUI = GetShutdownReasonUI();
699     Context.bFriendlyUI = ShellIsFriendlyUIActive();
700 
701     if (pgContext->hWlx && pgContext->pWlxFuncs && !Context.bFriendlyUI)
702     {
703         ret = pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx,
704                                                       pgContext->hDllInstance,
705                                                       MAKEINTRESOURCEW(Context.bReasonUI ? IDD_SHUTDOWN_REASON : IDD_SHUTDOWN),
706                                                       hwndDlg,
707                                                       ShutdownDialogProc,
708                                                       (LPARAM)&Context);
709     }
710     else
711     {
712         if (Context.bFriendlyUI)
713         {
714             ShutdownDialogId = IDD_SHUTDOWN_FANCY;
715         }
716 
717         ret = DialogBoxParamW(pgContext->hDllInstance,
718                               MAKEINTRESOURCEW(Context.bReasonUI ? IDD_SHUTDOWN_REASON : ShutdownDialogId),
719                               hwndDlg,
720                               ShutdownDialogProc,
721                               (LPARAM)&Context);
722     }
723 
724 #if 0
725     // FIXME: User impersonation!!
726     if (ret == IDOK)
727         SaveShutdownSelState(pgContext->nShutdownAction);
728 #endif
729 
730     return ret;
731 }
732 
733 
734 /*
735  * NOTES:
736  * - Based upon observations on the ShellShutdownDialog() function, the function doesn't actually
737  *   do anything except show a dialog box and returning a value based upon the value chosen. That
738  *   means that any code that calls the function has to execute the chosen action (shut down,
739  *   restart, etc.).
740  * - When this function is called in Windows XP, it shows the classic dialog box regardless if
741  *   SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\LogonType is enabled or not.
742  * - When the Help button is pushed, it sends the same return value as IDCANCEL (0x00), but
743  *   at the same time, it calls the help file directly from the dialog box.
744  * - When the dialog is created, it doesn't disable all other input from the other windows.
745  *   This is done elsewhere. When running the function ShellShutdownDialog() from XP/2K3, if the user clicks
746  *   out of the window, it automatically closes itself.
747  * - The parameter, lpUsername never seems to be used when calling the function from Windows XP. Either
748  *   it was a parameter that was never used in the final version before release, or it has a use that
749  *   is currently not known.
750  */
751 DWORD WINAPI
752 ShellShutdownDialog(
753     HWND   hParent,
754     LPWSTR lpUsername,
755     BOOL   bHideLogoff)
756 {
757     INT_PTR dlgValue;
758     DWORD ShutdownOptions;
759 
760     /*
761      * As we are called by the shell itself, don't use
762      * the cached GINA context but use a local copy here.
763      */
764     GINA_CONTEXT gContext = { 0 };
765     DWORD BufferSize;
766 
767     UNREFERENCED_PARAMETER(lpUsername);
768 
769     ShutdownOptions = GetAllowedShutdownOptions();
770     if (bHideLogoff)
771         ShutdownOptions &= ~WLX_SHUTDOWN_STATE_LOGOFF;
772 
773     /* Initialize our local GINA context */
774     gContext.hDllInstance = hDllInstance;
775     BufferSize = _countof(gContext.UserName);
776     // NOTE: Only when this function is called, Win checks inside
777     // HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
778     // value "Logon User Name", and determines whether it will display
779     // the user name.
780     GetUserNameW(gContext.UserName, &BufferSize);
781     gContext.nShutdownAction = LoadShutdownSelState();
782 
783     /* Load the shutdown dialog box */
784     dlgValue = ShutdownDialog(hParent, ShutdownOptions, &gContext);
785 
786     /* Determine what to do based on user selection */
787     if (dlgValue == IDOK)
788     {
789         SaveShutdownSelState(gContext.nShutdownAction);
790 
791         switch (gContext.nShutdownAction)
792         {
793             case WLX_SAS_ACTION_LOGOFF:
794                 return WLX_SHUTDOWN_STATE_LOGOFF;
795 
796             case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
797                 return WLX_SHUTDOWN_STATE_POWER_OFF;
798 
799             case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
800                 return WLX_SHUTDOWN_STATE_REBOOT;
801 
802             // 0x08
803 
804             case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
805                 return WLX_SHUTDOWN_STATE_SLEEP;
806 
807             // 0x20
808 
809             case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
810                 return WLX_SHUTDOWN_STATE_HIBERNATE;
811 
812             // 0x80
813         }
814     }
815     /* Help file is called directly here */
816     else if (dlgValue == IDHELP)
817     {
818         FIXME("Help is not implemented yet.");
819         MessageBoxW(hParent, L"Help is not implemented yet.", L"Message", MB_OK | MB_ICONEXCLAMATION);
820     }
821     else if (dlgValue == -1)
822     {
823         ERR("Failed to create dialog\n");
824     }
825 
826     return 0;
827 }
828