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)
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
22 #define WLX_SHUTDOWN_STATE_SLEEP 0x10
24 #define WLX_SHUTDOWN_STATE_HIBERNATE 0x40
27 /* Macros for fancy shut down dialog */
28 #define FONT_POINT_SIZE 13
30 #define DARK_GREY_COLOR RGB(244, 244, 244)
31 #define LIGHT_GREY_COLOR RGB(38, 38, 38)
33 /* Bitmap's size for buttons */
37 #define NUMBER_OF_BUTTONS 4
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)
51 typedef struct _SHUTDOWN_DLG_CONTEXT
53 PGINA_CONTEXT pgContext
;
56 DWORD ShutdownOptions
;
60 BOOL bIsSleepButtonReplaced
;
63 BOOL bIsButtonHot
[NUMBER_OF_BUTTONS
];
65 WNDPROC OldButtonProc
;
66 } SHUTDOWN_DLG_CONTEXT
, *PSHUTDOWN_DLG_CONTEXT
;
70 GetShutdownReasonUI(VOID
)
72 OSVERSIONINFOEX VersionInfo
;
73 DWORD dwValue
, dwSize
;
77 /* Query the policy value */
78 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
79 L
"Software\\Policies\\Microsoft\\Windows NT\\Reliability",
83 if (lRet
== ERROR_SUCCESS
)
86 dwSize
= sizeof(dwValue
);
87 RegQueryValueExW(hKey
,
95 return (dwValue
!= 0) ? TRUE
: FALSE
;
98 /* Query the machine value */
99 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
100 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Reliability",
104 if (lRet
== ERROR_SUCCESS
)
107 dwSize
= sizeof(dwValue
);
108 RegQueryValueExW(hKey
,
116 return (dwValue
!= 0) ? TRUE
: FALSE
;
119 /* Return the default value */
120 VersionInfo
.dwOSVersionInfoSize
= sizeof(VersionInfo
);
121 if (!GetVersionEx((POSVERSIONINFO
)&VersionInfo
))
125 // return (VersionInfo.wProductType == VER_NT_WORKSTATION) ? FALSE : TRUE;
130 IsFriendlyUIActive(VOID
)
132 DWORD dwType
, dwValue
, dwSize
;
136 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
137 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
141 if (lRet
!= ERROR_SUCCESS
)
144 /* CORE-17282 First check an optional ReactOS specific override, that Windows does not check.
145 We use this to allow users pairing 'Server'-configuration with FriendlyShutdown.
146 Otherwise users would have to change CSDVersion or LogonType (side-effects AppCompat) */
148 dwSize
= sizeof(dwValue
);
149 lRet
= RegQueryValueExW(hKey
,
150 L
"EnforceFriendlyShutdown",
156 if (lRet
== ERROR_SUCCESS
&& dwType
== REG_DWORD
&& dwValue
== 0x1)
162 /* Check product version number */
164 dwSize
= sizeof(dwValue
);
165 lRet
= RegQueryValueExW(hKey
,
173 if (lRet
!= ERROR_SUCCESS
|| dwType
!= REG_DWORD
|| dwValue
!= 0x300)
175 /* Allow Friendly UI only on Workstation */
179 /* Check LogonType value */
180 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
181 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
185 if (lRet
!= ERROR_SUCCESS
)
189 dwSize
= sizeof(dwValue
);
190 lRet
= RegQueryValueExW(hKey
,
198 if (lRet
!= ERROR_SUCCESS
|| dwType
!= REG_DWORD
)
201 return (dwValue
!= 0);
214 IsNetwareActive(VOID
)
222 IsShowHibernateButtonActive(VOID
)
226 DWORD dwValue
, dwSize
;
228 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
229 L
"SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Shutdown",
230 0, KEY_QUERY_VALUE
, &hKey
);
231 if (lRet
== ERROR_SUCCESS
)
234 dwSize
= sizeof(dwValue
);
236 lRet
= RegQueryValueExW(hKey
,
237 L
"ShowHibernateButton",
239 (LPBYTE
)&dwValue
, &dwSize
);
241 if (lRet
!= ERROR_SUCCESS
)
245 return (dwValue
!= 0);
252 ForceFriendlyUI(VOID
)
254 DWORD dwType
, dwValue
, dwSize
;
258 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
259 L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
263 if (lRet
== ERROR_SUCCESS
)
266 dwSize
= sizeof(dwValue
);
267 lRet
= RegQueryValueExW(hKey
,
275 if (lRet
== ERROR_SUCCESS
&& dwType
== REG_DWORD
)
276 return (dwValue
!= 0);
279 lRet
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
280 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
284 if (lRet
== ERROR_SUCCESS
)
287 dwSize
= sizeof(dwValue
);
288 lRet
= RegQueryValueExW(hKey
,
297 if (lRet
== ERROR_SUCCESS
&& dwType
== REG_DWORD
)
298 return (dwValue
!= 0);
306 DrawIconOnOwnerDrawnButtons(
307 DRAWITEMSTRUCT
* pdis
,
308 PSHUTDOWN_DLG_CONTEXT pContext
)
316 hdcMem
= CreateCompatibleDC(pdis
->hDC
);
317 hbmOld
= SelectObject(hdcMem
, pContext
->hImageStrip
);
320 /* Check the button ID for revelant bitmap to be used */
323 case IDC_BUTTON_SHUTDOWN
:
325 switch (pdis
->itemAction
)
332 if (pdis
->itemState
& ODS_SELECTED
)
334 y
= BUTTON_SHUTDOWN_PRESSED
;
336 else if (pContext
->bIsButtonHot
[0] || (pdis
->itemState
& ODS_FOCUS
))
338 y
= BUTTON_SHUTDOWN_FOCUSED
;
346 case IDC_BUTTON_REBOOT
:
348 switch (pdis
->itemAction
)
355 if (pdis
->itemState
& ODS_SELECTED
)
357 y
= BUTTON_REBOOT_PRESSED
;
359 else if (pContext
->bIsButtonHot
[1] || (pdis
->itemState
& ODS_FOCUS
))
361 y
= BUTTON_REBOOT_FOCUSED
;
369 case IDC_BUTTON_HIBERNATE
:
370 case IDC_BUTTON_SLEEP
:
372 switch (pdis
->itemAction
)
379 if (pdis
->itemState
& ODS_DISABLED
)
381 y
= BUTTON_SLEEP_DISABLED
;
383 else if (pdis
->itemState
& ODS_SELECTED
)
385 y
= BUTTON_SLEEP_PRESSED
;
387 else if ((pdis
->CtlID
== IDC_BUTTON_SLEEP
&& pContext
->bIsButtonHot
[2]) ||
388 (pdis
->CtlID
== IDC_BUTTON_HIBERNATE
&& pContext
->bIsButtonHot
[3]) ||
389 (pdis
->itemState
& ODS_FOCUS
))
391 y
= BUTTON_SLEEP_FOCUSED
;
400 /* Draw it on the required button */
401 bRet
= BitBlt(pdis
->hDC
,
402 (rect
.right
- rect
.left
- CX_BITMAP
) / 2,
403 (rect
.bottom
- rect
.top
- CY_BITMAP
) / 2,
404 CX_BITMAP
, CY_BITMAP
, hdcMem
, 0, y
, SRCCOPY
);
406 SelectObject(hdcMem
, hbmOld
);
414 ShellIsFriendlyUIActive(VOID
)
418 bActive
= IsFriendlyUIActive();
420 if ((IsDomainMember() || IsNetwareActive()) && !ForceFriendlyUI())
427 GetDefaultShutdownSelState(VOID
)
429 return WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
;
433 LoadShutdownSelState(VOID
)
436 HKEY hKeyCurrentUser
, hKey
;
437 DWORD dwValue
, dwTemp
, dwSize
;
439 /* Default to shutdown */
440 dwValue
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
;
442 /* Open the current user HKCU key */
443 lRet
= RegOpenCurrentUser(MAXIMUM_ALLOWED
, &hKeyCurrentUser
);
444 if (lRet
== ERROR_SUCCESS
)
446 /* Open the subkey */
447 lRet
= RegOpenKeyExW(hKeyCurrentUser
,
448 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
449 0, KEY_QUERY_VALUE
, &hKey
);
450 RegCloseKey(hKeyCurrentUser
);
452 if (lRet
!= ERROR_SUCCESS
)
456 dwSize
= sizeof(dwTemp
);
457 lRet
= RegQueryValueExW(hKey
,
460 (LPBYTE
)&dwTemp
, &dwSize
);
463 if (lRet
== ERROR_SUCCESS
)
467 case WLX_SHUTDOWN_STATE_LOGOFF
:
468 dwValue
= WLX_SAS_ACTION_LOGOFF
;
471 case WLX_SHUTDOWN_STATE_POWER_OFF
:
472 dwValue
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
;
475 case WLX_SHUTDOWN_STATE_REBOOT
:
476 dwValue
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
;
481 case WLX_SHUTDOWN_STATE_SLEEP
:
482 dwValue
= WLX_SAS_ACTION_SHUTDOWN_SLEEP
;
487 case WLX_SHUTDOWN_STATE_HIBERNATE
:
488 dwValue
= WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
;
500 OwnerDrawButtonSubclass(
506 PSHUTDOWN_DLG_CONTEXT pContext
;
507 pContext
= (PSHUTDOWN_DLG_CONTEXT
)GetWindowLongPtrW(hButton
, GWLP_USERDATA
);
509 int buttonID
= GetDlgCtrlID(hButton
);
516 POINT pt
= {GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)};
518 if (GetCapture() != hButton
)
521 if (buttonID
== IDC_BUTTON_SHUTDOWN
)
523 pContext
->bIsButtonHot
[0] = TRUE
;
525 else if (buttonID
== IDC_BUTTON_REBOOT
)
527 pContext
->bIsButtonHot
[1] = TRUE
;
529 else if (buttonID
== IDC_BUTTON_SLEEP
)
531 pContext
->bIsButtonHot
[2] = TRUE
;
533 else if (buttonID
== IDC_BUTTON_HIBERNATE
)
535 pContext
->bIsButtonHot
[3] = TRUE
;
537 SetCursor(LoadCursorW(NULL
, MAKEINTRESOURCEW(IDC_HAND
)));
540 ClientToScreen(hButton
, &pt
);
541 hwndTarget
= WindowFromPoint(pt
);
543 if (hwndTarget
!= hButton
)
546 if (buttonID
== IDC_BUTTON_SHUTDOWN
)
548 pContext
->bIsButtonHot
[0] = FALSE
;
550 else if (buttonID
== IDC_BUTTON_REBOOT
)
552 pContext
->bIsButtonHot
[1] = FALSE
;
554 else if (buttonID
== IDC_BUTTON_SLEEP
)
556 pContext
->bIsButtonHot
[2] = FALSE
;
558 else if (buttonID
== IDC_BUTTON_HIBERNATE
)
560 pContext
->bIsButtonHot
[3] = FALSE
;
563 InvalidateRect(hButton
, NULL
, FALSE
);
567 /* Whenever one of the buttons gets the keyboard focus, set it as default button */
570 SendMessageW(GetParent(hButton
), DM_SETDEFID
, buttonID
, 0);
574 /* Otherwise, set IDCANCEL as default button */
577 SendMessageW(GetParent(hButton
), DM_SETDEFID
, IDCANCEL
, 0);
581 return CallWindowProcW(pContext
->OldButtonProc
, hButton
, uMsg
, wParam
, lParam
);
585 AddPrefixToStaticTexts(
587 BOOL bIsSleepButtonReplaced
)
591 for (int i
= 0; i
< NUMBER_OF_BUTTONS
; i
++)
593 GetDlgItemTextW(hDlg
, IDC_BUTTON_HIBERNATE
+ i
, szBuffer
, _countof(szBuffer
));
594 SetDlgItemTextW(hDlg
, IDC_HIBERNATE_STATIC
+ i
, szBuffer
);
597 if (bIsSleepButtonReplaced
)
599 GetDlgItemTextW(hDlg
, IDC_BUTTON_HIBERNATE
, szBuffer
, _countof(szBuffer
));
600 SetDlgItemTextW(hDlg
, IDC_SLEEP_STATIC
, szBuffer
);
605 CreateToolTipForButtons(
612 HWND hwndTool
, hwndTip
;
616 hwndTool
= GetDlgItem(hDlg
, controlID
);
618 tool
.cbSize
= sizeof(tool
);
620 tool
.uFlags
= TTF_IDISHWND
| TTF_SUBCLASS
;
621 tool
.uId
= (UINT_PTR
)hwndTool
;
623 /* Create the tooltip */
624 hwndTip
= CreateWindowExW(0, TOOLTIPS_CLASSW
, NULL
,
625 WS_POPUP
| TTS_ALWAYSTIP
| TTS_BALLOON
,
626 CW_USEDEFAULT
, CW_USEDEFAULT
,
627 CW_USEDEFAULT
, CW_USEDEFAULT
,
628 hDlg
, NULL
, hInst
, NULL
);
630 /* Associate the tooltip with the tool. */
631 LoadStringW(hInst
, detailID
, szBuffer
, _countof(szBuffer
));
632 tool
.lpszText
= szBuffer
;
633 SendMessageW(hwndTip
, TTM_ADDTOOLW
, 0, (LPARAM
)&tool
);
634 LoadStringW(hInst
, titleID
, szBuffer
, _countof(szBuffer
));
635 SendMessageW(hwndTip
, TTM_SETTITLEW
, TTI_NONE
, (LPARAM
)szBuffer
);
636 SendMessageW(hwndTip
, TTM_SETMAXTIPWIDTH
, 0, 250);
640 ReplaceRequiredButton(
643 BOOL bIsAltKeyPressed
,
644 BOOL bIsSleepButtonReplaced
)
646 int destID
= IDC_BUTTON_SLEEP
;
647 int targetedID
= IDC_BUTTON_HIBERNATE
;
648 HWND hwndDest
, hwndTarget
;
652 /* If the sleep button has been already replaced earlier, bring sleep button back to its original position */
653 if (bIsSleepButtonReplaced
)
655 destID
= IDC_BUTTON_HIBERNATE
;
656 targetedID
= IDC_BUTTON_SLEEP
;
659 hwndDest
= GetDlgItem(hDlg
, destID
);
660 hwndTarget
= GetDlgItem(hDlg
, targetedID
);
662 /* Get the position of the destination button */
663 GetWindowRect(hwndDest
, &rect
);
665 /* Get the corrected translated coordinates which is relative to the client window */
666 MapWindowPoints(HWND_DESKTOP
, hDlg
, (LPPOINT
)&rect
, sizeof(RECT
)/sizeof(POINT
));
668 /* Set the position of targeted button and hide the destination button */
669 SetWindowPos(hwndTarget
,
673 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
675 EnableWindow(hwndDest
, FALSE
);
676 ShowWindow(hwndDest
, SW_HIDE
);
677 EnableWindow(hwndTarget
, TRUE
);
678 ShowWindow(hwndTarget
, SW_SHOW
);
679 SetFocus(hwndTarget
);
681 if (bIsAltKeyPressed
)
683 if (!bIsSleepButtonReplaced
)
685 GetDlgItemTextW(hDlg
, IDC_BUTTON_HIBERNATE
, szBuffer
, _countof(szBuffer
));
686 SetDlgItemTextW(hDlg
, IDC_SLEEP_STATIC
, szBuffer
);
690 GetDlgItemTextW(hDlg
, IDC_BUTTON_SLEEP
, szBuffer
, _countof(szBuffer
));
691 SetDlgItemTextW(hDlg
, IDC_SLEEP_STATIC
, szBuffer
);
696 if (!bIsSleepButtonReplaced
)
698 LoadStringW(hInstance
, IDS_SHUTDOWN_HIBERNATE
, szBuffer
, _countof(szBuffer
));
699 SetDlgItemTextW(hDlg
, IDC_SLEEP_STATIC
, szBuffer
);
703 LoadStringW(hInstance
, IDS_SHUTDOWN_SLEEP
, szBuffer
, _countof(szBuffer
));
704 SetDlgItemTextW(hDlg
, IDC_SLEEP_STATIC
, szBuffer
);
710 SaveShutdownSelState(
711 IN DWORD ShutdownCode
)
714 HKEY hKeyCurrentUser
, hKey
;
717 /* Open the current user HKCU key */
718 lRet
= RegOpenCurrentUser(MAXIMUM_ALLOWED
, &hKeyCurrentUser
);
719 if (lRet
== ERROR_SUCCESS
)
721 /* Create the subkey */
722 lRet
= RegCreateKeyExW(hKeyCurrentUser
,
723 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
725 REG_OPTION_NON_VOLATILE
,
728 RegCloseKey(hKeyCurrentUser
);
730 if (lRet
!= ERROR_SUCCESS
)
733 switch (ShutdownCode
)
735 case WLX_SAS_ACTION_LOGOFF
:
736 dwValue
= WLX_SHUTDOWN_STATE_LOGOFF
;
739 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
:
740 dwValue
= WLX_SHUTDOWN_STATE_POWER_OFF
;
743 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
:
744 dwValue
= WLX_SHUTDOWN_STATE_REBOOT
;
747 case WLX_SAS_ACTION_SHUTDOWN_SLEEP
:
748 dwValue
= WLX_SHUTDOWN_STATE_SLEEP
;
751 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
:
752 dwValue
= WLX_SHUTDOWN_STATE_HIBERNATE
;
759 (LPBYTE
)&dwValue
, sizeof(dwValue
));
764 GetDefaultShutdownOptions(VOID
)
766 return WLX_SHUTDOWN_STATE_POWER_OFF
| WLX_SHUTDOWN_STATE_REBOOT
;
770 GetAllowedShutdownOptions(VOID
)
774 // FIXME: Compute those options accordings to current user's rights!
775 Options
|= WLX_SHUTDOWN_STATE_LOGOFF
| WLX_SHUTDOWN_STATE_POWER_OFF
| WLX_SHUTDOWN_STATE_REBOOT
;
777 if (IsPwrSuspendAllowed())
778 Options
|= WLX_SHUTDOWN_STATE_SLEEP
;
780 if (IsPwrHibernateAllowed())
781 Options
|= WLX_SHUTDOWN_STATE_HIBERNATE
;
789 IN PSHUTDOWN_DLG_CONTEXT pContext
) // HINSTANCE hInstance
795 ShutdownCode
= SendDlgItemMessageW(hDlg
, IDC_SHUTDOWN_ACTION
, CB_GETCURSEL
, 0, 0);
796 if (ShutdownCode
== CB_ERR
) // Invalid selection
799 ShutdownCode
= SendDlgItemMessageW(hDlg
, IDC_SHUTDOWN_ACTION
, CB_GETITEMDATA
, ShutdownCode
, 0);
801 switch (ShutdownCode
)
803 case WLX_SAS_ACTION_LOGOFF
:
804 DescId
= IDS_SHUTDOWN_LOGOFF_DESC
;
807 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
:
808 DescId
= IDS_SHUTDOWN_SHUTDOWN_DESC
;
811 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
:
812 DescId
= IDS_SHUTDOWN_RESTART_DESC
;
815 case WLX_SAS_ACTION_SHUTDOWN_SLEEP
:
816 DescId
= IDS_SHUTDOWN_SLEEP_DESC
;
819 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
:
820 DescId
= IDS_SHUTDOWN_HIBERNATE_DESC
;
827 LoadStringW(pContext
->pgContext
->hDllInstance
, DescId
, szBuffer
, _countof(szBuffer
));
828 SetDlgItemTextW(hDlg
, IDC_SHUTDOWN_DESCRIPTION
, szBuffer
);
830 if (pContext
->bReasonUI
)
832 EnableWindow(GetDlgItem(hDlg
, IDC_REASON_PLANNED
), (ShutdownCode
!= WLX_SAS_ACTION_LOGOFF
));
833 EnableWindow(GetDlgItem(hDlg
, IDC_REASON_LIST
), (ShutdownCode
!= WLX_SAS_ACTION_LOGOFF
));
834 EnableWindow(GetDlgItem(hDlg
, IDC_REASON_COMMENT
), (ShutdownCode
!= WLX_SAS_ACTION_LOGOFF
));
841 IN PSHUTDOWN_DLG_CONTEXT pContext
)
843 PGINA_CONTEXT pgContext
= pContext
->pgContext
;
847 WCHAR szBuffer2
[256];
851 /* Create font for the IDC_TURN_OFF_STATIC static control */
853 lfHeight
= -MulDiv(FONT_POINT_SIZE
, GetDeviceCaps(hdc
, LOGPIXELSY
), 72);
854 ReleaseDC(hDlg
, hdc
);
855 pContext
->hfFont
= CreateFontW(lfHeight
, 0, 0, 0, FW_MEDIUM
, FALSE
, 0, 0, 0, 0, 0, 0, 0, L
"MS Shell Dlg");
856 SendDlgItemMessageW(hDlg
, IDC_TURN_OFF_STATIC
, WM_SETFONT
, (WPARAM
)pContext
->hfFont
, TRUE
);
858 /* Create a brush for static controls for fancy shut down dialog */
859 pContext
->hBrush
= CreateSolidBrush(DARK_GREY_COLOR
);
861 pContext
->hImageStrip
= LoadBitmapW(pgContext
->hDllInstance
, MAKEINTRESOURCEW(IDB_IMAGE_STRIP
));
863 hwndList
= GetDlgItem(hDlg
, IDC_SHUTDOWN_ACTION
);
865 /* Clear the content before it's used */
866 SendMessageW(hwndList
, CB_RESETCONTENT
, 0, 0);
868 /* Set the boolean flags to false */
869 pContext
->bIsSleepButtonReplaced
= FALSE
;
871 for (int i
= 0; i
< NUMBER_OF_BUTTONS
; i
++)
873 pContext
->bIsButtonHot
[i
] = FALSE
;
877 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_LOGOFF
)
879 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_LOGOFF
, szBuffer
, _countof(szBuffer
));
880 StringCchPrintfW(szBuffer2
, _countof(szBuffer2
), szBuffer
, pgContext
->UserName
);
881 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer2
);
883 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_LOGOFF
);
886 /* Shut down - DEFAULT */
887 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_POWER_OFF
)
889 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_SHUTDOWN
, szBuffer
, _countof(szBuffer
));
890 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
892 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
);
894 else if (pContext
->bFriendlyUI
)
896 EnableWindow(GetDlgItem(hDlg
, IDC_BUTTON_SHUTDOWN
), FALSE
);
900 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_REBOOT
)
902 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_RESTART
, szBuffer
, _countof(szBuffer
));
903 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
905 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_REBOOT
);
907 else if (pContext
->bFriendlyUI
)
909 EnableWindow(GetDlgItem(hDlg
, IDC_BUTTON_REBOOT
), FALSE
);
912 // if (pContext->ShutdownOptions & 0x08) {}
915 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_SLEEP
)
917 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_SLEEP
, szBuffer
, _countof(szBuffer
));
918 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
920 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_SLEEP
);
922 else if (pContext
->bFriendlyUI
)
924 EnableWindow(GetDlgItem(hDlg
, IDC_BUTTON_SLEEP
), IsPwrSuspendAllowed());
927 // if (pContext->ShutdownOptions & 0x20) {}
930 if (pContext
->ShutdownOptions
& WLX_SHUTDOWN_STATE_HIBERNATE
)
932 LoadStringW(pgContext
->hDllInstance
, IDS_SHUTDOWN_HIBERNATE
, szBuffer
, _countof(szBuffer
));
933 idx
= SendMessageW(hwndList
, CB_ADDSTRING
, 0, (LPARAM
)szBuffer
);
935 SendMessageW(hwndList
, CB_SETITEMDATA
, idx
, WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
);
937 else if (pContext
->bFriendlyUI
)
939 EnableWindow(GetDlgItem(hDlg
, IDC_BUTTON_HIBERNATE
), FALSE
);
942 // if (pContext->ShutdownOptions & 0x80) {}
944 /* Set the default shut down selection */
945 count
= SendMessageW(hwndList
, CB_GETCOUNT
, 0, 0);
946 for (i
= 0; i
< count
; i
++)
948 if (SendMessageW(hwndList
, CB_GETITEMDATA
, i
, 0) == pgContext
->nShutdownAction
)
950 SendMessageW(hwndList
, CB_SETCURSEL
, i
, 0);
955 /* Create tool tips for the buttons of fancy log off dialog */
956 CreateToolTipForButtons(IDC_BUTTON_HIBERNATE
,
957 IDS_SHUTDOWN_HIBERNATE_DESC
,
958 hDlg
, IDS_SHUTDOWN_HIBERNATE
,
959 pContext
->pgContext
->hDllInstance
);
960 CreateToolTipForButtons(IDC_BUTTON_SHUTDOWN
,
961 IDS_SHUTDOWN_SHUTDOWN_DESC
,
962 hDlg
, IDS_SHUTDOWN_SHUTDOWN
,
963 pContext
->pgContext
->hDllInstance
);
964 CreateToolTipForButtons(IDC_BUTTON_REBOOT
,
965 IDS_SHUTDOWN_RESTART_DESC
,
966 hDlg
, IDS_SHUTDOWN_RESTART
,
967 pContext
->pgContext
->hDllInstance
);
968 CreateToolTipForButtons(IDC_BUTTON_SLEEP
,
969 IDS_SHUTDOWN_SLEEP_DESC
,
970 hDlg
, IDS_SHUTDOWN_SLEEP
,
971 pContext
->pgContext
->hDllInstance
);
973 /* Gather old button func */
974 pContext
->OldButtonProc
= (WNDPROC
)GetWindowLongPtrW(GetDlgItem(hDlg
, IDC_BUTTON_HIBERNATE
), GWLP_WNDPROC
);
976 /* Make buttons to remember pContext and subclass the buttons */
977 for (int i
= 0; i
< NUMBER_OF_BUTTONS
; i
++)
979 SetWindowLongPtrW(GetDlgItem(hDlg
, IDC_BUTTON_HIBERNATE
+ i
), GWLP_USERDATA
, (LONG_PTR
)pContext
);
980 SetWindowLongPtrW(GetDlgItem(hDlg
, IDC_BUTTON_HIBERNATE
+ i
), GWLP_WNDPROC
, (LONG_PTR
)OwnerDrawButtonSubclass
);
983 /* Update the choice description based on the current selection */
984 UpdateShutdownDesc(hDlg
, pContext
);
990 IN PGINA_CONTEXT pgContext
)
994 idx
= SendDlgItemMessageW(hDlg
,
1001 pgContext
->nShutdownAction
=
1002 SendDlgItemMessageW(hDlg
,
1003 IDC_SHUTDOWN_ACTION
,
1018 PSHUTDOWN_DLG_CONTEXT pContext
;
1020 pContext
= (PSHUTDOWN_DLG_CONTEXT
)GetWindowLongPtrW(hDlg
, GWLP_USERDATA
);
1026 pContext
= (PSHUTDOWN_DLG_CONTEXT
)lParam
;
1027 SetWindowLongPtrW(hDlg
, GWLP_USERDATA
, (LONG_PTR
)pContext
);
1029 ShutdownOnInit(hDlg
, pContext
);
1031 /* Draw the logo bitmap */
1033 LoadImageW(pContext
->pgContext
->hDllInstance
, MAKEINTRESOURCEW(IDI_ROSLOGO
), IMAGE_BITMAP
, 0, 0, LR_DEFAULTCOLOR
);
1038 DeleteObject(pContext
->hBitmap
);
1039 DeleteObject(pContext
->hBrush
);
1040 DeleteObject(pContext
->hImageStrip
);
1041 DeleteObject(pContext
->hfFont
);
1043 /* Remove the subclass from the buttons */
1044 for (int i
= 0; i
< NUMBER_OF_BUTTONS
; i
++)
1046 SetWindowLongPtrW(GetDlgItem(hDlg
, IDC_BUTTON_HIBERNATE
+ i
), GWLP_WNDPROC
, (LONG_PTR
)pContext
->OldButtonProc
);
1053 * If the user deactivates the shutdown dialog (it loses its focus
1054 * while the dialog is not being closed), then destroy the dialog
1055 * and cancel shutdown.
1057 if (LOWORD(wParam
) == WA_INACTIVE
)
1059 if (!pContext
->bCloseDlg
)
1061 pContext
->bCloseDlg
= TRUE
;
1063 if (pContext
->bIsDialogModal
)
1069 DestroyWindow(hDlg
);
1080 if (pContext
->hBitmap
)
1082 BeginPaint(hDlg
, &ps
);
1083 DrawStateW(ps
.hdc
, NULL
, NULL
, (LPARAM
)pContext
->hBitmap
, (WPARAM
)0, 0, 0, 0, 0, DST_BITMAP
);
1084 EndPaint(hDlg
, &ps
);
1090 pContext
->bCloseDlg
= TRUE
;
1092 if (pContext
->bIsDialogModal
)
1094 EndDialog(hDlg
, IDCANCEL
);
1098 DestroyWindow(hDlg
);
1099 PostQuitMessage(IDCANCEL
);
1104 switch (LOWORD(wParam
))
1106 case IDC_BUTTON_SHUTDOWN
:
1107 ExitWindowsEx(EWX_SHUTDOWN
, SHTDN_REASON_MAJOR_OTHER
);
1110 case IDC_BUTTON_REBOOT
:
1111 ExitWindowsEx(EWX_REBOOT
, SHTDN_REASON_MAJOR_OTHER
);
1114 case IDC_BUTTON_SLEEP
:
1115 SetSuspendState(TRUE
, TRUE
, TRUE
);
1119 ShutdownOnOk(hDlg
, pContext
->pgContext
);
1124 pContext
->bCloseDlg
= TRUE
;
1126 if (pContext
->bIsDialogModal
)
1128 EndDialog(hDlg
, LOWORD(wParam
));
1132 DestroyWindow(hDlg
);
1133 PostQuitMessage(LOWORD(wParam
));
1137 case IDC_SHUTDOWN_ACTION
:
1138 UpdateShutdownDesc(hDlg
, pContext
);
1143 case WM_CTLCOLORSTATIC
:
1145 /* Either make background transparent or fill it with color for required static controls */
1146 HDC hdcStatic
= (HDC
)wParam
;
1147 UINT StaticID
= (UINT
)GetWindowLongPtrW((HWND
)lParam
, GWL_ID
);
1151 case IDC_TURN_OFF_STATIC
:
1152 SetTextColor(hdcStatic
, DARK_GREY_COLOR
);
1153 SetBkMode(hdcStatic
, TRANSPARENT
);
1154 return (INT_PTR
)GetStockObject(HOLLOW_BRUSH
);
1156 case IDC_HIBERNATE_STATIC
:
1157 case IDC_SHUTDOWN_STATIC
:
1158 case IDC_SLEEP_STATIC
:
1159 case IDC_RESTART_STATIC
:
1160 SetTextColor(hdcStatic
, LIGHT_GREY_COLOR
);
1161 SetBkMode(hdcStatic
, TRANSPARENT
);
1162 return (LONG_PTR
)pContext
->hBrush
;
1169 /* Draw bitmaps on required buttons */
1170 DRAWITEMSTRUCT
* pdis
= (DRAWITEMSTRUCT
*)lParam
;
1171 switch (pdis
->CtlID
)
1173 case IDC_BUTTON_SHUTDOWN
:
1174 case IDC_BUTTON_REBOOT
:
1175 case IDC_BUTTON_SLEEP
:
1176 case IDC_BUTTON_HIBERNATE
:
1177 return DrawIconOnOwnerDrawnButtons(pdis
, pContext
);
1191 IN DWORD ShutdownOptions
,
1192 IN PGINA_CONTEXT pgContext
)
1195 SHUTDOWN_DLG_CONTEXT Context
;
1196 BOOL bIsAltKeyPressed
= FALSE
;
1197 DWORD ShutdownDialogId
= IDD_SHUTDOWN
;
1202 DWORD ShutdownOptions
;
1204 // FIXME: User impersonation!!
1205 pgContext
->nShutdownAction
= LoadShutdownSelState();
1206 ShutdownOptions
= GetAllowedShutdownOptions();
1209 Context
.pgContext
= pgContext
;
1210 Context
.ShutdownOptions
= ShutdownOptions
;
1211 Context
.bCloseDlg
= FALSE
;
1212 Context
.bReasonUI
= GetShutdownReasonUI();
1213 Context
.bFriendlyUI
= ShellIsFriendlyUIActive();
1215 if (pgContext
->hWlx
&& pgContext
->pWlxFuncs
&& !Context
.bFriendlyUI
)
1217 Context
.bIsDialogModal
= TRUE
;
1218 ret
= pgContext
->pWlxFuncs
->WlxDialogBoxParam(pgContext
->hWlx
,
1219 pgContext
->hDllInstance
,
1220 MAKEINTRESOURCEW(Context
.bReasonUI
? IDD_SHUTDOWN_REASON
: IDD_SHUTDOWN
),
1227 if (Context
.bFriendlyUI
)
1229 if (IsShowHibernateButtonActive())
1231 ShutdownDialogId
= IDD_SHUTDOWN_FANCY_LONG
;
1235 ShutdownDialogId
= IDD_SHUTDOWN_FANCY
;
1239 Context
.bIsDialogModal
= FALSE
;
1240 hDlg
= CreateDialogParamW(pgContext
->hDllInstance
,
1241 MAKEINTRESOURCEW(Context
.bReasonUI
? IDD_SHUTDOWN_REASON
: ShutdownDialogId
),
1246 ShowWindow(hDlg
, SW_SHOW
);
1248 /* Detect either Alt or Shift key have been pressed or released */
1249 while (GetMessageW(&Msg
, NULL
, 0, 0))
1251 if (!IsDialogMessageW(hDlg
, &Msg
))
1253 TranslateMessage(&Msg
);
1254 DispatchMessageW(&Msg
);
1257 switch (Msg
.message
)
1261 /* If the Alt key has been pressed once, add prefix to static controls */
1262 if (Msg
.wParam
== VK_MENU
&& !bIsAltKeyPressed
)
1264 AddPrefixToStaticTexts(hDlg
, Context
.bIsSleepButtonReplaced
);
1265 bIsAltKeyPressed
= TRUE
;
1273 * If the Shift key has been pressed once, and both hibernate button and sleep button are enabled
1274 * replace the sleep button with hibernate button
1276 if (Msg
.wParam
== VK_SHIFT
)
1278 if (ShutdownDialogId
== IDD_SHUTDOWN_FANCY
&& !Context
.bIsSleepButtonReplaced
)
1280 if (IsPwrHibernateAllowed() && IsPwrSuspendAllowed())
1282 ReplaceRequiredButton(hDlg
,
1283 pgContext
->hDllInstance
,
1285 Context
.bIsSleepButtonReplaced
);
1286 Context
.bIsSleepButtonReplaced
= TRUE
;
1295 /* If the Shift key has been released after being pressed, replace the hibernate button with sleep button again */
1296 if (Msg
.wParam
== VK_SHIFT
)
1298 if (ShutdownDialogId
== IDD_SHUTDOWN_FANCY
&& Context
.bIsSleepButtonReplaced
)
1300 if (IsPwrHibernateAllowed() && IsPwrSuspendAllowed())
1302 ReplaceRequiredButton(hDlg
,
1303 pgContext
->hDllInstance
,
1305 Context
.bIsSleepButtonReplaced
);
1306 Context
.bIsSleepButtonReplaced
= FALSE
;
1318 // FIXME: User impersonation!!
1320 SaveShutdownSelState(pgContext
->nShutdownAction
);
1329 * - Based upon observations on the ShellShutdownDialog() function, the function doesn't actually
1330 * do anything except show a dialog box and returning a value based upon the value chosen. That
1331 * means that any code that calls the function has to execute the chosen action (shut down,
1333 * - When this function is called in Windows XP, it shows the classic dialog box regardless if
1334 * SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\LogonType is enabled or not.
1335 * - When the Help button is pushed, it sends the same return value as IDCANCEL (0x00), but
1336 * at the same time, it calls the help file directly from the dialog box.
1337 * - When the dialog is created, it doesn't disable all other input from the other windows.
1338 * This is done elsewhere. When running the function ShellShutdownDialog() from XP/2K3, if the user clicks
1339 * out of the window, it automatically closes itself.
1340 * - The parameter, lpUsername never seems to be used when calling the function from Windows XP. Either
1341 * it was a parameter that was never used in the final version before release, or it has a use that
1342 * is currently not known.
1345 ShellShutdownDialog(
1351 DWORD ShutdownOptions
;
1354 * As we are called by the shell itself, don't use
1355 * the cached GINA context but use a local copy here.
1357 GINA_CONTEXT gContext
= { 0 };
1360 UNREFERENCED_PARAMETER(lpUsername
);
1362 ShutdownOptions
= GetAllowedShutdownOptions();
1364 ShutdownOptions
&= ~WLX_SHUTDOWN_STATE_LOGOFF
;
1366 /* Initialize our local GINA context */
1367 gContext
.hDllInstance
= hDllInstance
;
1368 BufferSize
= _countof(gContext
.UserName
);
1369 // NOTE: Only when this function is called, Win checks inside
1370 // HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
1371 // value "Logon User Name", and determines whether it will display
1373 GetUserNameW(gContext
.UserName
, &BufferSize
);
1374 gContext
.nShutdownAction
= LoadShutdownSelState();
1376 /* Load the shutdown dialog box */
1377 dlgValue
= ShutdownDialog(hParent
, ShutdownOptions
, &gContext
);
1379 /* Determine what to do based on user selection */
1380 if (dlgValue
== IDOK
)
1382 SaveShutdownSelState(gContext
.nShutdownAction
);
1384 switch (gContext
.nShutdownAction
)
1386 case WLX_SAS_ACTION_LOGOFF
:
1387 return WLX_SHUTDOWN_STATE_LOGOFF
;
1389 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
:
1390 return WLX_SHUTDOWN_STATE_POWER_OFF
;
1392 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
:
1393 return WLX_SHUTDOWN_STATE_REBOOT
;
1397 case WLX_SAS_ACTION_SHUTDOWN_SLEEP
:
1398 return WLX_SHUTDOWN_STATE_SLEEP
;
1402 case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE
:
1403 return WLX_SHUTDOWN_STATE_HIBERNATE
;
1408 /* Help file is called directly here */
1409 else if (dlgValue
== IDHELP
)
1411 FIXME("Help is not implemented yet.");
1412 MessageBoxW(hParent
, L
"Help is not implemented yet.", L
"Message", MB_OK
| MB_ICONEXCLAMATION
);
1414 else if (dlgValue
== -1)
1416 ERR("Failed to create dialog\n");
1424 * - Undocumented, called from MS shell32.dll to show the turn off dialog.
1425 * - Seems to have the same purpose as ShellShutdownDialog.
1428 ShellTurnOffDialog(HWND hWnd
)
1430 return ShellShutdownDialog(hWnd
, NULL
, FALSE
);