mirror of
https://github.com/reactos/reactos.git
synced 2024-10-31 03:48:17 +00:00
553 lines
16 KiB
C
553 lines
16 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS msgina.dll
|
|
* FILE: lib/msgina/shutdown.c
|
|
* PURPOSE: Shutdown Dialog Box (GUI only)
|
|
* PROGRAMMERS: Lee Schroeder (spaceseel at gmail dot com)
|
|
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
|
*/
|
|
|
|
#include "msgina.h"
|
|
#include <powrprof.h>
|
|
#include <wingdi.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
|
|
|
|
typedef struct _SHUTDOWN_DLG_CONTEXT
|
|
{
|
|
PGINA_CONTEXT pgContext;
|
|
DWORD ShutdownOptions;
|
|
BOOL bCloseDlg;
|
|
} SHUTDOWN_DLG_CONTEXT, *PSHUTDOWN_DLG_CONTEXT;
|
|
|
|
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;
|
|
}
|
|
|
|
VOID
|
|
SaveShutdownSelState(
|
|
IN DWORD ShutdownCode)
|
|
{
|
|
LONG lRet;
|
|
HKEY hKeyCurrentUser, hKey;
|
|
DWORD dwValue = 0;
|
|
|
|
/* Open the current user HKCU key */
|
|
lRet = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
|
|
if (lRet == ERROR_SUCCESS)
|
|
{
|
|
/* Create the subkey */
|
|
lRet = RegCreateKeyExW(hKeyCurrentUser,
|
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
|
|
0, NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_SET_VALUE,
|
|
NULL, &hKey, NULL);
|
|
RegCloseKey(hKeyCurrentUser);
|
|
}
|
|
if (lRet != ERROR_SUCCESS)
|
|
return;
|
|
|
|
switch (ShutdownCode)
|
|
{
|
|
case WLX_SAS_ACTION_LOGOFF:
|
|
dwValue = WLX_SHUTDOWN_STATE_LOGOFF;
|
|
break;
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
|
|
dwValue = WLX_SHUTDOWN_STATE_POWER_OFF;
|
|
break;
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
|
|
dwValue = WLX_SHUTDOWN_STATE_REBOOT;
|
|
break;
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
|
|
dwValue = WLX_SHUTDOWN_STATE_SLEEP;
|
|
break;
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
|
|
dwValue = WLX_SHUTDOWN_STATE_HIBERNATE;
|
|
break;
|
|
}
|
|
|
|
RegSetValueExW(hKey,
|
|
L"Shutdown Setting",
|
|
0, REG_DWORD,
|
|
(LPBYTE)&dwValue, sizeof(dwValue));
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
DWORD
|
|
GetAllowedShutdownOptions(VOID)
|
|
{
|
|
DWORD Options = 0;
|
|
|
|
// FIXME: Compute those options accordings to current user's rights!
|
|
Options |= WLX_SHUTDOWN_STATE_LOGOFF | WLX_SHUTDOWN_STATE_POWER_OFF | WLX_SHUTDOWN_STATE_REBOOT;
|
|
|
|
if (IsPwrSuspendAllowed())
|
|
Options |= WLX_SHUTDOWN_STATE_SLEEP;
|
|
|
|
if (IsPwrHibernateAllowed())
|
|
Options |= WLX_SHUTDOWN_STATE_HIBERNATE;
|
|
|
|
return Options;
|
|
}
|
|
|
|
static VOID
|
|
UpdateShutdownDesc(
|
|
IN HWND hDlg,
|
|
IN PSHUTDOWN_DLG_CONTEXT pContext) // HINSTANCE hInstance
|
|
{
|
|
UINT DescId = 0;
|
|
DWORD ShutdownCode;
|
|
WCHAR szBuffer[256];
|
|
|
|
ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_LIST, CB_GETCURSEL, 0, 0);
|
|
if (ShutdownCode == CB_ERR) // Invalid selection
|
|
return;
|
|
|
|
ShutdownCode = SendDlgItemMessageW(hDlg, IDC_SHUTDOWN_LIST, CB_GETITEMDATA, ShutdownCode, 0);
|
|
|
|
switch (ShutdownCode)
|
|
{
|
|
case WLX_SAS_ACTION_LOGOFF:
|
|
DescId = IDS_SHUTDOWN_LOGOFF_DESC;
|
|
break;
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
|
|
DescId = IDS_SHUTDOWN_SHUTDOWN_DESC;
|
|
break;
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
|
|
DescId = IDS_SHUTDOWN_RESTART_DESC;
|
|
break;
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
|
|
DescId = IDS_SHUTDOWN_SLEEP_DESC;
|
|
break;
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
|
|
DescId = IDS_SHUTDOWN_HIBERNATE_DESC;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
LoadStringW(pContext->pgContext->hDllInstance, DescId, szBuffer, _countof(szBuffer));
|
|
SetDlgItemTextW(hDlg, IDC_SHUTDOWN_DESCRIPTION, szBuffer);
|
|
}
|
|
|
|
static VOID
|
|
ShutdownOnInit(
|
|
IN HWND hDlg,
|
|
IN PSHUTDOWN_DLG_CONTEXT pContext)
|
|
{
|
|
PGINA_CONTEXT pgContext = pContext->pgContext;
|
|
HWND hwndList;
|
|
INT idx, count, i;
|
|
WCHAR szBuffer[256];
|
|
WCHAR szBuffer2[256];
|
|
|
|
hwndList = GetDlgItem(hDlg, IDC_SHUTDOWN_LIST);
|
|
|
|
/* Clear the content before it's used */
|
|
SendMessageW(hwndList, CB_RESETCONTENT, 0, 0);
|
|
|
|
/* Log off */
|
|
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_LOGOFF)
|
|
{
|
|
LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_LOGOFF, szBuffer, _countof(szBuffer));
|
|
StringCchPrintfW(szBuffer2, _countof(szBuffer2), szBuffer, pgContext->UserName);
|
|
idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer2);
|
|
if (idx != CB_ERR)
|
|
SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_LOGOFF);
|
|
}
|
|
|
|
/* Shut down - DEFAULT */
|
|
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_POWER_OFF)
|
|
{
|
|
LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SHUTDOWN, szBuffer, _countof(szBuffer));
|
|
idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
|
|
if (idx != CB_ERR)
|
|
SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
|
|
}
|
|
|
|
/* Restart */
|
|
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_REBOOT)
|
|
{
|
|
LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_RESTART, szBuffer, _countof(szBuffer));
|
|
idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
|
|
if (idx != CB_ERR)
|
|
SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
|
|
}
|
|
|
|
// if (pContext->ShutdownOptions & 0x08) {}
|
|
|
|
/* Sleep */
|
|
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_SLEEP)
|
|
{
|
|
LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_SLEEP, szBuffer, _countof(szBuffer));
|
|
idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
|
|
if (idx != CB_ERR)
|
|
SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_SLEEP);
|
|
}
|
|
|
|
// if (pContext->ShutdownOptions & 0x20) {}
|
|
|
|
/* Hibernate */
|
|
if (pContext->ShutdownOptions & WLX_SHUTDOWN_STATE_HIBERNATE)
|
|
{
|
|
LoadStringW(pgContext->hDllInstance, IDS_SHUTDOWN_HIBERNATE, szBuffer, _countof(szBuffer));
|
|
idx = SendMessageW(hwndList, CB_ADDSTRING, 0, (LPARAM)szBuffer);
|
|
if (idx != CB_ERR)
|
|
SendMessageW(hwndList, CB_SETITEMDATA, idx, WLX_SAS_ACTION_SHUTDOWN_HIBERNATE);
|
|
}
|
|
|
|
// if (pContext->ShutdownOptions & 0x80) {}
|
|
|
|
/* Set the default shut down selection */
|
|
count = SendMessageW(hwndList, CB_GETCOUNT, 0, 0);
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (SendMessageW(hwndList, CB_GETITEMDATA, i, 0) == pgContext->nShutdownAction)
|
|
{
|
|
SendMessageW(hwndList, CB_SETCURSEL, i, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Update the choice description based on the current selection */
|
|
UpdateShutdownDesc(hDlg, pContext);
|
|
}
|
|
|
|
static VOID
|
|
ShutdownOnOk(
|
|
IN HWND hDlg,
|
|
IN PGINA_CONTEXT pgContext)
|
|
{
|
|
INT idx;
|
|
|
|
idx = SendDlgItemMessageW(hDlg,
|
|
IDC_SHUTDOWN_LIST,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0);
|
|
if (idx != CB_ERR)
|
|
{
|
|
pgContext->nShutdownAction =
|
|
SendDlgItemMessageW(hDlg,
|
|
IDC_SHUTDOWN_LIST,
|
|
CB_GETITEMDATA,
|
|
idx,
|
|
0);
|
|
}
|
|
}
|
|
|
|
static BOOL
|
|
CALLBACK
|
|
ShutdownDialogProc(
|
|
HWND hDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PSHUTDOWN_DLG_CONTEXT pContext;
|
|
|
|
pContext = (PSHUTDOWN_DLG_CONTEXT)GetWindowLongPtrW(hDlg, GWLP_USERDATA);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
pContext = (PSHUTDOWN_DLG_CONTEXT)lParam;
|
|
SetWindowLongPtrW(hDlg, GWLP_USERDATA, (LONG_PTR)pContext);
|
|
|
|
ShutdownOnInit(hDlg, pContext);
|
|
|
|
/* Draw the logo bitmap */
|
|
pContext->pgContext->hBitmap =
|
|
LoadImageW(pContext->pgContext->hDllInstance, MAKEINTRESOURCEW(IDI_ROSLOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
DeleteObject(pContext->pgContext->hBitmap);
|
|
return TRUE;
|
|
|
|
case WM_ACTIVATE:
|
|
{
|
|
/*
|
|
* If the user deactivates the shutdown dialog (it loses its focus
|
|
* while the dialog is not being closed), then destroy the dialog
|
|
* and cancel shutdown.
|
|
*/
|
|
if (LOWORD(wParam) == WA_INACTIVE)
|
|
{
|
|
if (!pContext->bCloseDlg)
|
|
{
|
|
pContext->bCloseDlg = TRUE;
|
|
EndDialog(hDlg, 0);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
case WM_PAINT:
|
|
{
|
|
PAINTSTRUCT ps;
|
|
if (pContext->pgContext->hBitmap)
|
|
{
|
|
BeginPaint(hDlg, &ps);
|
|
DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pContext->pgContext->hBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
|
|
EndPaint(hDlg, &ps);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_CLOSE:
|
|
pContext->bCloseDlg = TRUE;
|
|
EndDialog(hDlg, IDCANCEL);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
ShutdownOnOk(hDlg, pContext->pgContext);
|
|
|
|
/* Fall back */
|
|
case IDCANCEL:
|
|
case IDHELP:
|
|
pContext->bCloseDlg = TRUE;
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
break;
|
|
|
|
case IDC_SHUTDOWN_LIST:
|
|
UpdateShutdownDesc(hDlg, pContext);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
INT_PTR
|
|
ShutdownDialog(
|
|
IN HWND hwndDlg,
|
|
IN DWORD ShutdownOptions,
|
|
IN PGINA_CONTEXT pgContext)
|
|
{
|
|
INT_PTR ret;
|
|
SHUTDOWN_DLG_CONTEXT Context;
|
|
|
|
#if 0
|
|
DWORD ShutdownOptions;
|
|
|
|
// FIXME: User impersonation!!
|
|
pgContext->nShutdownAction = LoadShutdownSelState();
|
|
ShutdownOptions = GetAllowedShutdownOptions();
|
|
#endif
|
|
|
|
Context.pgContext = pgContext;
|
|
Context.ShutdownOptions = ShutdownOptions;
|
|
Context.bCloseDlg = FALSE;
|
|
|
|
if (pgContext->hWlx && pgContext->pWlxFuncs)
|
|
{
|
|
ret = pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx,
|
|
pgContext->hDllInstance,
|
|
MAKEINTRESOURCEW(IDD_SHUTDOWN_DLG),
|
|
hwndDlg,
|
|
ShutdownDialogProc,
|
|
(LPARAM)&Context);
|
|
}
|
|
else
|
|
{
|
|
ret = DialogBoxParamW(pgContext->hDllInstance,
|
|
MAKEINTRESOURCEW(IDD_SHUTDOWN_DLG),
|
|
hwndDlg,
|
|
ShutdownDialogProc,
|
|
(LPARAM)&Context);
|
|
}
|
|
|
|
#if 0
|
|
// FIXME: User impersonation!!
|
|
if (ret == IDOK)
|
|
SaveShutdownSelState(pgContext->nShutdownAction);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* NOTES:
|
|
* - Based upon observations on the ShellShutdownDialog() function, the function doesn't actually
|
|
* do anything except show a dialog box and returning a value based upon the value chosen. That
|
|
* means that any code that calls the function has to execute the chosen action (shut down,
|
|
* restart, etc.).
|
|
* - When this function is called in Windows XP, it shows the classic dialog box regardless if
|
|
* SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\LogonType is enabled or not.
|
|
* - 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
|
|
* 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)
|
|
{
|
|
INT_PTR dlgValue;
|
|
DWORD ShutdownOptions;
|
|
|
|
/*
|
|
* As we are called by the shell itself, don't use
|
|
* 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;
|
|
|
|
/* 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.
|
|
GetUserNameW(gContext.UserName, &BufferSize);
|
|
gContext.nShutdownAction = LoadShutdownSelState();
|
|
|
|
/* Load the shutdown dialog box */
|
|
dlgValue = ShutdownDialog(hParent, ShutdownOptions, &gContext);
|
|
|
|
/* Determine what to do based on user selection */
|
|
if (dlgValue == IDOK)
|
|
{
|
|
SaveShutdownSelState(gContext.nShutdownAction);
|
|
|
|
switch (gContext.nShutdownAction)
|
|
{
|
|
case WLX_SAS_ACTION_LOGOFF:
|
|
return WLX_SHUTDOWN_STATE_LOGOFF;
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
|
|
return WLX_SHUTDOWN_STATE_POWER_OFF;
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
|
|
return WLX_SHUTDOWN_STATE_REBOOT;
|
|
|
|
// 0x08
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_SLEEP:
|
|
return WLX_SHUTDOWN_STATE_SLEEP;
|
|
|
|
// 0x20
|
|
|
|
case WLX_SAS_ACTION_SHUTDOWN_HIBERNATE:
|
|
return WLX_SHUTDOWN_STATE_HIBERNATE;
|
|
|
|
// 0x80
|
|
}
|
|
}
|
|
/* Help file is called directly here */
|
|
else if (dlgValue == IDHELP)
|
|
{
|
|
FIXME("Help is not implemented yet.");
|
|
MessageBoxW(hParent, L"Help is not implemented yet.", L"Message", MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
else if (dlgValue == -1)
|
|
{
|
|
ERR("Failed to create dialog\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|