[MSGINA] Implement ShellTurnOffDialog (#3254)
[reactos.git] / dll / win32 / msgina / shutdown.c
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
829 /*
830 * NOTES:
831 * - Undocumented, called from MS shell32.dll to show the turn off dialog.
832 * - Seems to have the same purpose as ShellShutdownDialog.
833 */
834 DWORD WINAPI
835 ShellTurnOffDialog(HWND hWnd)
836 {
837 return ShellShutdownDialog(hWnd, NULL, FALSE);
838 }