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)
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
19 #define WLX_SHUTDOWN_STATE_SLEEP 0x10
21 #define WLX_SHUTDOWN_STATE_HIBERNATE 0x40
24 typedef struct _SHUTDOWN_DLG_CONTEXT
26 PGINA_CONTEXT pgContext
;
28 DWORD ShutdownOptions
;
32 } SHUTDOWN_DLG_CONTEXT
, *PSHUTDOWN_DLG_CONTEXT
;
37 GetShutdownReasonUI(VOID
)
39 OSVERSIONINFOEX VersionInfo
;
40 DWORD dwValue
, dwSize
;
44 /* Query the policy value */
45 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
46 L
"Software\\Policies\\Microsoft\\Windows NT\\Reliability",
50 if (lRet
== ERROR_SUCCESS
)
53 dwSize
= sizeof(dwValue
);
54 RegQueryValueExW(hKey
,
62 return (dwValue
!= 0) ? TRUE
: FALSE
;
65 /* Query the machine value */
66 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
67 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Reliability",
71 if (lRet
== ERROR_SUCCESS
)
74 dwSize
= sizeof(dwValue
);
75 RegQueryValueExW(hKey
,
83 return (dwValue
!= 0) ? TRUE
: FALSE
;
86 /* Return the default value */
87 VersionInfo
.dwOSVersionInfoSize
= sizeof(VersionInfo
);
88 if (!GetVersionEx((POSVERSIONINFO
)&VersionInfo
))
92 // return (VersionInfo.wProductType == VER_NT_WORKSTATION) ? FALSE : TRUE;
97 IsFriendlyUIActive(VOID
)
99 DWORD dwType
, dwValue
, dwSize
;
103 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
104 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
108 if (lRet
!= ERROR_SUCCESS
)
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) */
115 dwSize
= sizeof(dwValue
);
116 lRet
= RegQueryValueExW(hKey
,
117 L
"EnforceFriendlyShutdown",
123 if (lRet
== ERROR_SUCCESS
&& dwType
== REG_DWORD
&& dwValue
== 0x1)
129 /* Check product version number */
131 dwSize
= sizeof(dwValue
);
132 lRet
= RegQueryValueExW(hKey
,
140 if (lRet
!= ERROR_SUCCESS
|| dwType
!= REG_DWORD
|| dwValue
!= 0x300)
142 /* Allow Friendly UI only on Workstation */
146 /* Check LogonType value */
147 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
148 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
152 if (lRet
!= ERROR_SUCCESS
)
156 dwSize
= sizeof(dwValue
);
157 lRet
= RegQueryValueExW(hKey
,
165 if (lRet
!= ERROR_SUCCESS
|| dwType
!= REG_DWORD
)
168 return (dwValue
!= 0);
181 IsNetwareActive(VOID
)
189 ForceFriendlyUI(VOID
)
191 DWORD dwType
, dwValue
, dwSize
;
195 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
196 L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
200 if (lRet
== ERROR_SUCCESS
)
203 dwSize
= sizeof(dwValue
);
204 lRet
= RegQueryValueExW(hKey
,
212 if (lRet
== ERROR_SUCCESS
&& dwType
== REG_DWORD
)
213 return (dwValue
!= 0);
216 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
217 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
221 if (lRet
== ERROR_SUCCESS
)
224 dwSize
= sizeof(dwValue
);
225 lRet
= RegQueryValueExW(hKey
,
234 if (lRet
== ERROR_SUCCESS
&& dwType
== REG_DWORD
)
235 return (dwValue
!= 0);
243 ShellIsFriendlyUIActive(VOID
)
247 bActive
= IsFriendlyUIActive();
249 if ((IsDomainMember() || IsNetwareActive()) && !ForceFriendlyUI())
256 GetDefaultShutdownSelState(VOID
)
258 return WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
;
262 LoadShutdownSelState(VOID
)
265 HKEY hKeyCurrentUser
, hKey
;
266 DWORD dwValue
, dwTemp
, dwSize
;
268 /* Default to shutdown */
269 dwValue
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
;
271 /* Open the current user HKCU key */
272 lRet
= RegOpenCurrentUser(MAXIMUM_ALLOWED
, &hKeyCurrentUser
);
273 if (lRet
== ERROR_SUCCESS
)
275 /* Open the subkey */
276 lRet
= RegOpenKeyExW(hKeyCurrentUser
,
277 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
278 0, KEY_QUERY_VALUE
, &hKey
);
279 RegCloseKey(hKeyCurrentUser
);
281 if (lRet
!= ERROR_SUCCESS
)
285 dwSize
= sizeof(dwTemp
);
286 lRet
= RegQueryValueExW(hKey
,
289 (LPBYTE
)&dwTemp
, &dwSize
);
292 if (lRet
== ERROR_SUCCESS
)
296 case WLX_SHUTDOWN_STATE_LOGOFF
:
297 dwValue
= WLX_SAS_ACTION_LOGOFF
;
300 case WLX_SHUTDOWN_STATE_POWER_OFF
:
301 dwValue
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
;
304 case WLX_SHUTDOWN_STATE_REBOOT
:
305 dwValue
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
;
310 case WLX_SHUTDOWN_STATE_SLEEP
:
311 dwValue
= WLX_SAS_ACTION_SHUTDOWN_SLEEP
;
316 case WLX_SHUTDOWN_STATE_HIBERNATE
:
317 dwValue
= WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
;
328 SaveShutdownSelState(
329 IN DWORD ShutdownCode
)
332 HKEY hKeyCurrentUser
, hKey
;
335 /* Open the current user HKCU key */
336 lRet
= RegOpenCurrentUser(MAXIMUM_ALLOWED
, &hKeyCurrentUser
);
337 if (lRet
== ERROR_SUCCESS
)
339 /* Create the subkey */
340 lRet
= RegCreateKeyExW(hKeyCurrentUser
,
341 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
343 REG_OPTION_NON_VOLATILE
,
346 RegCloseKey(hKeyCurrentUser
);
348 if (lRet
!= ERROR_SUCCESS
)
351 switch (ShutdownCode
)
353 case WLX_SAS_ACTION_LOGOFF
:
354 dwValue
= WLX_SHUTDOWN_STATE_LOGOFF
;
357 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
:
358 dwValue
= WLX_SHUTDOWN_STATE_POWER_OFF
;
361 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
:
362 dwValue
= WLX_SHUTDOWN_STATE_REBOOT
;
365 case WLX_SAS_ACTION_SHUTDOWN_SLEEP
:
366 dwValue
= WLX_SHUTDOWN_STATE_SLEEP
;
369 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
:
370 dwValue
= WLX_SHUTDOWN_STATE_HIBERNATE
;
377 (LPBYTE
)&dwValue
, sizeof(dwValue
));
382 GetDefaultShutdownOptions(VOID
)
384 return WLX_SHUTDOWN_STATE_POWER_OFF
| WLX_SHUTDOWN_STATE_REBOOT
;
388 GetAllowedShutdownOptions(VOID
)
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
;
395 if (IsPwrSuspendAllowed())
396 Options
|= WLX_SHUTDOWN_STATE_SLEEP
;
398 if (IsPwrHibernateAllowed())
399 Options
|= WLX_SHUTDOWN_STATE_HIBERNATE
;
407 IN PSHUTDOWN_DLG_CONTEXT pContext
) // HINSTANCE hInstance
413 ShutdownCode
= SendDlgItemMessageW(hDlg
, IDC_SHUTDOWN_ACTION
, CB_GETCURSEL
, 0, 0);
414 if (ShutdownCode
== CB_ERR
) // Invalid selection
417 ShutdownCode
= SendDlgItemMessageW(hDlg
, IDC_SHUTDOWN_ACTION
, CB_GETITEMDATA
, ShutdownCode
, 0);
419 switch (ShutdownCode
)
421 case WLX_SAS_ACTION_LOGOFF
:
422 DescId
= IDS_SHUTDOWN_LOGOFF_DESC
;
425 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
:
426 DescId
= IDS_SHUTDOWN_SHUTDOWN_DESC
;
429 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
:
430 DescId
= IDS_SHUTDOWN_RESTART_DESC
;
433 case WLX_SAS_ACTION_SHUTDOWN_SLEEP
:
434 DescId
= IDS_SHUTDOWN_SLEEP_DESC
;
437 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
:
438 DescId
= IDS_SHUTDOWN_HIBERNATE_DESC
;
445 LoadStringW(pContext
->pgContext
->hDllInstance
, DescId
, szBuffer
, _countof(szBuffer
));
446 SetDlgItemTextW(hDlg
, IDC_SHUTDOWN_DESCRIPTION
, szBuffer
);
448 if (pContext
->bReasonUI
)
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
));
459 IN PSHUTDOWN_DLG_CONTEXT pContext
)
461 PGINA_CONTEXT pgContext
= pContext
->pgContext
;
465 WCHAR szBuffer2
[256];
467 hwndList
= GetDlgItem(hDlg
, IDC_SHUTDOWN_ACTION
);
469 /* Clear the content before it's used */
470 SendMessageW(hwndList
, CB_RESETCONTENT
, 0, 0);
473 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_LOGOFF
)
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
);
479 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_LOGOFF
);
482 /* Shut down - DEFAULT */
483 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_POWER_OFF
)
485 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_SHUTDOWN
, szBuffer
, _countof(szBuffer
));
486 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
488 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
);
490 else if (pContext
->bFriendlyUI
)
492 EnableWindow(GetDlgItem(hDlg
, IDC_BUTTON_SHUTDOWN
), FALSE
);
496 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_REBOOT
)
498 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_RESTART
, szBuffer
, _countof(szBuffer
));
499 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
501 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_REBOOT
);
503 else if (pContext
->bFriendlyUI
)
505 EnableWindow(GetDlgItem(hDlg
, IDC_BUTTON_REBOOT
), FALSE
);
508 // if (pContext->ShutdownOptions & 0x08) {}
511 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_SLEEP
)
513 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_SLEEP
, szBuffer
, _countof(szBuffer
));
514 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
516 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_SLEEP
);
518 else if (pContext
->bFriendlyUI
)
520 EnableWindow(GetDlgItem(hDlg
, IDC_BUTTON_SLEEP
), FALSE
);
523 // if (pContext->ShutdownOptions & 0x20) {}
526 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_HIBERNATE
)
528 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_HIBERNATE
, szBuffer
, _countof(szBuffer
));
529 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
531 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
);
534 // if (pContext->ShutdownOptions & 0x80) {}
536 /* Set the default shut down selection */
537 count
= SendMessageW(hwndList
, CB_GETCOUNT
, 0, 0);
538 for (i
= 0; i
< count
; i
++)
540 if (SendMessageW(hwndList
, CB_GETITEMDATA
, i
, 0) == pgContext
->nShutdownAction
)
542 SendMessageW(hwndList
, CB_SETCURSEL
, i
, 0);
547 /* Update the choice description based on the current selection */
548 UpdateShutdownDesc(hDlg
, pContext
);
554 IN PGINA_CONTEXT pgContext
)
558 idx
= SendDlgItemMessageW(hDlg
,
565 pgContext
->nShutdownAction
=
566 SendDlgItemMessageW(hDlg
,
582 PSHUTDOWN_DLG_CONTEXT pContext
;
584 pContext
= (PSHUTDOWN_DLG_CONTEXT
)GetWindowLongPtrW(hDlg
, GWLP_USERDATA
);
590 pContext
= (PSHUTDOWN_DLG_CONTEXT
)lParam
;
591 SetWindowLongPtrW(hDlg
, GWLP_USERDATA
, (LONG_PTR
)pContext
);
593 ShutdownOnInit(hDlg
, pContext
);
595 /* Draw the logo bitmap */
597 LoadImageW(pContext
->pgContext
->hDllInstance
, MAKEINTRESOURCEW(IDI_ROSLOGO
), IMAGE_BITMAP
, 0, 0, LR_DEFAULTCOLOR
);
602 DeleteObject(pContext
->hBitmap
);
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.
612 if (LOWORD(wParam
) == WA_INACTIVE
)
614 if (!pContext
->bCloseDlg
)
616 pContext
->bCloseDlg
= TRUE
;
626 if (pContext
->hBitmap
)
628 BeginPaint(hDlg
, &ps
);
629 DrawStateW(ps
.hdc
, NULL
, NULL
, (LPARAM
)pContext
->hBitmap
, (WPARAM
)0, 0, 0, 0, 0, DST_BITMAP
);
636 pContext
->bCloseDlg
= TRUE
;
637 EndDialog(hDlg
, IDCANCEL
);
641 switch (LOWORD(wParam
))
643 case IDC_BUTTON_SHUTDOWN
:
644 ExitWindowsEx(EWX_SHUTDOWN
, SHTDN_REASON_MAJOR_OTHER
);
647 case IDC_BUTTON_REBOOT
:
648 ExitWindowsEx(EWX_REBOOT
, SHTDN_REASON_MAJOR_OTHER
);
651 case IDC_BUTTON_SLEEP
:
652 SetSuspendState(TRUE
, TRUE
, TRUE
);
656 ShutdownOnOk(hDlg
, pContext
->pgContext
);
661 pContext
->bCloseDlg
= TRUE
;
662 EndDialog(hDlg
, LOWORD(wParam
));
665 case IDC_SHUTDOWN_ACTION
:
666 UpdateShutdownDesc(hDlg
, pContext
);
680 IN DWORD ShutdownOptions
,
681 IN PGINA_CONTEXT pgContext
)
684 SHUTDOWN_DLG_CONTEXT Context
;
685 DWORD ShutdownDialogId
= IDD_SHUTDOWN
;
688 DWORD ShutdownOptions
;
690 // FIXME: User impersonation!!
691 pgContext
->nShutdownAction
= LoadShutdownSelState();
692 ShutdownOptions
= GetAllowedShutdownOptions();
695 Context
.pgContext
= pgContext
;
696 Context
.ShutdownOptions
= ShutdownOptions
;
697 Context
.bCloseDlg
= FALSE
;
698 Context
.bReasonUI
= GetShutdownReasonUI();
699 Context
.bFriendlyUI
= ShellIsFriendlyUIActive();
701 if (pgContext
->hWlx
&& pgContext
->pWlxFuncs
&& !Context
.bFriendlyUI
)
703 ret
= pgContext
->pWlxFuncs
->WlxDialogBoxParam(pgContext
->hWlx
,
704 pgContext
->hDllInstance
,
705 MAKEINTRESOURCEW(Context
.bReasonUI
? IDD_SHUTDOWN_REASON
: IDD_SHUTDOWN
),
712 if (Context
.bFriendlyUI
)
714 ShutdownDialogId
= IDD_SHUTDOWN_FANCY
;
717 ret
= DialogBoxParamW(pgContext
->hDllInstance
,
718 MAKEINTRESOURCEW(Context
.bReasonUI
? IDD_SHUTDOWN_REASON
: ShutdownDialogId
),
725 // FIXME: User impersonation!!
727 SaveShutdownSelState(pgContext
->nShutdownAction
);
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,
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.
758 DWORD ShutdownOptions
;
761 * As we are called by the shell itself, don't use
762 * the cached GINA context but use a local copy here.
764 GINA_CONTEXT gContext
= { 0 };
767 UNREFERENCED_PARAMETER(lpUsername
);
769 ShutdownOptions
= GetAllowedShutdownOptions();
771 ShutdownOptions
&= ~WLX_SHUTDOWN_STATE_LOGOFF
;
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
780 GetUserNameW(gContext
.UserName
, &BufferSize
);
781 gContext
.nShutdownAction
= LoadShutdownSelState();
783 /* Load the shutdown dialog box */
784 dlgValue
= ShutdownDialog(hParent
, ShutdownOptions
, &gContext
);
786 /* Determine what to do based on user selection */
787 if (dlgValue
== IDOK
)
789 SaveShutdownSelState(gContext
.nShutdownAction
);
791 switch (gContext
.nShutdownAction
)
793 case WLX_SAS_ACTION_LOGOFF
:
794 return WLX_SHUTDOWN_STATE_LOGOFF
;
796 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
:
797 return WLX_SHUTDOWN_STATE_POWER_OFF
;
799 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
:
800 return WLX_SHUTDOWN_STATE_REBOOT
;
804 case WLX_SAS_ACTION_SHUTDOWN_SLEEP
:
805 return WLX_SHUTDOWN_STATE_SLEEP
;
809 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
:
810 return WLX_SHUTDOWN_STATE_HIBERNATE
;
815 /* Help file is called directly here */
816 else if (dlgValue
== IDHELP
)
818 FIXME("Help is not implemented yet.");
819 MessageBoxW(hParent
, L
"Help is not implemented yet.", L
"Message", MB_OK
| MB_ICONEXCLAMATION
);
821 else if (dlgValue
== -1)
823 ERR("Failed to create dialog\n");
831 * - Undocumented, called from MS shell32.dll to show the turn off dialog.
832 * - Seems to have the same purpose as ShellShutdownDialog.
835 ShellTurnOffDialog(HWND hWnd
)
837 return ShellShutdownDialog(hWnd
, NULL
, FALSE
);