windows-nt/Source/XPSP1/NT/shell/shell32/shtdndlg.c
2020-09-26 16:20:57 +08:00

493 lines
15 KiB
C

/*************************************************************************
Private shell shutdown dialog implementation
The shell needs a shutdown dialog implementation independent of MSGINA's
implementation to ensure it will function on NT4 and Win9x machines.
This version of shutdown should only be called if the LoadLib and
GetProcAddress for the MSGINA version fail.
This code should be kept in some type of sync with the code in
win/gina/msgina/shtdndlg.c
-dsheldon 10/27/98
*************************************************************************/
#include "shellprv.h"
#include <windowsx.h>
#include <help.h>
#define MAX_SHTDN_OPTIONS 7
#define MAX_CCH_NAME 64
#define MAX_CCH_DESC 256
typedef struct _SHUTDOWNOPTION
{
DWORD dwOption;
TCHAR szName[MAX_CCH_NAME + 1];
TCHAR szDesc[MAX_CCH_DESC + 1];
} SHUTDOWNOPTION, *PSHUTDOWNOPTION;
typedef struct _SHUTDOWNDLGDATA
{
SHUTDOWNOPTION rgShutdownOptions[MAX_SHTDN_OPTIONS];
int cShutdownOptions;
DWORD dwFlags;
DWORD dwItemSelect;
BOOL fEndDialogOnActivate;
} SHUTDOWNDLGDATA, *PSHUTDOWNDLGDATA;
// Internal function prototypes
void SetShutdownOptionDescription(HWND hwndCombo, HWND hwndStatic);
BOOL LoadShutdownOptionStrings(int idStringName, int idStringDesc,
PSHUTDOWNOPTION pOption);
BOOL BuildShutdownOptionArray(DWORD dwItems, LPCTSTR szUsername,
PSHUTDOWNDLGDATA pdata);
BOOL Shutdown_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
DWORD GetOptionSelection(HWND hwndCombo);
void SetShutdownOptionDescription(HWND hwndCombo, HWND hwndStatic);
BOOL Shutdown_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
BOOL_PTR CALLBACK Shutdown_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam);
// Copied function implementations and constants
// A function copied from gina that shutdown dialog needs.
/*-----------------------------------------------------------------------------
/ MoveControls
/ ------------
/ Load the image and add the control to the dialog.
/
/ In:
/ hWnd = window to move controls in
/ aID, cID = array of control ids to be moved
/ dx, dy = deltas to apply to controls
/
/ Out:
/ -
/----------------------------------------------------------------------------*/
VOID MoveControls(HWND hWnd, UINT* aID, INT cID, INT dx, INT dy, BOOL fSizeWnd)
{
RECT rc;
while ( --cID >= 0 )
{
HWND hWndCtrl = GetDlgItem(hWnd, aID[cID]);
if ( hWndCtrl )
{
GetWindowRect(hWndCtrl, &rc);
MapWindowPoints(NULL, hWnd, (LPPOINT)&rc, 2);
OffsetRect(&rc, dx, dy);
SetWindowPos(hWndCtrl, NULL, rc.left, rc.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
}
}
if ( fSizeWnd )
{
GetWindowRect(hWnd, &rc);
MapWindowPoints(NULL, GetParent(hWnd), (LPPOINT)&rc, 2);
SetWindowPos(hWnd, NULL,
0, 0, (rc.right-rc.left)+dx, (rc.bottom-rc.top)+dy,
SWP_NOZORDER|SWP_NOMOVE);
}
}
/****************************************************
Option flags (dwFlags)
----------------------
****************************************************/
#define SHTDN_NOHELP 0x000000001
#define SHTDN_NOPALETTECHANGE 0x000000002
// Shutdown reg value name
#define SHUTDOWN_SETTING TEXT("Shutdown Setting")
// Da code
// -------
BOOL LoadShutdownOptionStrings(int idStringName, int idStringDesc,
PSHUTDOWNOPTION pOption)
{
BOOL fSuccess = (LoadString(HINST_THISDLL, idStringName, pOption->szName,
ARRAYSIZE(pOption->szName)) != 0);
fSuccess &= (LoadString(HINST_THISDLL, idStringDesc, pOption->szDesc,
ARRAYSIZE(pOption->szDesc)) != 0);
return fSuccess;
}
BOOL BuildShutdownOptionArray(DWORD dwItems, LPCTSTR szUsername,
PSHUTDOWNDLGDATA pdata)
{
BOOL fSuccess = TRUE;
pdata->cShutdownOptions = 0;
if (dwItems & SHTDN_LOGOFF)
{
pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_LOGOFF;
// Note that logoff is a special case: format using a user name ala
// "log off <username>".
fSuccess &= LoadShutdownOptionStrings(IDS_LOGOFF_NAME,
IDS_LOGOFF_DESC,
&(pdata->rgShutdownOptions[pdata->cShutdownOptions]));
if (fSuccess)
{
TCHAR szTemp[ARRAYSIZE(pdata->rgShutdownOptions[pdata->cShutdownOptions].szName)];
if (szUsername != NULL)
{
wnsprintf(szTemp, ARRAYSIZE(szTemp),
pdata->rgShutdownOptions[pdata->cShutdownOptions].szName,
szUsername);
}
else
{
wnsprintf(szTemp, ARRAYSIZE(szTemp),
pdata->rgShutdownOptions[pdata->cShutdownOptions].szName,
TEXT(""));
}
// Now we have the real logoff title in szTemp; copy is back
lstrcpy(pdata->rgShutdownOptions[pdata->cShutdownOptions].szName,
szTemp);
// Success!
pdata->cShutdownOptions ++;
}
}
if (dwItems & SHTDN_SHUTDOWN)
{
pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_SHUTDOWN;
fSuccess &= LoadShutdownOptionStrings(IDS_SHUTDOWN_NAME,
IDS_SHUTDOWN_DESC,
&(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
}
if (dwItems & SHTDN_RESTART)
{
pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_RESTART;
fSuccess &= LoadShutdownOptionStrings(IDS_RESTART_NAME,
IDS_RESTART_DESC,
&(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
}
if (dwItems & SHTDN_RESTART_DOS)
{
pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_RESTART_DOS;
fSuccess &= LoadShutdownOptionStrings(IDS_RESTARTDOS_NAME,
IDS_RESTARTDOS_DESC,
&(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
}
if (dwItems & SHTDN_SLEEP)
{
pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_SLEEP;
fSuccess &= LoadShutdownOptionStrings(IDS_SLEEP_NAME,
IDS_SLEEP_DESC,
&(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
}
if (dwItems & SHTDN_SLEEP2)
{
pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_SLEEP2;
fSuccess &= LoadShutdownOptionStrings(IDS_SLEEP2_NAME,
IDS_SLEEP2_DESC,
&(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
}
if (dwItems & SHTDN_HIBERNATE)
{
pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_HIBERNATE;
fSuccess &= LoadShutdownOptionStrings(IDS_HIBERNATE_NAME,
IDS_HIBERNATE_DESC,
&(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
}
return fSuccess;
}
BOOL Shutdown_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
PSHUTDOWNDLGDATA pdata = (PSHUTDOWNDLGDATA) lParam;
HWND hwndCombo;
int iOption;
int iComboItem;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) lParam);
// Hide the help button and move over OK and Cancel if applicable
if (pdata->dwFlags & SHTDN_NOHELP)
{
static UINT rgidNoHelp[] = {IDOK, IDCANCEL};
RECT rc1, rc2;
int dx;
HWND hwndHelp = GetDlgItem(hwnd, IDHELP);
EnableWindow(hwndHelp, FALSE);
ShowWindow(hwndHelp, SW_HIDE);
GetWindowRect(hwndHelp, &rc1);
GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc2);
dx = rc1.left - rc2.left;
MoveControls(hwnd, rgidNoHelp, ARRAYSIZE(rgidNoHelp), dx, 0, FALSE);
}
// Add the items specified to the combo box
hwndCombo = GetDlgItem(hwnd, IDC_EXITOPTIONS_COMBO);
for (iOption = 0; iOption < pdata->cShutdownOptions; iOption ++)
{
// Add the option
iComboItem = ComboBox_AddString(hwndCombo,
pdata->rgShutdownOptions[iOption].szName);
if (iComboItem != (int) CB_ERR)
{
// Store a pointer to the option
ComboBox_SetItemData(hwndCombo, iComboItem,
&(pdata->rgShutdownOptions[iOption]));
// See if we should select this option
if (pdata->rgShutdownOptions[iOption].dwOption == pdata->dwItemSelect)
{
ComboBox_SetCurSel(hwndCombo, iComboItem);
}
}
}
// If we don't have a selection in the combo, do a default selection
if (ComboBox_GetCurSel(hwndCombo) == CB_ERR)
{
ComboBox_SetCurSel(hwndCombo, 0);
}
SetShutdownOptionDescription(hwndCombo,
GetDlgItem(hwnd, IDC_EXITOPTIONS_DESCRIPTION));
// If we get an activate message, dismiss the dialog, since we just lost
// focus
pdata->fEndDialogOnActivate = TRUE;
return TRUE;
}
DWORD GetOptionSelection(HWND hwndCombo)
{
DWORD dwResult;
PSHUTDOWNOPTION pOption;
int iItem = ComboBox_GetCurSel(hwndCombo);
if (iItem != (int) CB_ERR)
{
pOption = (PSHUTDOWNOPTION) ComboBox_GetItemData(hwndCombo, iItem);
dwResult = pOption->dwOption;
}
else
{
dwResult = SHTDN_NONE;
}
return dwResult;
}
void SetShutdownOptionDescription(HWND hwndCombo, HWND hwndStatic)
{
int iItem;
PSHUTDOWNOPTION pOption;
iItem = ComboBox_GetCurSel(hwndCombo);
if (iItem != CB_ERR)
{
pOption = (PSHUTDOWNOPTION) ComboBox_GetItemData(hwndCombo, iItem);
SetWindowText(hwndStatic, pOption->szDesc);
}
}
BOOL Shutdown_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
BOOL fHandled = FALSE;
DWORD dwDlgResult;
PSHUTDOWNDLGDATA pdata = (PSHUTDOWNDLGDATA)
GetWindowLongPtr(hwnd, GWLP_USERDATA);
switch (id)
{
case IDOK:
dwDlgResult = GetOptionSelection(GetDlgItem(hwnd, IDC_EXITOPTIONS_COMBO));
if (dwDlgResult != SHTDN_NONE)
{
pdata->fEndDialogOnActivate = FALSE;
fHandled = TRUE;
EndDialog(hwnd, (int) dwDlgResult);
}
break;
case IDCANCEL:
pdata->fEndDialogOnActivate = FALSE;
EndDialog(hwnd, (int) SHTDN_NONE);
fHandled = TRUE;
break;
case IDC_EXITOPTIONS_COMBO:
if (codeNotify == CBN_SELCHANGE)
{
SetShutdownOptionDescription(hwndCtl,
GetDlgItem(hwnd, IDC_EXITOPTIONS_DESCRIPTION));
fHandled = TRUE;
}
break;
case IDHELP:
WinHelp(hwnd, TEXT("windows.hlp>proc4"), HELP_CONTEXT, (DWORD) IDH_TRAY_SHUTDOWN_HELP);
break;
}
return fHandled;
}
BOOL_PTR CALLBACK Shutdown_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
HANDLE_MSG(hwnd, WM_INITDIALOG, Shutdown_OnInitDialog);
HANDLE_MSG(hwnd, WM_COMMAND, Shutdown_OnCommand);
case WM_INITMENUPOPUP:
{
EnableMenuItem((HMENU)wParam, SC_MOVE, MF_BYCOMMAND|MF_GRAYED);
}
break;
case WM_SYSCOMMAND:
// Blow off moves (only really needed for 32bit land).
if ((wParam & ~0x0F) == SC_MOVE)
return TRUE;
break;
case WM_ACTIVATE:
// If we're loosing the activation for some other reason than
// the user click OK/CANCEL then bail.
if (LOWORD(wParam) == WA_INACTIVE)
{
PSHUTDOWNDLGDATA pdata = (PSHUTDOWNDLGDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (pdata->fEndDialogOnActivate)
{
pdata->fEndDialogOnActivate = FALSE;
EndDialog(hwnd, SHTDN_NONE);
}
}
break;
}
return FALSE;
}
/****************************************************************************
ShutdownDialog
--------------
Launches the shutdown dialog.
hWlx and pfnWlxDialogBoxParam MUST be null for this shell-only version
Other flags are listed in shtdnp.h.
****************************************************************************/
DWORD ShutdownDialog(HWND hwndParent, DWORD dwItems, DWORD dwItemSelect,
LPCTSTR szUsername, DWORD dwFlags, void* hWlx,
void* pfnWlxDialogBoxParam)
{
// Array of shutdown options - the dialog data
SHUTDOWNDLGDATA data;
DWORD dwResult;
// Set the flags
data.dwFlags = dwFlags;
// Set the initially selected item
data.dwItemSelect = dwItemSelect;
// Read in the strings for the shutdown option names and descriptions
if (BuildShutdownOptionArray(dwItems, szUsername, &data))
{
// Display the dialog and return the user's selection
// ..if the caller wants, use a Wlx dialog box function
if ((hWlx != NULL) || (pfnWlxDialogBoxParam != NULL))
{
// Error; winlogon should never call this
// cheesy shell version of shutdown
dwResult = SHTDN_NONE;
}
else
{
// Use standard dialog box
dwResult = (DWORD) DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(IDD_EXITWINDOWS_DIALOG), hwndParent,
Shutdown_DialogProc, (LPARAM) &data);
}
}
else
{
dwResult = SHTDN_NONE;
}
return dwResult;
}
DWORD DownlevelShellShutdownDialog(HWND hwndParent, DWORD dwItems, LPCTSTR szUsername)
{
DWORD dwSelect = SHTDN_NONE;
DWORD dwDialogResult;
HKEY hkeyShutdown;
DWORD dwType;
DWORD dwDisposition;
LONG lResult;
// get the User's last selection.
lResult = RegCreateKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER,
0, 0, 0, KEY_READ, NULL, &hkeyShutdown, &dwDisposition);
if (lResult == ERROR_SUCCESS)
{
DWORD cbData = sizeof(dwSelect);
lResult = SHQueryValueEx(hkeyShutdown, SHUTDOWN_SETTING,
0, &dwType, (LPBYTE)&dwSelect, &cbData);
RegCloseKey(hkeyShutdown);
}
if (dwSelect == SHTDN_NONE)
{
dwSelect = SHTDN_SHUTDOWN;
}
dwDialogResult = ShutdownDialog(hwndParent, dwItems, dwSelect,
szUsername, SHTDN_NOPALETTECHANGE, NULL, NULL);
if (dwDialogResult != SHTDN_NONE)
{
// Save back the user's choice to the registry
if (RegCreateKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER,
0, 0, 0, KEY_WRITE, NULL, &hkeyShutdown, &dwDisposition) == ERROR_SUCCESS)
{
RegSetValueEx(hkeyShutdown, SHUTDOWN_SETTING,
0, REG_DWORD, (LPBYTE)&dwDialogResult, sizeof(dwDialogResult));
RegCloseKey(hkeyShutdown);
}
}
return dwDialogResult;
}