mirror of
https://github.com/reactos/reactos
synced 2025-10-06 08:22:58 +02:00
[MSGINA] Improve Security and Shutdown dialog features (#8372)
- Respect system policies for showing or hiding: * Security dialog "Lock Workstation", "Log Off", "Shut Down", "Change Password", "Task Manager" buttons; * "Log Off" entry in the Shutdown dialog; - Disable the "Shut Down" Security dialog button, and the "Stand by", "Shut down" entries in the Shutdown dialog, if the logged user doesn't have the SeShutdownPrivilege. - Add other missing `WLX_SHUTDOWN_STATE_*` shutdown flags that are supported by Windows. - Improve the retrieval of shutdown options to be displayed in the "Shut Down" dialog. In particular, don't hardcode any sort of defaults, but let them come from what the user can do (Is logoff allowed? Does (s)he have the rights to shutdown/reboot? etc.). If no shutdown options are available, then simply don't display the dialog! - Don't hardcode the default selected shutdown option. Either it comes from the user's registry and is valid (i.e. corresponds to an existing shutdown option in the dialog), otherwise, fall back to the first option in the dialog. In particular this means: * when opening the "Shut Down" dialog from the C-A-D Security dialog, by default we will select the "Log Off" option, or whatever the user last selected; * when opening the dialog from the "Turn Off" Start Menu item, default to the "Shut down" option, or whatever the user last selected. * when opening the dialog from the C-A-D "Log On" dialog (no user is logged in), the "Shut down" option will also be selected, or whatever the system operator last selected. - For the shell-invokable `ShellShutdownDialog()` function, implement support for using a custom display user name, or the one in the `"Logon User Name"` registry value saved by `WlxActivateUserShell()`. Plus, the 3rd parameter specifies the list of shutdown options to *exclude* from the options list.
This commit is contained in:
@@ -10,9 +10,7 @@
|
||||
|
||||
#include <wingdi.h>
|
||||
#include <winnls.h>
|
||||
#include <winreg.h>
|
||||
#include <ndk/exfuncs.h>
|
||||
#include <ndk/setypes.h>
|
||||
|
||||
typedef struct _DISPLAYSTATUSMSG
|
||||
{
|
||||
@@ -133,8 +131,6 @@ SetWelcomeText(HWND hWnd)
|
||||
DWORD BufSize, dwType, dwWelcomeSize, dwTitleLength;
|
||||
LONG rc;
|
||||
|
||||
TRACE("SetWelcomeText(%p)\n", hWnd);
|
||||
|
||||
/* Open the Winlogon key */
|
||||
rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
|
||||
@@ -529,8 +525,6 @@ static VOID
|
||||
GUIDisplaySASNotice(
|
||||
IN OUT PGINA_CONTEXT pgContext)
|
||||
{
|
||||
TRACE("GUIDisplaySASNotice()\n");
|
||||
|
||||
/* Display the notice window */
|
||||
pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx,
|
||||
pgContext->hDllInstance,
|
||||
@@ -816,9 +810,14 @@ ChangePasswordDialogProc(
|
||||
|
||||
|
||||
static VOID
|
||||
OnInitSecurityDlg(HWND hwnd,
|
||||
PGINA_CONTEXT pgContext)
|
||||
OnInitSecurityDlg(
|
||||
_In_ HWND hwnd,
|
||||
_In_ PGINA_CONTEXT pgContext)
|
||||
{
|
||||
HKEY hKeyCurrentUser, hKey;
|
||||
DWORD dwValue;
|
||||
LONG lRet;
|
||||
|
||||
WCHAR Buffer1[256];
|
||||
WCHAR Buffer2[256];
|
||||
WCHAR Buffer3[256];
|
||||
@@ -842,6 +841,74 @@ OnInitSecurityDlg(HWND hwnd,
|
||||
wsprintfW(Buffer4, Buffer1, Buffer2, Buffer3);
|
||||
|
||||
SetDlgItemTextW(hwnd, IDC_SECURITY_LOGONDATE, Buffer4);
|
||||
|
||||
lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
|
||||
0,
|
||||
KEY_QUERY_VALUE, &hKey);
|
||||
if (lRet == ERROR_SUCCESS)
|
||||
{
|
||||
lRet = ReadRegDwordValue(hKey, L"DisableLockWorkstation", &dwValue);
|
||||
if ((lRet == ERROR_SUCCESS) && !!dwValue)
|
||||
EnableWindow(GetDlgItem(hwnd, IDC_SECURITY_LOCK), FALSE);
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
/* Open the per-user registry key */
|
||||
lRet = RegOpenLoggedOnHKCU(pgContext->UserToken,
|
||||
KEY_QUERY_VALUE,
|
||||
&hKeyCurrentUser);
|
||||
if (lRet != ERROR_SUCCESS)
|
||||
{
|
||||
/* We couldn't, bail out */
|
||||
return;
|
||||
}
|
||||
|
||||
lRet = RegOpenKeyExW(hKeyCurrentUser,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
|
||||
0,
|
||||
KEY_QUERY_VALUE, &hKey);
|
||||
if (lRet == ERROR_SUCCESS)
|
||||
{
|
||||
lRet = ReadRegDwordValue(hKey, L"DisableLockWorkstation", &dwValue);
|
||||
if ((lRet == ERROR_SUCCESS) && !!dwValue)
|
||||
EnableWindow(GetDlgItem(hwnd, IDC_SECURITY_LOCK), FALSE);
|
||||
|
||||
lRet = ReadRegDwordValue(hKey, L"DisableChangePassword", &dwValue);
|
||||
if ((lRet == ERROR_SUCCESS) && !!dwValue)
|
||||
EnableWindow(GetDlgItem(hwnd, IDC_SECURITY_CHANGEPWD), FALSE);
|
||||
|
||||
lRet = ReadRegDwordValue(hKey, L"DisableTaskMgr", &dwValue);
|
||||
if ((lRet == ERROR_SUCCESS) && !!dwValue)
|
||||
EnableWindow(GetDlgItem(hwnd, IDC_SECURITY_TASKMGR), FALSE);
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
lRet = RegOpenKeyExW(hKeyCurrentUser,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
|
||||
0,
|
||||
KEY_QUERY_VALUE, &hKey);
|
||||
if (lRet == ERROR_SUCCESS)
|
||||
{
|
||||
lRet = ReadRegDwordValue(hKey, L"NoLogoff", &dwValue);
|
||||
if ((lRet == ERROR_SUCCESS) && !!dwValue)
|
||||
EnableWindow(GetDlgItem(hwnd, IDC_SECURITY_LOGOFF), FALSE);
|
||||
|
||||
// TODO: Disable also if "NoDisconnect" on Terminal Services
|
||||
/* Disable the "Shutdown" button if the user doesn't have shutdown privilege */
|
||||
lRet = ReadRegDwordValue(hKey, L"NoClose", &dwValue);
|
||||
if (((lRet == ERROR_SUCCESS) && !!dwValue) ||
|
||||
!TestTokenPrivilege(pgContext->UserToken, SE_SHUTDOWN_PRIVILEGE))
|
||||
{
|
||||
EnableWindow(GetDlgItem(hwnd, IDC_SECURITY_SHUTDOWN), FALSE);
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
RegCloseKey(hKeyCurrentUser);
|
||||
}
|
||||
|
||||
|
||||
@@ -918,48 +985,36 @@ OnLogOff(
|
||||
static
|
||||
INT
|
||||
OnShutDown(
|
||||
IN HWND hwndDlg,
|
||||
IN PGINA_CONTEXT pgContext)
|
||||
_In_ HWND hwndDlg,
|
||||
_In_ PGINA_CONTEXT pgContext,
|
||||
_In_ DWORD dwExcludeOptions)
|
||||
{
|
||||
HKEY hKeyCurrentUser = NULL;
|
||||
DWORD ShutdownOptions = 0;
|
||||
INT ret;
|
||||
DWORD ShutdownOptions;
|
||||
|
||||
TRACE("OnShutDown(%p %p)\n", hwndDlg, pgContext);
|
||||
|
||||
pgContext->nShutdownAction = GetDefaultShutdownSelState();
|
||||
ShutdownOptions = GetDefaultShutdownOptions();
|
||||
|
||||
if (pgContext->UserToken != NULL)
|
||||
/* Open the per-user registry key */
|
||||
if (RegOpenLoggedOnHKCU(pgContext->UserToken,
|
||||
KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
|
||||
&hKeyCurrentUser) != ERROR_SUCCESS)
|
||||
{
|
||||
if (ImpersonateLoggedOnUser(pgContext->UserToken))
|
||||
ERR("RegOpenLoggedOnHKCU() failed with error %ld\n", GetLastError());
|
||||
}
|
||||
pgContext->nShutdownAction = 0;
|
||||
if (hKeyCurrentUser)
|
||||
{
|
||||
pgContext->nShutdownAction = LoadShutdownSelState();
|
||||
ShutdownOptions = GetAllowedShutdownOptions();
|
||||
RevertToSelf();
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
|
||||
}
|
||||
ShutdownOptions = GetAllowedShutdownOptions(hKeyCurrentUser, pgContext->UserToken);
|
||||
pgContext->nShutdownAction = LoadShutdownSelState(hKeyCurrentUser);
|
||||
}
|
||||
ShutdownOptions &= ~dwExcludeOptions;
|
||||
|
||||
ret = ShutdownDialog(hwndDlg, ShutdownOptions, pgContext);
|
||||
|
||||
if (ret == IDOK)
|
||||
{
|
||||
if (pgContext->UserToken != NULL)
|
||||
{
|
||||
if (ImpersonateLoggedOnUser(pgContext->UserToken))
|
||||
{
|
||||
SaveShutdownSelState(pgContext->nShutdownAction);
|
||||
RevertToSelf();
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((ret == IDOK) && hKeyCurrentUser)
|
||||
SaveShutdownSelState(hKeyCurrentUser, pgContext->nShutdownAction);
|
||||
|
||||
if (hKeyCurrentUser)
|
||||
RegCloseKey(hKeyCurrentUser);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1031,7 +1086,7 @@ SecurityDialogProc(
|
||||
RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old);
|
||||
}
|
||||
}
|
||||
else if (OnShutDown(hwndDlg, pgContext) == IDOK)
|
||||
else if (OnShutDown(hwndDlg, pgContext, 0) == IDOK)
|
||||
{
|
||||
EndDialog(hwndDlg, pgContext->nShutdownAction);
|
||||
}
|
||||
@@ -1066,8 +1121,6 @@ GUILoggedOnSAS(
|
||||
{
|
||||
INT result;
|
||||
|
||||
TRACE("GUILoggedOnSAS()\n");
|
||||
|
||||
if (dwSasType != WLX_SAS_TYPE_CTRL_ALT_DEL)
|
||||
{
|
||||
/* Nothing to do for WLX_SAS_TYPE_TIMEOUT; the dialog will
|
||||
@@ -1377,8 +1430,11 @@ LogonDialogProc(
|
||||
return TRUE;
|
||||
|
||||
case IDC_LOGON_SHUTDOWN:
|
||||
if (OnShutDown(hwndDlg, pDlgData->pgContext) == IDOK)
|
||||
if (OnShutDown(hwndDlg, pDlgData->pgContext,
|
||||
WLX_SHUTDOWN_STATE_DISCONNECT | WLX_SHUTDOWN_STATE_LOGOFF) == IDOK)
|
||||
{
|
||||
EndDialog(hwndDlg, pDlgData->pgContext->nShutdownAction);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
@@ -1730,8 +1786,6 @@ static VOID
|
||||
GUIDisplayLockedNotice(
|
||||
IN OUT PGINA_CONTEXT pgContext)
|
||||
{
|
||||
TRACE("GUIdisplayLockedNotice()\n");
|
||||
|
||||
pgContext->pWlxFuncs->WlxDialogBoxParam(
|
||||
pgContext->hWlx,
|
||||
pgContext->hDllInstance,
|
||||
|
@@ -19,6 +19,7 @@ extern "C" {
|
||||
#include <winuser.h>
|
||||
#include <winwlx.h>
|
||||
#include <ndk/rtlfuncs.h>
|
||||
#include <ndk/setypes.h> // For SE_*_PRIVILEGE
|
||||
#include <ntsecapi.h>
|
||||
|
||||
#include <strsafe.h>
|
||||
@@ -123,20 +124,35 @@ CreateProfile(
|
||||
|
||||
/* shutdown.c */
|
||||
|
||||
DWORD
|
||||
GetDefaultShutdownSelState(VOID);
|
||||
/**
|
||||
* @brief Shutdown state flags
|
||||
* @see
|
||||
* https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc962586(v=technet.10)
|
||||
* https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc783367(v=ws.10)
|
||||
**/
|
||||
#define WLX_SHUTDOWN_STATE_LOGOFF 0x01 ///< "Log off <username>"
|
||||
#define WLX_SHUTDOWN_STATE_POWER_OFF 0x02 ///< "Shut down"
|
||||
#define WLX_SHUTDOWN_STATE_REBOOT 0x04 ///< "Restart"
|
||||
// 0x08 ///< "Restart in MS-DOS mode" - Yes, WinNT/2k/XP/2k3 msgina.dll/shell32.dll has it!
|
||||
#define WLX_SHUTDOWN_STATE_SLEEP 0x10 ///< "Stand by"
|
||||
#define WLX_SHUTDOWN_STATE_SLEEP2 0x20 ///< "Stand by (with wakeup events disabled)"
|
||||
#define WLX_SHUTDOWN_STATE_HIBERNATE 0x40 ///< "Hibernate"
|
||||
#define WLX_SHUTDOWN_STATE_DISCONNECT 0x80 ///< "Disconnect" (only available in Terminal Services sessions)
|
||||
#define WLX_SHUTDOWN_AUTOUPDATE 0x100 ///< Set when updates are queued
|
||||
|
||||
DWORD
|
||||
LoadShutdownSelState(VOID);
|
||||
LoadShutdownSelState(
|
||||
_In_ HKEY hKeyCurrentUser);
|
||||
|
||||
VOID
|
||||
SaveShutdownSelState(DWORD ShutdownCode);
|
||||
SaveShutdownSelState(
|
||||
_In_ HKEY hKeyCurrentUser,
|
||||
_In_ DWORD ShutdownCode);
|
||||
|
||||
DWORD
|
||||
GetDefaultShutdownOptions(VOID);
|
||||
|
||||
DWORD
|
||||
GetAllowedShutdownOptions(VOID);
|
||||
GetAllowedShutdownOptions(
|
||||
_In_opt_ HKEY hKeyCurrentUser,
|
||||
_In_opt_ HANDLE hUserToken);
|
||||
|
||||
INT_PTR
|
||||
ShutdownDialog(
|
||||
@@ -164,6 +180,11 @@ ReadRegDwordValue(
|
||||
_In_ PCWSTR pszValue,
|
||||
_Out_ PDWORD pValue);
|
||||
|
||||
BOOL
|
||||
TestTokenPrivilege(
|
||||
_In_opt_ HANDLE hToken,
|
||||
_In_ ULONG Privilege);
|
||||
|
||||
PWSTR
|
||||
DuplicateString(
|
||||
_In_opt_ PCWSTR Str);
|
||||
|
@@ -14,16 +14,6 @@
|
||||
#include <windowsx.h>
|
||||
#include <commctrl.h>
|
||||
|
||||
/* Shutdown state flags */
|
||||
#define WLX_SHUTDOWN_STATE_LOGOFF 0x01
|
||||
#define WLX_SHUTDOWN_STATE_POWER_OFF 0x02
|
||||
#define WLX_SHUTDOWN_STATE_REBOOT 0x04
|
||||
// 0x08
|
||||
#define WLX_SHUTDOWN_STATE_SLEEP 0x10
|
||||
// 0x20
|
||||
#define WLX_SHUTDOWN_STATE_HIBERNATE 0x40
|
||||
// 0x80
|
||||
|
||||
/* Macros for fancy shutdown dialog */
|
||||
#define FONT_POINT_SIZE 13
|
||||
|
||||
@@ -73,6 +63,61 @@ typedef struct _SHUTDOWN_DLG_CONTEXT
|
||||
WNDPROC OldButtonProc;
|
||||
} SHUTDOWN_DLG_CONTEXT, *PSHUTDOWN_DLG_CONTEXT;
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Looks up a policy value on both HKEY_LOCAL_MACHINE
|
||||
* and HKEY_CURRENT_USER, under the same policy sub-key.
|
||||
*
|
||||
* @note
|
||||
* HKEY_LOCAL_MACHINE policies trump over HKEY_CURRENT_USER ones.
|
||||
**/
|
||||
LONG
|
||||
GetPolicyDWORDValue(
|
||||
_In_opt_ HKEY hKeyCurrentUser,
|
||||
_In_ PCWSTR pPolicyKey,
|
||||
_In_ PCWSTR ValueName,
|
||||
_Out_ PDWORD pValue)
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD dwValue;
|
||||
LONG rc;
|
||||
|
||||
*pValue = 0;
|
||||
|
||||
/* Query the policy value in HKEY_LOCAL_MACHINE */
|
||||
rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, pPolicyKey, 0,
|
||||
KEY_QUERY_VALUE, &hKey);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
rc = ReadRegDwordValue(hKey, ValueName, &dwValue);
|
||||
RegCloseKey(hKey);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
*pValue = dwValue;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* If not found, query the policy value in HKEY_CURRENT_USER */
|
||||
rc = RegOpenKeyExW(hKeyCurrentUser ? hKeyCurrentUser : HKEY_CURRENT_USER,
|
||||
pPolicyKey, 0,
|
||||
KEY_QUERY_VALUE, &hKey);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
rc = ReadRegDwordValue(hKey, ValueName, &dwValue);
|
||||
RegCloseKey(hKey);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
*pValue = dwValue;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
BOOL
|
||||
GetShutdownReasonUI(VOID)
|
||||
@@ -431,78 +476,6 @@ ShellIsFriendlyUIActive(VOID)
|
||||
return bActive;
|
||||
}
|
||||
|
||||
DWORD
|
||||
GetDefaultShutdownSelState(VOID)
|
||||
{
|
||||
return WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
|
||||
}
|
||||
|
||||
DWORD
|
||||
LoadShutdownSelState(VOID)
|
||||
{
|
||||
LONG lRet;
|
||||
HKEY hKeyCurrentUser, hKey;
|
||||
DWORD dwValue, dwTemp, dwSize;
|
||||
|
||||
/* Default to shutdown */
|
||||
dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
|
||||
|
||||
/* Open the current user HKCU key */
|
||||
lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
|
||||
if (lRet == ERROR_SUCCESS)
|
||||
{
|
||||
/* Open the subkey */
|
||||
lRet = RegOpenKeyExW(hKeyCurrentUser,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
|
||||
0, KEY_QUERY_VALUE, &hKey);
|
||||
RegCloseKey(hKeyCurrentUser);
|
||||
}
|
||||
if (lRet != ERROR_SUCCESS)
|
||||
return dwValue;
|
||||
|
||||
/* Read the value */
|
||||
dwSize = sizeof(dwTemp);
|
||||
lRet = RegQueryValueExW(hKey,
|
||||
L"Shutdown Setting",
|
||||
NULL, NULL,
|
||||
(LPBYTE)&dwTemp, &dwSize);
|
||||
RegCloseKey(hKey);
|
||||
|
||||
if (lRet == ERROR_SUCCESS)
|
||||
{
|
||||
switch (dwTemp)
|
||||
{
|
||||
case WLX_SHUTDOWN_STATE_LOGOFF:
|
||||
dwValue = WLX_SAS_ACTION_LOGOFF;
|
||||
break;
|
||||
|
||||
case WLX_SHUTDOWN_STATE_POWER_OFF:
|
||||
dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
|
||||
break;
|
||||
|
||||
case WLX_SHUTDOWN_STATE_REBOOT:
|
||||
dwValue = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
|
||||
break;
|
||||
|
||||
// 0x08
|
||||
|
||||
case WLX_SHUTDOWN_STATE_SLEEP:
|
||||
dwValue = WLX_SAS_ACTION_SHUTDOWN_SLEEP;
|
||||
break;
|
||||
|
||||
// 0x20
|
||||
|
||||
case WLX_SHUTDOWN_STATE_HIBERNATE:
|
||||
dwValue = WLX_SAS_ACTION_SHUTDOWN_HIBERNATE;
|
||||
break;
|
||||
|
||||
// 0x80
|
||||
}
|
||||
}
|
||||
|
||||
return dwValue;
|
||||
}
|
||||
|
||||
static INT_PTR
|
||||
CALLBACK
|
||||
OwnerDrawButtonSubclass(
|
||||
@@ -719,18 +692,78 @@ VOID OnTimer(
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
SaveShutdownSelState(
|
||||
IN DWORD ShutdownCode)
|
||||
DWORD
|
||||
LoadShutdownSelState(
|
||||
_In_ HKEY hKeyCurrentUser)
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD dwValue, dwTemp, dwSize;
|
||||
LONG lRet;
|
||||
HKEY hKeyCurrentUser, hKey;
|
||||
DWORD dwValue = 0;
|
||||
|
||||
/* Open the current user HKCU key */
|
||||
lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
|
||||
/* Default to first item */
|
||||
dwValue = 0;
|
||||
|
||||
/* Open the subkey */
|
||||
lRet = RegOpenKeyExW(hKeyCurrentUser,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
|
||||
0, KEY_QUERY_VALUE, &hKey);
|
||||
if (lRet != ERROR_SUCCESS)
|
||||
return dwValue;
|
||||
|
||||
/* Read the value */
|
||||
dwSize = sizeof(dwTemp);
|
||||
lRet = RegQueryValueExW(hKey,
|
||||
L"Shutdown Setting",
|
||||
NULL, NULL,
|
||||
(LPBYTE)&dwTemp, &dwSize);
|
||||
RegCloseKey(hKey);
|
||||
|
||||
if (lRet == ERROR_SUCCESS)
|
||||
{
|
||||
switch (dwTemp)
|
||||
{
|
||||
case WLX_SHUTDOWN_STATE_LOGOFF:
|
||||
dwValue = WLX_SAS_ACTION_LOGOFF;
|
||||
break;
|
||||
|
||||
case WLX_SHUTDOWN_STATE_POWER_OFF:
|
||||
dwValue = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
|
||||
break;
|
||||
|
||||
case WLX_SHUTDOWN_STATE_REBOOT:
|
||||
dwValue = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
|
||||
break;
|
||||
|
||||
// 0x08
|
||||
|
||||
case WLX_SHUTDOWN_STATE_SLEEP:
|
||||
dwValue = WLX_SAS_ACTION_SHUTDOWN_SLEEP;
|
||||
break;
|
||||
|
||||
case WLX_SHUTDOWN_STATE_SLEEP2:
|
||||
dwValue = WLX_SAS_ACTION_SHUTDOWN_SLEEP2;
|
||||
break;
|
||||
|
||||
case WLX_SHUTDOWN_STATE_HIBERNATE:
|
||||
dwValue = WLX_SAS_ACTION_SHUTDOWN_HIBERNATE;
|
||||
break;
|
||||
|
||||
// WLX_SHUTDOWN_STATE_DISCONNECT
|
||||
}
|
||||
}
|
||||
|
||||
return dwValue;
|
||||
}
|
||||
|
||||
VOID
|
||||
SaveShutdownSelState(
|
||||
_In_ HKEY hKeyCurrentUser,
|
||||
_In_ DWORD ShutdownCode)
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD dwValue = 0;
|
||||
LONG lRet;
|
||||
|
||||
/* Create the subkey */
|
||||
lRet = RegCreateKeyExW(hKeyCurrentUser,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
|
||||
@@ -738,8 +771,6 @@ SaveShutdownSelState(
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
KEY_SET_VALUE,
|
||||
NULL, &hKey, NULL);
|
||||
RegCloseKey(hKeyCurrentUser);
|
||||
}
|
||||
if (lRet != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
@@ -774,18 +805,38 @@ SaveShutdownSelState(
|
||||
}
|
||||
|
||||
DWORD
|
||||
GetDefaultShutdownOptions(VOID)
|
||||
{
|
||||
return WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
|
||||
}
|
||||
|
||||
DWORD
|
||||
GetAllowedShutdownOptions(VOID)
|
||||
GetAllowedShutdownOptions(
|
||||
_In_opt_ HKEY hKeyCurrentUser,
|
||||
_In_opt_ HANDLE hUserToken)
|
||||
{
|
||||
DWORD Options = 0;
|
||||
DWORD dwPolicyValue;
|
||||
|
||||
// FIXME: Compute those options accordings to current user's rights!
|
||||
Options |= WLX_SHUTDOWN_STATE_LOGOFF | WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
|
||||
dwPolicyValue = 0;
|
||||
GetPolicyDWORDValue(hKeyCurrentUser,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
|
||||
L"NoLogoff", &dwPolicyValue);
|
||||
if (dwPolicyValue == 0)
|
||||
Options |= WLX_SHUTDOWN_STATE_LOGOFF;
|
||||
|
||||
#if 0 // TODO: Enable and lookup on a Terminal Services session
|
||||
dwPolicyValue = 0;
|
||||
GetPolicyDWORDValue(hKeyCurrentUser,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
|
||||
L"NoDisconnect", &dwPolicyValue);
|
||||
if (dwPolicyValue == 0)
|
||||
Options |= WLX_SHUTDOWN_STATE_DISCONNECT;
|
||||
#endif
|
||||
|
||||
/* Add shutdown options only if the user has shutdown privilege */
|
||||
if (!TestTokenPrivilege(hUserToken, SE_SHUTDOWN_PRIVILEGE))
|
||||
return Options; // The user doesn't have them, bail out.
|
||||
|
||||
Options |= WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
|
||||
|
||||
// NOTE: "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power" value "Shutdown"
|
||||
// for "advanced" sleep options. See the 3rd parameter of:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/powrprof/nf-powrprof-setsuspendstate
|
||||
|
||||
if (IsPwrSuspendAllowed())
|
||||
Options |= WLX_SHUTDOWN_STATE_SLEEP;
|
||||
@@ -793,24 +844,34 @@ GetAllowedShutdownOptions(VOID)
|
||||
if (IsPwrHibernateAllowed())
|
||||
Options |= WLX_SHUTDOWN_STATE_HIBERNATE;
|
||||
|
||||
// TODO: Consider Windows 8+ support for:
|
||||
// "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power" value "HiberbootEnabled"
|
||||
|
||||
// TODO: Add WLX_SHUTDOWN_AUTOUPDATE if:
|
||||
// - Policy "Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU" value "NoAUShutdownOption"
|
||||
// is absent or zero;
|
||||
// - SystemBatteryState detects the computer is on external power;
|
||||
// - wuaueng.dll!ordinal_4 tells there are pending updates.
|
||||
|
||||
return Options;
|
||||
}
|
||||
|
||||
static VOID
|
||||
UpdateShutdownDesc(
|
||||
IN HWND hDlg,
|
||||
IN PSHUTDOWN_DLG_CONTEXT pContext) // HINSTANCE hInstance
|
||||
_In_ HWND hDlg,
|
||||
_In_ PSHUTDOWN_DLG_CONTEXT pContext) // HINSTANCE hInstance
|
||||
{
|
||||
UINT DescId = 0;
|
||||
HWND hwndList = GetDlgItem(hDlg, IDC_SHUTDOWN_ACTION);
|
||||
DWORD ShutdownCode;
|
||||
UINT DescId = 0;
|
||||
WCHAR szBuffer[256];
|
||||
|
||||
ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_ACTION, CB_GETCURSEL, 0, 0);
|
||||
ShutdownCode = SendMessageW(hwndList, CB_GETCURSEL, 0, 0);
|
||||
if (ShutdownCode != CB_ERR)
|
||||
ShutdownCode = SendMessageW(hwndList, CB_GETITEMDATA, ShutdownCode, 0);
|
||||
if (ShutdownCode == CB_ERR) // Invalid selection
|
||||
return;
|
||||
|
||||
ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_ACTION, CB_GETITEMDATA, ShutdownCode, 0);
|
||||
|
||||
switch (ShutdownCode)
|
||||
{
|
||||
case WLX_SAS_ACTION_LOGOFF:
|
||||
@@ -842,9 +903,10 @@ UpdateShutdownDesc(
|
||||
|
||||
if (pContext->bReasonUI)
|
||||
{
|
||||
EnableWindow(GetDlgItem(hDlg, IDC_REASON_PLANNED), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
|
||||
EnableWindow(GetDlgItem(hDlg, IDC_REASON_LIST), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
|
||||
EnableWindow(GetDlgItem(hDlg, IDC_REASON_COMMENT), (ShutdownCode != WLX_SAS_ACTION_LOGOFF));
|
||||
BOOL bNotLogoff = (ShutdownCode != WLX_SAS_ACTION_LOGOFF);
|
||||
EnableWindow(GetDlgItem(hDlg, IDC_REASON_PLANNED), bNotLogoff);
|
||||
EnableWindow(GetDlgItem(hDlg, IDC_REASON_LIST), bNotLogoff);
|
||||
EnableWindow(GetDlgItem(hDlg, IDC_REASON_COMMENT), bNotLogoff);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -932,7 +994,7 @@ ShutdownOnInit(
|
||||
SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_LOGOFF);
|
||||
}
|
||||
|
||||
/* Shut down - DEFAULT */
|
||||
/* Shut down */
|
||||
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_POWER_OFF)
|
||||
{
|
||||
LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SHUTDOWN, szBuffer, _countof(szBuffer));
|
||||
@@ -961,7 +1023,7 @@ ShutdownOnInit(
|
||||
SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_SLEEP);
|
||||
}
|
||||
|
||||
// if (pContext->ShutdownOptions & 0x20) {}
|
||||
// if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_SLEEP2) {}
|
||||
|
||||
/* Hibernate */
|
||||
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_HIBERNATE)
|
||||
@@ -972,9 +1034,11 @@ ShutdownOnInit(
|
||||
SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_HIBERNATE);
|
||||
}
|
||||
|
||||
// if (pContext->ShutdownOptions & 0x80) {}
|
||||
// if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_DISCONNECT) {}
|
||||
|
||||
/* Set the default shut down selection */
|
||||
// if (pContext->ShutdownOptions & WLX_SHUTDOWN_AUTOUPDATE) {}
|
||||
|
||||
/* Set the default selection */
|
||||
count = SendMessageW(hwndList, CB_GETCOUNT, 0, 0);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
@@ -984,6 +1048,11 @@ ShutdownOnInit(
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* If no item was selected (nShutdownAction with value 0 or invalid,
|
||||
* or an action that is currently unavailable), set the selection to
|
||||
* the first list item. */
|
||||
if (count && (SendMessageW(hwndList, CB_GETCURSEL, 0, 0) == CB_ERR))
|
||||
SendMessageW(hwndList, CB_SETCURSEL, 0, 0);
|
||||
|
||||
/* Update the choice description based on the current selection */
|
||||
UpdateShutdownDesc(hDlg, pContext);
|
||||
@@ -991,24 +1060,16 @@ ShutdownOnInit(
|
||||
|
||||
static VOID
|
||||
ShutdownOnOk(
|
||||
IN HWND hDlg,
|
||||
IN PGINA_CONTEXT pgContext)
|
||||
_In_ HWND hDlg,
|
||||
_In_ PGINA_CONTEXT pgContext)
|
||||
{
|
||||
INT idx;
|
||||
|
||||
idx = SendDlgItemMessageW(hDlg,
|
||||
IDC_SHUTDOWN_ACTION,
|
||||
CB_GETCURSEL,
|
||||
0,
|
||||
0);
|
||||
if (idx != CB_ERR)
|
||||
HWND hwndList = GetDlgItem(hDlg, IDC_SHUTDOWN_ACTION);
|
||||
DWORD ShutdownCode = SendMessageW(hwndList, CB_GETCURSEL, 0, 0);
|
||||
if (ShutdownCode != CB_ERR)
|
||||
{
|
||||
pgContext->nShutdownAction =
|
||||
SendDlgItemMessageW(hDlg,
|
||||
IDC_SHUTDOWN_ACTION,
|
||||
CB_GETITEMDATA,
|
||||
idx,
|
||||
0);
|
||||
ShutdownCode = SendMessageW(hwndList, CB_GETITEMDATA, ShutdownCode, 0);
|
||||
if (ShutdownCode != CB_ERR)
|
||||
pgContext->nShutdownAction = ShutdownCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1030,7 +1091,6 @@ ShutdownDialogProc(
|
||||
{
|
||||
pContext = (PSHUTDOWN_DLG_CONTEXT)lParam;
|
||||
SetWindowLongPtrW(hDlg, GWLP_USERDATA, (LONG_PTR)pContext);
|
||||
|
||||
ShutdownOnInit(hDlg, pContext);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1153,13 +1213,15 @@ ShutdownDialog(
|
||||
SHUTDOWN_DLG_CONTEXT Context = {0};
|
||||
|
||||
#if 0
|
||||
DWORD ShutdownOptions;
|
||||
|
||||
// FIXME: User impersonation!!
|
||||
pgContext->nShutdownAction = LoadShutdownSelState();
|
||||
ShutdownOptions = GetAllowedShutdownOptions();
|
||||
ShutdownOptions = GetAllowedShutdownOptions(???, pgContext->UserToken);
|
||||
pgContext->nShutdownAction = LoadShutdownSelState(???);
|
||||
ShutdownOptions &= ~dwExcludeOptions;
|
||||
#endif
|
||||
|
||||
/* Bail out early if no shutdown options are available */
|
||||
if (ShutdownOptions == 0)
|
||||
return IDCANCEL;
|
||||
|
||||
Context.pgContext = pgContext;
|
||||
Context.ShutdownOptions = ShutdownOptions;
|
||||
Context.ShutdownDialogId = IDD_SHUTDOWN;
|
||||
@@ -1181,14 +1243,10 @@ ShutdownDialog(
|
||||
if (Context.bFriendlyUI)
|
||||
{
|
||||
if (IsShowHibernateButtonActive())
|
||||
{
|
||||
Context.ShutdownDialogId = IDD_SHUTDOWN_FANCY_LONG;
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.ShutdownDialogId = IDD_SHUTDOWN_FANCY;
|
||||
}
|
||||
}
|
||||
|
||||
ret = DialogBoxParamW(pgContext->hDllInstance,
|
||||
MAKEINTRESOURCEW(Context.bReasonUI ? IDD_SHUTDOWN_REASON : Context.ShutdownDialogId),
|
||||
@@ -1197,10 +1255,11 @@ ShutdownDialog(
|
||||
(LPARAM)&Context);
|
||||
}
|
||||
|
||||
// TODO: Handle shutdown reasons.
|
||||
|
||||
#if 0
|
||||
// FIXME: User impersonation!!
|
||||
if (ret == IDOK)
|
||||
SaveShutdownSelState(pgContext->nShutdownAction);
|
||||
SaveShutdownSelState(???, pgContext->nShutdownAction);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
@@ -1218,17 +1277,17 @@ ShutdownDialog(
|
||||
* - When the Help button is pushed, it sends the same return value as IDCANCEL (0x00), but
|
||||
* at the same time, it calls the help file directly from the dialog box.
|
||||
* - When the dialog is created, it doesn't disable all other input from the other windows.
|
||||
* This is done elsewhere. When running the function ShellShutdownDialog() from XP/2K3, if the user clicks
|
||||
* out of the window, it automatically closes itself.
|
||||
* - The parameter, lpUsername never seems to be used when calling the function from Windows XP. Either
|
||||
* This is done elsewhere. When running the function ShellShutdownDialog() from XP/2K3, if the user
|
||||
* clicks out of the window, it automatically closes itself.
|
||||
* - The parameter pUserName, never seems to be used when calling the function from Windows XP. Either
|
||||
* it was a parameter that was never used in the final version before release, or it has a use that
|
||||
* is currently not known.
|
||||
*/
|
||||
DWORD WINAPI
|
||||
ShellShutdownDialog(
|
||||
HWND hParent,
|
||||
LPWSTR lpUsername,
|
||||
BOOL bHideLogoff)
|
||||
_In_ HWND hWndParent,
|
||||
_In_opt_ LPCWSTR pUserName,
|
||||
_In_ DWORD dwExcludeOptions)
|
||||
{
|
||||
INT_PTR dlgValue;
|
||||
DWORD ShutdownOptions;
|
||||
@@ -1238,31 +1297,62 @@ ShellShutdownDialog(
|
||||
* the cached GINA context but use a local copy here.
|
||||
*/
|
||||
GINA_CONTEXT gContext = {0};
|
||||
DWORD BufferSize;
|
||||
|
||||
UNREFERENCED_PARAMETER(lpUsername);
|
||||
|
||||
ShutdownOptions = GetAllowedShutdownOptions();
|
||||
if (bHideLogoff)
|
||||
ShutdownOptions &= ~WLX_SHUTDOWN_STATE_LOGOFF;
|
||||
ShutdownOptions = GetAllowedShutdownOptions(HKEY_CURRENT_USER, NULL);
|
||||
ShutdownOptions &= ~dwExcludeOptions;
|
||||
|
||||
/* Initialize our local GINA context */
|
||||
gContext.hDllInstance = hDllInstance;
|
||||
BufferSize = _countof(gContext.UserName);
|
||||
// NOTE: Only when this function is called, Win checks inside
|
||||
// HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
|
||||
// value "Logon User Name", and determines whether it will display
|
||||
// the user name.
|
||||
gContext.nShutdownAction = LoadShutdownSelState(HKEY_CURRENT_USER);
|
||||
if (gContext.nShutdownAction == 0)
|
||||
gContext.nShutdownAction = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
|
||||
|
||||
if (pUserName)
|
||||
{
|
||||
/* Use the caller-given user name */
|
||||
StringCbCopyW(gContext.UserName, sizeof(gContext.UserName), pUserName);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use either the convenience "Logon User Name" registered by
|
||||
* WlxActivateUserShell(), or if not found, retrieve a user name
|
||||
* via GetUserNameW() */
|
||||
HKEY hKey;
|
||||
LONG lRet;
|
||||
lRet = RegOpenKeyExW(HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
|
||||
0,
|
||||
KEY_QUERY_VALUE, &hKey);
|
||||
if (lRet == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD dwType, cbData = sizeof(gContext.UserName);
|
||||
lRet = RegQueryValueExW(hKey,
|
||||
L"Logon User Name",
|
||||
NULL,
|
||||
&dwType,
|
||||
(PBYTE)gContext.UserName,
|
||||
&cbData);
|
||||
RegCloseKey(hKey);
|
||||
|
||||
/* NULL-terminate the string */
|
||||
if (lRet != ERROR_SUCCESS)
|
||||
cbData = 0;
|
||||
gContext.UserName[cbData / sizeof(WCHAR)] = UNICODE_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD BufferSize = _countof(gContext.UserName);
|
||||
GetUserNameW(gContext.UserName, &BufferSize);
|
||||
gContext.nShutdownAction = LoadShutdownSelState();
|
||||
}
|
||||
}
|
||||
|
||||
/* Load the shutdown dialog box */
|
||||
dlgValue = ShutdownDialog(hParent, ShutdownOptions, &gContext);
|
||||
dlgValue = ShutdownDialog(hWndParent, ShutdownOptions, &gContext);
|
||||
|
||||
/* Determine what to do based on user selection */
|
||||
if (dlgValue == IDOK)
|
||||
{
|
||||
SaveShutdownSelState(gContext.nShutdownAction);
|
||||
SaveShutdownSelState(HKEY_CURRENT_USER, gContext.nShutdownAction);
|
||||
|
||||
switch (gContext.nShutdownAction)
|
||||
{
|
||||
@@ -1280,19 +1370,20 @@ ShellShutdownDialog(
|
||||
case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
|
||||
return WLX_SHUTDOWN_STATE_SLEEP;
|
||||
|
||||
// 0x20
|
||||
case WLX_SAS_ACTION_SHUTDOWN_SLEEP2:
|
||||
return WLX_SHUTDOWN_STATE_SLEEP2;
|
||||
|
||||
case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
|
||||
return WLX_SHUTDOWN_STATE_HIBERNATE;
|
||||
|
||||
// 0x80
|
||||
// WLX_SHUTDOWN_STATE_DISCONNECT
|
||||
}
|
||||
}
|
||||
/* Help file is called directly here */
|
||||
else if (dlgValue == IDHELP)
|
||||
{
|
||||
FIXME("Help is not implemented yet.\n");
|
||||
MessageBoxW(hParent, L"Help is not implemented yet.", L"Message", MB_OK | MB_ICONEXCLAMATION);
|
||||
MessageBoxW(hWndParent, L"Help is not implemented yet.", L"Message", MB_OK | MB_ICONEXCLAMATION);
|
||||
}
|
||||
else if (dlgValue == -1)
|
||||
{
|
||||
@@ -1310,5 +1401,5 @@ ShellShutdownDialog(
|
||||
DWORD WINAPI
|
||||
ShellTurnOffDialog(HWND hWnd)
|
||||
{
|
||||
return ShellShutdownDialog(hWnd, NULL, FALSE);
|
||||
return ShellShutdownDialog(hWnd, NULL, 0);
|
||||
}
|
||||
|
@@ -108,6 +108,64 @@ ReadRegDwordValue(
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Verifies whether the specified token has the given privilege.
|
||||
*
|
||||
* @see
|
||||
* shell32!SHTestTokenPrivilegeW(),
|
||||
* http://undoc.airesoft.co.uk/shell32.dll/SHTestTokenPrivilegeW.php
|
||||
* and setupapi!DoesUserHavePrivilege().
|
||||
*/
|
||||
BOOL
|
||||
TestTokenPrivilege(
|
||||
_In_opt_ HANDLE hToken,
|
||||
_In_ ULONG Privilege)
|
||||
{
|
||||
LUID PrivilegeLuid = {Privilege, 0};
|
||||
HANDLE hNewToken = NULL;
|
||||
PTOKEN_PRIVILEGES pTokenPriv;
|
||||
DWORD dwLength;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (!hToken)
|
||||
{
|
||||
/* Open effective token */
|
||||
ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hNewToken);
|
||||
if (!ret && (GetLastError() == ERROR_NO_TOKEN))
|
||||
ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hNewToken);
|
||||
if (!ret || !hNewToken)
|
||||
return FALSE;
|
||||
hToken = hNewToken;
|
||||
}
|
||||
|
||||
dwLength = 0;
|
||||
ret = GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwLength);
|
||||
if (!ret && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
|
||||
goto Quit;
|
||||
|
||||
ret = FALSE;
|
||||
pTokenPriv = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, dwLength);
|
||||
if (!pTokenPriv)
|
||||
goto Quit;
|
||||
|
||||
if (GetTokenInformation(hToken, TokenPrivileges, pTokenPriv, dwLength, &dwLength))
|
||||
{
|
||||
DWORD i, cPrivs = pTokenPriv->PrivilegeCount;
|
||||
for (i = 0; !ret && i < cPrivs; ++i)
|
||||
{
|
||||
ret = RtlEqualLuid(&PrivilegeLuid, &pTokenPriv->Privileges[i].Luid);
|
||||
}
|
||||
}
|
||||
|
||||
LocalFree(pTokenPriv);
|
||||
|
||||
Quit:
|
||||
if (hToken == hNewToken)
|
||||
CloseHandle(hNewToken);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PWSTR
|
||||
DuplicateString(
|
||||
_In_opt_ PCWSTR Str)
|
||||
|
@@ -1603,7 +1603,7 @@ VOID ExitWindowsDialog_backup(HWND hWndOwner)
|
||||
*/
|
||||
void WINAPI ExitWindowsDialog(HWND hWndOwner)
|
||||
{
|
||||
typedef DWORD (WINAPI *ShellShFunc)(HWND hParent, WCHAR *Username, BOOL bHideLogoff);
|
||||
typedef DWORD (WINAPI *ShellShFunc)(HWND hWndParent, LPCWSTR pUserName, DWORD dwExcludeOptions);
|
||||
HINSTANCE msginaDll = LoadLibraryW(L"msgina.dll");
|
||||
|
||||
TRACE("(%p)\n", hWndOwner);
|
||||
@@ -1623,11 +1623,10 @@ void WINAPI ExitWindowsDialog(HWND hWndOwner)
|
||||
}
|
||||
|
||||
ShellShFunc pShellShutdownDialog = (ShellShFunc)GetProcAddress(msginaDll, "ShellShutdownDialog");
|
||||
|
||||
if (pShellShutdownDialog)
|
||||
{
|
||||
/* Actually call the function */
|
||||
DWORD returnValue = pShellShutdownDialog(parent, NULL, FALSE);
|
||||
DWORD returnValue = pShellShutdownDialog(parent, NULL, 0);
|
||||
|
||||
switch (returnValue)
|
||||
{
|
||||
|
Reference in New Issue
Block a user