Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

672 lines
22 KiB

#include "shellprv.h"
#pragma hdrstop
#define DLGSEL_LOGOFF 0
#define DLGSEL_SHUTDOWN 1
#define DLGSEL_SHUTDOWN_AND_RESTART 2
#define DLGSEL_SHUTDOWN_AND_RESTART_DOS 3
#define SHUTDOWN_SETTING TEXT("Shutdown Setting")
// BUGBUG:: This will be pif.h...
#ifndef OPENPROPS_FORCEREALMODE
#define OPENPROPS_FORCEREALMODE 0x0004
#endif
void FlushRecentDocMRU(void);
void FlushRunDlgMRU(void);
void _FlushPerLogonCache(void);
// thunk to 16 bit code to do this
//
extern BOOL WINAPI SHRestartWindows(DWORD dwReturn);
#define ROP_DPna 0x000A0329
// Process all of the strange ExitWindowsEx codes and privileges.
//
BOOL CommonRestart(DWORD dwExitWinCode)
{
BOOL fOk;
DWORD dwExtraExitCode = 0;
#ifdef WINNT
DWORD OldState, Status;
DWORD dwErrorSave;
SetLastError(0); // Be really safe about last error value!
Status = SetPrivilegeAttribute(SE_SHUTDOWN_NAME,
SE_PRIVILEGE_ENABLED,
&OldState);
dwErrorSave = GetLastError(); // ERROR_NOT_ALL_ASSIGNED sometimes
#endif
switch (dwExitWinCode) {
case EWX_SHUTDOWN:
// By default (all platforms), we assume powerdown is possible
dwExtraExitCode = EWX_POWEROFF;
// On NT, we can check to see if machine really supports powerdown, and if not,
// remove the powerdown bit from our extra exit code
#ifdef WINNT
if (0 == GetProfileInt(TEXT("WINLOGON"), TEXT("PowerdownAfterShutdown"), 0))
{
dwExtraExitCode = 0;
}
#endif
// Fall through...
case EWX_REBOOT:
case EWX_LOGOFF:
fOk = ExitWindowsEx(dwExitWinCode | dwExtraExitCode, 0);
break;
default:
fOk = SHRestartWindows(dwExitWinCode);
break;
}
#ifdef WINNT
//
// If we were able to set the privilege, then reset it.
//
if (NT_SUCCESS(Status) && dwErrorSave == 0)
{
SetPrivilegeAttribute(SE_SHUTDOWN_NAME, OldState, NULL);
}
else
{
//
// Otherwise, if we failed, then it must have been some
// security stuff.
//
if (!fOk)
{
ShellMessageBox(HINST_THISDLL, NULL,
dwExitWinCode == EWX_SHUTDOWN ?
MAKEINTRESOURCE(IDS_NO_PERMISSION_SHUTDOWN) :
MAKEINTRESOURCE(IDS_NO_PERMISSION_RESTART),
dwExitWinCode == EWX_SHUTDOWN ?
MAKEINTRESOURCE(IDS_SHUTDOWN) :
MAKEINTRESOURCE(IDS_RESTART),
MB_OK | MB_ICONSTOP);
}
}
#endif
return (fOk);
}
/* Display a dialog asking the user to restart Windows, with a button that
** will do it for them if possible.
*/
int WINAPI RestartDialog(HWND hParent, LPCTSTR lpPrompt, DWORD dwReturn)
{
UINT id;
LPCTSTR pszMsg;
FlushRecentDocMRU();
FlushRunDlgMRU();
_IconCacheSave();
if (lpPrompt && *lpPrompt == TEXT('#'))
{
pszMsg = lpPrompt + 1;
}
else if (dwReturn == EWX_SHUTDOWN)
{
pszMsg = MAKEINTRESOURCE(IDS_RSDLG_SHUTDOWN);
}
else
{
pszMsg = MAKEINTRESOURCE(IDS_RSDLG_RESTART);
}
id = ShellMessageBox(HINST_THISDLL, hParent, pszMsg, MAKEINTRESOURCE(IDS_RSDLG_TITLE),
MB_YESNO | MB_ICONQUESTION, lpPrompt ? lpPrompt : c_szNULL);
if (id == IDYES)
{
CommonRestart(dwReturn);
}
return id;
}
//---------------------------------------------------------------------------
const WORD c_GrayBits[] = {0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA};
HBRUSH CreateDitheredBrush(void)
{
HBITMAP hbmp = CreateBitmap(8, 8, 1, 1, c_GrayBits);
if (hbmp)
{
HBRUSH hbr = CreatePatternBrush(hbmp);
DeleteObject(hbmp);
return hbr;
}
return NULL;
}
// ---------------------------------------------------------------------------
LRESULT CALLBACK FakeDesktopWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg) {
case WM_CREATE:
return TRUE;
case WM_NCPAINT:
return 0;
case WM_ACTIVATE:
DebugMsg(DM_TRACE, TEXT("FakeWndProc; WM_ACTIVATE %d hwnd=%d"), LOWORD(wparam), lparam);
if (LOWORD(wparam) == WA_INACTIVE)
{
if (lparam == 0 || GetWindow((HWND)lparam,GW_OWNER) != hwnd)
{
DebugMsg(DM_TRACE, TEXT("FakeWndProc: death"));
ShowWindow(hwnd, SW_HIDE);
PostMessage(hwnd, WM_CLOSE, 0, 0);
}
return 0;
}
break;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
TCHAR const c_szFakeDesktopClass[] = TEXT("FakeDesktopWClass");;
// ---------------------------------------------------------------------------
// Create a topmost window that sits on top of the desktop but which
// ignores WM_ERASEBKGND and never paints itself.
HWND CreateFakeDesktopWindow(void)
{
// Bad things will happen if we try to do this multiple times...
if (FindWindow(c_szFakeDesktopClass, NULL))
{
DebugMsg(DM_ERROR, TEXT("s.cfdw: Shutdown desktop already exists."));
return NULL;
}
else
{
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = FakeDesktopWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = HINST_THISDLL;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = c_szFakeDesktopClass;
// don't really care if this is already registered...
RegisterClass(&wc);
return CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
c_szFakeDesktopClass, NULL, WS_POPUP, 0, 0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN), NULL, NULL, HINST_THISDLL, NULL);
}
}
// ---------------------------------------------------------------------------
void DitherWindow(HWND hwnd)
{
HDC hdc = GetDC(hwnd);
if (hdc)
{
HBRUSH hbr = CreateDitheredBrush();
if (hbr)
{
RECT rc;
HBRUSH hbrOld = SelectObject(hdc, hbr);
GetClientRect(hwnd, &rc);
PatBlt(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, ROP_DPna);
SelectObject(hdc, hbrOld);
DeleteObject(hbr);
}
ReleaseDC(hwnd, hdc);
}
}
// ---------------------------------------------------------------------------
const int c_idEWMoveUp[] = {IDD_LOGOFF, IDOK, IDCANCEL, IDHELP};
void ExitWindowsInitRemoveButton(HWND hdlg, int idRemove, int idAbove, int iStart)
{
HWND hwndT;
RECT rcT;
int dy;
int i;
// We need to calculate how much room we need
// to compress out of the dialog
hwndT = GetDlgItem(hdlg, idRemove);
GetWindowRect(hwndT, &rcT);
dy = rcT.top;
GetWindowRect(GetDlgItem(hdlg, idAbove), &rcT);
dy -= rcT.top;
// Now destroy the window.
DestroyWindow(hwndT);
// Move the OK and Cancel buttons up
for (i = iStart; i < ARRAYSIZE(c_idEWMoveUp); i++)
{
hwndT = GetDlgItem(hdlg, c_idEWMoveUp[i]);
if (hwndT)
{
GetClientRect(hwndT, &rcT);
MapWindowPoints(hwndT, hdlg, (LPPOINT)&rcT, 2);
SetWindowPos(hwndT, NULL, rcT.left, rcT.top-dy,
0, 0, SWP_NOSIZE|SWP_NOZORDER);
}
}
// Now shrink the dialog.
GetWindowRect(hdlg, (LPRECT)&rcT);
SetWindowPos(hdlg, NULL, 0, 0, rcT.right - rcT.left,
rcT.bottom - rcT.top - dy,
SWP_NOMOVE|SWP_NOZORDER);
}
BOOL CALLBACK ExitWindowsDlgProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
{
int idCmd;
HWND hwndP;
HCURSOR hcur;
static BOOL s_fEndDialog = FALSE;
DWORD dwShutdown = DLGSEL_SHUTDOWN;
HKEY hkeyShutdown = NULL;
DWORD dwDisposition, dwType;
DWORD cbData;
LONG lResult;
switch (msg)
{
case WM_INITMENUPOPUP:
EnableMenuItem((HMENU)wparam, SC_MOVE, MF_BYCOMMAND|MF_GRAYED);
break;
// Blow off moves (only really needed for 32bit land).
case WM_SYSCOMMAND:
if ((wparam & ~0x0F) == SC_MOVE)
return TRUE;
break;
case WM_INITDIALOG:
//
// We flush two MRU's here (RecentMRU and RunDlgMRU).
// Note that they won't flush if there is any reference count.
//
// We could call them when the user actually selects the shutdown,
// but I put them here to leave the shutdown process simple.
//
FlushRecentDocMRU();
FlushRunDlgMRU();
_IconCacheSave();
// We need to see if the user is allowed to exit to dos
// or not... If not we need to remove the control and move
// all of the other controls on up...
if ((GetSystemMetrics(SM_NETWORK) & RNC_LOGON) == 0)
ExitWindowsInitRemoveButton(hdlg, IDD_LOGOFF, IDD_RESTARTDOS, 1);
// Don't have restart to dos if restricted or in clean boot as it
// won't work there!
if (SHRestricted(REST_NOEXITTODOS) || GetSystemMetrics(SM_CLEANBOOT))
ExitWindowsInitRemoveButton(hdlg, IDD_RESTARTDOS, IDD_RESTART, 0);
// Reset the end dialog flag.
s_fEndDialog = FALSE;
//
// Initial setting is User's last selection.
//
lResult = RegCreateKeyEx(HKEY_CURRENT_USER,
c_szRegExplorer,
0,
0,
0,
KEY_READ,
NULL,
&hkeyShutdown,
&dwDisposition);
if (lResult == ERROR_SUCCESS) {
cbData = sizeof(dwShutdown);
lResult = RegQueryValueEx(hkeyShutdown,
SHUTDOWN_SETTING,
0,
&dwType,
(LPBYTE)&dwShutdown,
&cbData);
RegCloseKey(hkeyShutdown);
}
if (lResult == ERROR_SUCCESS) {
hwndP = NULL;
switch(dwShutdown) {
case DLGSEL_SHUTDOWN:
hwndP = GetDlgItem(hdlg, IDD_SHUTDOWN);
CheckDlgButton(hdlg, IDD_SHUTDOWN, 1);
break;
case DLGSEL_SHUTDOWN_AND_RESTART:
hwndP = GetDlgItem(hdlg, IDD_RESTART);
CheckDlgButton(hdlg, IDD_RESTART, 1);
break;
case DLGSEL_SHUTDOWN_AND_RESTART_DOS:
hwndP = GetDlgItem(hdlg, IDD_RESTARTDOS);
CheckDlgButton(hdlg, IDD_RESTARTDOS, 1);
break;
default:
if (GetDlgItem(hdlg, IDD_LOGOFF)) {
CheckDlgButton(hdlg, IDD_LOGOFF, 1);
hwndP = GetDlgItem(hdlg, IDD_LOGOFF);
} else {
CheckDlgButton(hdlg, IDD_SHUTDOWN, 1);
hwndP = GetDlgItem(hdlg, IDD_SHUTDOWN);
}
break;
}
if (hwndP)
{
SetFocus(hwndP);
return FALSE; // Set focus to same item
}
} else {
CheckDlgButton(hdlg, IDD_SHUTDOWN, 1);
}
return TRUE;
case WM_COMMAND:
idCmd = GET_WM_COMMAND_ID(wparam, lparam);
switch (idCmd)
{
case IDD_LOGOFF:
case IDD_RESTART:
case IDD_RESTARTDOS:
case IDD_SHUTDOWN:
if (GET_WM_COMMAND_CMD(wparam, lparam) ==
BN_DBLCLK)
{
// The (power) user double-clicked a radio
// button so just do it.
goto UseCommandId;
}
break;
case IDOK:
//
// Figure out which option we should return
//
if (IsDlgButtonChecked(hdlg, IDD_LOGOFF)) {
idCmd = IDD_LOGOFF;
dwShutdown = DLGSEL_LOGOFF;
}
else if (IsDlgButtonChecked(hdlg, IDD_RESTART)) {
idCmd = IDD_RESTART;
dwShutdown = DLGSEL_SHUTDOWN_AND_RESTART;
}
else if (IsDlgButtonChecked(hdlg, IDD_RESTARTDOS)) {
idCmd = IDD_RESTARTDOS;
dwShutdown = DLGSEL_SHUTDOWN_AND_RESTART_DOS;
}
else {
idCmd = IDD_SHUTDOWN;
dwShutdown = DLGSEL_SHUTDOWN;
}
//
// Save user's shutdown selection.
//
if (RegCreateKeyEx(HKEY_CURRENT_USER,
c_szRegExplorer,
0,
0,
0,
KEY_WRITE,
NULL,
&hkeyShutdown,
&dwDisposition) == ERROR_SUCCESS) {
RegSetValueEx(hkeyShutdown,
SHUTDOWN_SETTING,
0,
REG_DWORD,
(LPBYTE)&dwShutdown,
sizeof(dwShutdown));
RegCloseKey(hkeyShutdown);
}
// Now Fall through
case IDCANCEL:
UseCommandId:
s_fEndDialog = TRUE;
//ShowWindow(hdlg, SW_HIDE);
hcur = LoadCursor(NULL, IDC_WAIT);;
SetCursor(hcur);
if (NULL != (hwndP = GetWindow(hdlg, GW_OWNER)))
SetClassLong(hwndP, GCL_HCURSOR, (LONG)hcur);
_IconCacheSave();
_FlushPerLogonCache();
EndDialog(hdlg, idCmd);
break;
case IDHELP:
WinHelp(hdlg, TEXT("windows.hlp>proc4"), HELP_CONTEXT, (DWORD) IDH_TRAY_SHUTDOWN_HELP);
break;
}
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 && !s_fEndDialog)
{
s_fEndDialog = TRUE;
EndDialog(hdlg, IDCANCEL);
}
break;
}
return FALSE;
}
// ---------------------------------------------------------------------------
// Function to try to exit to dos
void ExitToDos(HWND hwnd)
{
#ifndef WINNT // NT doesn't have this functionality
// For now I will assume that the pif is called sdam.pif in the windows
// directory... If it is not found we should generate it, but for now I will
// fallback to ExitWindowsExec of command.com...
TCHAR szPath[MAX_PATH];
TCHAR szCommand[MAX_PATH];
SHELLEXECUTEINFO sei;
GetWindowsDirectory(szPath, ARRAYSIZE(szPath));
LoadString(HINST_THISDLL, IDS_RSDLG_PIFFILENAME, szCommand, ARRAYSIZE(szCommand));
PathCombine(szPath, szPath, szCommand);
if (!PathFileExists(szPath))
{
PROPPRG ProgramProps;
int hPif;
lstrcpy(szCommand, TEXT("command.com"));
PathResolve(szCommand, NULL, 0);
hPif = PifMgr_OpenProperties(szCommand, szPath, 0, OPENPROPS_INFONLY|OPENPROPS_FORCEREALMODE);
if (!hPif)
{
DebugMsg(DM_TRACE, TEXT("ExitToDos: PifMgr_OpenProperties *failed*"));
goto Abort;
}
if (!PifMgr_GetProperties(hPif, (LPSTR)MAKEINTATOM(GROUP_PRG), &ProgramProps, SIZEOF(ProgramProps), 0))
{
DebugMsg(DM_TRACE, TEXT("ExitToDos: PifMgr_GetProperties *failed*"));
goto Abort;
}
PathQuoteSpaces(szCommand);
lstrcpyn(ProgramProps.achCmdLine, szCommand, ARRAYSIZE(ProgramProps.achCmdLine));
// We probably do not wan't to prompt the user again that they are going into
// MSDOS Mode...
//
ProgramProps.flPrgInit |= PRGINIT_REALMODESILENT | PRGINIT_REALMODE;
if (!PifMgr_SetProperties(hPif, MAKEINTATOM(GROUP_PRG), &ProgramProps, SIZEOF(ProgramProps), 0))
{
DebugMsg(DM_TRACE, TEXT("ExitToDos: PifMgr_SetProperties *failed*"));
Abort:
// BUGBUG:: SHould probably put up a message here...
MessageBeep(0);
return;
}
PifMgr_CloseProperties(hPif, 0);
}
// We need to try to exec it now...
FillExecInfo(sei, hwnd, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);
ShellExecuteEx(&sei);
#endif
}
// ---------------------------------------------------------------------------
// Shutdown thread
static HWND s_hwndParent = NULL;
int WINAPI ShutdownThread(DWORD nCmd)
{
BOOL f=FALSE;
HWND hwnd;
switch(nCmd)
{
case IDD_SHUTDOWN:
f = CommonRestart(EWX_SHUTDOWN);
break;
case IDD_RESTART:
if (GetAsyncKeyState(VK_SHIFT < 0))
f = CommonRestart(EW_RESTARTWINDOWS);
else
f = CommonRestart(EWX_REBOOT);
break;
case IDD_LOGOFF:
f = CommonRestart(EWX_LOGOFF);
break;
case IDD_RESTARTDOS: // Special hack to mean exit to dos
// restart to dos, implies that we need to find the appropriate
// pif file and exec it. We may also need to initialize it if
// it does not exist...
ExitToDos(s_hwndParent);
// Fall through and leave f False...
break;
}
//
// if the shutdown worked terminate the calling app
//
if (f)
{
#ifdef WINNT
// On NT, we can't post this WM_QUIT message because it causes
// the explorer to exit without saving any of the folder window
// states. We need to wait around and let the system shut us
// down.
#else
// BUGBUG - Shouldn't this work the same way as on NT?
if (s_hwndParent)
PostMessage(s_hwndParent, WM_QUIT, 0, 0);
#endif
}
else
{
if (NULL != (hwnd = FindWindow(c_szFakeDesktopClass, NULL)))
PostMessage(hwnd, WM_CLOSE, 0, 0);
}
return f;
}
// ---------------------------------------------------------------------------
// Display a dialog asking a user if they want to exit windows with a button
// to shutdown instead.
void WINAPI ExitWindowsDialog(HWND hwndParent)
{
int nCmd;
HWND hwndBackground;
DWORD dw;
HANDLE h;
s_hwndParent = hwndParent;
hwndBackground = CreateFakeDesktopWindow();
if (hwndBackground)
{
ShowWindow(hwndBackground, SW_SHOW);
SetForegroundWindow(hwndBackground);
DitherWindow(hwndBackground);
nCmd = DialogBox(HINST_THISDLL, MAKEINTRESOURCE(DLG_EXITWINDOWS), hwndBackground, ExitWindowsDlgProc);
SetForegroundWindow(hwndBackground);
if (nCmd == IDCANCEL)
{
ShowWindow(hwndBackground, SW_HIDE);
}
else
{
//
// have another thread call ExitWindows() so our
// main pump keeps running durring shutdown.
//
if (NULL != (h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ShutdownThread, (LPVOID)nCmd, 0, &dw)))
{
CloseHandle(h);
}
else
{
ShowWindow(hwndBackground, SW_HIDE);
ShutdownThread(nCmd);
}
}
}
}
//
// Flush global cache for each logon.
//
void _FlushPerLogonCache(void)
{
extern void SpecialFolderIDTerminate(void);
ENTERCRITICAL;
SpecialFolderIDTerminate();
InvalidateDriveType(-1);
LEAVECRITICAL;
}