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.

773 lines
23 KiB

  1. /**************************** Module Header ********************************\
  2. * Module Name: mnsys.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * System Menu Routines
  7. *
  8. * History:
  9. * 10-10-90 JimA Cleanup.
  10. * 03-18-91 IanJa Window revalidation added (none required)
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. void _SetCloseDefault(PMENU pSubMenu);
  15. PWND FindFakeMDIChild(PWND pwndParent);
  16. /***************************************************************************\
  17. * LoadSysDesktopMenu
  18. *
  19. * Loads and locks a desktop system menu. Since we have to call the client
  20. * to load the menu, while thread 1 is loading the menu, thread 2
  21. * might grab the critical section, check pdesk->spmenu* and decide that
  22. * the menu needs to be loaded. Hence we could load the menu more than once.
  23. * this function handles that case to avoid leaking menus.
  24. *
  25. * 10/24/97 Gerardob Created
  26. \***************************************************************************/
  27. #ifdef LAME_BUTTON
  28. PMENU xxxLoadSysDesktopMenu (PMENU * ppmenu, UINT uMenuId, PWND pwnd)
  29. #else
  30. PMENU xxxLoadSysDesktopMenu (PMENU * ppmenu, UINT uMenuId)
  31. #endif // LAME_BUTTON
  32. {
  33. PMENU pmenu;
  34. /*
  35. * This should only be called when the menu hasn't been loaded
  36. */
  37. UserAssert(*ppmenu == NULL);
  38. #ifdef LAME_BUTTON
  39. pmenu = xxxLoadSysMenu(uMenuId, pwnd);
  40. #else
  41. pmenu = xxxLoadSysMenu(uMenuId);
  42. #endif // LAME_BUTTON
  43. if (pmenu == NULL) {
  44. return NULL;
  45. }
  46. /*
  47. * If someone beat us loading the menu, destroy this one
  48. * and return the one already loaded
  49. */
  50. if (*ppmenu != NULL) {
  51. UserAssert(TestMF(*ppmenu, MFSYSMENU));
  52. RIPMSG1(RIP_WARNING,
  53. "LoadSysDesktopMenu: Menu loaded during callback. ppmenu:%#p",
  54. ppmenu);
  55. _DestroyMenu(pmenu);
  56. return *ppmenu;
  57. }
  58. /*
  59. * Mark it, lock it and done
  60. */
  61. SetMF(pmenu, MFSYSMENU);
  62. LockDesktopMenu(ppmenu, pmenu);
  63. return pmenu;
  64. }
  65. /***************************************************************************\
  66. * Lock/UnlockDesktopMenu
  67. *
  68. * These functions lock/unlock a pmenu into a desktop structure (spmenuSys or
  69. * spmenuDialogSys) and mark/clear it as such.
  70. * We mark these menus so we can identify them quickly on single bit test.
  71. * We also don't want any one to modify these menus or any submenu.
  72. *
  73. * Note that this assumes that there is only one submenu. If more are added,
  74. * these functions have to be fixed accordingly.
  75. *
  76. * 08/18/97 Gerardob Created
  77. \***************************************************************************/
  78. PVOID LockDesktopMenu(PMENU * ppmenu, PMENU pmenu)
  79. {
  80. PMENU pSubMenu;
  81. PTHREADINFO ptiDesktop;
  82. /*
  83. * We only load desktop sys menus once.
  84. */
  85. UserAssert(*ppmenu == NULL);
  86. if (pmenu == NULL) {
  87. return NULL;
  88. }
  89. SetMF(pmenu, MFDESKTOP);
  90. /*
  91. * This is awful but this is the real owner of this object. We used to set it
  92. * to NULL but that was forcing us to handle the NULL owner all over the place
  93. */
  94. ptiDesktop = PtiCurrent()->rpdesk->rpwinstaParent->pTerm->ptiDesktop;
  95. HMChangeOwnerProcess(pmenu, ptiDesktop);
  96. pSubMenu = pmenu->rgItems->spSubMenu;
  97. UserAssert(pSubMenu != NULL);
  98. SetMF(pSubMenu, MFDESKTOP);
  99. HMChangeOwnerProcess(pSubMenu, ptiDesktop);
  100. #if DBG
  101. {
  102. /*
  103. * Assert that there are no other submenus that would need to be
  104. * marked as MFDESKTOP.
  105. */
  106. PITEM pitem;
  107. UINT uItems;
  108. UserAssert(pmenu->cItems == 1);
  109. pitem = pSubMenu->rgItems;
  110. uItems = pSubMenu->cItems;
  111. while (uItems--) {
  112. UserAssert(pitem->spSubMenu == NULL);
  113. pitem++;
  114. }
  115. }
  116. #endif
  117. return Lock(ppmenu, pmenu);
  118. }
  119. PVOID UnlockDesktopMenu(PMENU * ppmenu)
  120. {
  121. UserAssert(*ppmenu != NULL);
  122. UserAssert(TestMF(*ppmenu, MFDESKTOP));
  123. ClearMF(*ppmenu, MFDESKTOP);
  124. UserAssert(TestMF((*ppmenu)->rgItems->spSubMenu, MFDESKTOP));
  125. ClearMF((*ppmenu)->rgItems->spSubMenu, MFDESKTOP);
  126. return Unlock(ppmenu);
  127. }
  128. /***************************************************************************\
  129. * GetSysMenuHandle
  130. *
  131. * Returns a handle to the system menu of the given window. NULL if
  132. * the window doesn't have a system menu.
  133. *
  134. * History:
  135. \***************************************************************************/
  136. PMENU xxxGetSysMenuHandle(
  137. PWND pwnd)
  138. {
  139. PMENU pMenu;
  140. CheckLock(pwnd);
  141. if (TestWF(pwnd, WFSYSMENU)) {
  142. pMenu = pwnd->spmenuSys;
  143. /*
  144. * If the window doesn't have a System Menu, use the default one.
  145. */
  146. if (pMenu == NULL) {
  147. /*
  148. * Grab the menu from the desktop. If the desktop menu
  149. * has not been loaded and this is not a system thread,
  150. * load it now. Callbacks cannot be made from a system
  151. * thread or when a thread is in cleanup.
  152. */
  153. pMenu = pwnd->head.rpdesk->spmenuSys;
  154. /*
  155. * Do not do callbacks if the thread is exiting. We ran into this when
  156. * destroying a thread's window and the window it was promoting to
  157. * foreground was a hard error popup.
  158. */
  159. if (pMenu == NULL && !(PtiCurrent()->TIF_flags & (TIF_SYSTEMTHREAD | TIF_INCLEANUP))) {
  160. #ifdef LAME_BUTTON
  161. pMenu = xxxLoadSysDesktopMenu (&pwnd->head.rpdesk->spmenuSys, ID_SYSMENU, pwnd);
  162. #else
  163. pMenu = xxxLoadSysDesktopMenu (&pwnd->head.rpdesk->spmenuSys, ID_SYSMENU);
  164. #endif // LAME_BUTTON
  165. }
  166. }
  167. } else {
  168. pMenu = NULL;
  169. }
  170. return pMenu;
  171. }
  172. /***************************************************************************\
  173. *
  174. * GetSysMenu()
  175. *
  176. * Sets up the system menu first, then returns it.
  177. *
  178. \***************************************************************************/
  179. PMENU xxxGetSysMenu(PWND pwnd, BOOL fSubMenu)
  180. {
  181. PMENU pMenu;
  182. CheckLock(pwnd);
  183. xxxSetSysMenu(pwnd);
  184. if ((pMenu = xxxGetSysMenuHandle(pwnd)) != NULL) {
  185. if (fSubMenu)
  186. pMenu = _GetSubMenu(pMenu, 0);
  187. }
  188. return(pMenu);
  189. }
  190. /***************************************************************************\
  191. * IsSmallerThanScreen
  192. *
  193. \***************************************************************************/
  194. BOOL IsSmallerThanScreen(PWND pwnd)
  195. {
  196. int dxMax, dyMax;
  197. PMONITOR pMonitor;
  198. pMonitor = _MonitorFromWindow(pwnd, MONITOR_DEFAULTTOPRIMARY);
  199. dxMax = pMonitor->rcWork.right - pMonitor->rcWork.left;
  200. dyMax = pMonitor->rcWork.bottom - pMonitor->rcWork.top;
  201. if ((pwnd->rcWindow.right - pwnd->rcWindow.left < dxMax) ||
  202. (pwnd->rcWindow.bottom - pwnd->rcWindow.top < dyMax)) {
  203. return TRUE;
  204. }
  205. return FALSE;
  206. }
  207. /***************************************************************************\
  208. * SetSysMenu
  209. *
  210. * !
  211. *
  212. * History:
  213. \***************************************************************************/
  214. void xxxSetSysMenu(
  215. PWND pwnd)
  216. {
  217. PMENU pMenu;
  218. UINT wSize;
  219. UINT wMinimize;
  220. UINT wMaximize;
  221. UINT wMove;
  222. UINT wRestore;
  223. UINT wDefault;
  224. BOOL fFramedDialogBox;
  225. TL tlmenu;
  226. CheckLock(pwnd);
  227. /*
  228. * Get the handle of the current system menu.
  229. */
  230. if ((pMenu = xxxGetSysMenuHandle(pwnd)) != NULL) {
  231. pMenu = _GetSubMenu(pMenu, 0);
  232. if (!pMenu)
  233. return;
  234. ThreadLockAlways(pMenu, &tlmenu);
  235. /*
  236. * System modal window: no size, icon, zoom, or move.
  237. */
  238. // No system modal windows on NT.
  239. // wSize = wMaximize = wMinimize = wMove =
  240. // (UINT)((_GetSysModalWindow() == NULL) || hTaskLockInput ? 0: MFS_GRAYED);
  241. wSize = wMaximize = wMinimize = wMove = 0;
  242. wRestore = MFS_GRAYED;
  243. //
  244. // Default menu command is close.
  245. //
  246. wDefault = SC_CLOSE;
  247. /*
  248. * Minimized exceptions: no minimize, restore.
  249. */
  250. // we need to reverse these because VB has a "special" window
  251. // that is both minimized but without a minbox.
  252. if (TestWF(pwnd, WFMINIMIZED))
  253. {
  254. wRestore = 0;
  255. wMinimize = MFS_GRAYED;
  256. wSize = MFS_GRAYED;
  257. wDefault = SC_RESTORE;
  258. if (IsTrayWindow(pwnd))
  259. wMove = MFS_GRAYED;
  260. }
  261. else if (!TestWF(pwnd, WFMINBOX))
  262. wMinimize = MFS_GRAYED;
  263. /*
  264. * Maximized exceptions: no maximize, restore.
  265. */
  266. if (!TestWF(pwnd, WFMAXBOX))
  267. wMaximize = MFS_GRAYED;
  268. else if (TestWF(pwnd, WFMAXIMIZED)) {
  269. wRestore = 0;
  270. /*
  271. * If the window is maximized but it isn't larger than the
  272. * screen, we allow the user to move the window around the
  273. * desktop (but we don't allow resizing).
  274. */
  275. wMove = MFS_GRAYED;
  276. if (!TestWF(pwnd, WFCHILD)) {
  277. if (IsSmallerThanScreen(pwnd)) {
  278. wMove = 0;
  279. }
  280. }
  281. wSize = MFS_GRAYED;
  282. wMaximize = MFS_GRAYED;
  283. }
  284. if (!TestWF(pwnd, WFSIZEBOX))
  285. wSize = MFS_GRAYED;
  286. /*
  287. * Are we dealing with a framed dialog box with a sys menu?
  288. * Dialogs with min/max/size boxes get a regular system menu
  289. * (as opposed to the dialog menu)
  290. */
  291. fFramedDialogBox =
  292. (((TestWF(pwnd, WFBORDERMASK) == (BYTE)LOBYTE(WFDLGFRAME))
  293. || (TestWF(pwnd, WEFDLGMODALFRAME)))
  294. && !TestWF(pwnd, WFSIZEBOX | WFMINBOX | WFMAXBOX));
  295. if (!fFramedDialogBox) {
  296. xxxEnableMenuItem(pMenu, (UINT)SC_SIZE, wSize);
  297. if (!TestWF(pwnd, WEFTOOLWINDOW))
  298. {
  299. xxxEnableMenuItem(pMenu, (UINT)SC_MINIMIZE, wMinimize);
  300. xxxEnableMenuItem(pMenu, (UINT)SC_MAXIMIZE, wMaximize);
  301. xxxEnableMenuItem(pMenu, (UINT)SC_RESTORE, wRestore);
  302. }
  303. }
  304. xxxEnableMenuItem(pMenu, (UINT)SC_MOVE, wMove);
  305. #if DBG
  306. /*
  307. * Assert that nobody managed to change the desktop menus.
  308. */
  309. if (TestMF(pMenu, MFSYSMENU)) {
  310. PITEM pItem = MNLookUpItem(pMenu, SC_CLOSE, FALSE, NULL);
  311. UserAssert((pItem != NULL) && !TestMFS(pItem, MFS_GRAYED));
  312. }
  313. #endif
  314. if (wDefault == SC_CLOSE)
  315. _SetCloseDefault(pMenu);
  316. else
  317. _SetMenuDefaultItem(pMenu, wDefault, MF_BYCOMMAND);
  318. ThreadUnlock(&tlmenu);
  319. }
  320. }
  321. /***************************************************************************\
  322. * GetSystemMenu
  323. *
  324. * !
  325. *
  326. * History:
  327. \***************************************************************************/
  328. PMENU xxxGetSystemMenu(
  329. PWND pwnd,
  330. BOOL fRevert)
  331. {
  332. PMENU pmenu;
  333. CheckLock(pwnd);
  334. /*
  335. * Should we start with a fresh copy?
  336. */
  337. pmenu = pwnd->spmenuSys;
  338. if (fRevert) {
  339. /*
  340. * Destroy the old system menu.
  341. */
  342. if ((pmenu != NULL) && !TestMF(pmenu, MFSYSMENU)) {
  343. if (UnlockWndMenu(pwnd, &pwnd->spmenuSys)) {
  344. _DestroyMenu(pmenu);
  345. }
  346. }
  347. } else {
  348. /*
  349. * Do we need to load a new system menu?
  350. */
  351. if (((pmenu == NULL) || TestMF(pmenu, MFSYSMENU))
  352. && TestWF(pwnd, WFSYSMENU)) {
  353. PPOPUPMENU pGlobalPopupMenu;
  354. UINT uMenuId = (pwnd->spmenuSys == NULL ? ID_SYSMENU : ID_DIALOGSYSMENU);
  355. #ifdef LAME_BUTTON
  356. pmenu = xxxLoadSysMenu(uMenuId, pwnd);
  357. #else
  358. pmenu = xxxLoadSysMenu(uMenuId);
  359. #endif // LAME_BUTTON
  360. if (pmenu == NULL) {
  361. RIPMSG1(RIP_WARNING, "_GetSystemMenu: xxxLoadSysMenu Failed. pwnd:%#p", pwnd);
  362. }
  363. LockWndMenu(pwnd, &pwnd->spmenuSys, pmenu);
  364. pmenu = pwnd->spmenuSys;
  365. pGlobalPopupMenu = GetpGlobalPopupMenu(pwnd);
  366. if ((pGlobalPopupMenu != NULL)
  367. && !pGlobalPopupMenu->fIsTrackPopup
  368. && (pGlobalPopupMenu->spwndPopupMenu == pwnd)) {
  369. UserAssert(pGlobalPopupMenu->spwndNotify == pwnd);
  370. if (pGlobalPopupMenu->fIsSysMenu) {
  371. Lock(&pGlobalPopupMenu->spmenu, pmenu);
  372. } else {
  373. Lock(&pGlobalPopupMenu->spmenuAlternate, pmenu);
  374. }
  375. }
  376. }
  377. }
  378. /*
  379. * Return the handle to the system menu.
  380. */
  381. if (pwnd->spmenuSys != NULL) {
  382. /*
  383. * The app is probably going to modify this menu and then we'll need to
  384. * redraw the caption buttons. Hence we need to store the window pointer
  385. * in this pmenu or we won't be able to know what window to repaint.
  386. * The bogus thing is that we cannot call LockWndMenu here because this is
  387. * not the actual pmenuSys.
  388. */
  389. pmenu = _GetSubMenu(pwnd->spmenuSys, 0);
  390. if (pmenu) {
  391. SetMF(pmenu, MFAPPSYSMENU);
  392. Lock(&pmenu->spwndNotify, pwnd);
  393. }
  394. return pmenu;
  395. }
  396. return NULL;
  397. }
  398. /***************************************************************************\
  399. * MenuItemState
  400. *
  401. * Sets the menu item flags identified by wMask to the states identified
  402. * by wFlags.
  403. *
  404. * History:
  405. * 10-11-90 JimA Translated from ASM
  406. \***************************************************************************/
  407. DWORD MenuItemState(
  408. PMENU pMenu,
  409. UINT wCmd,
  410. DWORD wFlags,
  411. DWORD wMask,
  412. PMENU *ppMenu)
  413. {
  414. PITEM pItem;
  415. DWORD wRet;
  416. /*
  417. * Get a pointer the the menu item
  418. */
  419. if ((pItem = MNLookUpItem(pMenu, wCmd, (BOOL) (wFlags & MF_BYPOSITION), ppMenu)) == NULL)
  420. return (DWORD)-1;
  421. /*
  422. * Return previous state
  423. */
  424. wRet = pItem->fState & wMask;
  425. /*
  426. * Set new state
  427. */
  428. pItem->fState ^= ((wRet ^ wFlags) & wMask);
  429. return wRet;
  430. }
  431. /***************************************************************************\
  432. * EnableMenuItem
  433. *
  434. * Enable, disable or gray a menu item.
  435. *
  436. * History:
  437. * 10-11-90 JimA Translated from ASM
  438. \***************************************************************************/
  439. DWORD xxxEnableMenuItem(
  440. PMENU pMenu,
  441. UINT wIDEnableItem,
  442. UINT wEnable)
  443. {
  444. DWORD dres;
  445. PMENU pRealMenu;
  446. PPOPUPMENU ppopup;
  447. CheckLock(pMenu);
  448. dres = MenuItemState(pMenu, wIDEnableItem, wEnable,
  449. MFS_GRAYED, &pRealMenu);
  450. /*
  451. * If enabling/disabling a system menu item, redraw the caption buttons
  452. */
  453. if (TestMF(pMenu, MFAPPSYSMENU) && (pMenu->spwndNotify != NULL) && (wEnable != dres)) {
  454. TL tlpwnd;
  455. switch (wIDEnableItem) {
  456. case SC_SIZE:
  457. case SC_MOVE:
  458. case SC_MINIMIZE:
  459. case SC_MAXIMIZE:
  460. case SC_CLOSE:
  461. case SC_RESTORE:
  462. ThreadLock(pMenu->spwndNotify, &tlpwnd);
  463. xxxRedrawTitle(pMenu->spwndNotify, DC_BUTTONS);
  464. ThreadUnlock(&tlpwnd);
  465. }
  466. }
  467. /* 367162: If the menu is already being displayed we need to redraw it */
  468. if(pRealMenu && (ppopup = MNGetPopupFromMenu(pRealMenu, NULL))){
  469. xxxMNUpdateShownMenu(ppopup, NULL, MNUS_DEFAULT);
  470. }
  471. return dres;
  472. }
  473. /***************************************************************************\
  474. * CheckMenuItem (API)
  475. *
  476. * Check or un-check a popup menu item.
  477. *
  478. * History:
  479. * 10-11-90 JimA Translated from ASM
  480. \***************************************************************************/
  481. DWORD _CheckMenuItem(
  482. PMENU pMenu,
  483. UINT wIDCheckItem,
  484. UINT wCheck)
  485. {
  486. return MenuItemState(pMenu, wIDCheckItem, wCheck, (UINT)MF_CHECKED, NULL);
  487. }
  488. /***************************************************************************\
  489. *
  490. * SetMenuDefaultItem() -
  491. *
  492. * Sets the default item in the menu, by command or by position based on the
  493. * fByPosition flag.
  494. * We unset all the other items as the default, then set the given one.
  495. *
  496. * The return value is TRUE if the given item was set as default, FALSE
  497. * if not.
  498. *
  499. \***************************************************************************/
  500. BOOL _SetMenuDefaultItem(PMENU pMenu, UINT wID, BOOL fByPosition)
  501. {
  502. UINT iItem;
  503. UINT cItems;
  504. PITEM pItem;
  505. PITEM pItemFound;
  506. PMENU pMenuFound;
  507. //
  508. // We need to check if wId actually exists on this menu. 0xFFFF means
  509. // clear all default items.
  510. //
  511. if (wID != MFMWFP_NOITEM)
  512. {
  513. pItemFound = MNLookUpItem(pMenu, wID, fByPosition, &pMenuFound);
  514. // item must be on same menu and can't be a separator
  515. if ((pItemFound == NULL) || (pMenuFound != pMenu) || TestMFT(pItemFound, MFT_SEPARATOR))
  516. return(FALSE);
  517. }
  518. else
  519. pItemFound = NULL;
  520. pItem = pMenu->rgItems;
  521. cItems = pMenu->cItems;
  522. // Walk the menu list, clearing MFS_DEFAULT from all other items, and
  523. // setting MFS_DEFAULT on the requested one.
  524. for (iItem = 0; iItem < cItems; iItem++, pItem++) {
  525. //
  526. // Note we don't change the state of lpItemFound if it exists. This
  527. // is so that below, where we try to set the default, we can tell
  528. // if we need to recalculate the underline.
  529. //
  530. if (TestMFS(pItem, MFS_DEFAULT) && (pItem != pItemFound))
  531. {
  532. //
  533. // We are changing the default item. As such, it will be drawn
  534. // with a different font than the one used to calculate it, if
  535. // the menu has already been drawn once. We need to ensure
  536. // that the underline gets drawn in the right place the next
  537. // time the menu comes up. Cause it to recalculate.
  538. //
  539. // We do NOT do this if the item
  540. // (a) isn't default--otherwise we'll recalculate the
  541. // underline for every system menu item every time we go into
  542. // menu mode because sysmenu init will call SetMenuDefaultItem.
  543. // (b) isn't the item we're going to set as the default.
  544. // That way we don't recalculate the underline when the item
  545. // isn't changing state.
  546. //
  547. ClearMFS(pItem, MFS_DEFAULT);
  548. pItem->ulX = UNDERLINE_RECALC;
  549. pItem->ulWidth = 0;
  550. }
  551. }
  552. if (wID != MFMWFP_NOITEM)
  553. {
  554. if (!TestMFS(pItemFound, MFS_DEFAULT))
  555. {
  556. //
  557. // We are changing from non-default to default. Clear out
  558. // the underline info. If the menu has never painted, this
  559. // won't do anything. But it matters a lot if it has.
  560. //
  561. SetMFS(pItemFound, MFS_DEFAULT);
  562. pItemFound->ulX = UNDERLINE_RECALC;
  563. pItemFound->ulWidth = 0;
  564. }
  565. }
  566. return(TRUE);
  567. }
  568. // --------------------------------------------------------------------------
  569. //
  570. // SetCloseDefault()
  571. //
  572. // Tries to find a close item in the first level of menu items. Looks
  573. // for SC_CLOSE, then a couple other IDs. We'd rather not do lstrstri's
  574. // for "Close", which is slow.
  575. //
  576. // --------------------------------------------------------------------------
  577. void _SetCloseDefault(PMENU pSubMenu)
  578. {
  579. if (!_SetMenuDefaultItem(pSubMenu, SC_CLOSE, MF_BYCOMMAND))
  580. {
  581. //
  582. // Let's try a couple other values.
  583. // * Project -- 0x7000 less
  584. // * FoxPro -- 0xC070
  585. //
  586. if (!_SetMenuDefaultItem(pSubMenu, SC_CLOSE - 0x7000, MF_BYCOMMAND))
  587. _SetMenuDefaultItem(pSubMenu, 0xC070, MF_BYCOMMAND);
  588. }
  589. }
  590. // --------------------------------------------------------------------------
  591. //
  592. // FindFakeMDIChild()
  593. //
  594. // Attempts to find first child visible child window in the zorder that
  595. // has a system menu or is maxed. We can't check for an exact system
  596. // menu match because several apps make their own copy of the sys menu.
  597. //
  598. // --------------------------------------------------------------------------
  599. PWND FindFakeMDIChild(PWND pwnd)
  600. {
  601. PWND pwndReturn;
  602. // Skip invisible windows and their descendants
  603. if (!TestWF(pwnd, WFVISIBLE))
  604. return(NULL);
  605. // Did we hit pay dirt?
  606. if (TestWF(pwnd, WFCHILD) && (TestWF(pwnd, WFMAXIMIZED) || (pwnd->spmenuSys)))
  607. return(pwnd);
  608. // Check our children
  609. for (pwnd = pwnd->spwndChild; pwnd; pwnd = pwnd->spwndNext)
  610. {
  611. pwndReturn = FindFakeMDIChild(pwnd);
  612. if (pwndReturn)
  613. return(pwndReturn);
  614. }
  615. return(NULL);
  616. }
  617. // --------------------------------------------------------------------------
  618. //
  619. // SetupFakeMDIAppStuff()
  620. //
  621. // For apps that mess around with their own MDI (Excel, Word, Project,
  622. // Quattro Pro), we want to make them a little more Chicago friendly.
  623. // Namely we:
  624. //
  625. // (1) Set the default menu item to SC_CLOSE if there isn't one (this
  626. // won't help FoxPro, but they do so much wrong stuff it doesn't
  627. // really matter).
  628. // That way double-clicks will still work.
  629. //
  630. // (2) Get the right small icon.
  631. //
  632. // The way we do this is to go find the child window of the menu bar parent
  633. // who has a system menu that is this one.
  634. //
  635. // If the system menu is the standard one, then we can't do (2).
  636. //
  637. // --------------------------------------------------------------------------
  638. void SetupFakeMDIAppStuff(PMENU lpMenu, PITEM lpItem)
  639. {
  640. PMENU pSubMenu;
  641. PWND pwndParent;
  642. PWND pwndChild;
  643. if (!(pSubMenu = lpItem->spSubMenu))
  644. return;
  645. pwndParent = lpMenu->spwndNotify;
  646. //
  647. // Set up the default menu item. Project and FoxPro renumber their
  648. // IDs so we do some special stuff for them, among others.
  649. //
  650. if (!TestWF(pwndParent, WFWIN40COMPAT))
  651. {
  652. if (_GetMenuDefaultItem(pSubMenu, TRUE, GMDI_USEDISABLED) == -1L)
  653. _SetCloseDefault(pSubMenu);
  654. }
  655. //
  656. // Don't touch the HIWORD if we don't find an HWND. That way apps
  657. // like Excel which have starting-up maxed children can benefit a little.
  658. // The first time the menu bar is redrawn, the child isn't visible/
  659. // around (they add the item too early). But if it redraws later, or
  660. // you max a child, the icon will kick in.
  661. //
  662. if (pwndChild = FindFakeMDIChild(pwndParent)) {
  663. lpItem->dwItemData = (ULONG_PTR)HWq(pwndChild);
  664. // lpItem->dwTypeData = MAKELONG(LOWORD(lpItem->dwTypeData), HW16(hwndChild));
  665. }
  666. }