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.

1079 lines
29 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: wow.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains shared code between USER32 and USER16
  7. * No New CODE should be added to this file, unless its shared
  8. * with USER16.
  9. *
  10. * History:
  11. * 29-DEC-93 NanduriR shared user32/user16 code.
  12. \***************************************************************************/
  13. #include "wow.h"
  14. #ifdef _USERK_
  15. #define CHECK_RESTRICTED() \
  16. if (((PTHREADINFO)W32GetCurrentThread())->TIF_flags & TIF_RESTRICTED) { \
  17. if (!ValidateHandleSecure(h)) \
  18. pobj = NULL; \
  19. } \
  20. #else
  21. #define CHECK_RESTRICTED() \
  22. if (pci && (pci->dwTIFlags & TIF_RESTRICTED) && pobj) { \
  23. if (!NtUserValidateHandleSecure(h)) \
  24. pobj = NULL; \
  25. } \
  26. #endif
  27. #ifdef _USERK_
  28. #define GET_CURRENT_CLIENTINFO() \
  29. { \
  30. PW32THREAD pW32Thread; \
  31. \
  32. pW32Thread = W32GetCurrentThread(); \
  33. \
  34. if (pW32Thread) { \
  35. pci = ((PTHREADINFO)pW32Thread)->pClientInfo; \
  36. } else { \
  37. pci = NULL; \
  38. } \
  39. }
  40. #else
  41. #define GET_CURRENT_CLIENTINFO() \
  42. pci = GetClientInfo();
  43. #endif // _USERK_
  44. /*
  45. * We have two types of desktop validation:
  46. *
  47. */
  48. #ifdef _USERK_
  49. #define DESKTOPVALIDATE(pci, pobj) \
  50. UNREFERENCED_PARAMETER(pci);
  51. #define DESKTOPVALIDATECCX(pti, pobj) \
  52. try { \
  53. if (((PVOID)pobj >= pti->pClientInfo->pDeskInfo->pvDesktopBase) && \
  54. ((PVOID)pobj < pti->pClientInfo->pDeskInfo->pvDesktopLimit)) { \
  55. pobj = (PBYTE)pobj - pti->ulClientDelta; \
  56. } \
  57. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { \
  58. pobj = NULL; \
  59. } \
  60. #define SHAREDVALIDATE(pobj)
  61. #else
  62. #define DESKTOPVALIDATE(pci, pobj) \
  63. if (pci->pDeskInfo && \
  64. pobj >= pci->pDeskInfo->pvDesktopBase && \
  65. pobj < pci->pDeskInfo->pvDesktopLimit) { \
  66. pobj = (KERNEL_PVOID)((KERNEL_ULONG_PTR)pobj - pci->ulClientDelta); \
  67. } else { \
  68. pobj = (KERNEL_PVOID)NtUserCallOneParam((ULONG_PTR)h, \
  69. SFI__MAPDESKTOPOBJECT); \
  70. } \
  71. #define SHAREDVALIDATE(pobj) \
  72. pobj = REBASESHAREDPTRALWAYS(pobj);
  73. #endif // _USERK_
  74. /*
  75. * Keep the general path through validation straight without jumps - that
  76. * means tunneling if()'s for this routine - this'll make validation fastest
  77. * because of instruction caching.
  78. *
  79. * In order to have the validation code in one place only, we define
  80. * the *ValidateHandleMacro macros which are to be included by the
  81. * HMValidateHanlde* routines. We don't make these into functions
  82. * because we're optimizing on time, not size.
  83. */
  84. #define ValidateHandleMacro(pci, pobj, h, bType) \
  85. StartValidateHandleMacro(h) \
  86. BeginAliveValidateHandleMacro() \
  87. BeginTypeValidateHandleMacro(pobj, bType) \
  88. DESKTOPVALIDATE(pci, pobj) \
  89. EndTypeValidateHandleMacro \
  90. EndAliveValidateHandleMacro() \
  91. EndValidateHandleMacro
  92. #ifdef _USERK_
  93. #define ValidateCatHandleMacro(pci, pobj, h, bType) \
  94. StartValidateHandleMacro(h) \
  95. BeginTypeValidateHandleMacro(pobj, bType) \
  96. DESKTOPVALIDATE(pci, pobj) \
  97. EndTypeValidateHandleMacro \
  98. EndValidateHandleMacro
  99. #define ValidateCatHandleMacroCcx(pti, pobj, h, bType) \
  100. StartValidateHandleMacro(h) \
  101. BeginTypeValidateHandleMacro(pobj, bType) \
  102. DESKTOPVALIDATECCX(pti, pobj) \
  103. EndTypeValidateHandleMacro \
  104. EndValidateHandleMacro
  105. #endif
  106. #define ValidateSharedHandleMacro(pobj, h, bType) \
  107. StartValidateHandleMacro(h) \
  108. BeginAliveValidateHandleMacro() \
  109. BeginTypeValidateHandleMacro(pobj, bType) \
  110. SHAREDVALIDATE(pobj) \
  111. EndTypeValidateHandleMacro \
  112. EndAliveValidateHandleMacro() \
  113. EndValidateHandleMacro
  114. /*
  115. * The handle validation routines should be optimized for time, not size,
  116. * since they get called so often.
  117. */
  118. #pragma optimize("t", on)
  119. /***************************************************************************\
  120. * HMValidateHandle
  121. *
  122. * This routine validates a handle manager handle.
  123. *
  124. * 01-22-92 ScottLu Created.
  125. \***************************************************************************/
  126. PVOID FASTCALL HMValidateHandle(
  127. HANDLE h,
  128. BYTE bType)
  129. {
  130. DWORD dwError;
  131. KERNEL_PVOID pobj = NULL;
  132. PCLIENTINFO pci;
  133. GET_CURRENT_CLIENTINFO();
  134. #if DBG && !defined(_USERK_)
  135. /*
  136. * We don't want 32 bit apps passing 16 bit handles
  137. * we should consider failing this before we get
  138. * stuck supporting it (Some VB apps do this).
  139. */
  140. if (pci && (h != NULL)
  141. && (HMUniqFromHandle(h) == 0)
  142. && !(pci->dwTIFlags & TIF_16BIT)) {
  143. RIPMSG3(RIP_WARNING, "HMValidateHandle: 32bit process [%d] using 16 bit handle [%#p] bType:%#lx",
  144. HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), h, (DWORD)bType);
  145. }
  146. #endif
  147. /*
  148. * Object can't be located in shared memory.
  149. */
  150. UserAssert(bType != TYPE_MONITOR);
  151. /*
  152. * Validation macro. Falls through if the handle is invalid.
  153. */
  154. ValidateHandleMacro(pci, pobj, h, bType);
  155. /*
  156. * check for secure process
  157. */
  158. CHECK_RESTRICTED();
  159. if (pobj != NULL) {
  160. return KPVOID_TO_PVOID(pobj);
  161. }
  162. switch (bType) {
  163. case TYPE_WINDOW:
  164. dwError = ERROR_INVALID_WINDOW_HANDLE;
  165. break;
  166. case TYPE_MENU:
  167. dwError = ERROR_INVALID_MENU_HANDLE;
  168. break;
  169. case TYPE_CURSOR:
  170. dwError = ERROR_INVALID_CURSOR_HANDLE;
  171. break;
  172. case TYPE_ACCELTABLE:
  173. dwError = ERROR_INVALID_ACCEL_HANDLE;
  174. break;
  175. case TYPE_HOOK:
  176. dwError = ERROR_INVALID_HOOK_HANDLE;
  177. break;
  178. case TYPE_SETWINDOWPOS:
  179. dwError = ERROR_INVALID_DWP_HANDLE;
  180. break;
  181. default:
  182. dwError = ERROR_INVALID_HANDLE;
  183. break;
  184. }
  185. RIPERR2(dwError,
  186. RIP_WARNING,
  187. "HMValidateHandle: Invalid:%#p Type:%#lx",
  188. h, (DWORD)bType);
  189. /*
  190. * If we get here, it's an error.
  191. */
  192. return NULL;
  193. }
  194. /***************************************************************************\
  195. * HMValidateHandleNoSecure
  196. *
  197. * This routine validates a handle manager handle.
  198. *
  199. * 01-22-92 ScottLu Created.
  200. \***************************************************************************/
  201. PVOID FASTCALL HMValidateHandleNoSecure(
  202. HANDLE h,
  203. BYTE bType)
  204. {
  205. KERNEL_PVOID pobj = NULL;
  206. PCLIENTINFO pci;
  207. GET_CURRENT_CLIENTINFO();
  208. #if !defined(_USERK_)
  209. /*
  210. * We don't want 32 bit apps passing 16 bit handles
  211. * we should consider failing this before we get
  212. * stuck supporting it (Some VB apps do this).
  213. */
  214. if (pci && (h != NULL)
  215. && (HMUniqFromHandle(h) == 0)
  216. && !(pci->dwTIFlags & TIF_16BIT)) {
  217. RIPMSG3(RIP_WARNING, "HMValidateHandle: 32bit process [%d] using 16 bit handle [%#p] bType:%#lx",
  218. HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), h, (DWORD)bType);
  219. }
  220. #endif
  221. /*
  222. * Object can't be located in shared memory.
  223. */
  224. UserAssert(bType != TYPE_MONITOR);
  225. /*
  226. * Validation macro.
  227. */
  228. ValidateHandleMacro(pci, pobj, h, bType);
  229. return KPVOID_TO_PVOID(pobj);
  230. }
  231. #if defined(_USERK_)
  232. PVOID FASTCALL HMValidateCatHandleNoSecure(
  233. HANDLE h,
  234. BYTE bType)
  235. {
  236. PVOID pobj = NULL;
  237. PCLIENTINFO pci;
  238. GET_CURRENT_CLIENTINFO();
  239. /*
  240. * Object can't be located in shared memory.
  241. */
  242. UserAssert(bType != TYPE_MONITOR);
  243. /*
  244. * Validation macro.
  245. */
  246. ValidateCatHandleMacro(pci, pobj, h, bType);
  247. return pobj;
  248. }
  249. PVOID FASTCALL HMValidateCatHandleNoSecureCCX(
  250. HANDLE h,
  251. BYTE bType,
  252. PTHREADINFO pti)
  253. {
  254. PVOID pobj = NULL;
  255. /*
  256. * Object can't be located in shared memory.
  257. */
  258. UserAssert(bType != TYPE_MONITOR);
  259. /*
  260. * Validation macro.
  261. */
  262. ValidateCatHandleMacroCcx(pti, pobj, h, bType);
  263. return pobj;
  264. }
  265. PVOID FASTCALL HMValidateCatHandleNoRip(
  266. HANDLE h,
  267. BYTE bType)
  268. {
  269. PVOID pobj = NULL;
  270. PCLIENTINFO pci;
  271. /*
  272. * This is the fastest way way to do validation, because
  273. * unlike HMValidateHandle, this function doesn't set the
  274. * last error.
  275. *
  276. * Validation macro. Falls through if the handle is invalid.
  277. */
  278. GET_CURRENT_CLIENTINFO();
  279. /*
  280. * Object can't be located in shared memory.
  281. */
  282. UserAssert(bType != TYPE_MONITOR);
  283. ValidateCatHandleMacro(pci, pobj, h, bType);
  284. /*
  285. * check for secure process
  286. */
  287. CHECK_RESTRICTED();
  288. return pobj;
  289. }
  290. #endif
  291. PVOID FASTCALL HMValidateHandleNoRip(
  292. HANDLE h,
  293. BYTE bType)
  294. {
  295. KERNEL_PVOID pobj = NULL;
  296. PCLIENTINFO pci;
  297. /*
  298. * This is the fastest way way to do validation, because
  299. * unlike HMValidateHandle, this function doesn't set the
  300. * last error.
  301. *
  302. * Validation macro. Falls through if the handle is invalid.
  303. */
  304. GET_CURRENT_CLIENTINFO();
  305. /*
  306. * Object can't be located in shared memory.
  307. */
  308. UserAssert(bType != TYPE_MONITOR);
  309. ValidateHandleMacro(pci, pobj, h, bType);
  310. /*
  311. * check for secure process
  312. */
  313. CHECK_RESTRICTED();
  314. return KPVOID_TO_PVOID(pobj);
  315. }
  316. #if DBG && !defined(_USERK_)
  317. /*
  318. * HMValidateHandleNoDesktop is a debug-client-side only function
  319. * used to verify a given handle without calling DESKTOPVALIDATE.
  320. * If the handle is valid, it returns the object's kernel pointer
  321. * which can be used as a BOOL value only.
  322. * Use this function to verify handles for which corresponding phe->phead
  323. * is a pool allocation (as opposed to desktop-heap allocations).
  324. */
  325. KERNEL_PVOID FASTCALL HMValidateHandleNoDesktop(
  326. HANDLE h,
  327. BYTE bType)
  328. {
  329. KERNEL_PVOID pobj = NULL;
  330. StartValidateHandleMacro(h)
  331. BeginTypeValidateHandleMacro(pobj, bType)
  332. EndTypeValidateHandleMacro
  333. EndValidateHandleMacro
  334. return pobj;
  335. }
  336. #endif
  337. /***************************************************************************\
  338. * HMValidateSharedHandle
  339. *
  340. * This routine validates a handle manager handle allocated in
  341. * shared memory.
  342. *
  343. * History:
  344. * 02-Apr-1997 adams Created.
  345. \***************************************************************************/
  346. PVOID FASTCALL HMValidateSharedHandle(
  347. HANDLE h,
  348. BYTE bType)
  349. {
  350. DWORD dwError;
  351. KERNEL_PVOID pobj = NULL;
  352. #if DBG && !defined(_USERK_)
  353. /*
  354. * We don't want 32 bit apps passing 16 bit handles
  355. * we should consider failing this before we get
  356. * stuck supporting it (Some VB apps do this).
  357. */
  358. if ((h != NULL)
  359. && (HMUniqFromHandle(h) == 0)
  360. && !(GetClientInfo()->dwTIFlags & TIF_16BIT)) {
  361. RIPMSG3(RIP_WARNING, "HMValidateHandle: 32bit process [%d] using 16 bit handle [%#p] bType:%#lx",
  362. HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), h, (DWORD)bType);
  363. }
  364. #endif
  365. /*
  366. * Validation macro. Falls through if the handle is invalid.
  367. */
  368. ValidateSharedHandleMacro(pobj, h, bType);
  369. if (pobj != NULL)
  370. return KPVOID_TO_PVOID(pobj);
  371. switch (bType) {
  372. case TYPE_MONITOR:
  373. dwError = ERROR_INVALID_MONITOR_HANDLE;
  374. break;
  375. default:
  376. dwError = ERROR_INVALID_HANDLE;
  377. break;
  378. }
  379. RIPERR2(dwError,
  380. RIP_WARNING,
  381. "HMValidateSharedHandle: Invalid:%#p Type:%#lx",
  382. h, (DWORD)bType);
  383. /*
  384. * If we get here, it's an error.
  385. */
  386. return NULL;
  387. }
  388. /*
  389. * Switch back to default optimization.
  390. */
  391. #pragma optimize("", on)
  392. /***************************************************************************\
  393. * MNLookUpItem
  394. *
  395. * Return a pointer to the menu item specified by wCmd and wFlags
  396. *
  397. * History:
  398. * 10-11-90 JimA Translated from ASM
  399. * 01-07-93 FritzS Ported from Chicago
  400. \***************************************************************************/
  401. PITEM MNLookUpItem(
  402. PMENU pMenu,
  403. UINT wCmd,
  404. BOOL fByPosition,
  405. PMENU *ppMenuItemIsOn)
  406. {
  407. PITEM pItem;
  408. PITEM pItemRet = NULL;
  409. PITEM pItemMaybe;
  410. PMENU pMenuMaybe = NULL;
  411. int i;
  412. if (ppMenuItemIsOn != NULL)
  413. *ppMenuItemIsOn = NULL;
  414. if (pMenu == NULL || !pMenu->cItems || wCmd == MFMWFP_NOITEM) {
  415. // RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "MNLookUpItem: invalid item");
  416. return NULL;
  417. }
  418. /*
  419. * dwFlags determines how we do the search
  420. */
  421. if (fByPosition) {
  422. if (wCmd < (UINT)pMenu->cItems) {
  423. pItemRet = &((PITEM)REBASEALWAYS(pMenu, rgItems))[wCmd];
  424. if (ppMenuItemIsOn != NULL)
  425. *ppMenuItemIsOn = pMenu;
  426. return (pItemRet);
  427. } else
  428. return NULL;
  429. }
  430. /*
  431. * Walk down the menu and try to find an item with an ID of wCmd.
  432. * The search procedes from the end of the menu (as was done in
  433. * assembler).
  434. */
  435. /* this is the Chicago code, which walks from the front of the menu -- Fritz */
  436. // for (pItem = &pMenu->rgItems[i - 1]; pItemRet == NULL && i--; --pItem) {
  437. for (i = 0, pItem = REBASEALWAYS(pMenu, rgItems); i < (int)pMenu->cItems;
  438. i++, pItem++) {
  439. /*
  440. * If the item is a popup, recurse down the tree
  441. */
  442. if (pItem->spSubMenu != NULL) {
  443. //
  444. // COMPAT:
  445. // Allow apps to pass in menu handle as ID in menu APIs. We
  446. // remember that this popup had a menu handle with the same ID
  447. // value. This is a 2nd choice though. We still want to see
  448. // if there's some actual command that has this ID value first.
  449. //
  450. if (pItem->wID == wCmd) {
  451. pMenuMaybe = pMenu;
  452. pItemMaybe = pItem;
  453. }
  454. pItemRet = MNLookUpItem((PMENU)REBASEPTR(pMenu, pItem->spSubMenu),
  455. wCmd, FALSE, ppMenuItemIsOn);
  456. if (pItemRet != NULL)
  457. return pItemRet;
  458. } else if (pItem->wID == wCmd) {
  459. /*
  460. * Found the item, now save things for later
  461. */
  462. if (ppMenuItemIsOn != NULL)
  463. *ppMenuItemIsOn = pMenu;
  464. return pItem;
  465. }
  466. }
  467. if (pMenuMaybe) {
  468. // no non popup menu match found -- use the 2nd choice popup menu
  469. // match
  470. if (ppMenuItemIsOn != NULL)
  471. *ppMenuItemIsOn = pMenuMaybe;
  472. return(pItemMaybe);
  473. }
  474. return(NULL);
  475. }
  476. /***************************************************************************\
  477. * GetMenuState
  478. *
  479. * Either returns the state of a menu item or the state and item count
  480. * of a popup.
  481. *
  482. * History:
  483. * 10-11-90 JimA Translated from ASM
  484. \***************************************************************************/
  485. UINT _GetMenuState(
  486. PMENU pMenu,
  487. UINT wId,
  488. UINT dwFlags)
  489. {
  490. PITEM pItem;
  491. DWORD fFlags;
  492. /*
  493. * If the item does not exist, leave
  494. */
  495. if ((pItem = MNLookUpItem(pMenu, wId, (BOOL) (dwFlags & MF_BYPOSITION), NULL)) == NULL)
  496. return (UINT)-1;
  497. fFlags = pItem->fState | pItem->fType;
  498. #ifndef _USERK_
  499. /*
  500. * Add old MFT_BITMAP flag to keep old apps happy
  501. */
  502. if ((pItem->hbmp != NULL) && (pItem->lpstr == NULL)) {
  503. fFlags |= MFT_BITMAP;
  504. }
  505. #endif
  506. if (pItem->spSubMenu != NULL) {
  507. /*
  508. * If the item is a popup, return item count in high byte and
  509. * popup flags in low byte
  510. */
  511. fFlags = ((fFlags | MF_POPUP) & 0x00FF) +
  512. (((PMENU)REBASEPTR(pMenu, pItem->spSubMenu))->cItems << 8);
  513. }
  514. return fFlags;
  515. }
  516. /***************************************************************************\
  517. * GetPrevPwnd
  518. *
  519. *
  520. *
  521. * History:
  522. * 11-05-90 darrinm Ported from Win 3.0 sources.
  523. \***************************************************************************/
  524. PWND GetPrevPwnd(
  525. PWND pwndList,
  526. PWND pwndFind)
  527. {
  528. PWND pwndFound, pwndNext;
  529. if (pwndList == NULL)
  530. return NULL;
  531. if (pwndList->spwndParent == NULL)
  532. return NULL;
  533. pwndNext = REBASEPWND(pwndList, spwndParent);
  534. pwndNext = REBASEPWND(pwndNext, spwndChild);
  535. pwndFound = NULL;
  536. while (pwndNext != NULL) {
  537. if (pwndNext == pwndFind)
  538. break;
  539. pwndFound = pwndNext;
  540. pwndNext = REBASEPWND(pwndNext, spwndNext);
  541. }
  542. return (pwndNext == pwndFind) ? pwndFound : NULL;
  543. }
  544. /***************************************************************************\
  545. * _GetWindow (API)
  546. *
  547. *
  548. * History:
  549. * 11-05-90 darrinm Ported from Win 3.0 sources.
  550. * 02-19-91 JimA Added enum access check
  551. * 05-04-02 DarrinM Removed enum access check and moved to USERRTL.DLL
  552. \***************************************************************************/
  553. PWND _GetWindow(
  554. PWND pwnd,
  555. UINT cmd)
  556. {
  557. PWND pwndT;
  558. BOOL fRebase = FALSE;
  559. /*
  560. * If this is a desktop window, return NULL for sibling or
  561. * parent information.
  562. */
  563. if (GETFNID(pwnd) == FNID_DESKTOP) {
  564. switch (cmd) {
  565. case GW_CHILD:
  566. break;
  567. default:
  568. return NULL;
  569. break;
  570. }
  571. }
  572. /*
  573. * Rebase the returned window at the end of the routine
  574. * to avoid multiple test for pwndT == NULL.
  575. */
  576. pwndT = NULL;
  577. switch (cmd) {
  578. case GW_HWNDNEXT:
  579. pwndT = pwnd->spwndNext;
  580. fRebase = TRUE;
  581. break;
  582. case GW_HWNDFIRST:
  583. if (pwnd->spwndParent) {
  584. pwndT = REBASEPWND(pwnd, spwndParent);
  585. pwndT = REBASEPWND(pwndT, spwndChild);
  586. if (GetAppCompatFlags(NULL) & GACF_IGNORETOPMOST) {
  587. while (pwndT != NULL) {
  588. if (!TestWF(pwndT, WEFTOPMOST))
  589. break;
  590. pwndT = REBASEPWND(pwndT, spwndNext);
  591. }
  592. }
  593. }
  594. break;
  595. case GW_HWNDLAST:
  596. pwndT = GetPrevPwnd(pwnd, NULL);
  597. break;
  598. case GW_HWNDPREV:
  599. pwndT = GetPrevPwnd(pwnd, pwnd);
  600. break;
  601. case GW_OWNER:
  602. pwndT = pwnd->spwndOwner;
  603. fRebase = TRUE;
  604. break;
  605. case GW_CHILD:
  606. pwndT = pwnd->spwndChild;
  607. fRebase = TRUE;
  608. break;
  609. #if !defined(_USERK_)
  610. case GW_ENABLEDPOPUP:
  611. pwndT = (PWND)NtUserCallHwnd(PtoHq(pwnd), SFI_DWP_GETENABLEDPOPUP);
  612. fRebase = TRUE;
  613. break;
  614. #endif
  615. default:
  616. RIPERR0(ERROR_INVALID_GW_COMMAND, RIP_VERBOSE, "");
  617. return NULL;
  618. }
  619. if (pwndT != NULL && fRebase)
  620. pwndT = REBASEPTR(pwnd, pwndT);
  621. return pwndT;
  622. }
  623. /***************************************************************************\
  624. * _GetParent (API)
  625. *
  626. *
  627. *
  628. * History:
  629. * 11-12-90 darrinm Ported.
  630. * 02-19-91 JimA Added enum access check
  631. * 05-04-92 DarrinM Removed enum access check and moved to USERRTL.DLL
  632. \***************************************************************************/
  633. PWND _GetParent(
  634. PWND pwnd)
  635. {
  636. /*
  637. * For 1.03 compatibility reasons, we should return NULL
  638. * for top level "tiled" windows and owner for other popups.
  639. * pwndOwner is set to NULL in xxxCreateWindow for top level
  640. * "tiled" windows.
  641. */
  642. if (!(TestwndTiled(pwnd))) {
  643. if (TestwndChild(pwnd))
  644. pwnd = REBASEPWND(pwnd, spwndParent);
  645. else
  646. pwnd = REBASEPWND(pwnd, spwndOwner);
  647. return pwnd;
  648. }
  649. /*
  650. * The window was not a child window; they may have been just testing
  651. * if it was
  652. */
  653. return NULL;
  654. }
  655. /***************************************************************************\
  656. * GetSubMenu
  657. *
  658. * Return the handle of a popup menu.
  659. *
  660. * History:
  661. * 10-11-90 JimA Translated from ASM
  662. \***************************************************************************/
  663. PMENU _GetSubMenu(
  664. PMENU pMenu,
  665. int nPos)
  666. {
  667. PITEM pItem;
  668. PMENU pPopup = NULL;
  669. /*
  670. * Make sure nPos refers to a valid popup
  671. */
  672. if ((UINT)nPos < (UINT)((PMENU)pMenu)->cItems) {
  673. pItem = &((PITEM)REBASEALWAYS(pMenu, rgItems))[nPos];
  674. if (pItem->spSubMenu != NULL)
  675. pPopup = (PMENU)REBASEPTR(pMenu, pItem->spSubMenu);
  676. }
  677. return pPopup;
  678. }
  679. /***************************************************************************\
  680. * _IsChild (API)
  681. *
  682. *
  683. *
  684. * History:
  685. * 11-07-90 darrinm Translated from Win 3.0 ASM code.
  686. \***************************************************************************/
  687. BOOL _IsChild(
  688. PWND pwndParent,
  689. PWND pwnd)
  690. {
  691. /*
  692. * Don't need a test to get out of the loop because the
  693. * desktop is not a child.
  694. */
  695. while (pwnd != NULL) {
  696. if (!TestwndChild(pwnd))
  697. return FALSE;
  698. pwnd = REBASEPWND(pwnd, spwndParent);
  699. if (pwndParent == pwnd)
  700. return TRUE;
  701. }
  702. return FALSE;
  703. }
  704. /***************************************************************************\
  705. * _IsWindowVisible (API)
  706. *
  707. * IsWindowVisible returns the TRUEVIS state of a window, rather than just
  708. * the state of its WFVISIBLE flag. According to this routine, a window is
  709. * considered visible when it and all the windows on its parent chain are
  710. * visible (WFVISIBLE flag set). A special case hack was put in that causes
  711. * any icon window being dragged to be considered as visible.
  712. *
  713. * History:
  714. * 11-12-90 darrinm Ported.
  715. \***************************************************************************/
  716. BOOL _IsWindowVisible(
  717. PWND pwnd)
  718. {
  719. /*
  720. * Check if this is the iconic window being moved around with a mouse
  721. * If so, return a TRUE, though, strictly speaking, it is hidden.
  722. * This helps the Tracer guys from going crazy!
  723. * Fix for Bug #57 -- SANKAR -- 08-08-89 --
  724. */
  725. if (pwnd == NULL)
  726. return TRUE;
  727. for (;;) {
  728. if (!TestWF(pwnd, WFVISIBLE))
  729. return FALSE;
  730. if (GETFNID(pwnd) == FNID_DESKTOP)
  731. break;
  732. pwnd = REBASEPWND(pwnd, spwndParent);
  733. }
  734. return TRUE;
  735. }
  736. /***************************************************************************\
  737. * _ClientToScreen (API)
  738. *
  739. * Map a point from client to screen-relative coordinates.
  740. *
  741. * History:
  742. * 11-12-90 darrinm Translated from Win 3.0 ASM code.
  743. \***************************************************************************/
  744. VOID _ClientToScreen(
  745. PWND pwnd,
  746. PPOINT ppt)
  747. {
  748. /*
  749. * Client and screen coordinates are the same for the
  750. * desktop window.
  751. */
  752. if (GETFNID(pwnd) != FNID_DESKTOP) {
  753. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  754. ppt->x = pwnd->rcClient.right - ppt->x;
  755. } else {
  756. ppt->x += pwnd->rcClient.left;
  757. }
  758. ppt->y += pwnd->rcClient.top;
  759. }
  760. }
  761. /***************************************************************************\
  762. * _GetClientRect (API)
  763. *
  764. *
  765. *
  766. * History:
  767. * 26-Oct-1990 DarrinM Implemented.
  768. \***************************************************************************/
  769. VOID _GetClientRect(
  770. PWND pwnd,
  771. LPRECT prc)
  772. {
  773. /*
  774. * If this is a 3.1 app, and it's minimized, then we need to return
  775. * a rectangle other than the real-client-rect. This is necessary since
  776. * there is no client-rect-size in Win4.0. Apps such as PackRat 1.0
  777. * will GPF if returned a empty-rect.
  778. */
  779. if (TestWF(pwnd, WFMINIMIZED) && !TestWF(pwnd, WFWIN40COMPAT)) {
  780. prc->left = 0;
  781. prc->top = 0;
  782. prc->right = SYSMETRTL(CXMINIMIZED);
  783. prc->bottom = SYSMETRTL(CYMINIMIZED);
  784. } else {
  785. if (GETFNID(pwnd) != FNID_DESKTOP) {
  786. *prc = pwnd->rcClient;
  787. OffsetRect(prc, -pwnd->rcClient.left, -pwnd->rcClient.top);
  788. } else {
  789. /*
  790. * For compatibility, return the rect of the primary
  791. * monitor for the desktop window.
  792. */
  793. prc->left = prc->top = 0;
  794. prc->right = SYSMETRTL(CXSCREEN);
  795. prc->bottom = SYSMETRTL(CYSCREEN);
  796. }
  797. }
  798. }
  799. /***************************************************************************\
  800. * _GetWindowRect (API)
  801. *
  802. *
  803. *
  804. * History:
  805. * 26-Oct-1990 DarrinM Implemented.
  806. \***************************************************************************/
  807. VOID _GetWindowRect(
  808. PWND pwnd,
  809. LPRECT prc)
  810. {
  811. if (GETFNID(pwnd) != FNID_DESKTOP) {
  812. *prc = pwnd->rcWindow;
  813. } else {
  814. /*
  815. * For compatibility, return the rect of the primary
  816. * monitor for the desktop window.
  817. */
  818. prc->left = 0;
  819. prc->top = 0;
  820. prc->right = SYSMETRTL(CXSCREEN);
  821. prc->bottom = SYSMETRTL(CYSCREEN);
  822. }
  823. }
  824. /***************************************************************************\
  825. * _ScreenToClient (API)
  826. *
  827. * Map a point from screen to client-relative coordinates.
  828. *
  829. * History:
  830. * 11-12-90 darrinm Translated from Win 3.0 ASM code.
  831. \***************************************************************************/
  832. VOID _ScreenToClient(
  833. PWND pwnd,
  834. PPOINT ppt)
  835. {
  836. /*
  837. * Client and screen coordinates are the same for the
  838. * desktop window.
  839. */
  840. if (GETFNID(pwnd) != FNID_DESKTOP) {
  841. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  842. ppt->x = pwnd->rcClient.right - ppt->x;
  843. } else {
  844. ppt->x -= pwnd->rcClient.left;
  845. }
  846. ppt->y -= pwnd->rcClient.top;
  847. }
  848. }
  849. /***************************************************************************\
  850. * PhkNextValid
  851. *
  852. * This helper routine walk the phkNext chain looking for the next valid
  853. * hook (i.e., not marked as destroyed). If the end of the local (or
  854. * thread specific) hook chain is reached, then it jumps to the global
  855. * (or desktop) chain.
  856. *
  857. * Once a hook is destroyed, we don't want anymore activity on it; however,
  858. * if the hook is locked at destroy time (= someone is calling it), then
  859. * we keep it in the list so CallNextHook will work properly
  860. *
  861. * History:
  862. * 03/24/96 GerardoB Moved to rtl and added *Valid stuff.
  863. * 01-30-91 DavidPe Created.
  864. \***************************************************************************/
  865. PHOOK PhkNextValid(PHOOK phk)
  866. {
  867. #if DBG
  868. int iHook = phk->iHook;
  869. #ifdef _USERK_
  870. CheckCritInShared();
  871. #endif
  872. #endif
  873. do {
  874. /*
  875. * If this hook is marked as destroyed, it must be either
  876. * locked or we should be in the process of destroying it
  877. */
  878. UserAssert(!(phk->flags & HF_DESTROYED)
  879. || (((PHEAD)phk)->cLockObj != 0)
  880. || (phk->flags & HF_INCHECKWHF));
  881. /*
  882. * Get the next hook
  883. */
  884. if (phk->phkNext != NULL) {
  885. phk = REBASEALWAYS(phk, phkNext);
  886. } else if (!(phk->flags & HF_GLOBAL)) {
  887. #ifdef _USERK_
  888. phk = PtiCurrent()->pDeskInfo->aphkStart[phk->iHook + 1];
  889. #else
  890. PCLIENTINFO pci = GetClientInfo();
  891. phk = pci->pDeskInfo->aphkStart[phk->iHook + 1];
  892. /*
  893. * If it found a pointer, rebase it.
  894. */
  895. if (phk != NULL) {
  896. (KPBYTE)phk -= pci->ulClientDelta;
  897. }
  898. #endif
  899. UserAssert((phk == NULL) || (phk->flags & HF_GLOBAL));
  900. } else {
  901. return NULL;
  902. }
  903. /*
  904. * If destroyed, keep looking.
  905. */
  906. } while ((phk != NULL) && (phk->flags & HF_DESTROYED));
  907. #ifdef _USERK_
  908. DbgValidateHooks(phk, iHook);
  909. #endif
  910. return phk;
  911. }