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
;
31 } SHUTDOWN_DLG_CONTEXT
, *PSHUTDOWN_DLG_CONTEXT
;
36 GetShutdownReasonUI(VOID
)
38 OSVERSIONINFOEX VersionInfo
;
39 DWORD dwValue
, dwSize
;
43 /* Query the policy value */
44 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
45 L
"Software\\Policies\\Microsoft\\Windows NT\\Reliability",
49 if (lRet
== ERROR_SUCCESS
)
52 dwSize
= sizeof(dwValue
);
53 RegQueryValueExW(hKey
,
61 return (dwValue
!= 0) ? TRUE
: FALSE
;
64 /* Query the machine value */
65 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
66 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Reliability",
70 if (lRet
== ERROR_SUCCESS
)
73 dwSize
= sizeof(dwValue
);
74 RegQueryValueExW(hKey
,
82 return (dwValue
!= 0) ? TRUE
: FALSE
;
85 /* Return the default value */
86 VersionInfo
.dwOSVersionInfoSize
= sizeof(VersionInfo
);
87 if (!GetVersionEx((POSVERSIONINFO
)&VersionInfo
))
91 // return (VersionInfo.wProductType == VER_NT_WORKSTATION) ? FALSE : TRUE;
95 GetDefaultShutdownSelState(VOID
)
97 return WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
;
101 LoadShutdownSelState(VOID
)
104 HKEY hKeyCurrentUser
, hKey
;
105 DWORD dwValue
, dwTemp
, dwSize
;
107 /* Default to shutdown */
108 dwValue
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
;
110 /* Open the current user HKCU key */
111 lRet
= RegOpenCurrentUser(MAXIMUM_ALLOWED
, &hKeyCurrentUser
);
112 if (lRet
== ERROR_SUCCESS
)
114 /* Open the subkey */
115 lRet
= RegOpenKeyExW(hKeyCurrentUser
,
116 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
117 0, KEY_QUERY_VALUE
, &hKey
);
118 RegCloseKey(hKeyCurrentUser
);
120 if (lRet
!= ERROR_SUCCESS
)
124 dwSize
= sizeof(dwTemp
);
125 lRet
= RegQueryValueExW(hKey
,
128 (LPBYTE
)&dwTemp
, &dwSize
);
131 if (lRet
== ERROR_SUCCESS
)
135 case WLX_SHUTDOWN_STATE_LOGOFF
:
136 dwValue
= WLX_SAS_ACTION_LOGOFF
;
139 case WLX_SHUTDOWN_STATE_POWER_OFF
:
140 dwValue
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
;
143 case WLX_SHUTDOWN_STATE_REBOOT
:
144 dwValue
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
;
149 case WLX_SHUTDOWN_STATE_SLEEP
:
150 dwValue
= WLX_SAS_ACTION_SHUTDOWN_SLEEP
;
155 case WLX_SHUTDOWN_STATE_HIBERNATE
:
156 dwValue
= WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
;
167 SaveShutdownSelState(
168 IN DWORD ShutdownCode
)
171 HKEY hKeyCurrentUser
, hKey
;
174 /* Open the current user HKCU key */
175 lRet
= RegOpenCurrentUser(MAXIMUM_ALLOWED
, &hKeyCurrentUser
);
176 if (lRet
== ERROR_SUCCESS
)
178 /* Create the subkey */
179 lRet
= RegCreateKeyExW(hKeyCurrentUser
,
180 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
182 REG_OPTION_NON_VOLATILE
,
185 RegCloseKey(hKeyCurrentUser
);
187 if (lRet
!= ERROR_SUCCESS
)
190 switch (ShutdownCode
)
192 case WLX_SAS_ACTION_LOGOFF
:
193 dwValue
= WLX_SHUTDOWN_STATE_LOGOFF
;
196 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
:
197 dwValue
= WLX_SHUTDOWN_STATE_POWER_OFF
;
200 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
:
201 dwValue
= WLX_SHUTDOWN_STATE_REBOOT
;
204 case WLX_SAS_ACTION_SHUTDOWN_SLEEP
:
205 dwValue
= WLX_SHUTDOWN_STATE_SLEEP
;
208 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
:
209 dwValue
= WLX_SHUTDOWN_STATE_HIBERNATE
;
216 (LPBYTE
)&dwValue
, sizeof(dwValue
));
221 GetDefaultShutdownOptions(VOID
)
223 return WLX_SHUTDOWN_STATE_POWER_OFF
| WLX_SHUTDOWN_STATE_REBOOT
;
227 GetAllowedShutdownOptions(VOID
)
231 // FIXME: Compute those options accordings to current user's rights!
232 Options
|= WLX_SHUTDOWN_STATE_LOGOFF
| WLX_SHUTDOWN_STATE_POWER_OFF
| WLX_SHUTDOWN_STATE_REBOOT
;
234 if (IsPwrSuspendAllowed())
235 Options
|= WLX_SHUTDOWN_STATE_SLEEP
;
237 if (IsPwrHibernateAllowed())
238 Options
|= WLX_SHUTDOWN_STATE_HIBERNATE
;
246 IN PSHUTDOWN_DLG_CONTEXT pContext
) // HINSTANCE hInstance
252 ShutdownCode
= SendDlgItemMessageW(hDlg
, IDC_SHUTDOWN_ACTION
, CB_GETCURSEL
, 0, 0);
253 if (ShutdownCode
== CB_ERR
) // Invalid selection
256 ShutdownCode
= SendDlgItemMessageW(hDlg
, IDC_SHUTDOWN_ACTION
, CB_GETITEMDATA
, ShutdownCode
, 0);
258 switch (ShutdownCode
)
260 case WLX_SAS_ACTION_LOGOFF
:
261 DescId
= IDS_SHUTDOWN_LOGOFF_DESC
;
264 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
:
265 DescId
= IDS_SHUTDOWN_SHUTDOWN_DESC
;
268 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
:
269 DescId
= IDS_SHUTDOWN_RESTART_DESC
;
272 case WLX_SAS_ACTION_SHUTDOWN_SLEEP
:
273 DescId
= IDS_SHUTDOWN_SLEEP_DESC
;
276 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
:
277 DescId
= IDS_SHUTDOWN_HIBERNATE_DESC
;
284 LoadStringW(pContext
->pgContext
->hDllInstance
, DescId
, szBuffer
, _countof(szBuffer
));
285 SetDlgItemTextW(hDlg
, IDC_SHUTDOWN_DESCRIPTION
, szBuffer
);
287 if (pContext
->bReasonUI
)
289 EnableWindow(GetDlgItem(hDlg
, IDC_REASON_PLANNED
), (ShutdownCode
!= WLX_SAS_ACTION_LOGOFF
));
290 EnableWindow(GetDlgItem(hDlg
, IDC_REASON_LIST
), (ShutdownCode
!= WLX_SAS_ACTION_LOGOFF
));
291 EnableWindow(GetDlgItem(hDlg
, IDC_REASON_COMMENT
), (ShutdownCode
!= WLX_SAS_ACTION_LOGOFF
));
298 IN PSHUTDOWN_DLG_CONTEXT pContext
)
300 PGINA_CONTEXT pgContext
= pContext
->pgContext
;
304 WCHAR szBuffer2
[256];
306 hwndList
= GetDlgItem(hDlg
, IDC_SHUTDOWN_ACTION
);
308 /* Clear the content before it's used */
309 SendMessageW(hwndList
, CB_RESETCONTENT
, 0, 0);
312 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_LOGOFF
)
314 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_LOGOFF
, szBuffer
, _countof(szBuffer
));
315 StringCchPrintfW(szBuffer2
, _countof(szBuffer2
), szBuffer
, pgContext
->UserName
);
316 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer2
);
318 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_LOGOFF
);
321 /* Shut down - DEFAULT */
322 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_POWER_OFF
)
324 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_SHUTDOWN
, szBuffer
, _countof(szBuffer
));
325 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
327 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
);
331 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_REBOOT
)
333 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_RESTART
, szBuffer
, _countof(szBuffer
));
334 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
336 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_REBOOT
);
339 // if (pContext->ShutdownOptions & 0x08) {}
342 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_SLEEP
)
344 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_SLEEP
, szBuffer
, _countof(szBuffer
));
345 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
347 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_SLEEP
);
350 // if (pContext->ShutdownOptions & 0x20) {}
353 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_HIBERNATE
)
355 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_HIBERNATE
, szBuffer
, _countof(szBuffer
));
356 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
358 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
);
361 // if (pContext->ShutdownOptions & 0x80) {}
363 /* Set the default shut down selection */
364 count
= SendMessageW(hwndList
, CB_GETCOUNT
, 0, 0);
365 for (i
= 0; i
< count
; i
++)
367 if (SendMessageW(hwndList
, CB_GETITEMDATA
, i
, 0) == pgContext
->nShutdownAction
)
369 SendMessageW(hwndList
, CB_SETCURSEL
, i
, 0);
374 /* Update the choice description based on the current selection */
375 UpdateShutdownDesc(hDlg
, pContext
);
381 IN PGINA_CONTEXT pgContext
)
385 idx
= SendDlgItemMessageW(hDlg
,
392 pgContext
->nShutdownAction
=
393 SendDlgItemMessageW(hDlg
,
409 PSHUTDOWN_DLG_CONTEXT pContext
;
411 pContext
= (PSHUTDOWN_DLG_CONTEXT
)GetWindowLongPtrW(hDlg
, GWLP_USERDATA
);
417 pContext
= (PSHUTDOWN_DLG_CONTEXT
)lParam
;
418 SetWindowLongPtrW(hDlg
, GWLP_USERDATA
, (LONG_PTR
)pContext
);
420 ShutdownOnInit(hDlg
, pContext
);
422 /* Draw the logo bitmap */
424 LoadImageW(pContext
->pgContext
->hDllInstance
, MAKEINTRESOURCEW(IDI_ROSLOGO
), IMAGE_BITMAP
, 0, 0, LR_DEFAULTCOLOR
);
429 DeleteObject(pContext
->hBitmap
);
435 * If the user deactivates the shutdown dialog (it loses its focus
436 * while the dialog is not being closed), then destroy the dialog
437 * and cancel shutdown.
439 if (LOWORD(wParam
) == WA_INACTIVE
)
441 if (!pContext
->bCloseDlg
)
443 pContext
->bCloseDlg
= TRUE
;
453 if (pContext
->hBitmap
)
455 BeginPaint(hDlg
, &ps
);
456 DrawStateW(ps
.hdc
, NULL
, NULL
, (LPARAM
)pContext
->hBitmap
, (WPARAM
)0, 0, 0, 0, 0, DST_BITMAP
);
463 pContext
->bCloseDlg
= TRUE
;
464 EndDialog(hDlg
, IDCANCEL
);
468 switch (LOWORD(wParam
))
471 ShutdownOnOk(hDlg
, pContext
->pgContext
);
476 pContext
->bCloseDlg
= TRUE
;
477 EndDialog(hDlg
, LOWORD(wParam
));
480 case IDC_SHUTDOWN_ACTION
:
481 UpdateShutdownDesc(hDlg
, pContext
);
495 IN DWORD ShutdownOptions
,
496 IN PGINA_CONTEXT pgContext
)
499 SHUTDOWN_DLG_CONTEXT Context
;
502 DWORD ShutdownOptions
;
504 // FIXME: User impersonation!!
505 pgContext
->nShutdownAction
= LoadShutdownSelState();
506 ShutdownOptions
= GetAllowedShutdownOptions();
509 Context
.pgContext
= pgContext
;
510 Context
.ShutdownOptions
= ShutdownOptions
;
511 Context
.bCloseDlg
= FALSE
;
512 Context
.bReasonUI
= GetShutdownReasonUI();
514 if (pgContext
->hWlx
&& pgContext
->pWlxFuncs
)
516 ret
= pgContext
->pWlxFuncs
->WlxDialogBoxParam(pgContext
->hWlx
,
517 pgContext
->hDllInstance
,
518 MAKEINTRESOURCEW(Context
.bReasonUI
? IDD_SHUTDOWN_REASON
: IDD_SHUTDOWN
),
525 ret
= DialogBoxParamW(pgContext
->hDllInstance
,
526 MAKEINTRESOURCEW(Context
.bReasonUI
? IDD_SHUTDOWN_REASON
: IDD_SHUTDOWN
),
533 // FIXME: User impersonation!!
535 SaveShutdownSelState(pgContext
->nShutdownAction
);
544 * - Based upon observations on the ShellShutdownDialog() function, the function doesn't actually
545 * do anything except show a dialog box and returning a value based upon the value chosen. That
546 * means that any code that calls the function has to execute the chosen action (shut down,
548 * - When this function is called in Windows XP, it shows the classic dialog box regardless if
549 * SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\LogonType is enabled or not.
550 * - When the Help button is pushed, it sends the same return value as IDCANCEL (0x00), but
551 * at the same time, it calls the help file directly from the dialog box.
552 * - When the dialog is created, it doesn't disable all other input from the other windows.
553 * This is done elsewhere. When running the function ShellShutdownDialog() from XP/2K3, if the user clicks
554 * out of the window, it automatically closes itself.
555 * - The parameter, lpUsername never seems to be used when calling the function from Windows XP. Either
556 * it was a parameter that was never used in the final version before release, or it has a use that
557 * is currently not known.
566 DWORD ShutdownOptions
;
569 * As we are called by the shell itself, don't use
570 * the cached GINA context but use a local copy here.
572 GINA_CONTEXT gContext
= { 0 };
575 UNREFERENCED_PARAMETER(lpUsername
);
577 ShutdownOptions
= GetAllowedShutdownOptions();
579 ShutdownOptions
&= ~WLX_SHUTDOWN_STATE_LOGOFF
;
581 /* Initialize our local GINA context */
582 gContext
.hDllInstance
= hDllInstance
;
583 BufferSize
= _countof(gContext
.UserName
);
584 // NOTE: Only when this function is called, Win checks inside
585 // HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
586 // value "Logon User Name", and determines whether it will display
588 GetUserNameW(gContext
.UserName
, &BufferSize
);
589 gContext
.nShutdownAction
= LoadShutdownSelState();
591 /* Load the shutdown dialog box */
592 dlgValue
= ShutdownDialog(hParent
, ShutdownOptions
, &gContext
);
594 /* Determine what to do based on user selection */
595 if (dlgValue
== IDOK
)
597 SaveShutdownSelState(gContext
.nShutdownAction
);
599 switch (gContext
.nShutdownAction
)
601 case WLX_SAS_ACTION_LOGOFF
:
602 return WLX_SHUTDOWN_STATE_LOGOFF
;
604 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
:
605 return WLX_SHUTDOWN_STATE_POWER_OFF
;
607 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
:
608 return WLX_SHUTDOWN_STATE_REBOOT
;
612 case WLX_SAS_ACTION_SHUTDOWN_SLEEP
:
613 return WLX_SHUTDOWN_STATE_SLEEP
;
617 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
:
618 return WLX_SHUTDOWN_STATE_HIBERNATE
;
623 /* Help file is called directly here */
624 else if (dlgValue
== IDHELP
)
626 FIXME("Help is not implemented yet.");
627 MessageBoxW(hParent
, L
"Help is not implemented yet.", L
"Message", MB_OK
| MB_ICONEXCLAMATION
);
629 else if (dlgValue
== -1)
631 ERR("Failed to create dialog\n");