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

  1. /**************************** Module Header ********************************\
  2. * Module Name: syscmd.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * System Command Routines
  7. *
  8. * History:
  9. * 01-25-91 IanJa Added handle revalidation
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. /***************************************************************************\
  14. * xxxHandleNCMouseGuys
  15. *
  16. * History:
  17. * 11-09-90 DavidPe Ported.
  18. \***************************************************************************/
  19. void xxxHandleNCMouseGuys(
  20. PWND pwnd,
  21. UINT message,
  22. int htArea,
  23. LPARAM lParam)
  24. {
  25. UINT syscmd;
  26. PWND pwndT;
  27. TL tlpwndT;
  28. CheckLock(pwnd);
  29. syscmd = 0xFFFF;
  30. switch (htArea) {
  31. case HTCAPTION:
  32. switch (message) {
  33. case WM_NCLBUTTONDBLCLK:
  34. if (TestWF(pwnd, WFMINIMIZED) || TestWF(pwnd, WFMAXIMIZED)) {
  35. syscmd = SC_RESTORE;
  36. } else if (TestWF(pwnd, WFMAXBOX)) {
  37. syscmd = SC_MAXIMIZE;
  38. }
  39. break;
  40. case WM_NCLBUTTONDOWN:
  41. pwndT = GetTopLevelWindow(pwnd);
  42. ThreadLock(pwndT, &tlpwndT);
  43. xxxActivateWindow(pwndT, AW_USE2);
  44. ThreadUnlock(&tlpwndT);
  45. syscmd = SC_MOVE;
  46. break;
  47. }
  48. break;
  49. case HTSYSMENU:
  50. case HTMENU:
  51. case HTHSCROLL:
  52. case HTVSCROLL:
  53. if (message == WM_NCLBUTTONDOWN || message == WM_NCLBUTTONDBLCLK) {
  54. switch (htArea) {
  55. case HTSYSMENU:
  56. if (message == WM_NCLBUTTONDBLCLK) {
  57. syscmd = SC_CLOSE;
  58. break;
  59. }
  60. /*
  61. *** FALL THRU **
  62. */
  63. case HTMENU:
  64. syscmd = SC_MOUSEMENU;
  65. break;
  66. case HTHSCROLL:
  67. syscmd = SC_HSCROLL;
  68. break;
  69. case HTVSCROLL:
  70. syscmd = SC_VSCROLL;
  71. break;
  72. }
  73. }
  74. break;
  75. }
  76. switch (syscmd) {
  77. case SC_MINIMIZE:
  78. case SC_MAXIMIZE:
  79. case SC_CLOSE:
  80. /*
  81. * Only do double click commands on an upclick.
  82. * This code is very sensitive to changes from this state.
  83. * Eat any mouse messages.
  84. */
  85. /*
  86. * Bug #152: WM_NCLBUTTONUP message missing from double click.
  87. * This code was broken in Windows 3.x and the test for whether
  88. * the mouse button was down always failed, so no mouse messages
  89. * were ever eaten. We'll emulate this by not even doing the test.
  90. *
  91. *
  92. * {
  93. * PQ pqCurrent;
  94. * MSG msg;
  95. *
  96. * pqCurrent = PtiCurrent()->pq;
  97. * if (TestKeyStateDown(pqCurrent, VK_LBUTTON)) {
  98. * xxxCapture(PtiCurrent(), pwnd, WINDOW_CAPTURE);
  99. *
  100. * while (TestKeyStateDown(pqCurrent, VK_LBUTTON)) {
  101. * if (!xxxPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST,
  102. * PM_REMOVE)) {
  103. * if (!xxxSleepThread(QS_MOUSE, 0, TRUE))
  104. * break;
  105. * }
  106. * }
  107. *
  108. * xxxReleaseCapture();
  109. *
  110. * }
  111. * }
  112. *
  113. */
  114. /*
  115. ** FALL THRU **
  116. */
  117. case SC_SIZE:
  118. case SC_MOVE:
  119. /*
  120. * For SysCommands on system menu, don't do if menu item is
  121. * disabled.
  122. */
  123. if (TestWF(pwnd, WFSYSMENU)) {
  124. xxxSetSysMenu(pwnd);
  125. if (_GetMenuState(xxxGetSysMenuHandle(pwnd), (syscmd & 0xFFF0),
  126. MF_BYCOMMAND) & MFS_GRAYED) {
  127. return;
  128. }
  129. }
  130. break;
  131. }
  132. if (syscmd != 0xFFFF) {
  133. xxxSendMessage(pwnd, WM_SYSCOMMAND, syscmd | htArea, lParam);
  134. }
  135. }
  136. /***************************************************************************\
  137. * StartScreenSaver
  138. *
  139. * History:
  140. * 11-12-90 MikeHar ported.
  141. \***************************************************************************/
  142. void StartScreenSaver(
  143. BOOL bOnlyIfSecure)
  144. {
  145. /*
  146. * If a screen saver is already running or we're in the midst of powering
  147. * down the machine, ignore this request.
  148. */
  149. if (gppiScreenSaver != NULL || gPowerState.fInProgress)
  150. return;
  151. if (gspwndLogonNotify != NULL) {
  152. if( glinp.dwFlags & LINP_POWEROFF ) {
  153. /*
  154. * If the monitor is turned off. Tell winlogon to handle the
  155. * screen saver in a special manner.
  156. */
  157. _PostMessage(gspwndLogonNotify,
  158. WM_LOGONNOTIFY, LOGON_INPUT_TIMEOUT, 2);
  159. } else {
  160. /*
  161. * Let the logon process take care of the screen saver
  162. */
  163. _PostMessage(gspwndLogonNotify,
  164. WM_LOGONNOTIFY, LOGON_INPUT_TIMEOUT, bOnlyIfSecure);
  165. }
  166. }
  167. }
  168. /***************************************************************************\
  169. * xxxSysCommand
  170. *
  171. * History:
  172. * 11-12-90 MikeHar ported.
  173. * 02-07-91 DavidPe Added Win 3.1 WH_CBT support.
  174. \***************************************************************************/
  175. void xxxSysCommand(
  176. PWND pwnd,
  177. DWORD cmd,
  178. LPARAM lParam)
  179. {
  180. UINT htArea;
  181. PWND pwndSwitch;
  182. PMENUSTATE pMenuState;
  183. TL tlpwnd;
  184. POINT pt;
  185. DWORD dw;
  186. PWND pwndCapture;
  187. PTHREADINFO pti;
  188. CheckLock(pwnd);
  189. htArea = (UINT)(cmd & 0x0F);
  190. cmd -= htArea;
  191. /*
  192. * Intense hack o' death.
  193. */
  194. if (lParam == 0x00010000L)
  195. lParam = 0L;
  196. /*
  197. * If the system doesn't have capture (ie CLENT_CAPTURE_INTERNAL)
  198. * do the sys command. Also, do the sys command for the special case
  199. * where the window receiving the sys command is a console window that
  200. * is in full screen mode. In this case we let the sys command through.
  201. *
  202. * Also if this a SC_SCREENSAVE then we handle it anyway and
  203. * switching desktops will do the cancel. SC_SCREENSAVER
  204. * is special so we can start the screen saver even if we are in
  205. * menu mode for security so NT bug 10975 Banker's Trust
  206. */
  207. pti = GETPTI(pwnd);
  208. /*
  209. * For 32bit apps (and apps on seperate queues), we need to check
  210. * the capture in the queue. Otherwise, on MDI child-destruction
  211. * we would get the restore when they shouldn't. This broke MSGOLF
  212. * who during the restore, AV'd because they assumed this wouldn't
  213. * happen. On 16bit shared apps, we want to check the internal
  214. * capture. Otherwise, when doing 16bit drag-and-drop, we would
  215. * not restore the minimized window if we had a queue-capture-window.
  216. */
  217. /*
  218. * But... it is too broad a change to just check internal capture for all WoW apps. Some
  219. * apps depend on bailing out when they have capture set. (Adobe Persuasion, NT bug 68794,
  220. * for SC_MOVE). So, let's restrict the hack to SC_RESTORE to keep Ole drag-and-drop working.
  221. * See NT bug 6109. FritzS
  222. */
  223. pwndCapture = ((pti->TIF_flags & TIF_16BIT) && (cmd == SC_RESTORE)) ? gspwndInternalCapture :
  224. pti->pq->spwndCapture;
  225. if ((!pwndCapture && !TestWF(pwnd, WFDISABLED)) ||
  226. (pwnd == gspwndFullScreen) ||
  227. (cmd == SC_SCREENSAVE) ||
  228. (cmd == SC_MONITORPOWER) ||
  229. (cmd == SC_TASKLIST)) {
  230. /*
  231. * Perform the sys command
  232. */
  233. #ifdef SYSMODALWINDOWS
  234. if (gspwndSysModal != NULL) {
  235. switch (cmd) {
  236. case SC_SIZE:
  237. case SC_MOVE:
  238. case SC_MINIMIZE:
  239. case SC_MAXIMIZE:
  240. case SC_NEXTWINDOW:
  241. case SC_PREVWINDOW:
  242. case SC_SCREENSAVE:
  243. return;
  244. }
  245. }
  246. #endif
  247. /*
  248. * Call the CBT hook asking if it's okay to do this command.
  249. * If not, return from here.
  250. */
  251. if (IsHooked(PtiCurrent(), WHF_CBT) && xxxCallHook(HCBT_SYSCOMMAND,
  252. (DWORD)cmd, (DWORD)lParam, WH_CBT)) {
  253. return;
  254. }
  255. switch (cmd) {
  256. case SC_RESTORE:
  257. cmd = SW_RESTORE;
  258. if (TestWF(pwnd, WFMINIMIZED) || !TestWF(pwnd, WFMAXIMIZED))
  259. PlayEventSound(USER_SOUND_RESTOREUP);
  260. else
  261. PlayEventSound(USER_SOUND_RESTOREDOWN);
  262. goto MinMax;
  263. case SC_MINIMIZE:
  264. cmd = SW_MINIMIZE;
  265. /*
  266. * Are we already minimized?
  267. */
  268. if (TestWF(pwnd, WFMINIMIZED))
  269. break;
  270. PlayEventSound(USER_SOUND_MINIMIZE);
  271. goto MinMax;
  272. case SC_MAXIMIZE:
  273. cmd = SW_SHOWMAXIMIZED;
  274. /*
  275. * Are we already maximized?
  276. */
  277. if (TestWF(pwnd, WFMAXIMIZED))
  278. break;
  279. PlayEventSound(USER_SOUND_MAXIMIZE);
  280. MinMax:
  281. xxxShowWindow(pwnd, cmd | TEST_PUDF(PUDF_ANIMATE));
  282. return;
  283. case SC_SIZE:
  284. {
  285. xxxMoveSize(pwnd, htArea, _GetMessagePos());
  286. }
  287. return;
  288. case SC_MOVE:
  289. //
  290. // Don't enter movesize loop unless the user is actually
  291. // dragging from the caption. Otherwise, put up the system
  292. // menu on a minimized window.
  293. //
  294. //
  295. // Are we dragging with the left mouse button?
  296. //
  297. dw = _GetMessagePos();
  298. POINTSTOPOINT( pt, MAKEPOINTS(dw));
  299. if ( !htArea ||
  300. xxxIsDragging(pwnd, pt, WM_LBUTTONUP)) {
  301. /*
  302. * We are moving. Enter move/size loop.
  303. */
  304. {
  305. xxxMoveSize(pwnd, (htArea == 0) ? WMSZ_KEYMOVE : WMSZ_MOVE, dw);
  306. }
  307. } else {
  308. /*
  309. * Activate our window, just like we would have in
  310. * MoveSize().
  311. */
  312. xxxSetWindowPos(pwnd, PWND_TOP, 0, 0, 0, 0,
  313. SWP_NOMOVE | SWP_NOSIZE);
  314. if (TestWF(pwnd, WFMINIMIZED)) {
  315. /*
  316. * Try to popup the system menu
  317. */
  318. xxxSendMessage(pwnd, WM_SYSCOMMAND, SC_KEYMENU,
  319. (DWORD) (TestWF(pwnd, WFCHILD) ? '-' : MENUSYSMENU));
  320. }
  321. }
  322. return;
  323. case SC_CLOSE:
  324. xxxSendMessage(pwnd, WM_CLOSE, 0L, 0L);
  325. return;
  326. case SC_NEXTWINDOW:
  327. case SC_PREVWINDOW:
  328. xxxOldNextWindow((UINT)lParam);
  329. break;
  330. case SC_CONTEXTHELP:
  331. xxxHelpLoop(pwnd);
  332. break;
  333. case SC_KEYMENU:
  334. /*
  335. * A menu was selected via keyboard
  336. */
  337. pMenuState = xxxMNStartMenuState(pwnd, cmd, lParam);
  338. if (pMenuState != NULL) {
  339. UserAssert(PtiCurrent() == pMenuState->ptiMenuStateOwner);
  340. /*
  341. * Make sure we are not fullscreen
  342. */
  343. if (gspwndFullScreen == pwnd) {
  344. PWND pwndT;
  345. TL tlpwndT;
  346. pwndT = _GetDesktopWindow();
  347. ThreadLock(pwndT, &tlpwndT);
  348. xxxMakeWindowForegroundWithState(pwndT, GDIFULLSCREEN);
  349. ThreadUnlock(&tlpwndT);
  350. }
  351. pMenuState->fUnderline = TRUE;
  352. xxxMNKeyFilter(pMenuState->pGlobalPopupMenu, pMenuState, (UINT)lParam);
  353. if (!pMenuState->fModelessMenu) {
  354. xxxMNEndMenuState (TRUE);
  355. }
  356. }
  357. /*
  358. * Capture must have been unlocked
  359. */
  360. UserAssert(!(PtiCurrent()->pq->QF_flags & QF_CAPTURELOCKED));
  361. return;
  362. case SC_MOUSEMENU:
  363. case SC_DEFAULT:
  364. /*
  365. * If the window is not foreground, eat the command to avoid
  366. * wasting time flashing the system menu.
  367. *
  368. * We used to check if the top level window was WFFRAMEON (so a
  369. * child window's system menu works like Win 3.1) but Excel's
  370. * (SDM) dialogs allow you to access their menus even though
  371. * the child and parent appear to be inactive.
  372. */
  373. if (!(GETPTI(pwnd)->pq == gpqForeground))
  374. return;
  375. /*
  376. * A mouse click occurred on a toplevel menu.
  377. */
  378. pMenuState = xxxMNStartMenuState(pwnd, cmd, lParam);
  379. if (pMenuState != NULL) {
  380. UserAssert(PtiCurrent() == pMenuState->ptiMenuStateOwner);
  381. xxxMNLoop(pMenuState->pGlobalPopupMenu, pMenuState, lParam, (cmd==SC_DEFAULT));
  382. if (!pMenuState->fModelessMenu) {
  383. xxxMNEndMenuState (TRUE);
  384. }
  385. }
  386. /*
  387. * Capture must have been unlocked
  388. */
  389. UserAssert(!(PtiCurrent()->pq->QF_flags & QF_CAPTURELOCKED));
  390. return;
  391. case SC_VSCROLL:
  392. case SC_HSCROLL:
  393. xxxSBTrackInit(pwnd, lParam, htArea, (_GetKeyState(VK_SHIFT) < 0) ? SCROLL_DIRECT : SCROLL_NORMAL);
  394. return;
  395. case SC_TASKLIST:
  396. // _PostThreadMessage(gptiTasklist, WM_SYSCOMMAND, SC_TASKLIST, 0);
  397. // if (!FCallTray() ||
  398. // !CallHook(HSHELL_TASKMAN, (WPARAM) HW16(hwnd), (LPARAM) 0, WH_SHELL))
  399. /*
  400. * Winlogon will set lParam to -1 to indicate that we really want a task list,
  401. * not just the start menu. We indicate this to the shell by passing a NULL
  402. * window ptr
  403. * This message is really intended for the SHELL, so give them the right
  404. * to set the foreground.
  405. */
  406. if (FDoTray() && (FCallHookTray() || FPostTray(pwnd->head.rpdesk))) {
  407. PWND pwndTaskman = pwnd->head.rpdesk->pDeskInfo->spwndTaskman;
  408. if (FCallHookTray()) {
  409. xxxCallHook(HSHELL_TASKMAN, (WPARAM)HWq(pwnd), (LPARAM) 0, WH_SHELL);
  410. }
  411. if ((FPostTray(pwnd->head.rpdesk)) && (pwndTaskman != NULL)) {
  412. glinp.ptiLastWoken = GETPTI(pwndTaskman);
  413. _PostMessage(pwndTaskman, gpsi->uiShellMsg, HSHELL_TASKMAN,
  414. lParam == (ULONG)(-1) ? (LPARAM) -1 :(LPARAM)HWq(pwnd));
  415. }
  416. } else if (gptiTasklist != NULL) {
  417. glinp.ptiLastWoken = gptiTasklist;
  418. _PostThreadMessage(gptiTasklist, WM_SYSCOMMAND, SC_TASKLIST, 0);
  419. // LATER -- FritzS
  420. // HCURSOR hCursorLast;
  421. // static char CODESEG szTask[] = " %d %d";
  422. // ShowCursor(TRUE);
  423. // hCursorLast = SetCursor32(hCursWait, TRUE);
  424. // Try in the windows directory first.
  425. // GetWindowsDirectory(szBuff, sizeof(szBuff));
  426. // if (szBuff[lstrlen(szBuff) - 1] != '\\')
  427. // lstrcatn(szBuff, "\\", sizeof(szBuff));
  428. // lstrcatn(szBuff, (LPSTR)pTaskManName, sizeof(szBuff));
  429. // wvsprintf(szBuff+lstrlen(szBuff), (LPSTR)szTask, (LPSTR)&lParam);
  430. // if (WinExec((LPSTR)szBuff, SW_SHOWNORMAL) <= 32)
  431. // {
  432. // // If it wasn't in the windows directory then try
  433. // // searching the full path.
  434. // lstrcpyn(szBuff, pTaskManName, sizeof(szBuff));
  435. // wvsprintf(szBuff+lstrlen(szBuff), (LPSTR)szTask, (LPSTR)&lParam);
  436. // WinExec((LPSTR)szBuff, SW_SHOWNORMAL);
  437. // }
  438. //
  439. // ShowCursor(FALSE);
  440. // SetCursor32(hCursorLast, TRUE);
  441. }
  442. break;
  443. case SC_MONITORPOWER:
  444. /*
  445. * If we're powering down the machine, or if we are switching protocol,ignore this request.
  446. */
  447. if (gPowerState.fInProgress || gfSwitchInProgress) {
  448. break;
  449. }
  450. switch (lParam) {
  451. case POWERON_PHASE:
  452. if ( (glinp.dwFlags & LINP_POWERTIMEOUTS) ||
  453. (glinp.dwFlags & LINP_POWEROFF) ) {
  454. glinp.dwFlags &= ~LINP_POWEROFF;
  455. glinp.dwFlags &= ~LINP_POWERTIMEOUTS;
  456. DrvSetMonitorPowerState(gpDispInfo->pmdev,
  457. PowerDeviceD0);
  458. }
  459. break;
  460. case LOWPOWER_PHASE:
  461. if ((glinp.dwFlags & LINP_LOWPOWER) == 0) {
  462. glinp.dwFlags |= LINP_LOWPOWER;
  463. DrvSetMonitorPowerState(gpDispInfo->pmdev,
  464. PowerDeviceD1);
  465. }
  466. break;
  467. case POWEROFF_PHASE:
  468. if ((glinp.dwFlags & LINP_POWEROFF) == 0) {
  469. glinp.dwFlags |= LINP_POWEROFF;
  470. DrvSetMonitorPowerState(gpDispInfo->pmdev,
  471. PowerDeviceD3);
  472. }
  473. break;
  474. default:
  475. break;
  476. }
  477. break;
  478. case SC_SCREENSAVE:
  479. pwndSwitch = RevalidateHwnd(ghwndSwitch);
  480. // Lock out screen save until we get another input message.
  481. if (pwndSwitch != NULL && pwnd != pwndSwitch) {
  482. _PostMessage(pwndSwitch, WM_SYSCOMMAND, SC_SCREENSAVE, 0L);
  483. } else {
  484. StartScreenSaver(FALSE);
  485. }
  486. break;
  487. case SC_HOTKEY:
  488. /*
  489. * Loword of the lparam is window to switch to
  490. */
  491. pwnd = ValidateHwnd((HWND)lParam);
  492. if (pwnd != NULL) {
  493. pwndSwitch = _GetLastActivePopup(pwnd);
  494. if (pwndSwitch != NULL)
  495. pwnd = pwndSwitch;
  496. ThreadLockAlways(pwnd, &tlpwnd);
  497. xxxSetForegroundWindow(pwnd, FALSE);
  498. ThreadUnlock(&tlpwnd);
  499. if (TestWF(pwnd, WFMINIMIZED))
  500. _PostMessage(pwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
  501. }
  502. break;
  503. }
  504. }
  505. }
  506. /***************************************************************************\
  507. * _RegisterTasklist (Private API)
  508. *
  509. * History:
  510. * 05-01-91 DavidPe Created.
  511. \***************************************************************************/
  512. BOOL _RegisterTasklist(
  513. PWND pwndTasklist)
  514. {
  515. #ifdef LATER
  516. //
  517. // JimA - ??? Why do this?
  518. //
  519. PETHREAD Thread;
  520. Thread = PsGetCurrentThread();
  521. pRitCSRThread->ThreadHandle = Thread->ThreadHandle;
  522. #endif
  523. gptiTasklist = GETPTI(pwndTasklist);
  524. ghwndSwitch = HWq(pwndTasklist);
  525. /*
  526. * Don't allow an app to call AttachThreadInput() on task man -
  527. * we want taskman to be unsynchronized at all times (so the user
  528. * can bring it up and kill other apps).
  529. */
  530. GETPTI(pwndTasklist)->TIF_flags |= TIF_DONTATTACHQUEUE;
  531. return TRUE;
  532. }