Leaked source code of windows server 2003
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.
 
 
 
 
 
 

623 lines
20 KiB

/**************************** Module Header ********************************\
* Module Name: syscmd.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* System Command Routines
*
* History:
* 01-25-91 IanJa Added handle revalidation
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* xxxHandleNCMouseGuys
*
* History:
* 11-09-90 DavidPe Ported.
\***************************************************************************/
void xxxHandleNCMouseGuys(
PWND pwnd,
UINT message,
int htArea,
LPARAM lParam)
{
UINT syscmd;
PWND pwndT;
TL tlpwndT;
CheckLock(pwnd);
syscmd = 0xFFFF;
switch (htArea) {
case HTCAPTION:
switch (message) {
case WM_NCLBUTTONDBLCLK:
if (TestWF(pwnd, WFMINIMIZED) || TestWF(pwnd, WFMAXIMIZED)) {
syscmd = SC_RESTORE;
} else if (TestWF(pwnd, WFMAXBOX)) {
syscmd = SC_MAXIMIZE;
}
break;
case WM_NCLBUTTONDOWN:
pwndT = GetTopLevelWindow(pwnd);
ThreadLock(pwndT, &tlpwndT);
xxxActivateWindow(pwndT, AW_USE2);
ThreadUnlock(&tlpwndT);
syscmd = SC_MOVE;
break;
}
break;
case HTSYSMENU:
case HTMENU:
case HTHSCROLL:
case HTVSCROLL:
if (message == WM_NCLBUTTONDOWN || message == WM_NCLBUTTONDBLCLK) {
switch (htArea) {
case HTSYSMENU:
if (message == WM_NCLBUTTONDBLCLK) {
syscmd = SC_CLOSE;
break;
}
/*
*** FALL THRU **
*/
case HTMENU:
syscmd = SC_MOUSEMENU;
break;
case HTHSCROLL:
syscmd = SC_HSCROLL;
break;
case HTVSCROLL:
syscmd = SC_VSCROLL;
break;
}
}
break;
}
switch (syscmd) {
case SC_MINIMIZE:
case SC_MAXIMIZE:
case SC_CLOSE:
/*
* Only do double click commands on an upclick.
* This code is very sensitive to changes from this state.
* Eat any mouse messages.
*/
/*
* Bug #152: WM_NCLBUTTONUP message missing from double click.
* This code was broken in Windows 3.x and the test for whether
* the mouse button was down always failed, so no mouse messages
* were ever eaten. We'll emulate this by not even doing the test.
*
*
* {
* PQ pqCurrent;
* MSG msg;
*
* pqCurrent = PtiCurrent()->pq;
* if (TestKeyStateDown(pqCurrent, VK_LBUTTON)) {
* xxxCapture(PtiCurrent(), pwnd, WINDOW_CAPTURE);
*
* while (TestKeyStateDown(pqCurrent, VK_LBUTTON)) {
* if (!xxxPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST,
* PM_REMOVE)) {
* if (!xxxSleepThread(QS_MOUSE, 0, TRUE))
* break;
* }
* }
*
* xxxReleaseCapture();
*
* }
* }
*
*/
/*
** FALL THRU **
*/
case SC_SIZE:
case SC_MOVE:
/*
* For SysCommands on system menu, don't do if menu item is
* disabled.
*/
if (TestWF(pwnd, WFSYSMENU)) {
xxxSetSysMenu(pwnd);
if (_GetMenuState(xxxGetSysMenuHandle(pwnd), (syscmd & 0xFFF0),
MF_BYCOMMAND) & MFS_GRAYED) {
return;
}
}
break;
}
if (syscmd != 0xFFFF) {
xxxSendMessage(pwnd, WM_SYSCOMMAND, syscmd | htArea, lParam);
}
}
/***************************************************************************\
* StartScreenSaver
*
* History:
* 11-12-90 MikeHar ported.
\***************************************************************************/
void StartScreenSaver(
BOOL bOnlyIfSecure)
{
/*
* If a screen saver is already running or we're in the midst of powering
* down the machine, ignore this request.
*/
if (gppiScreenSaver != NULL || gPowerState.fInProgress)
return;
if (gspwndLogonNotify != NULL) {
if( glinp.dwFlags & LINP_POWEROFF ) {
/*
* If the monitor is turned off. Tell winlogon to handle the
* screen saver in a special manner.
*/
_PostMessage(gspwndLogonNotify,
WM_LOGONNOTIFY, LOGON_INPUT_TIMEOUT, 2);
} else {
/*
* Let the logon process take care of the screen saver
*/
_PostMessage(gspwndLogonNotify,
WM_LOGONNOTIFY, LOGON_INPUT_TIMEOUT, bOnlyIfSecure);
}
}
}
/***************************************************************************\
* xxxSysCommand
*
* History:
* 11-12-90 MikeHar ported.
* 02-07-91 DavidPe Added Win 3.1 WH_CBT support.
\***************************************************************************/
void xxxSysCommand(
PWND pwnd,
DWORD cmd,
LPARAM lParam)
{
UINT htArea;
PWND pwndSwitch;
PMENUSTATE pMenuState;
TL tlpwnd;
POINT pt;
DWORD dw;
PWND pwndCapture;
PTHREADINFO pti;
CheckLock(pwnd);
htArea = (UINT)(cmd & 0x0F);
cmd -= htArea;
/*
* Intense hack o' death.
*/
if (lParam == 0x00010000L)
lParam = 0L;
/*
* If the system doesn't have capture (ie CLENT_CAPTURE_INTERNAL)
* do the sys command. Also, do the sys command for the special case
* where the window receiving the sys command is a console window that
* is in full screen mode. In this case we let the sys command through.
*
* Also if this a SC_SCREENSAVE then we handle it anyway and
* switching desktops will do the cancel. SC_SCREENSAVER
* is special so we can start the screen saver even if we are in
* menu mode for security so NT bug 10975 Banker's Trust
*/
pti = GETPTI(pwnd);
/*
* For 32bit apps (and apps on seperate queues), we need to check
* the capture in the queue. Otherwise, on MDI child-destruction
* we would get the restore when they shouldn't. This broke MSGOLF
* who during the restore, AV'd because they assumed this wouldn't
* happen. On 16bit shared apps, we want to check the internal
* capture. Otherwise, when doing 16bit drag-and-drop, we would
* not restore the minimized window if we had a queue-capture-window.
*/
/*
* But... it is too broad a change to just check internal capture for all WoW apps. Some
* apps depend on bailing out when they have capture set. (Adobe Persuasion, NT bug 68794,
* for SC_MOVE). So, let's restrict the hack to SC_RESTORE to keep Ole drag-and-drop working.
* See NT bug 6109. FritzS
*/
pwndCapture = ((pti->TIF_flags & TIF_16BIT) && (cmd == SC_RESTORE)) ? gspwndInternalCapture :
pti->pq->spwndCapture;
if ((!pwndCapture && !TestWF(pwnd, WFDISABLED)) ||
(pwnd == gspwndFullScreen) ||
(cmd == SC_SCREENSAVE) ||
(cmd == SC_MONITORPOWER) ||
(cmd == SC_TASKLIST)) {
/*
* Perform the sys command
*/
#ifdef SYSMODALWINDOWS
if (gspwndSysModal != NULL) {
switch (cmd) {
case SC_SIZE:
case SC_MOVE:
case SC_MINIMIZE:
case SC_MAXIMIZE:
case SC_NEXTWINDOW:
case SC_PREVWINDOW:
case SC_SCREENSAVE:
return;
}
}
#endif
/*
* Call the CBT hook asking if it's okay to do this command.
* If not, return from here.
*/
if (IsHooked(PtiCurrent(), WHF_CBT) && xxxCallHook(HCBT_SYSCOMMAND,
(DWORD)cmd, (DWORD)lParam, WH_CBT)) {
return;
}
switch (cmd) {
case SC_RESTORE:
cmd = SW_RESTORE;
if (TestWF(pwnd, WFMINIMIZED) || !TestWF(pwnd, WFMAXIMIZED))
PlayEventSound(USER_SOUND_RESTOREUP);
else
PlayEventSound(USER_SOUND_RESTOREDOWN);
goto MinMax;
case SC_MINIMIZE:
cmd = SW_MINIMIZE;
/*
* Are we already minimized?
*/
if (TestWF(pwnd, WFMINIMIZED))
break;
PlayEventSound(USER_SOUND_MINIMIZE);
goto MinMax;
case SC_MAXIMIZE:
cmd = SW_SHOWMAXIMIZED;
/*
* Are we already maximized?
*/
if (TestWF(pwnd, WFMAXIMIZED))
break;
PlayEventSound(USER_SOUND_MAXIMIZE);
MinMax:
xxxShowWindow(pwnd, cmd | TEST_PUDF(PUDF_ANIMATE));
return;
case SC_SIZE:
{
xxxMoveSize(pwnd, htArea, _GetMessagePos());
}
return;
case SC_MOVE:
//
// Don't enter movesize loop unless the user is actually
// dragging from the caption. Otherwise, put up the system
// menu on a minimized window.
//
//
// Are we dragging with the left mouse button?
//
dw = _GetMessagePos();
POINTSTOPOINT( pt, MAKEPOINTS(dw));
if ( !htArea ||
xxxIsDragging(pwnd, pt, WM_LBUTTONUP)) {
/*
* We are moving. Enter move/size loop.
*/
{
xxxMoveSize(pwnd, (htArea == 0) ? WMSZ_KEYMOVE : WMSZ_MOVE, dw);
}
} else {
/*
* Activate our window, just like we would have in
* MoveSize().
*/
xxxSetWindowPos(pwnd, PWND_TOP, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE);
if (TestWF(pwnd, WFMINIMIZED)) {
/*
* Try to popup the system menu
*/
xxxSendMessage(pwnd, WM_SYSCOMMAND, SC_KEYMENU,
(DWORD) (TestWF(pwnd, WFCHILD) ? '-' : MENUSYSMENU));
}
}
return;
case SC_CLOSE:
xxxSendMessage(pwnd, WM_CLOSE, 0L, 0L);
return;
case SC_NEXTWINDOW:
case SC_PREVWINDOW:
xxxOldNextWindow((UINT)lParam);
break;
case SC_CONTEXTHELP:
xxxHelpLoop(pwnd);
break;
case SC_KEYMENU:
/*
* A menu was selected via keyboard
*/
pMenuState = xxxMNStartMenuState(pwnd, cmd, lParam);
if (pMenuState != NULL) {
UserAssert(PtiCurrent() == pMenuState->ptiMenuStateOwner);
/*
* Make sure we are not fullscreen
*/
if (gspwndFullScreen == pwnd) {
PWND pwndT;
TL tlpwndT;
pwndT = _GetDesktopWindow();
ThreadLock(pwndT, &tlpwndT);
xxxMakeWindowForegroundWithState(pwndT, GDIFULLSCREEN);
ThreadUnlock(&tlpwndT);
}
pMenuState->fUnderline = TRUE;
xxxMNKeyFilter(pMenuState->pGlobalPopupMenu, pMenuState, (UINT)lParam);
if (!pMenuState->fModelessMenu) {
xxxMNEndMenuState (TRUE);
}
}
/*
* Capture must have been unlocked
*/
UserAssert(!(PtiCurrent()->pq->QF_flags & QF_CAPTURELOCKED));
return;
case SC_MOUSEMENU:
case SC_DEFAULT:
/*
* If the window is not foreground, eat the command to avoid
* wasting time flashing the system menu.
*
* We used to check if the top level window was WFFRAMEON (so a
* child window's system menu works like Win 3.1) but Excel's
* (SDM) dialogs allow you to access their menus even though
* the child and parent appear to be inactive.
*/
if (!(GETPTI(pwnd)->pq == gpqForeground))
return;
/*
* A mouse click occurred on a toplevel menu.
*/
pMenuState = xxxMNStartMenuState(pwnd, cmd, lParam);
if (pMenuState != NULL) {
UserAssert(PtiCurrent() == pMenuState->ptiMenuStateOwner);
xxxMNLoop(pMenuState->pGlobalPopupMenu, pMenuState, lParam, (cmd==SC_DEFAULT));
if (!pMenuState->fModelessMenu) {
xxxMNEndMenuState (TRUE);
}
}
/*
* Capture must have been unlocked
*/
UserAssert(!(PtiCurrent()->pq->QF_flags & QF_CAPTURELOCKED));
return;
case SC_VSCROLL:
case SC_HSCROLL:
xxxSBTrackInit(pwnd, lParam, htArea, (_GetKeyState(VK_SHIFT) < 0) ? SCROLL_DIRECT : SCROLL_NORMAL);
return;
case SC_TASKLIST:
// _PostThreadMessage(gptiTasklist, WM_SYSCOMMAND, SC_TASKLIST, 0);
// if (!FCallTray() ||
// !CallHook(HSHELL_TASKMAN, (WPARAM) HW16(hwnd), (LPARAM) 0, WH_SHELL))
/*
* Winlogon will set lParam to -1 to indicate that we really want a task list,
* not just the start menu. We indicate this to the shell by passing a NULL
* window ptr
* This message is really intended for the SHELL, so give them the right
* to set the foreground.
*/
if (FDoTray() && (FCallHookTray() || FPostTray(pwnd->head.rpdesk))) {
PWND pwndTaskman = pwnd->head.rpdesk->pDeskInfo->spwndTaskman;
if (FCallHookTray()) {
xxxCallHook(HSHELL_TASKMAN, (WPARAM)HWq(pwnd), (LPARAM) 0, WH_SHELL);
}
if ((FPostTray(pwnd->head.rpdesk)) && (pwndTaskman != NULL)) {
glinp.ptiLastWoken = GETPTI(pwndTaskman);
_PostMessage(pwndTaskman, gpsi->uiShellMsg, HSHELL_TASKMAN,
lParam == (ULONG)(-1) ? (LPARAM) -1 :(LPARAM)HWq(pwnd));
}
} else if (gptiTasklist != NULL) {
glinp.ptiLastWoken = gptiTasklist;
_PostThreadMessage(gptiTasklist, WM_SYSCOMMAND, SC_TASKLIST, 0);
// LATER -- FritzS
// HCURSOR hCursorLast;
// static char CODESEG szTask[] = " %d %d";
// ShowCursor(TRUE);
// hCursorLast = SetCursor32(hCursWait, TRUE);
// Try in the windows directory first.
// GetWindowsDirectory(szBuff, sizeof(szBuff));
// if (szBuff[lstrlen(szBuff) - 1] != '\\')
// lstrcatn(szBuff, "\\", sizeof(szBuff));
// lstrcatn(szBuff, (LPSTR)pTaskManName, sizeof(szBuff));
// wvsprintf(szBuff+lstrlen(szBuff), (LPSTR)szTask, (LPSTR)&lParam);
// if (WinExec((LPSTR)szBuff, SW_SHOWNORMAL) <= 32)
// {
// // If it wasn't in the windows directory then try
// // searching the full path.
// lstrcpyn(szBuff, pTaskManName, sizeof(szBuff));
// wvsprintf(szBuff+lstrlen(szBuff), (LPSTR)szTask, (LPSTR)&lParam);
// WinExec((LPSTR)szBuff, SW_SHOWNORMAL);
// }
//
// ShowCursor(FALSE);
// SetCursor32(hCursorLast, TRUE);
}
break;
case SC_MONITORPOWER:
/*
* If we're powering down the machine, or if we are switching protocol,ignore this request.
*/
if (gPowerState.fInProgress || gfSwitchInProgress) {
break;
}
switch (lParam) {
case POWERON_PHASE:
if ( (glinp.dwFlags & LINP_POWERTIMEOUTS) ||
(glinp.dwFlags & LINP_POWEROFF) ) {
glinp.dwFlags &= ~LINP_POWEROFF;
glinp.dwFlags &= ~LINP_POWERTIMEOUTS;
DrvSetMonitorPowerState(gpDispInfo->pmdev,
PowerDeviceD0);
}
break;
case LOWPOWER_PHASE:
if ((glinp.dwFlags & LINP_LOWPOWER) == 0) {
glinp.dwFlags |= LINP_LOWPOWER;
DrvSetMonitorPowerState(gpDispInfo->pmdev,
PowerDeviceD1);
}
break;
case POWEROFF_PHASE:
if ((glinp.dwFlags & LINP_POWEROFF) == 0) {
glinp.dwFlags |= LINP_POWEROFF;
DrvSetMonitorPowerState(gpDispInfo->pmdev,
PowerDeviceD3);
}
break;
default:
break;
}
break;
case SC_SCREENSAVE:
pwndSwitch = RevalidateHwnd(ghwndSwitch);
// Lock out screen save until we get another input message.
if (pwndSwitch != NULL && pwnd != pwndSwitch) {
_PostMessage(pwndSwitch, WM_SYSCOMMAND, SC_SCREENSAVE, 0L);
} else {
StartScreenSaver(FALSE);
}
break;
case SC_HOTKEY:
/*
* Loword of the lparam is window to switch to
*/
pwnd = ValidateHwnd((HWND)lParam);
if (pwnd != NULL) {
pwndSwitch = _GetLastActivePopup(pwnd);
if (pwndSwitch != NULL)
pwnd = pwndSwitch;
ThreadLockAlways(pwnd, &tlpwnd);
xxxSetForegroundWindow(pwnd, FALSE);
ThreadUnlock(&tlpwnd);
if (TestWF(pwnd, WFMINIMIZED))
_PostMessage(pwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
}
break;
}
}
}
/***************************************************************************\
* _RegisterTasklist (Private API)
*
* History:
* 05-01-91 DavidPe Created.
\***************************************************************************/
BOOL _RegisterTasklist(
PWND pwndTasklist)
{
#ifdef LATER
//
// JimA - ??? Why do this?
//
PETHREAD Thread;
Thread = PsGetCurrentThread();
pRitCSRThread->ThreadHandle = Thread->ThreadHandle;
#endif
gptiTasklist = GETPTI(pwndTasklist);
ghwndSwitch = HWq(pwndTasklist);
/*
* Don't allow an app to call AttachThreadInput() on task man -
* we want taskman to be unsynchronized at all times (so the user
* can bring it up and kill other apps).
*/
GETPTI(pwndTasklist)->TIF_flags |= TIF_DONTATTACHQUEUE;
return TRUE;
}