Skip to content

Commit c687f6e

Browse files
committed
[MSGINA] Don't depend on powrprof.dll; fix shutdown from fancy dialog (reactos#8391)
CORE-19104 - Use `NtPowerInformation()` and the `IS_PWR_*` macros instead. - Fancy shutdown dialog: * Enable or disable the hibernate/sleep buttons depending on the previously-determined available shutdown options. * Don't invoke `ExitWindowsEx()` or `SetSuspendState()` directly within Msgina, but return a suitable `WLX_SAS_ACTION_SHUTDOWN_*` value, like what's done by the classic dialog. The power action proper is then performed by the caller of the shutdown dialog: either Shell32 or Winlogon.
1 parent ecf718e commit c687f6e

File tree

2 files changed

+69
-24
lines changed

2 files changed

+69
-24
lines changed

dll/win32/msgina/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ add_library(msgina MODULE
2323
set_module_type(msgina win32dll UNICODE)
2424
target_link_libraries(msgina wine uuid ${PSEH_LIB} cpprt atl_classes)
2525
add_delay_importlibs(msgina secur32)
26-
add_importlibs(msgina advapi32 user32 gdi32 powrprof userenv msvcrt kernel32 ntdll)
26+
add_importlibs(msgina advapi32 user32 gdi32 userenv msvcrt kernel32 ntdll)
2727
add_pch(msgina msgina.h "${PCH_SKIP_SOURCE}")
2828
add_cd_file(TARGET msgina DESTINATION reactos/system32 FOR all)

dll/win32/msgina/shutdown.c

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
*/
1010

1111
#include "msgina.h"
12-
#include <powrprof.h>
1312
#include <wingdi.h>
1413
#include <windowsx.h>
1514
#include <commctrl.h>
15+
#include <ndk/pofuncs.h>
1616

1717
/* Macros for fancy shutdown dialog */
1818
#define FONT_POINT_SIZE 13
@@ -587,7 +587,7 @@ CreateToolTipForButtons(
587587
CW_USEDEFAULT, CW_USEDEFAULT,
588588
hDlg, NULL, hInst, NULL);
589589

590-
/* Associate the tooltip with the tool. */
590+
/* Associate the tooltip with the tool */
591591
LoadStringW(hInst, detailID, szBuffer, _countof(szBuffer));
592592
tool.lpszText = szBuffer;
593593
SendMessageW(hwndTip, TTM_ADDTOOLW, 0, (LPARAM)&tool);
@@ -811,6 +811,8 @@ GetAllowedShutdownOptions(
811811
{
812812
DWORD Options = 0;
813813
DWORD dwPolicyValue;
814+
SYSTEM_POWER_CAPABILITIES PowerCaps;
815+
NTSTATUS Status;
814816

815817
dwPolicyValue = 0;
816818
GetPolicyDWORDValue(hKeyCurrentUser,
@@ -832,17 +834,27 @@ GetAllowedShutdownOptions(
832834
if (!TestTokenPrivilege(hUserToken, SE_SHUTDOWN_PRIVILEGE))
833835
return Options; // The user doesn't have them, bail out.
834836

837+
/* We can always shutdown and restart */
835838
Options |= WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
836839

837-
// NOTE: "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power" value "Shutdown"
838-
// for "advanced" sleep options. See the 3rd parameter of:
839-
// https://learn.microsoft.com/en-us/windows/win32/api/powrprof/nf-powrprof-setsuspendstate
840+
/* Determine whether extra power options are available */
841+
Status = NtPowerInformation(SystemPowerCapabilities, NULL, 0, &PowerCaps, sizeof(PowerCaps));
842+
if (!NT_SUCCESS(Status))
843+
{
844+
ERR("NtPowerInformation(SystemPowerCapabilities) failed (Status 0x%08lx)\n", Status);
845+
}
846+
else
847+
{
848+
if (IS_PWR_SUSPEND_ALLOWED(&PowerCaps))
849+
Options |= WLX_SHUTDOWN_STATE_SLEEP;
840850

841-
if (IsPwrSuspendAllowed())
842-
Options |= WLX_SHUTDOWN_STATE_SLEEP;
851+
// TODO: "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power" value "Shutdown"
852+
// for sleep options. In particular, if set it tells that wakeup events can be disabled.
853+
// This will enable WLX_SHUTDOWN_STATE_SLEEP2 support.
843854

844-
if (IsPwrHibernateAllowed())
845-
Options |= WLX_SHUTDOWN_STATE_HIBERNATE;
855+
if (IS_PWR_HIBERNATE_ALLOWED(&PowerCaps))
856+
Options |= WLX_SHUTDOWN_STATE_HIBERNATE;
857+
}
846858

847859
// TODO: Consider Windows 8+ support for:
848860
// "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power" value "HiberbootEnabled"
@@ -918,6 +930,8 @@ ShutdownOnFriendlyInit(
918930
PGINA_CONTEXT pgContext = pContext->pgContext;
919931
HDC hdc;
920932
LONG lfHeight;
933+
BOOLEAN bCanSuspend = !!(pContext->ShutdownOptions & (WLX_SHUTDOWN_STATE_SLEEP | WLX_SHUTDOWN_STATE_SLEEP2));
934+
BOOLEAN bCanHibernate = !!(pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_HIBERNATE);
921935

922936
/* Create font for the IDC_TURN_OFF_STATIC static control */
923937
hdc = GetDC(hDlg);
@@ -936,10 +950,10 @@ ShutdownOnFriendlyInit(
936950
pContext->bIsSleepButtonReplaced = FALSE;
937951
pContext->bTimer = FALSE;
938952

939-
EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_HIBERNATE), FALSE);
940-
EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SLEEP), IsPwrSuspendAllowed());
953+
EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_HIBERNATE), bCanHibernate);
954+
EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SLEEP), bCanSuspend);
941955

942-
/* Gather old button func */
956+
/* Gather old button function */
943957
pContext->OldButtonProc = (WNDPROC)GetWindowLongPtrW(GetDlgItem(hDlg, IDC_BUTTON_HIBERNATE), GWLP_WNDPROC);
944958

945959
/* Set bIsButtonHot to false, create tooltips for each buttons, make buttons to remember pContext and subclass the buttons */
@@ -952,10 +966,10 @@ ShutdownOnFriendlyInit(
952966
CreateToolTipForButtons(IDC_BUTTON_SHUTDOWN + i,
953967
IDS_SHUTDOWN_SHUTDOWN_DESC + i,
954968
hDlg, IDS_SHUTDOWN_SHUTDOWN + i,
955-
pContext->pgContext->hDllInstance);
969+
pgContext->hDllInstance);
956970
}
957971

958-
if (pContext->ShutdownDialogId == IDD_SHUTDOWN_FANCY && IsPwrSuspendAllowed())
972+
if ((pContext->ShutdownDialogId == IDD_SHUTDOWN_FANCY) && bCanSuspend)
959973
{
960974
pContext->iTimer = SetTimer(hDlg, 0, 50, NULL);
961975
pContext->bTimer = TRUE;
@@ -1126,18 +1140,49 @@ ShutdownDialogProc(
11261140
case WM_COMMAND:
11271141
switch (LOWORD(wParam))
11281142
{
1129-
case IDC_BUTTON_SHUTDOWN:
1130-
ExitWindowsEx(EWX_SHUTDOWN, SHTDN_REASON_MAJOR_OTHER);
1131-
break;
1132-
1133-
case IDC_BUTTON_REBOOT:
1134-
ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_OTHER);
1135-
break;
1143+
/* Check for fancy shutdown dialog buttons */
1144+
case IDC_BUTTON_SHUTDOWN: case IDC_BUTTON_REBOOT:
1145+
case IDC_BUTTON_SLEEP: case IDC_BUTTON_HIBERNATE:
1146+
{
1147+
DWORD Button = LOWORD(wParam);
1148+
PGINA_CONTEXT pgContext = pContext->pgContext;
1149+
pgContext->nShutdownAction = 0;
1150+
if (Button == IDC_BUTTON_SHUTDOWN)
1151+
{
1152+
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_POWER_OFF)
1153+
pgContext->nShutdownAction = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
1154+
}
1155+
else if (Button == IDC_BUTTON_REBOOT)
1156+
{
1157+
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_REBOOT)
1158+
pgContext->nShutdownAction = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
1159+
}
1160+
else if (Button == IDC_BUTTON_SLEEP)
1161+
{
1162+
if (pContext->ShutdownOptions & (WLX_SHUTDOWN_STATE_SLEEP | WLX_SHUTDOWN_STATE_SLEEP2))
1163+
{
1164+
/* Choose "Sleep with wakeup events disabled" if
1165+
* available, otherwise use the regular sleep mode */
1166+
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_SLEEP2)
1167+
pgContext->nShutdownAction = WLX_SAS_ACTION_SHUTDOWN_SLEEP2;
1168+
else
1169+
pgContext->nShutdownAction = WLX_SAS_ACTION_SHUTDOWN_SLEEP;
1170+
}
1171+
}
1172+
else if (Button == IDC_BUTTON_HIBERNATE)
1173+
{
1174+
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_HIBERNATE)
1175+
pgContext->nShutdownAction = WLX_SAS_ACTION_SHUTDOWN_HIBERNATE;
1176+
}
1177+
if (pgContext->nShutdownAction == 0)
1178+
break;
11361179

1137-
case IDC_BUTTON_SLEEP:
1138-
SetSuspendState(TRUE, TRUE, TRUE);
1180+
pContext->bCloseDlg = TRUE;
1181+
EndDialog(hDlg, IDOK);
11391182
break;
1183+
}
11401184

1185+
/* Classic shutdown dialog buttons */
11411186
case IDOK:
11421187
ShutdownOnOk(hDlg, pContext->pgContext);
11431188

0 commit comments

Comments
 (0)