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.

3139 lines
103 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: createw.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Contains xxxCreateWindow, xxxDestroyWindow, and a few close friends.
  7. *
  8. * Note that during creation or deletion, the window is locked so that
  9. * it can't be deleted recursively.
  10. *
  11. * History:
  12. * 19-Oct-1990 DarrinM Created.
  13. * 11-Feb-1991 JimA Added access checks.
  14. * 19-Feb-1991 MikeKe Added Revalidation code
  15. * 20-Jan-1992 IanJa ANSI/UNICODE neutralization
  16. \***************************************************************************/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. BOOL WantImeWindow(PWND pwndParent, PWND pwnd);
  20. #if DBG
  21. VOID VerifyWindowLink(PWND pwnd, PWND pwndParent, BOOL fLink);
  22. #endif
  23. /***************************************************************************\
  24. * xxxCreateWindowEx (API)
  25. *
  26. * History:
  27. * 10-18-90 darrinm Ported from Win 3.0 sources.
  28. * 02-07-91 DavidPe Added Win 3.1 WH_CBT support.
  29. * 02-11-91 JimA Added access checks.
  30. * 04-11-92 ChandanC Added initialization of WOW words
  31. \***************************************************************************/
  32. PWND xxxCreateWindowEx(
  33. DWORD dwExStyle,
  34. PLARGE_STRING cczpstrNVClass,
  35. PLARGE_STRING cczpstrClass,
  36. PLARGE_STRING cczpstrName,
  37. DWORD style,
  38. int x,
  39. int y,
  40. int cx,
  41. int cy,
  42. PWND pwndParent,
  43. PMENU pMenu,
  44. HANDLE hInstance,
  45. LPVOID lpCreateParams,
  46. DWORD dwExpWinVerAndFlags,
  47. PACTIVATION_CONTEXT pActCtx)
  48. {
  49. /*
  50. * The buffers for Class and Name may be client memory, and access
  51. * to those buffers must be protected.
  52. */
  53. UINT mask = 0;
  54. BOOL fChild;
  55. BOOL fDefPos = FALSE;
  56. BOOL fStartup = FALSE;
  57. PCLS pcls;
  58. PPCLS ppcls;
  59. RECT rc;
  60. int dx, dy;
  61. SIZERECT src;
  62. int sw = SW_SHOW;
  63. PWND pwnd;
  64. PWND pwndZOrder, pwndHardError;
  65. CREATESTRUCTEX csex;
  66. PDESKTOP pdesk;
  67. ATOM atomT;
  68. PTHREADINFO ptiCurrent = PtiCurrent();
  69. TL tlpwnd;
  70. TL tlpwndParent;
  71. TL tlpwndParentT;
  72. BOOL fLockParent = FALSE;
  73. WORD wWFAnsiCreator = 0;
  74. DWORD dw;
  75. DWORD dwMinMax;
  76. PMONITOR pMonitor;
  77. BOOL fTiled;
  78. CheckLock(pwndParent);
  79. UserAssert(IsWinEventNotifyDeferredOK());
  80. #ifdef LAZY_CLASS_INIT
  81. if ((ptiCurrent->ppi->W32PF_Flags & W32PF_CLASSESREGISTERED) == 0) {
  82. if (!LW_RegisterWindows()) {
  83. RIPERR0(ERROR_INVALID_PARAMETER,
  84. RIP_WARNING,
  85. "LW_RegisterWindows failed.");
  86. return NULL;
  87. }
  88. }
  89. #endif
  90. /*
  91. * For Edit Controls (including those in comboboxes), we must know whether
  92. * the App used an ANSI or a Unicode CreateWindow call. This is passed in
  93. * with the private WS_EX_ANSICREATOR dwExStyle bit, but we MUST NOT leave
  94. * out this bit in the window's dwExStyle! Transfer to the internal window
  95. * flag WFANSICREATOR immediately.
  96. */
  97. if (dwExStyle & WS_EX_ANSICREATOR) {
  98. wWFAnsiCreator = WFANSICREATOR;
  99. dwExStyle &= ~WS_EX_ANSICREATOR;
  100. }
  101. /*
  102. * After grocking any bits, we should no longer be using any private bits.
  103. */
  104. UserAssert((dwExStyle & WS_EXP_PRIVATE) == 0);
  105. /*
  106. * If this thread has already been in xxxDestroyThreadInfo, then this window
  107. * is probably going to end up with a bogus pti.
  108. */
  109. UserAssert(!(ptiCurrent->TIF_flags & TIF_INCLEANUP));
  110. pdesk = ptiCurrent->rpdesk;
  111. /*
  112. * If a parent window is specified, make sure it's on the same desktop.
  113. */
  114. if (pwndParent != NULL && pwndParent->head.rpdesk != pdesk) {
  115. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "");
  116. return NULL;
  117. }
  118. /*
  119. * Set a flag indicating whether it is a child window.
  120. */
  121. fChild = ((HIWORD(style) & MaskWF(WFTYPEMASK)) == MaskWF(WFCHILD));
  122. /*
  123. * The WS_EX_LAYOUT_RTL flag is set if,
  124. *
  125. * (1) WS_EX_LAYOUT_RTL set in dwExStyle parameter of the CreateWindow call.
  126. *
  127. * (2) If the window is created from DialogBox class, then it can't inherit
  128. * from its parent and it has to specify WS_EX_LAYOUTRTL explicitly to
  129. * enable mirroring on it.
  130. *
  131. * (3) If the window is an owned window then the window is left to right
  132. * layout and the algorithm terminates. (An owned window is one created
  133. * with an HWND passed in the hWndParent paremeter to CreateWindow(Ex),
  134. * but without the WS_CHILD flag present in it's styles.
  135. *
  136. * (4) If the window is a child window, and it's parent is right to left
  137. * layout, and it's parent does not have the WS_EX_NOINHERIT_LAYOUT flag
  138. * set in it's extended styles, then the window is right to left layout
  139. * and the algorithm terminates.
  140. *
  141. * (5) If the hWndParent parameter to Createwindow(Ex) was NULL, and the
  142. * process calling CreateWindow(Ex) has called
  143. * SetProcessDefaultLayout(LAYOUT_RTL), then the window is right to left
  144. * layout and the algorithm terminates.
  145. *
  146. * (6) In all other cases, the layout is left to right.
  147. */
  148. if (!(dwExStyle & WS_EX_LAYOUTRTL)) {
  149. if (pwndParent != NULL) {
  150. if (fChild && TestWF(pwndParent, WEFLAYOUTRTL) && !TestWF(pwndParent, WEFNOINHERITLAYOUT)) {
  151. dwExStyle |= WS_EX_LAYOUTRTL;
  152. }
  153. } else if (!(!IS_PTR(cczpstrNVClass) && (PTR_TO_ID(cczpstrNVClass) == PTR_TO_ID(DIALOGCLASS)))) {
  154. if ((PpiCurrent()->dwLayout & LAYOUT_RTL)) {
  155. dwExStyle |= WS_EX_LAYOUTRTL;
  156. }
  157. }
  158. }
  159. /*
  160. * Ensure that we can create the window. If there is no desktop
  161. * yet, assume that this will be the root desktop window and allow
  162. * the creation.
  163. */
  164. if (ptiCurrent->hdesk) {
  165. RETURN_IF_ACCESS_DENIED(
  166. ptiCurrent->amdesk, DESKTOP_CREATEWINDOW, NULL);
  167. }
  168. if (fChild) {
  169. /*
  170. * Don't allow child windows without a parent handle.
  171. */
  172. if (pwndParent == NULL) {
  173. RIPERR0(ERROR_TLW_WITH_WSCHILD, RIP_WARNING, "");
  174. return NULL;
  175. }
  176. if (!ValidateParentDepth(NULL, pwndParent)) {
  177. RIPERR0(ERROR_INVALID_PARAMETER,
  178. RIP_WARNING,
  179. "Exceeded nested children limit");
  180. return NULL;
  181. }
  182. }
  183. /*
  184. * Make sure we can get the window class.
  185. */
  186. if (IS_PTR(cczpstrClass)) {
  187. /*
  188. * UserFindAtom protects access of the string.
  189. */
  190. atomT = UserFindAtom(cczpstrClass->Buffer);
  191. } else {
  192. atomT = PTR_TO_ID(cczpstrClass);
  193. }
  194. if (atomT == 0) {
  195. CantFindClassMessageAndFail:
  196. #if DBG
  197. if (IS_PTR(cczpstrNVClass)) {
  198. try {
  199. RIPMSG1(RIP_VERBOSE,
  200. "Couldn't find class string %ws",
  201. cczpstrNVClass->Buffer);
  202. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  203. }
  204. } else {
  205. RIPMSG1(RIP_VERBOSE,
  206. "Couldn't find class atom 0x%x",
  207. cczpstrNVClass);
  208. }
  209. #endif
  210. RIPERR0(ERROR_CANNOT_FIND_WND_CLASS, RIP_VERBOSE, "");
  211. return NULL;
  212. }
  213. /*
  214. * First scan the private classes. If we don't find the class there scan
  215. * the public classes. If we don't find it there, fail.
  216. */
  217. ppcls = GetClassPtr(atomT, ptiCurrent->ppi, hInstance);
  218. if (ppcls == NULL) {
  219. goto CantFindClassMessageAndFail;
  220. }
  221. pcls = *ppcls;
  222. if (NeedsWindowEdge(style, dwExStyle, Is400Compat(dwExpWinVerAndFlags))) {
  223. dwExStyle |= WS_EX_WINDOWEDGE;
  224. } else {
  225. dwExStyle &= ~WS_EX_WINDOWEDGE;
  226. }
  227. /*
  228. * Allocate memory for regular windows.
  229. */
  230. pwnd = HMAllocObject(
  231. ptiCurrent, pdesk, TYPE_WINDOW, sizeof(WND) + pcls->cbwndExtra);
  232. if (pwnd == NULL) {
  233. RIPERR0(ERROR_OUTOFMEMORY,
  234. RIP_WARNING,
  235. "Out of pool in xxxCreateWindowEx");
  236. return NULL;
  237. }
  238. /*
  239. * Stuff in the pq, class pointer, and window style.
  240. */
  241. pwnd->pcls = pcls;
  242. pwnd->style = style & ~WS_VISIBLE;
  243. pwnd->ExStyle = dwExStyle & ~(WS_EX_LAYERED | WS_EX_COMPOSITED);
  244. pwnd->cbwndExtra = pcls->cbwndExtra;
  245. /*
  246. * Increment the window reference count in the class structure.
  247. * Because xxxFreeWindow() decrements the count, incrementing has
  248. * to be done now. In the case of error, xxxFreeWindow() will decrement it.
  249. */
  250. if (!ReferenceClass(pcls, pwnd)) {
  251. HMFreeObject(pwnd);
  252. goto CantFindClassMessageAndFail;
  253. }
  254. /*
  255. * Set the window active App context to be activated whenever we call
  256. * the user WndProc.
  257. */
  258. pwnd->pActCtx = pActCtx;
  259. /*
  260. * Button control doesn't need input context. Other windows
  261. * will associate with the default input context.
  262. * N.b. this comparison needs to be performed on the NV class
  263. * name.
  264. */
  265. if (pcls->atomNVClassName == gpsi->atomSysClass[ICLS_BUTTON]) {
  266. pwnd->hImc = NULL_HIMC;
  267. } else {
  268. pwnd->hImc = (HIMC)PtoH(ptiCurrent->spDefaultImc);
  269. }
  270. /*
  271. * Update the window count. Doing this now will ensure that if
  272. * the creation fails, xxxFreeWindow will keep the window count
  273. * correct.
  274. */
  275. ptiCurrent->cWindows++;
  276. /*
  277. * Get the class from the window because ReferenceClass may have
  278. * cloned the class.
  279. */
  280. pcls = pwnd->pcls;
  281. /*
  282. * This is a replacement for the &lpCreateParams stuff that used to
  283. * pass a pointer directly to the parameters on the stack. This
  284. * step must be done AFTER referencing the class because we
  285. * may use the ANSI class name.
  286. */
  287. RtlZeroMemory(&csex, sizeof(csex));
  288. csex.cs.dwExStyle = dwExStyle;
  289. csex.cs.hInstance = hInstance;
  290. if (!IS_PTR(cczpstrNVClass)) {
  291. csex.cs.lpszClass = (LPWSTR)cczpstrNVClass;
  292. } else {
  293. if (wWFAnsiCreator) {
  294. csex.cs.lpszClass = (LPWSTR)pcls->lpszAnsiClassName;
  295. if (IS_PTR(csex.cs.lpszClass)) {
  296. RtlInitLargeAnsiString(
  297. (PLARGE_ANSI_STRING)&csex.strClass,
  298. (LPSTR)csex.cs.lpszClass,
  299. (UINT)-1);
  300. }
  301. } else {
  302. csex.cs.lpszClass = cczpstrNVClass->Buffer;
  303. csex.strClass = *cczpstrNVClass;
  304. }
  305. }
  306. if (cczpstrName != NULL) {
  307. csex.cs.lpszName = cczpstrName->Buffer;
  308. csex.strName = *cczpstrName;
  309. }
  310. csex.cs.style = style;
  311. csex.cs.x = x;
  312. csex.cs.y = y;
  313. csex.cs.cx = cx;
  314. csex.cs.cy = cy;
  315. csex.cs.hwndParent = HW(pwndParent);
  316. /*
  317. * If pMenu is non-NULL and the window is not a child, pMenu must
  318. * be a menu.
  319. * Child windows get their UIState bits from their parent. Top level ones
  320. * remain with the default cleared bits.
  321. *
  322. * The below test is equivalent to TestwndChild().
  323. */
  324. if (fChild) {
  325. csex.cs.hMenu = (HMENU)pMenu;
  326. pwnd->ExStyle |= pwndParent->ExStyle & WS_EXP_UIVALID;
  327. #if WS_EXP_UIACCELHIDDEN != 0x40000000
  328. #error Fix UISTATE bits copying if you moved the UISTATE bits from ExStyle
  329. #endif
  330. } else {
  331. csex.cs.hMenu = PtoH(pMenu);
  332. }
  333. csex.cs.lpCreateParams = lpCreateParams;
  334. /*
  335. * ThreadLock: we are going to be doing multiple callbacks here.
  336. */
  337. ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
  338. /*
  339. * set the parent to be the desktop window (if exists)
  340. * before any callback. This way we'll always have a
  341. * pointer on spwndParent
  342. */
  343. if (pwnd->head.rpdesk) {
  344. Lock(&(pwnd->spwndParent), PWNDMESSAGE(pwnd));
  345. }
  346. /*
  347. * Create the class small icon if there isn't one since we are in context
  348. * and we are creating a window from this class...
  349. */
  350. if (pcls->spicn && !pcls->spicnSm) {
  351. xxxCreateClassSmIcon(pcls);
  352. }
  353. /*
  354. * Store the instance handle and window proc address. We do this earlier
  355. * than Windows because they have a bug were a message can be sent
  356. * but lpfnWndProc is not set (3986 CBT WM_CREATE not allowed.)
  357. */
  358. pwnd->hModule = hInstance;
  359. /*
  360. * Get rid of EditWndProc plain.
  361. */
  362. pwnd->lpfnWndProc = (WNDPROC_PWND)MapClientNeuterToClientPfn(pcls, 0, wWFAnsiCreator);
  363. /*
  364. * If this window class has a server-side window procedure, mark
  365. * it as such. If the app subclasses it later with an app-side proc
  366. * then this mark will be removed.
  367. */
  368. if (pcls->CSF_flags & CSF_SERVERSIDEPROC) {
  369. SetWF(pwnd, WFSERVERSIDEPROC);
  370. UserAssert(!(pcls->CSF_flags & CSF_ANSIPROC));
  371. }
  372. /*
  373. * If this window was created with an ANSI CreateWindow*() call, mark
  374. * it as such so edit controls will be created correctly. (A combobox
  375. * will be able to pass the WFANSICREATOR bit on to its edit control)
  376. */
  377. SetWF(pwnd, wWFAnsiCreator);
  378. /*
  379. * If this window belongs to an ANSI class or it is a WFANSICREATOR
  380. * control, then mark it as an ANSI window
  381. */
  382. if ((pcls->CSF_flags & CSF_ANSIPROC) ||
  383. (wWFAnsiCreator &&
  384. ((atomT == gpsi->atomSysClass[ICLS_BUTTON]) ||
  385. (atomT == gpsi->atomSysClass[ICLS_COMBOBOX]) ||
  386. (atomT == gpsi->atomSysClass[ICLS_COMBOLISTBOX]) ||
  387. (atomT == gpsi->atomSysClass[ICLS_DIALOG]) ||
  388. (atomT == gpsi->atomSysClass[ICLS_EDIT]) ||
  389. (atomT == gpsi->atomSysClass[ICLS_LISTBOX]) ||
  390. (atomT == gpsi->atomSysClass[ICLS_MDICLIENT]) ||
  391. (atomT == gpsi->atomSysClass[ICLS_IME]) ||
  392. (atomT == gpsi->atomSysClass[ICLS_STATIC])))) {
  393. SetWF(pwnd, WFANSIPROC);
  394. }
  395. /*
  396. * If a 3.1-compatible application is creating the window, set this
  397. * bit to enable various backward-compatibility hacks.
  398. *
  399. * If it's not 3.1 compatible, see if we need to turn on the PixieHack
  400. * (see wmupdate.c for more info on this)
  401. */
  402. dw = GetAppCompatFlags(ptiCurrent);
  403. if (dw & GACF_RANDOM3XUI) {
  404. SetWF(pwnd, WFOLDUI);
  405. dwExStyle &= 0x0000003f;
  406. csex.cs.dwExStyle &= 0x0000003f;
  407. }
  408. pwnd->hMod16 = ((ptiCurrent->TIF_flags & TIF_16BIT) && !TestWF(pwnd, WFSERVERSIDEPROC))? xxxClientWOWGetProcModule(pwnd->lpfnWndProc):0;
  409. if (Is310Compat(dwExpWinVerAndFlags)) {
  410. SetWF(pwnd, WFWIN31COMPAT);
  411. if (Is400Compat(dwExpWinVerAndFlags)) {
  412. SetWF(pwnd, WFWIN40COMPAT);
  413. if (Is500Compat(dwExpWinVerAndFlags)) {
  414. SetWF(pwnd, WFWIN50COMPAT);
  415. }
  416. }
  417. } else if (dw & GACF_ALWAYSSENDNCPAINT) {
  418. SetWF(pwnd, WFALWAYSSENDNCPAINT);
  419. }
  420. /*
  421. * If we've got a registered DefWindowProc handler, make sure it's DLL
  422. * is loaded for this process.
  423. */
  424. if (IsInsideUserApiHook()) {
  425. xxxLoadUserApiHook();
  426. }
  427. /*
  428. * Inform the CBT hook that a window is being created. Pass it the
  429. * CreateParams and the window handle that the new one will be inserted
  430. * after. The CBT hook handler returns TRUE to prevent the window
  431. * from being created. It can also modify the CREATESTRUCT info, which
  432. * will affect the size, parent, and position of the window.
  433. * Defaultly position non-child windows at the top of their list.
  434. */
  435. if (IsHooked(ptiCurrent, WHF_CBT)) {
  436. CBT_CREATEWND cbt;
  437. /*
  438. * Use the extended createstruct so the hook thunk can
  439. * handle the strings correctly.
  440. */
  441. cbt.lpcs = (LPCREATESTRUCT)&csex;
  442. cbt.hwndInsertAfter = HWND_TOP;
  443. if ((BOOL)xxxCallHook(HCBT_CREATEWND, (WPARAM)HWq(pwnd),
  444. (LPARAM)&cbt, WH_CBT)) {
  445. goto MemError;
  446. } else {
  447. /*
  448. * The CreateHook may have modified some parameters so write them
  449. * out (in Windows 3.1 we used to write directly to the variables
  450. * on the stack).
  451. */
  452. x = csex.cs.x;
  453. y = csex.cs.y;
  454. cx = csex.cs.cx;
  455. cy = csex.cs.cy;
  456. pwndZOrder = PWInsertAfter(cbt.hwndInsertAfter);
  457. }
  458. } else {
  459. pwndZOrder = (PWND)HWND_TOP;
  460. }
  461. if (!(fTiled = TestwndTiled(pwnd))) {
  462. /*
  463. * CW_USEDEFAULT is only valid for tiled and overlapped windows.
  464. * Don't let it be used.
  465. */
  466. if (x == CW_USEDEFAULT || x == CW2_USEDEFAULT) {
  467. x = 0;
  468. y = 0;
  469. }
  470. if (cx == CW_USEDEFAULT || cx == CW2_USEDEFAULT) {
  471. cx = 0;
  472. cy = 0;
  473. }
  474. }
  475. /*
  476. * Make local copies of these parameters.
  477. */
  478. src.x = x;
  479. src.y = y;
  480. src.cx = cx;
  481. src.cy = cy;
  482. /*
  483. * Position Child Windows
  484. */
  485. if (fChild = (BOOL)TestwndChild(pwnd)) {
  486. /*
  487. * Child windows are offset from the parent's origin.
  488. */
  489. UserAssert(pwndParent);
  490. if (pwndParent != PWNDDESKTOP(pwnd)) {
  491. src.x += pwndParent->rcClient.left;
  492. src.y += pwndParent->rcClient.top;
  493. }
  494. /*
  495. * Defaultly position child windows at bottom of their list.
  496. */
  497. pwndZOrder = PWND_BOTTOM;
  498. }
  499. /*
  500. * Position Tiled Windows
  501. */
  502. /*
  503. * Is this a Tiled/Overlapping window?
  504. */
  505. if (fTiled) {
  506. /*
  507. * Force the WS_CLIPSIBLINGS window style and add a caption and
  508. * a border.
  509. */
  510. SetWF(pwnd, WFCLIPSIBLINGS);
  511. mask = MaskWF(WFCAPTION) | MaskWF(WFBORDER);
  512. //
  513. // We add on a raised edge since IF the person had passed in WS_CAPTION,
  514. // and didn't specify any 3D borders, we would've added it on to the
  515. // style bits above.
  516. //
  517. if (TestWF(pwnd, WFWIN40COMPAT)) {
  518. SetWF(pwnd, WEFWINDOWEDGE);
  519. }
  520. /*
  521. * Set bit that will force size message to be sent at SHOW time.
  522. */
  523. SetWF(pwnd, WFSENDSIZEMOVE);
  524. /*
  525. * Here is how the "tiled" window initial positioning works...
  526. * If the app is a 1.0x app, then we use our standard "stair step"
  527. * default positioning scheme. Otherwise, we check the x & cx
  528. * parameters. If either of these == CW_USEDEFAULT then use the
  529. * default position/size, otherwise use the position/size they
  530. * specified. If not using default position, use SW_SHOW for the
  531. * xxxShowWindow() parameter, otherwise use the y parameter given.
  532. *
  533. * In 32-bit world, CW_USEDEFAULT is 0x80000000, but apps still
  534. * store word-oriented values either in dialog templates or
  535. * in their own structures. So CreateWindow still recognizes the
  536. * 16 bit equivalent, which is 0x8000, CW2_USEDEFAULT. The original
  537. * is changed because parameters to CreateWindow() are 32 bit
  538. * values, which can cause sign extention, or weird results if
  539. * 16 bit math assumptions are being made, etc.
  540. */
  541. /*
  542. * Default to passing the y parameter to xxxShowWindow().
  543. */
  544. if (x == CW_USEDEFAULT || x == CW2_USEDEFAULT) {
  545. /*
  546. * If the y value is not CW_USEDEFAULT, use it as a SW_* command.
  547. */
  548. if (src.y != CW_USEDEFAULT && src.y != CW2_USEDEFAULT) {
  549. sw = src.y;
  550. }
  551. }
  552. /*
  553. * Allow the shell to tell us what monitor to run this app on
  554. */
  555. pMonitor = NULL;
  556. if ( x == CW_USEDEFAULT ||
  557. x == CW2_USEDEFAULT ||
  558. cx == CW_USEDEFAULT ||
  559. cx == CW2_USEDEFAULT) {
  560. if (ptiCurrent->ppi->hMonitor) {
  561. pMonitor = ValidateHmonitor(ptiCurrent->ppi->hMonitor);
  562. } else if (pwndParent) {
  563. pMonitor = _MonitorFromWindow(pwndParent, MONITOR_DEFAULTTONEAREST);
  564. }
  565. }
  566. if (!pMonitor) {
  567. pMonitor = GetPrimaryMonitor();
  568. }
  569. SetTiledRect(pwnd, &rc, pMonitor);
  570. /*
  571. * Did the app ask for default positioning?
  572. */
  573. if (x == CW_USEDEFAULT || x == CW2_USEDEFAULT) {
  574. /*
  575. * Use default positioning.
  576. */
  577. if (ptiCurrent->ppi->usi.dwFlags & STARTF_USEPOSITION ) {
  578. fStartup = TRUE;
  579. x = src.x = ptiCurrent->ppi->usi.dwX;
  580. y = src.y = ptiCurrent->ppi->usi.dwY;
  581. } else {
  582. x = src.x = rc.left;
  583. y = src.y = rc.top;
  584. }
  585. fDefPos = TRUE;
  586. } else {
  587. /*
  588. * Use the apps specified positioning. Undo the "stacking"
  589. * effect caused by SetTiledRect().
  590. */
  591. if (pMonitor->cWndStack) {
  592. pMonitor->cWndStack--;
  593. }
  594. }
  595. /*
  596. * Did the app ask for default sizing?
  597. */
  598. if (src.cx == CW_USEDEFAULT || src.cx == CW2_USEDEFAULT) {
  599. /*
  600. * Use default sizing.
  601. */
  602. if (ptiCurrent->ppi->usi.dwFlags & STARTF_USESIZE) {
  603. fStartup = TRUE;
  604. src.cx = ptiCurrent->ppi->usi.dwXSize;
  605. src.cy = ptiCurrent->ppi->usi.dwYSize;
  606. } else {
  607. src.cx = rc.right - x;
  608. src.cy = rc.bottom - y;
  609. }
  610. fDefPos = TRUE;
  611. } else if (fDefPos) {
  612. /*
  613. * The app wants default positioning but not default sizing.
  614. * Make sure that it's still entirely visible by moving the
  615. * window.
  616. */
  617. dx = (src.x + src.cx) - pMonitor->rcMonitor.right;
  618. dy = (src.y + src.cy) - pMonitor->rcMonitor.bottom;
  619. if (dx > 0) {
  620. x -= dx;
  621. src.x = x;
  622. if (src.x < pMonitor->rcMonitor.left) {
  623. src.x = x = pMonitor->rcMonitor.left;
  624. }
  625. }
  626. if (dy > 0) {
  627. y -= dy;
  628. src.y = y;
  629. if (src.y < pMonitor->rcMonitor.top) {
  630. src.y = y = pMonitor->rcMonitor.top;
  631. }
  632. }
  633. }
  634. }
  635. /*
  636. * If we have used any startup postitions, turn off the startup
  637. * info so we don't use it again.
  638. */
  639. if (fStartup) {
  640. ptiCurrent->ppi->usi.dwFlags &=
  641. ~(STARTF_USESIZE | STARTF_USEPOSITION);
  642. }
  643. if (TestwndPopup(pwnd)) {
  644. /*
  645. * Force the clipsiblings/overlap style.
  646. */
  647. SetWF(pwnd, WFCLIPSIBLINGS);
  648. }
  649. /*
  650. * Shove in those default style bits.
  651. */
  652. *(((WORD *)&pwnd->style) + 1) |= mask;
  653. /*
  654. * Menu/SysMenu Stuff
  655. */
  656. /*
  657. * If there is no menu handle given and it's not a child window but
  658. * there is a class menu, use the class menu.
  659. */
  660. if (pMenu == NULL && !fChild && (pcls->lpszMenuName != NULL)) {
  661. UNICODE_STRING strMenuName;
  662. RtlInitUnicodeStringOrId(&strMenuName, pcls->lpszMenuName);
  663. pMenu = xxxClientLoadMenu(pcls->hModule, &strMenuName);
  664. csex.cs.hMenu = PtoH(pMenu);
  665. /*
  666. * This load fails if the caller does not have DESKTOP_CREATEMENU
  667. * permission but that's ok they will just get a window without a menu
  668. */
  669. }
  670. /*
  671. * Store the menu handle.
  672. */
  673. if (TestwndChild(pwnd)) {
  674. /*
  675. * It's an id in this case.
  676. */
  677. pwnd->spmenu = pMenu;
  678. } else {
  679. /*
  680. * It's a real handle in this case.
  681. */
  682. LockWndMenu(pwnd, &pwnd->spmenu, pMenu);
  683. }
  684. /*
  685. * Parent/Owner Stuff
  686. */
  687. /*
  688. * If this isn't a child window, reset the Owner/Parent info.
  689. */
  690. if (!fChild) {
  691. Lock(&(pwnd->spwndLastActive), pwnd);
  692. if ((pwndParent != NULL) &&
  693. (pwndParent != pwndParent->head.rpdesk->spwndMessage) &&
  694. (pwndParent != pwndParent->head.rpdesk->pDeskInfo->spwnd)) {
  695. PWND pwndOwner = GetTopLevelWindow(pwndParent);
  696. if (!ValidateOwnerDepth(pwnd, pwndOwner)) {
  697. RIPERR1(ERROR_INVALID_PARAMETER,
  698. RIP_WARNING,
  699. "Exceeded nested owner limit for pwnd %#p",
  700. pwnd);
  701. goto MemError;
  702. }
  703. #if DBG
  704. if (pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) {
  705. UserAssert(!TestCF(pwndOwner, CFIME));
  706. }
  707. #endif
  708. Lock(&(pwnd->spwndOwner), pwndOwner);
  709. if (pwnd->spwndOwner && TestWF(pwnd->spwndOwner, WEFTOPMOST)) {
  710. /*
  711. * If this window's owner is a topmost window, then it has to
  712. * be one also since a window must be above its owner.
  713. */
  714. SetWF(pwnd, WEFTOPMOST);
  715. }
  716. /*
  717. * If this is a owner window on another thread, share input
  718. * state so this window gets z-ordered correctly.
  719. */
  720. if (atomT != gpsi->atomSysClass[ICLS_IME] &&
  721. pwnd->spwndOwner != NULL &&
  722. GETPTI(pwnd->spwndOwner) != ptiCurrent) {
  723. /*
  724. * No need to DeferWinEventNotify() here: pwnd and pwndParent
  725. * are locked and because we called ReferenceClass(pcls, pwnd),
  726. * pcls is safe until xxxFreeWindow(pwnd). (IanJa)
  727. */
  728. zzzAttachThreadInput(ptiCurrent, GETPTI(pwnd->spwndOwner), TRUE);
  729. }
  730. } else {
  731. pwnd->spwndOwner = NULL;
  732. }
  733. #if DBG
  734. if (ptiCurrent->rpdesk != NULL) {
  735. UserAssert(!(ptiCurrent->rpdesk->dwDTFlags & (DF_DESTROYED | DF_DESKWNDDESTROYED | DF_DYING)));
  736. }
  737. #endif
  738. if ((pwndParent == NULL) ||
  739. (pwndParent != pwndParent->head.rpdesk->spwndMessage)) {
  740. pwndParent = _GetDesktopWindow();
  741. ThreadLockWithPti(ptiCurrent, pwndParent, &tlpwndParent);
  742. fLockParent = TRUE;
  743. }
  744. }
  745. /*
  746. * Store backpointer to parent.
  747. */
  748. if ((pwnd->spwndNext != NULL) || (pwnd->spwndPrev != NULL)) {
  749. RIPMSG1(RIP_WARNING, "Window %#p linked in too early (in a hook callback)", pwnd);
  750. UnlinkWindow(pwnd, pwnd->spwndParent);
  751. }
  752. Lock(&(pwnd->spwndParent), pwndParent);
  753. /*
  754. * Final Window Positioning
  755. */
  756. if (!TestWF(pwnd, WFWIN31COMPAT)) {
  757. /*
  758. * BACKWARD COMPATIBILITY HACK
  759. *
  760. * In 3.0, CS_PARENTDC overrides WS_CLIPCHILDREN and WS_CLIPSIBLINGS,
  761. * but only if the parent is not WS_CLIPCHILDREN.
  762. * This behavior is required by PowerPoint and Charisma, among others.
  763. */
  764. if ((pcls->style & CS_PARENTDC) &&
  765. !TestWF(pwndParent, WFCLIPCHILDREN)) {
  766. #if DBG
  767. if (TestWF(pwnd, WFCLIPCHILDREN))
  768. RIPMSG0(RIP_WARNING, "WS_CLIPCHILDREN overridden by CS_PARENTDC");
  769. if (TestWF(pwnd, WFCLIPSIBLINGS))
  770. RIPMSG0(RIP_WARNING, "WS_CLIPSIBLINGS overridden by CS_PARENTDC");
  771. #endif
  772. ClrWF(pwnd, (WFCLIPCHILDREN | WFCLIPSIBLINGS));
  773. }
  774. }
  775. /*
  776. * If this is a child window being created in a parent window
  777. * of a different thread, but not on the desktop, attach their
  778. * input streams together. [windows with WS_CHILD can be created
  779. * on the desktop, that's why we check both the style bits
  780. * and the parent window.]
  781. */
  782. if (TestwndChild(pwnd) && (pwndParent != PWNDDESKTOP(pwnd)) &&
  783. (ptiCurrent != GETPTI(pwndParent))) {
  784. /*
  785. * No need to DeferWinEventNotify() - there is an xxx call just below
  786. */
  787. zzzAttachThreadInput(ptiCurrent, GETPTI(pwndParent), TRUE);
  788. }
  789. /*
  790. * Make sure the window is between the minimum and maximum sizes.
  791. */
  792. /*
  793. * HACK ALERT!
  794. * This sends WM_GETMINMAXINFO to a (tiled or sizable) window before
  795. * it has been created (before it is sent WM_NCCREATE).
  796. * Maybe some app expects this, so we mustn't reorder the messages.
  797. */
  798. xxxAdjustSize(pwnd, &src.cx, &src.cy);
  799. /*
  800. * Check for a window being created full screen.
  801. *
  802. * Note the check for a non-NULL pdeskParent -- this is important for CreateWindowStation
  803. */
  804. if (pwnd->head.rpdesk != NULL &&
  805. !TestWF(pwnd, WFCHILD) &&
  806. !TestWF(pwnd, WEFTOOLWINDOW)) {
  807. xxxCheckFullScreen(pwnd, &src);
  808. }
  809. if (src.cx < 0) {
  810. RIPMSG1(RIP_WARNING, "xxxCreateWindowEx: adjusted cx in pwnd %#p", pwnd);
  811. src.cx = 0;
  812. }
  813. if (src.cy < 0) {
  814. RIPMSG1(RIP_WARNING, "xxxCreateWindowEx: adjusted cy in pwnd %#p", pwnd);
  815. src.cy = 0;
  816. }
  817. /*
  818. * Calculate final window dimensions...
  819. */
  820. RECTFromSIZERECT(&pwnd->rcWindow, &src);
  821. if (TestCF2(pcls, CFOWNDC) || (TestCF2(pcls, CFCLASSDC) && pcls->pdce == NULL)) {
  822. if (NULL == CreateCacheDC(pwnd, DCX_OWNDC, NULL)) {
  823. RIPMSG1(RIP_WARNING, "xxxCreateWindowEx: pwnd %#p failed to create cached DC",
  824. pwnd);
  825. goto MemError;
  826. }
  827. }
  828. /*
  829. * Setup Layered and Composited windows.
  830. *
  831. * NOTE: This MUST be done AFTER CreateCacheDC() has built any DC's used for
  832. * OWNDC windows, since the redirection functions need to convert these DC's
  833. * to use redirection. In Windows 2000, this was done before calling
  834. * CreateCacheDC(), and would Assert inside ResetOrg() when because a new
  835. * DC was built that was not setup for redirection.
  836. */
  837. if (dwExStyle & WS_EX_LAYERED) {
  838. if (!xxxSetLayeredWindow(pwnd, FALSE)) {
  839. RIPMSG1(RIP_WARNING, "xxxCreateWindowEx: pwnd %#p failed to setup layered window", pwnd);
  840. goto MemError;
  841. }
  842. }
  843. if (dwExStyle & WS_EX_COMPOSITED) {
  844. /*
  845. * We only want to turn WS_EX_COMPOSITED on if the parent-chain doesn't
  846. * already have WS_EX_COMPOSITED turned on.
  847. */
  848. if (GetStyleWindow(pwnd->spwndParent, WEFCOMPOSITED) == NULL) {
  849. if (!SetRedirectedWindow(pwnd, REDIRECT_COMPOSITED)) {
  850. RIPMSG1(RIP_WARNING, "xxxCreateWindowEx: pwnd %#p failed to setup composited window", pwnd);
  851. goto MemError;
  852. }
  853. SetWF(pwnd, WEFCOMPOSITED);
  854. }
  855. }
  856. /*
  857. * Update the create struct now that we've modified some passed in
  858. * parameters.
  859. */
  860. csex.cs.x = x;
  861. csex.cs.y = y;
  862. csex.cs.cx = cx;
  863. csex.cs.cy = cy;
  864. /*
  865. * Send a NCCREATE message to the window.
  866. */
  867. if (!xxxSendMessage(pwnd, WM_NCCREATE, 0L, (LPARAM)&csex)) {
  868. MemError:
  869. #if DBG
  870. if (!IS_PTR(cczpstrNVClass)) {
  871. RIPMSG2(RIP_WARNING,
  872. (pwndParent) ?
  873. "xxxCreateWindowEx failed, Class=%#.4x, ID=%d" :
  874. "xxxCreateWindowEx failed, Class=%#.4x",
  875. PTR_TO_ID(cczpstrNVClass),
  876. (LONG_PTR) pMenu);
  877. } else {
  878. RIPMSG2(RIP_WARNING,
  879. (pwndParent) ?
  880. "xxxCreateWindowEx failed, Class=\"%s\", ID=%d" :
  881. "xxxCreateWindowEx failed, Class=\"%s\"",
  882. pcls->lpszAnsiClassName,
  883. (LONG_PTR) pMenu);
  884. }
  885. #endif
  886. if (fLockParent)
  887. ThreadUnlock(&tlpwndParent);
  888. /*
  889. * Set the state as destroyed so any z-ordering events will be ignored.
  890. * We cannot NULL out the owner field until WM_NCDESTROY is sent or
  891. * apps like Rumba fault (they call GetParent after every message).
  892. */
  893. SetWF(pwnd, WFDESTROYED);
  894. /*
  895. * Unset the visible flag so we don't think in xxxDestroyWindow that
  896. * this window is visible.
  897. */
  898. if (TestWF(pwnd, WFVISIBLE)) {
  899. SetVisible(pwnd, SV_UNSET);
  900. }
  901. /*
  902. * FreeWindow performs a ThreadUnlock.
  903. */
  904. xxxFreeWindow(pwnd, &tlpwnd);
  905. return NULL;
  906. }
  907. /*
  908. * We need to set the lame button flag before doing the CFNOCLOSE stuff
  909. * below or the app won't get the lame button menu item in its sysmenu.
  910. */
  911. #ifdef LAME_BUTTON
  912. if (NeedsLameButton(pwnd, pwndParent)) {
  913. SetWF(pwnd, WEFLAMEBUTTON);
  914. }
  915. #endif // LAME_BUTTON
  916. /*
  917. * Delete the Close menu item if directed.
  918. */
  919. if (TestCF(pwnd, CFNOCLOSE)) {
  920. /*
  921. * Do this by position since the separator does not have an ID.
  922. */
  923. pMenu = xxxGetSystemMenu(pwnd, FALSE);
  924. if (pMenu != NULL) {
  925. TL tlpMenu;
  926. ThreadLock(pMenu, &tlpMenu);
  927. xxxDeleteMenu(pMenu, 5
  928. #ifdef LAME_BUTTON
  929. + !!TestWF(pwnd, WEFLAMEBUTTON)
  930. #endif // LAME_BUTTON
  931. , MF_BYPOSITION);
  932. xxxDeleteMenu(pMenu, 5
  933. #ifdef LAME_BUTTON
  934. + !!TestWF(pwnd, WEFLAMEBUTTON)
  935. #endif // LAME_BUTTON
  936. , MF_BYPOSITION);
  937. ThreadUnlock(&tlpMenu);
  938. }
  939. }
  940. /*
  941. * WM_NCCREATE processing may have changed the window text. Change
  942. * the CREATESTRUCT to point to the real window text.
  943. *
  944. * MSMoney needs this because it clears the window and we need to
  945. * reflect the new name back into the cs structure.
  946. * A better thing to do would be to have a pointer to the CREATESTRUCT
  947. * within the window itself so that DefWindowProc can change the
  948. * the window name in the CREATESTRUCT to point to the real name and
  949. * this funky check is no longer needed.
  950. *
  951. * DefSetText converts a pointer to NULL to a NULL title so
  952. * we don't want to over-write cs.lpszName if it was a pointer to
  953. * a NULL string and pName is NULL. Approach Database for Windows creates
  954. * windows with a pointer to NULL and then accesses the pointer later
  955. * during WM_CREATE
  956. */
  957. if (TestWF(pwnd, WFTITLESET))
  958. if (!(csex.strName.Buffer != NULL && csex.strName.Length == 0 &&
  959. pwnd->strName.Buffer == NULL)) {
  960. csex.cs.lpszName = pwnd->strName.Buffer;
  961. RtlCopyMemory(&csex.strName, &pwnd->strName, sizeof(LARGE_STRING));
  962. }
  963. /*
  964. * The Window is now officially "created." Change the relevant global
  965. * stuff.
  966. */
  967. /*
  968. * Create per thread default IME window.
  969. */
  970. if (IS_IME_ENABLED() && ptiCurrent->spwndDefaultIme == NULL) {
  971. /*
  972. * Avoid creating the default IME window to any of message only windows
  973. * or windows on no I/O desktop.
  974. */
  975. if (WantImeWindow(pwndParent, pwnd)) {
  976. BOOL bReinit;
  977. //
  978. // Make sure we are not creating a window for Ole,
  979. // for it does not pump messages even though
  980. // they creates a window.
  981. //
  982. UserAssert(gaOleMainThreadWndClass != atomT);
  983. Lock(&(ptiCurrent->spwndDefaultIme),
  984. xxxCreateDefaultImeWindow(pwnd, atomT, hInstance));
  985. /*
  986. * If keybaord layout is switched but Imm activation was skipped
  987. * while spwndDefaultIme was gone, do the activation now.
  988. */
  989. #if _DBG
  990. if (ptiCurrent->spDefaultImc == NULL) {
  991. RIPMSG1(RIP_WARNING, "xxxCreateWindowEx: ptiCurrent(%08p)->spDefaultImc is NULL.", ptiCurrent);
  992. }
  993. ASSERT(ptiCurrent->pClientInfo);
  994. #endif
  995. #ifdef CUAS_ENABLE
  996. /*
  997. * Load IME and Activate TIM for CUAS.
  998. * We can do this after ptiCurrent->spwndDefaultIME is valid.
  999. */
  1000. if (ptiCurrent->spwndDefaultIme) {
  1001. TL tlpwndIme;
  1002. ThreadLockAlways(ptiCurrent->spwndDefaultIme, &tlpwndIme);
  1003. xxxSendMessage(ptiCurrent->spwndDefaultIme, WM_IME_SYSTEM, (WPARAM)IMS_LOADTHREADLAYOUT, (LPARAM)0L);
  1004. ThreadUnlock(&tlpwndIme);
  1005. }
  1006. #endif
  1007. try {
  1008. bReinit = ((ptiCurrent->pClientInfo->CI_flags & CI_INPUTCONTEXT_REINIT) != 0);
  1009. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  1010. goto MemError2;
  1011. }
  1012. if (ptiCurrent->spwndDefaultIme && bReinit) {
  1013. TL tlpwndIme;
  1014. TAGMSG1(DBGTAG_IMM,
  1015. "xxxCreateDefaultImeWindow: ptiCurrent(%08p)->spDefaultImc->fNeedClientImcActivate is set.",
  1016. ptiCurrent);
  1017. /*
  1018. * Make this client side callback to force the input context
  1019. * to be reinitialized appropriately (keyboard layout has
  1020. * changed since this thread was taking a nap without a
  1021. * window but still a GUI thread).
  1022. *
  1023. * Windows NT Bug #294964.
  1024. */
  1025. ThreadLock(ptiCurrent->spwndDefaultIme, &tlpwndIme);
  1026. xxxSendMessage(ptiCurrent->spwndDefaultIme,
  1027. WM_IME_SYSTEM,
  1028. (WPARAM)IMS_ACTIVATETHREADLAYOUT,
  1029. (LPARAM)ptiCurrent->spklActive->hkl);
  1030. // Reset the flag.
  1031. try {
  1032. ptiCurrent->pClientInfo->CI_flags &= ~CI_INPUTCONTEXT_REINIT;
  1033. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  1034. ThreadUnlock(&tlpwndIme);
  1035. goto MemError2;
  1036. }
  1037. ThreadUnlock(&tlpwndIme);
  1038. }
  1039. } else {
  1040. TAGMSG0(DBGTAG_IMM,
  1041. "xxxCreateWindowEx: default IME window not created.");
  1042. }
  1043. }
  1044. /*
  1045. * Update the Parent/Child linked list. Don't (re)link the window if a
  1046. * diffrent parent was set during a callback (e.g., WM_GETMINMAXINFO).
  1047. */
  1048. if (pwndParent != NULL && pwnd->spwndParent == pwndParent) {
  1049. /*
  1050. * Unlink this window first, it might have been linked already by
  1051. * calling SetParent() in any of the messages that we had previously
  1052. * sent (e.g. WM_GETMINMAXINFO).
  1053. */
  1054. UnlinkWindow(pwnd, pwnd->spwndParent);
  1055. if (!fChild && (pwndParent != pwndParent->head.rpdesk->spwndMessage)) {
  1056. /*
  1057. * If this is a top-level window, and it's not part of the
  1058. * topmost pile of windows, then we have to make sure it
  1059. * doesn't go on top of any of the topmost windows.
  1060. *
  1061. * If he's trying to put the window on the top, or trying
  1062. * to insert it after one of the topmost windows, insert
  1063. * it after the last topmost window in the pile.
  1064. */
  1065. if (!TestWF(pwnd, WEFTOPMOST)) {
  1066. if (pwndZOrder == PWND_TOP ||
  1067. (IS_PTR(pwndZOrder) && TestWF(pwndZOrder, WEFTOPMOST))) {
  1068. pwndZOrder = CalcForegroundInsertAfter(pwnd);
  1069. }
  1070. } else {
  1071. pwndHardError = GETTOPMOSTINSERTAFTER(pwnd);
  1072. if (pwndHardError != NULL) {
  1073. pwndZOrder = pwndHardError;
  1074. }
  1075. }
  1076. }
  1077. LinkWindow(pwnd, pwndZOrder, pwndParent);
  1078. }
  1079. #if DBG
  1080. if (pwndParent != NULL) {
  1081. VerifyWindowLink (pwnd, pwnd->spwndParent, TRUE);
  1082. if (pwnd->spwndParent != pwndParent) {
  1083. RIPMSGF1(RIP_WARNING,
  1084. "Window 0x%p re-parented during callback",
  1085. pwnd);
  1086. }
  1087. }
  1088. #endif
  1089. /*
  1090. * Send a NCCALCSIZE message to the window and have it return the official
  1091. * size of its client area.
  1092. */
  1093. if (fChild && TestWF(pwndParent, WEFLAYOUTRTL)) {
  1094. cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
  1095. pwnd->rcWindow.right = pwndParent->rcClient.right - (pwnd->rcWindow.left - pwndParent->rcClient.left);
  1096. pwnd->rcWindow.left = pwnd->rcWindow.right - cx;
  1097. }
  1098. CopyRect(&rc, &pwnd->rcWindow);
  1099. xxxSendMessage(pwnd, WM_NCCALCSIZE, 0L, (LPARAM)&rc);
  1100. pwnd->rcClient = rc;
  1101. /*
  1102. * Send a CREATE message to the window.
  1103. */
  1104. if (xxxSendMessage(pwnd, WM_CREATE, 0L, (LPARAM)&csex) == -1L) {
  1105. #if DBG
  1106. if (!IS_PTR(cczpstrNVClass)) {
  1107. RIPMSG1(RIP_WARNING,
  1108. "CreateWindow() send of WM_CREATE failed, Class = 0x%x",
  1109. PTR_TO_ID(cczpstrNVClass));
  1110. } else {
  1111. RIPMSG1(RIP_WARNING,
  1112. "CreateWindow() send of WM_CREATE failed, Class = \"%s\"",
  1113. pcls->lpszAnsiClassName);
  1114. }
  1115. #endif
  1116. MemError2:
  1117. if (fLockParent) {
  1118. ThreadUnlock(&tlpwndParent);
  1119. }
  1120. if (ThreadUnlock(&tlpwnd)) {
  1121. xxxDestroyWindow(pwnd);
  1122. }
  1123. return NULL;
  1124. }
  1125. /*
  1126. * Flag that the window is created. WoW uses this bit to determine that
  1127. * an fnid of 0 really means 0.
  1128. */
  1129. SetWF(pwnd, WFISINITIALIZED);
  1130. /*
  1131. * Notify anyone who is listening that the window is created. Do this
  1132. * before we size/move/max/min/show it so that event observers can count
  1133. * on getting notifications for those things also.
  1134. *
  1135. * But do this AFTER WM_CREATE is sent. The window and its data will not
  1136. * be fully initialized until then. Since the purpose of an event is to
  1137. * let watchers turn around and do querying, we want their queries to
  1138. * succeed and not fault.
  1139. */
  1140. xxxWindowEvent(EVENT_OBJECT_CREATE, pwnd, OBJID_WINDOW, INDEXID_OBJECT, 0);
  1141. /*
  1142. * If this is a Tiled/Overlapped window, don't send size or move msgs yet.
  1143. */
  1144. if (!TestWF(pwnd, WFSENDSIZEMOVE)) {
  1145. xxxSendSizeMessage(pwnd, SIZENORMAL);
  1146. if (pwndParent != NULL && PWNDDESKTOP(pwnd) != pwndParent) {
  1147. rc.left -= pwndParent->rcClient.left;
  1148. rc.top -= pwndParent->rcClient.top;
  1149. }
  1150. xxxSendMessage(pwnd, WM_MOVE, 0L, MAKELONG(rc.left, rc.top));
  1151. }
  1152. /*
  1153. * Min/Max Stuff
  1154. */
  1155. /*
  1156. * If app specified either min/max style, then we must call our minmax
  1157. * code to get it all set up correctly so that when the show is done,
  1158. * the window is displayed right.
  1159. */
  1160. dwMinMax = MINMAX_KEEPHIDDEN | TEST_PUDF(PUDF_ANIMATE);
  1161. if (TestWF(pwnd, WFMINIMIZED)) {
  1162. SetMinimize(pwnd, SMIN_CLEAR);
  1163. xxxMinMaximize(pwnd, SW_SHOWMINNOACTIVE, dwMinMax);
  1164. } else if (TestWF(pwnd, WFMAXIMIZED)) {
  1165. ClrWF(pwnd, WFMAXIMIZED);
  1166. xxxMinMaximize(pwnd, SW_SHOWMAXIMIZED, dwMinMax);
  1167. }
  1168. /*
  1169. * Send notification if it's a child.
  1170. */
  1171. if (fChild && !TestWF(pwnd, WEFNOPARENTNOTIFY) &&
  1172. (pwnd->spwndParent != NULL)) {
  1173. ThreadLockAlwaysWithPti(ptiCurrent, pwnd->spwndParent, &tlpwndParentT);
  1174. xxxSendMessage(pwnd->spwndParent, WM_PARENTNOTIFY,
  1175. MAKELONG(WM_CREATE, PTR_TO_ID(pwnd->spmenu)), (LPARAM)HWq(pwnd));
  1176. ThreadUnlock(&tlpwndParentT);
  1177. }
  1178. /*
  1179. * Show the Window
  1180. */
  1181. if (style & WS_VISIBLE) {
  1182. xxxShowWindow(pwnd, sw | TEST_PUDF(PUDF_ANIMATE));
  1183. }
  1184. /*
  1185. * Try and set the application's hot key. Use the Win95 logic of
  1186. * looking for the first tiled and/or APPWINDOW to be created by
  1187. * this process.
  1188. */
  1189. if (TestwndTiled(pwnd) || TestWF(pwnd, WEFAPPWINDOW)) {
  1190. if (ptiCurrent->ppi->dwHotkey) {
  1191. /*
  1192. * Ignore hot keys for WowExe the first thread of a wow process.
  1193. */
  1194. if (!(ptiCurrent->TIF_flags & TIF_16BIT) || (ptiCurrent->ppi->cThreads > 1)) {
  1195. #ifdef LATER
  1196. /*
  1197. * Win95 sets the hot key directly, we on the other hand send
  1198. * a WM_SETHOTKEY message to the app. Which is right?
  1199. */
  1200. DWP_SetHotKey(pwnd, ptiCurrent->ppi->dwHotkey);
  1201. #else
  1202. xxxSendMessage(pwnd, WM_SETHOTKEY, ptiCurrent->ppi->dwHotkey, 0);
  1203. #endif
  1204. ptiCurrent->ppi->dwHotkey = 0;
  1205. }
  1206. }
  1207. }
  1208. if (fLockParent)
  1209. ThreadUnlock(&tlpwndParent);
  1210. return ThreadUnlock(&tlpwnd);
  1211. }
  1212. BOOL WantImeWindow(
  1213. PWND pwndParent,
  1214. PWND pwnd)
  1215. {
  1216. PDESKTOP pdesk;
  1217. UserAssert(pwnd);
  1218. if (PtiCurrent()->TIF_flags & TIF_DISABLEIME) {
  1219. return FALSE;
  1220. }
  1221. if (TestWF(pwnd, WFSERVERSIDEPROC)) {
  1222. return FALSE;
  1223. }
  1224. pdesk = pwnd->head.rpdesk;
  1225. if (pdesk == NULL || pdesk->rpwinstaParent == NULL) {
  1226. return FALSE;
  1227. }
  1228. // Check whether pwnd's desktop has I/O.
  1229. if (pdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO) {
  1230. return FALSE;
  1231. }
  1232. // Check if the owner window is message-only window.
  1233. if (pwndParent) {
  1234. PWND pwndT = pwndParent;
  1235. while (pwndT && pdesk == pwndT->head.rpdesk) {
  1236. if (pwndT == pdesk->spwndMessage) {
  1237. return FALSE;
  1238. }
  1239. pwndT = pwndT->spwndParent;
  1240. }
  1241. }
  1242. return TRUE;
  1243. }
  1244. /***************************************************************************\
  1245. * SetTiledRect
  1246. *
  1247. * History:
  1248. * 10-19-90 darrinm Ported from Win 3.0 sources.
  1249. \***************************************************************************/
  1250. VOID SetTiledRect(
  1251. PWND pwnd,
  1252. LPRECT lprc,
  1253. PMONITOR pMonitor)
  1254. {
  1255. POINT pt;
  1256. RECT rcT;
  1257. UserAssert(pMonitor->cWndStack >= 0);
  1258. /*
  1259. * Get available desktop area, minus minimized spacing area.
  1260. */
  1261. GetRealClientRect(PWNDDESKTOP(pwnd), &rcT, GRC_MINWNDS, pMonitor);
  1262. /*
  1263. * Increment the count of stacked windows.
  1264. */
  1265. pMonitor->cWndStack++;
  1266. /*
  1267. * We want the left edge of the new window to align with the
  1268. * right edge of the old window's system menu. And we want the
  1269. * top edge of the new window to align with the bottom edge of the
  1270. * selected caption area (caption height - cyBorder) of the old
  1271. * window.
  1272. */
  1273. #define X_TILED (SYSMET(CXSIZEFRAME) + SYSMET(CXSIZE))
  1274. #define Y_TILED (SYSMET(CYSIZEFRAME) + SYSMET(CYSIZE))
  1275. pt.x = pMonitor->cWndStack * X_TILED;
  1276. pt.y = pMonitor->cWndStack * Y_TILED;
  1277. /*
  1278. * If below upper top left 1/4 of free area, reset.
  1279. */
  1280. if ( (pt.x > ((rcT.right-rcT.left) / 4)) ||
  1281. (pt.y > ((rcT.bottom-rcT.top) / 4)) ) {
  1282. pMonitor->cWndStack = 0;
  1283. pt.x = X_TILED;
  1284. pt.y = Y_TILED;
  1285. }
  1286. #undef X_TILED
  1287. #undef Y_TILED
  1288. /*
  1289. * Get starting position
  1290. */
  1291. pt.x += rcT.left;
  1292. pt.y += rcT.top;
  1293. lprc->left = pt.x;
  1294. lprc->top = pt.y;
  1295. lprc->right = pt.x + MultDiv(rcT.right-rcT.left, 3, 4);
  1296. lprc->bottom = pt.y + MultDiv(rcT.bottom-rcT.top, 3, 4);
  1297. }
  1298. /***************************************************************************\
  1299. * xxxAdjustSize
  1300. *
  1301. * Make sure that *lpcx and *lpcy are within the legal limits.
  1302. *
  1303. * History:
  1304. * 10-19-90 darrinm Ported from Win 3.0 sources.
  1305. \***************************************************************************/
  1306. VOID xxxAdjustSize(
  1307. PWND pwnd,
  1308. LPINT lpcx,
  1309. LPINT lpcy)
  1310. {
  1311. POINT ptmin, ptmax;
  1312. MINMAXINFO mmi;
  1313. CheckLock(pwnd);
  1314. /*
  1315. * If this window is sizeable or if this window is tiled, check size.
  1316. */
  1317. if (TestwndTiled(pwnd) || TestWF(pwnd, WFSIZEBOX)) {
  1318. /*
  1319. * Get size info from pwnd.
  1320. */
  1321. xxxInitSendValidateMinMaxInfo(pwnd, &mmi);
  1322. if (TestWF(pwnd, WFMINIMIZED)) {
  1323. ptmin = mmi.ptReserved;
  1324. ptmax = mmi.ptMaxSize;
  1325. } else {
  1326. ptmin = mmi.ptMinTrackSize;
  1327. ptmax = mmi.ptMaxTrackSize;
  1328. }
  1329. //
  1330. // Make sure we're less than the max, and greater than the min
  1331. //
  1332. *lpcx = max(ptmin.x, min(*lpcx, ptmax.x));
  1333. *lpcy = max(ptmin.y, min(*lpcy, ptmax.y));
  1334. }
  1335. }
  1336. #if DBG
  1337. /***************************************************************************\
  1338. * VerifyWindowLink
  1339. *
  1340. * History:
  1341. * 10/28/96 GerardoB Added
  1342. \***************************************************************************/
  1343. VOID VerifyWindowLink(
  1344. PWND pwnd,
  1345. PWND pwndParent,
  1346. BOOL fLink)
  1347. {
  1348. BOOL fFirstFound = FALSE;
  1349. BOOL fInFound = FALSE;
  1350. PWND pwndNext = pwndParent->spwndChild;
  1351. PWND pwndFirst = pwndNext;
  1352. while (pwndNext != NULL) {
  1353. if (pwndFirst == pwndNext) {
  1354. if (fFirstFound) {
  1355. RIPMSG1(RIP_ERROR, "Loop in %#p spwndNext chain", pwnd);
  1356. return;
  1357. } else {
  1358. fFirstFound = TRUE;
  1359. }
  1360. }
  1361. if (pwndNext == pwnd) fInFound = TRUE;
  1362. pwndNext = pwndNext->spwndNext;
  1363. }
  1364. if (fLink && !fInFound) {
  1365. RIPMSG1(RIP_ERROR, "pwnd 0x%p not found in spwndNext chain", pwnd);
  1366. }
  1367. }
  1368. #endif
  1369. /***************************************************************************\
  1370. * LinkWindow
  1371. *
  1372. * History:
  1373. \***************************************************************************/
  1374. VOID LinkWindow(
  1375. PWND pwnd,
  1376. PWND pwndInsert,
  1377. PWND pwndParent)
  1378. {
  1379. if (pwndParent->spwndChild == pwnd) {
  1380. RIPMSG0(RIP_WARNING, "Attempting to link a window to itself");
  1381. return;
  1382. }
  1383. UserAssert(pwnd != pwndInsert);
  1384. UserAssert((pwnd->spwndParent == NULL) || (pwnd->spwndParent == pwndParent));
  1385. if (pwndInsert == PWND_TOP) {
  1386. /*
  1387. * We are at the top of the list.
  1388. */
  1389. LinkTop:
  1390. #if DBG
  1391. /*
  1392. * If the first child is topmost, so must be pwnd, but only for
  1393. * top-level windows.
  1394. *
  1395. * IME or IME related windows are the exceptions, because ImeSetTopmost
  1396. * and its friends do most of the relinking on its own: When LinkWindow
  1397. * is called, it's possible TOPMOST flags are left in intermediate
  1398. * state. By the time the all window relinking finishes, TOPMOST flags
  1399. * have been taken care of and they are just fine.
  1400. */
  1401. if (pwndParent == PWNDDESKTOP(pwndParent) &&
  1402. pwndParent->spwndChild &&
  1403. FSwpTopmost(pwndParent->spwndChild) &&
  1404. pwndParent != PWNDMESSAGE(pwndParent) &&
  1405. // Check if the target is IME related window
  1406. !TestCF(pwnd, CFIME) && pwnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]) {
  1407. /*
  1408. * There are few cases that cause the z-ordering code to leave the
  1409. * WFTOGGLETOPMOST bit set. One is when SWP_NOOWNERZORDER is used
  1410. * when changing the topmost state of a window; in this case,
  1411. * ZOrderByOwner2 doesn't add ownees to the psmwp list, still
  1412. * SetTopMost sets the bit on all the ownees.
  1413. *
  1414. * Another case is when SetWindowPos gets re-entered on the same
  1415. * window. It's too late to attempt to fix this ancient behavior
  1416. * (2/24/99) so let's turn off the assert for now.
  1417. */
  1418. if (!FSwpTopmost(pwnd)) {
  1419. RIPMSG1(RIP_WARNING, "LinkWindow pwnd:%p is not FSwpTopmost", pwnd);
  1420. }
  1421. }
  1422. #endif // DBG
  1423. if (pwndParent->spwndChild != NULL) {
  1424. Lock(&pwndParent->spwndChild->spwndPrev, pwnd);
  1425. Lock(&pwnd->spwndNext, pwndParent->spwndChild);
  1426. }
  1427. Lock(&(pwndParent->spwndChild), pwnd);
  1428. UserAssert(pwnd->spwndPrev == NULL);
  1429. } else {
  1430. if (pwndInsert == PWND_BOTTOM) {
  1431. /*
  1432. * Find bottom-most window.
  1433. */
  1434. if (((pwndInsert = pwndParent->spwndChild) == NULL) ||
  1435. TestWF(pwndInsert, WFBOTTOMMOST))
  1436. goto LinkTop;
  1437. /*
  1438. * Since we know (ahem) that there's only one bottommost window,
  1439. * we can't possibly insert after it. Either we're inserting
  1440. * the bottomost window, in which case it's not in the linked
  1441. * list currently, or we're inserting some other window.
  1442. */
  1443. while (pwndInsert->spwndNext != NULL) {
  1444. if (TestWF(pwndInsert->spwndNext, WFBOTTOMMOST)) {
  1445. #if DBG
  1446. UserAssert(pwnd != pwndInsert->spwndNext);
  1447. if (TestWF(pwnd, WFBOTTOMMOST))
  1448. UserAssert(FALSE);
  1449. #endif
  1450. break;
  1451. }
  1452. pwndInsert = pwndInsert->spwndNext;
  1453. }
  1454. }
  1455. UserAssert(pwnd != pwndInsert);
  1456. UserAssert(pwnd != pwndInsert->spwndNext);
  1457. UserAssert(!TestWF(pwndInsert, WFDESTROYED));
  1458. UserAssert(TestWF(pwnd, WFCHILD) || !TestWF(pwnd, WEFTOPMOST) || TestWF(pwndInsert, WEFTOPMOST) || TestWF(pwnd, WFTOGGLETOPMOST) || (pwndParent != PWNDDESKTOP(pwndInsert)));
  1459. UserAssert(pwnd->spwndParent == pwndInsert->spwndParent);
  1460. if (pwndInsert->spwndNext != NULL) {
  1461. Lock(&pwndInsert->spwndNext->spwndPrev, pwnd);
  1462. Lock(&pwnd->spwndNext, pwndInsert->spwndNext);
  1463. }
  1464. Lock(&pwnd->spwndPrev, pwndInsert);
  1465. Lock(&pwndInsert->spwndNext, pwnd);
  1466. }
  1467. if (TestWF(pwnd, WEFLAYERED))
  1468. TrackLayeredZorder(pwnd);
  1469. #if DBG
  1470. VerifyWindowLink (pwnd, pwndParent, TRUE);
  1471. #endif
  1472. }
  1473. /***************************************************************************\
  1474. * xxxDestroyWindow (API)
  1475. *
  1476. * Destroy the specified window. The window passed in is not thread locked.
  1477. *
  1478. * History:
  1479. * 10-20-90 darrinm Ported from Win 3.0 sources.
  1480. * 02-07-91 DavidPe Added Win 3.1 WH_CBT support.
  1481. * 02-11-91 JimA Added access checks.
  1482. \***************************************************************************/
  1483. BOOL xxxDestroyWindow(
  1484. PWND pwnd)
  1485. {
  1486. PMENUSTATE pMenuState, pmnsEnd;
  1487. PTHREADINFO pti = PtiCurrent();
  1488. TL tlpwnd, tlpwndFocus, tlpwndParent;
  1489. PWND pwndFocus;
  1490. BOOL fAlreadyDestroyed;
  1491. DWORD dwDisableHooks;
  1492. dwDisableHooks = 0;
  1493. ThreadLockWithPti(pti, pwnd, &tlpwnd);
  1494. /*
  1495. * First, if this handle has been marked for destruction, that means it
  1496. * is possible that the current thread is not its owner! (meaning we're
  1497. * being called from a handle unlock call). In this case, set the owner
  1498. * to be the current thread so inter-thread send messages occur.
  1499. */
  1500. fAlreadyDestroyed = HMIsMarkDestroy(pwnd);
  1501. if (fAlreadyDestroyed) {
  1502. /*
  1503. * UserAssert(dwInAtomicOperation > 0);
  1504. * This Assert ensures that we are here only because of an unlock
  1505. * on a previously destroyed window. We BEGIN/ENDATOMICHCHECK in
  1506. * HMDestroyUnlockedObject to ensure we don't leave the crit sect
  1507. * unexpectedly, which gives us dwInAtomicCheck > 0. We set
  1508. * TIF_DISABLEHOOKS to prevent a callback in Unlock
  1509. * However, it is currently possible destroy the same window handle
  1510. * twice, since we don't (yet) fail to revalidate zombie handles:
  1511. * GerardoB may change this, at which time we should probably restore
  1512. * this Assert, and test #76902 (close winmsd.exe) again. (preventing
  1513. * hooks in a second destroy of a zombie window should be OK) - IanJa
  1514. */
  1515. // UserAssert(dwInAtomicOperation > 0);
  1516. if (HMPheFromObject(pwnd)->pOwner != pti) {
  1517. UserAssert(PsGetCurrentThreadWin32Thread());
  1518. HMChangeOwnerThread(pwnd, pti);
  1519. }
  1520. dwDisableHooks = pti->TIF_flags & TIF_DISABLEHOOKS;
  1521. pti->TIF_flags |= TIF_DISABLEHOOKS;
  1522. } else {
  1523. /*
  1524. * Ensure that we can destroy the window. JIMA: no other process or thread
  1525. * should be able to destroy any other process or thread's window.
  1526. */
  1527. if (pti != GETPTI(pwnd)) {
  1528. RIPERR0(ERROR_ACCESS_DENIED,
  1529. RIP_WARNING,
  1530. "Access denied in xxxDestroyWindow");
  1531. goto FalseReturn;
  1532. }
  1533. }
  1534. /*
  1535. * First ask the CBT hook if we can destroy this window.
  1536. * If this object has already been destroyed OR this thread is currently
  1537. * in cleanup mode, *do not* make any callbacks via hooks to the client
  1538. * process.
  1539. */
  1540. if (!fAlreadyDestroyed && !(pti->TIF_flags & TIF_INCLEANUP) &&
  1541. IsHooked(pti, WHF_CBT)) {
  1542. if (xxxCallHook(HCBT_DESTROYWND, (WPARAM)HWq(pwnd), 0, WH_CBT)) {
  1543. goto FalseReturn;
  1544. }
  1545. }
  1546. /*
  1547. * If the window we are destroying is in menu mode, end the menu
  1548. */
  1549. pMenuState = GetpMenuState(pwnd);
  1550. if ((pMenuState != NULL)
  1551. && (pwnd == pMenuState->pGlobalPopupMenu->spwndNotify)) {
  1552. MNEndMenuStateNotify(pMenuState);
  1553. /*
  1554. * Signal all states to end. The window(s) will be unlocked when
  1555. * the menu exits; we cannot unlock it now because the menu
  1556. * code could fault.
  1557. */
  1558. pmnsEnd = pMenuState;
  1559. do {
  1560. UserAssert(pwnd == pMenuState->pGlobalPopupMenu->spwndNotify);
  1561. pMenuState->fInsideMenuLoop = FALSE;
  1562. pMenuState = pMenuState->pmnsPrev;
  1563. } while (pMenuState != NULL) ;
  1564. /*
  1565. * All states have been signaled to exit, so once we callback
  1566. * we cannot count on pmnsEnd->pmnsPrev to be valid. Thus
  1567. * we simply end the current menu here and let the others go
  1568. * on their own. No state points to pwnd anymore so that
  1569. * should be OK.
  1570. */
  1571. if (!pmnsEnd->fModelessMenu) {
  1572. xxxEndMenu(pmnsEnd);
  1573. }
  1574. }
  1575. if (ghwndSwitch == HWq(pwnd)) {
  1576. ghwndSwitch = NULL;
  1577. }
  1578. if (!TestWF(pwnd, WFCHILD) && (pwnd->spwndOwner == NULL)) {
  1579. if (TestWF(pwnd, WFHASPALETTE)) {
  1580. xxxFlushPalette(pwnd);
  1581. }
  1582. }
  1583. /*
  1584. * Disassociate thread state if this is top level and owned by a different
  1585. * thread. This is done to begin with so these windows z-order together.
  1586. */
  1587. if (pwnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
  1588. !TestwndChild(pwnd) && pwnd->spwndOwner != NULL &&
  1589. GETPTI(pwnd->spwndOwner) != GETPTI(pwnd)) {
  1590. /*
  1591. * No need to zzzDeferWinEventNotify() - there is an xxx call just below
  1592. */
  1593. zzzAttachThreadInput(GETPTI(pwnd), GETPTI(pwnd->spwndOwner), FALSE);
  1594. }
  1595. /*
  1596. * If we are a child window without the WS_NOPARENTNOTIFY style, send
  1597. * the appropriate notification message.
  1598. *
  1599. * NOTE: Although it would appear that we are illegally cramming a
  1600. * a WORD (WM_DESTROY) and a DWORD (pwnd->spmenu) into a single LONG
  1601. * (wParam) this isn't really the case because we first test if this
  1602. * is a child window. The pMenu field in a child window is really
  1603. * the window's id and only the LOWORD is significant.
  1604. */
  1605. if (TestWF(pwnd, WFCHILD) && !TestWF(pwnd, WEFNOPARENTNOTIFY) &&
  1606. pwnd->spwndParent != NULL) {
  1607. ThreadLockAlwaysWithPti(pti, pwnd->spwndParent, &tlpwndParent);
  1608. xxxSendMessage(pwnd->spwndParent, WM_PARENTNOTIFY,
  1609. MAKELONG(WM_DESTROY, PTR_TO_ID(pwnd->spmenu)), (LPARAM)HWq(pwnd));
  1610. ThreadUnlock(&tlpwndParent);
  1611. }
  1612. /*
  1613. * Mark this window as beginning the destroy process. This is necessary
  1614. * to prevent window-management calls such as ShowWindow or SetWindowPos
  1615. * from coming in and changing the visible-state of the window
  1616. * once we hide it. Otherwise, if the app attempts to make it
  1617. * visible, then we can get our vis-rgns messed up once we truely
  1618. * destroy the window.
  1619. *
  1620. * Don't mark the mother desktop with this bit. The xxxSetWindowPos()
  1621. * will fail for this window, and thus possibly cause an assertion
  1622. * in the xxxFreeWindow() call when we check for the visible-bit.
  1623. */
  1624. if (pwnd->spwndParent && (pwnd->spwndParent->head.rpdesk != NULL)) {
  1625. SetWF(pwnd, WFINDESTROY);
  1626. }
  1627. /*
  1628. * Hide the window.
  1629. */
  1630. if (TestWF(pwnd, WFVISIBLE)) {
  1631. if (TestWF(pwnd, WFCHILD)) {
  1632. xxxShowWindow(pwnd, SW_HIDE | TEST_PUDF(PUDF_ANIMATE));
  1633. } else {
  1634. /*
  1635. * Hide this window without activating anyone else.
  1636. */
  1637. xxxSetWindowPos(pwnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW |
  1638. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
  1639. (fAlreadyDestroyed ? SWP_DEFERDRAWING : 0));
  1640. }
  1641. /*
  1642. * Under low memory conditions, the above attempt to hide could fail.
  1643. */
  1644. if (TestWF(pwnd, WFVISIBLE)) {
  1645. RIPMSG0(RIP_WARNING, "xxxDestroyWindow: normal hide failed");
  1646. SetVisible(pwnd, SV_UNSET);
  1647. /*
  1648. * Invalidate windows below so they redraw properly.
  1649. */
  1650. xxxRedrawWindow(NULL, &pwnd->rcWindow, NULL, RDW_INVALIDATE |
  1651. RDW_ERASE | RDW_ALLCHILDREN);
  1652. }
  1653. } else if (IsTrayWindow(pwnd)) {
  1654. PostShellHookMessages(HSHELL_WINDOWDESTROYED,
  1655. (LPARAM)PtoHq( pwnd ));
  1656. }
  1657. /*
  1658. * Destroy any owned windows.
  1659. * [msadek], the check for FNID_GHOST is to fix bug# 380208, 382758
  1660. * where we recieve QEVENT_HUNGTHREAD for the owner window first.
  1661. * since we post the event multiple times (once for each owned window)
  1662. * We are guranteed to go through xxxDestroyWindow for owned windows too.
  1663. */
  1664. if (!TestWF(pwnd, WFCHILD) && (GETFNID(pwnd) != FNID_GHOST)) {
  1665. xxxDW_DestroyOwnedWindows(pwnd);
  1666. /*
  1667. * And remove the window hot-key, if it has one
  1668. */
  1669. DWP_SetHotKey(pwnd, 0);
  1670. }
  1671. /*
  1672. * If the window has already been destroyed, don't muck with
  1673. * activation because we may already be in the middle of
  1674. * an activation event. Changing activation now may cause us
  1675. * to leave our critical section while holding the display lock.
  1676. * This will result in a deadlock if another thread gets the
  1677. * critical section before we do and attempts to lock the
  1678. * display.
  1679. */
  1680. if (!fAlreadyDestroyed) {
  1681. PWND pwndActivate = NULL;
  1682. TL tlpwndActivate;
  1683. UINT cmdActivate;
  1684. /*
  1685. * If hiding the active window, activate someone else.
  1686. * This call is strategically located after DestroyOwnedWindows() so we
  1687. * don't end up activating our owner window.
  1688. *
  1689. * If the window is a popup, try to activate his creator not the top
  1690. * window in the Z list.
  1691. */
  1692. if (pwnd == pti->pq->spwndActive) {
  1693. if (TestWF(pwnd, WFPOPUP) && pwnd->spwndOwner) {
  1694. pwndActivate = pwnd->spwndOwner;
  1695. cmdActivate = AW_TRY;
  1696. } else {
  1697. pwndActivate = pwnd;
  1698. cmdActivate = AW_SKIP;
  1699. }
  1700. } else if ((pti->pq->spwndActive == NULL) && (gpqForeground == pti->pq)) {
  1701. pwndActivate = pwnd;
  1702. cmdActivate = AW_SKIP;
  1703. }
  1704. if (pwndActivate) {
  1705. ThreadLockAlwaysWithPti(pti, pwndActivate, &tlpwndActivate);
  1706. if (!xxxActivateWindow(pwndActivate, cmdActivate) ||
  1707. ((cmdActivate == AW_SKIP) && (pwnd == pti->pq->spwndActive))) {
  1708. if ((cmdActivate == AW_SKIP) || (pwnd == pti->pq->spwndActive)) {
  1709. Unlock(&pti->pq->spwndActive);
  1710. pwndFocus = Unlock(&pti->pq->spwndFocus);
  1711. if (IS_IME_ENABLED() && pwndFocus != NULL) {
  1712. ThreadLockAlwaysWithPti(pti, pwndFocus, &tlpwndFocus);
  1713. xxxFocusSetInputContext(pwndFocus, FALSE, FALSE);
  1714. ThreadUnlock(&tlpwndFocus);
  1715. }
  1716. if (pti->pq == gpqForeground) {
  1717. xxxWindowEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT,
  1718. INDEXID_CONTAINER, 0);
  1719. xxxWindowEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW,
  1720. INDEXID_CONTAINER, WEF_USEPWNDTHREAD);
  1721. }
  1722. zzzInternalDestroyCaret();
  1723. }
  1724. }
  1725. ThreadUnlock(&tlpwndActivate);
  1726. }
  1727. }
  1728. /*
  1729. * Fix last active popup.
  1730. */
  1731. {
  1732. PWND pwndOwner = pwnd->spwndOwner;
  1733. if (pwndOwner != NULL) {
  1734. while (pwndOwner->spwndOwner != NULL) {
  1735. pwndOwner = pwndOwner->spwndOwner;
  1736. }
  1737. if (pwnd == pwndOwner->spwndLastActive) {
  1738. /*
  1739. * If pwndOwner is marked for destruction, locking it here
  1740. * will prevent it from ever being freed, thus preventing
  1741. * the associated session memory from going away. Just
  1742. * unlock pwndOwner->spwndLastActive in this case.
  1743. * [msadek- 03/02/2002]
  1744. */
  1745. if (HMIsMarkDestroy(pwndOwner)) {
  1746. Unlock(&pwndOwner->spwndLastActive);
  1747. } else {
  1748. Lock(&(pwndOwner->spwndLastActive), pwnd->spwndOwner);
  1749. }
  1750. }
  1751. }
  1752. }
  1753. if (!fAlreadyDestroyed) {
  1754. /*
  1755. * Note we do this BEFORE telling the app the window is dying. Note
  1756. * also that we do NOT loop through the children generating DESTROY
  1757. * events. DESTROY of a parent implies DESTROY of all children (see
  1758. * Windows NT Bug #71846).
  1759. */
  1760. if (!TestWF(pwnd, WFDESTROYED)) {
  1761. xxxWindowEvent(EVENT_OBJECT_DESTROY, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, 0);
  1762. }
  1763. /*
  1764. * Send destroy messages before the WindowLockStart in case
  1765. * he tries to destroy windows as a result.
  1766. */
  1767. xxxDW_SendDestroyMessages(pwnd);
  1768. }
  1769. /*
  1770. * Check the owner of IME window again.
  1771. * If thread is destroying, don't bother to check.
  1772. */
  1773. if (IS_IME_ENABLED() && !(pti->TIF_flags & TIF_INCLEANUP) &&
  1774. pti->spwndDefaultIme != NULL &&
  1775. !TestCF(pwnd, CFIME) &&
  1776. pwnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]) {
  1777. if (fAlreadyDestroyed) {
  1778. RIPMSG2(RIP_VERBOSE,
  1779. "xxxDestroyWindow: in final destruction of 0x%p, ime=0x%p",
  1780. pwnd,
  1781. pti->spwndDefaultIme);
  1782. } else {
  1783. if (!TestWF(pwnd, WFCHILD)) {
  1784. if (ImeCanDestroyDefIME(pti->spwndDefaultIme, pwnd)) {
  1785. TAGMSG1(DBGTAG_IMM, "xxxDestroyWindow: destroying (1) the default IME window=%p", pti->spwndDefaultIme);
  1786. xxxDestroyWindow(pti->spwndDefaultIme);
  1787. }
  1788. } else if (pwnd->spwndParent != NULL) {
  1789. if (ImeCanDestroyDefIMEforChild(pti->spwndDefaultIme, pwnd)) {
  1790. TAGMSG1(DBGTAG_IMM, "xxxDestroyWindow: destroying (2) the default IME window=%p", pti->spwndDefaultIme);
  1791. xxxDestroyWindow(pti->spwndDefaultIme);
  1792. }
  1793. }
  1794. }
  1795. }
  1796. if ((pwnd->spwndParent != NULL) && !fAlreadyDestroyed) {
  1797. /*
  1798. * TestwndChild() on checks to WFCHILD bit. Make sure this
  1799. * window wasn't SetParent()'ed to the desktop as well.
  1800. */
  1801. if (TestwndChild(pwnd) && (pwnd->spwndParent != PWNDDESKTOP(pwnd)) &&
  1802. (GETPTI(pwnd) != GETPTI(pwnd->spwndParent))) {
  1803. /*
  1804. * pwnd is threadlocked, so no need to DeferWinEventNotify()
  1805. */
  1806. CheckLock(pwnd);
  1807. zzzAttachThreadInput(GETPTI(pwnd), GETPTI(pwnd->spwndParent), FALSE);
  1808. }
  1809. UnlinkWindow(pwnd, pwnd->spwndParent);
  1810. }
  1811. /*
  1812. * This in intended to check for a case where we destroy the window,
  1813. * but it's still listed as the active-window in the queue. This
  1814. * could cause problems in window-activation (see xxxActivateThisWindow)
  1815. * where we attempt to activate another window and in the process, try
  1816. * to deactivate this window (bad).
  1817. */
  1818. #if DBG
  1819. if (pwnd == pti->pq->spwndActive) {
  1820. RIPMSG1(RIP_WARNING, "xxxDestroyWindow: pwnd == pti->pq->spwndActive (%#p)", pwnd);
  1821. }
  1822. #endif
  1823. /*
  1824. * Set the state as destroyed so any z-ordering events will be ignored.
  1825. * We cannot NULL out the owner field until WM_NCDESTROY is send or
  1826. * apps like Rumba fault (they call GetParent after every message)
  1827. */
  1828. SetWF(pwnd, WFDESTROYED);
  1829. /*
  1830. * FreeWindow performs a ThreadUnlock.
  1831. */
  1832. xxxFreeWindow(pwnd, &tlpwnd);
  1833. if (fAlreadyDestroyed) {
  1834. pti->TIF_flags = (pti->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks;
  1835. }
  1836. return TRUE;
  1837. FalseReturn:
  1838. if (fAlreadyDestroyed) {
  1839. pti->TIF_flags = (pti->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks;
  1840. }
  1841. ThreadUnlock(&tlpwnd);
  1842. return FALSE;
  1843. }
  1844. /***************************************************************************\
  1845. * xxxDW_DestroyOwnedWindows
  1846. *
  1847. * History:
  1848. * 10-20-90 darrinm Ported from Win 3.0 sources.
  1849. * 07-22-91 darrinm Re-ported from Win 3.1 sources.
  1850. \***************************************************************************/
  1851. VOID xxxDW_DestroyOwnedWindows(
  1852. PWND pwndParent)
  1853. {
  1854. PWND pwnd, pwndDesktop;
  1855. PDESKTOP pdeskParent;
  1856. PWND pwndDefaultIme = GETPTI(pwndParent)->spwndDefaultIme;
  1857. CheckLock(pwndParent);
  1858. if ((pdeskParent = pwndParent->head.rpdesk) == NULL)
  1859. return;
  1860. pwndDesktop = pdeskParent->pDeskInfo->spwnd;
  1861. /*
  1862. * During shutdown, the desktop owner window will be
  1863. * destroyed. In this case, pwndDesktop will be NULL.
  1864. */
  1865. if (pwndDesktop == NULL)
  1866. return;
  1867. pwnd = pwndDesktop->spwndChild;
  1868. while (pwnd != NULL) {
  1869. if (pwnd->spwndOwner == pwndParent) {
  1870. /*
  1871. * We don't destroy the IME window here
  1872. * unless the thread is doing cleanup.
  1873. */
  1874. if (IS_IME_ENABLED() && !(GETPTI(pwndParent)->TIF_flags & TIF_INCLEANUP) &&
  1875. pwnd == pwndDefaultIme) {
  1876. Unlock(&pwnd->spwndOwner);
  1877. pwnd = pwnd->spwndNext;
  1878. continue;
  1879. }
  1880. /*
  1881. * If the window doesn't get destroyed, set its owner to NULL.
  1882. * A good example of this is trying to destroy a window created
  1883. * by another thread or process, but there are other cases.
  1884. */
  1885. if (!xxxDestroyWindow(pwnd)) {
  1886. Unlock(&pwnd->spwndOwner);
  1887. }
  1888. /*
  1889. * Start the search over from the beginning since the app could
  1890. * have caused other windows to be created or activation/z-order
  1891. * changes.
  1892. */
  1893. pwnd = pwndDesktop->spwndChild;
  1894. } else {
  1895. pwnd = pwnd->spwndNext;
  1896. }
  1897. }
  1898. }
  1899. /***************************************************************************\
  1900. * xxxDW_SendDestroyMessages
  1901. *
  1902. * History:
  1903. * 10-20-90 darrinm Ported from Win 3.0 sources.
  1904. \***************************************************************************/
  1905. VOID xxxDW_SendDestroyMessages(
  1906. PWND pwnd)
  1907. {
  1908. PWND pwndChild;
  1909. PWND pwndNext;
  1910. TL tlpwndNext;
  1911. TL tlpwndChild;
  1912. PWINDOWSTATION pwinsta;
  1913. CheckLock(pwnd);
  1914. /*
  1915. * Be sure the window gets any resulting messages before being destroyed.
  1916. */
  1917. xxxCheckFocus(pwnd);
  1918. pwinsta = _GetProcessWindowStation(NULL);
  1919. if (pwinsta != NULL && pwnd == pwinsta->spwndClipOwner) {
  1920. /*
  1921. * Pass along the pwnd which is the reason we are dismissing the
  1922. * clipboard. We want to later make sure the owner is still this
  1923. * window after we make callbacks and clear the owner
  1924. */
  1925. xxxDisownClipboard(pwnd);
  1926. }
  1927. /*
  1928. * Send the WM_DESTROY message.
  1929. */
  1930. #if _DBG
  1931. if (pwnd == PtiCurrent()->spwndDefaultIme) {
  1932. TAGMSG2(DBGTAG_IMM, "xxxDW_SendDestroyMessages: sending WM_DESTROY message to def IME=%p, pti=%p", pwnd, PtiCurrent());
  1933. }
  1934. #endif
  1935. xxxSendMessage(pwnd, WM_DESTROY, 0L, 0L);
  1936. /*
  1937. * Now send destroy message to all children of pwnd.
  1938. * Enumerate down (pwnd->spwndChild) and sideways (pwnd->spwndNext).
  1939. * We do it this way because parents often assume that child windows still
  1940. * exist during WM_DESTROY message processing.
  1941. */
  1942. pwndChild = pwnd->spwndChild;
  1943. while (pwndChild != NULL) {
  1944. pwndNext = pwndChild->spwndNext;
  1945. ThreadLock(pwndNext, &tlpwndNext);
  1946. ThreadLockAlways(pwndChild, &tlpwndChild);
  1947. xxxDW_SendDestroyMessages(pwndChild);
  1948. ThreadUnlock(&tlpwndChild);
  1949. pwndChild = pwndNext;
  1950. /*
  1951. * The unlock may nuke the next window. If so, get out.
  1952. */
  1953. if (!ThreadUnlock(&tlpwndNext))
  1954. break;
  1955. }
  1956. xxxCheckFocus(pwnd);
  1957. }
  1958. /***************************************************************************\
  1959. * xxxFW_DestroyAllChildren
  1960. *
  1961. * History:
  1962. * 11-06-90 darrinm Ported from Win 3.0 sources.
  1963. \***************************************************************************/
  1964. VOID xxxFW_DestroyAllChildren(
  1965. PWND pwnd)
  1966. {
  1967. PWND pwndChild;
  1968. TL tlpwndChild;
  1969. PTHREADINFO pti;
  1970. PTHREADINFO ptiCurrent = PtiCurrent();
  1971. CheckLock(pwnd);
  1972. while (pwnd->spwndChild != NULL) {
  1973. pwndChild = pwnd->spwndChild;
  1974. /*
  1975. * ThreadLock prior to the unlink in case pwndChild
  1976. * is already marked as destroyed.
  1977. */
  1978. ThreadLockAlwaysWithPti(ptiCurrent, pwndChild, &tlpwndChild);
  1979. /*
  1980. * Propagate the VISIBLE flag. We need to do this so that
  1981. * when a child window gets destroyed we don't try to hide it
  1982. * if the WFVISIBLE flag is set.
  1983. */
  1984. if (TestWF(pwndChild, WFVISIBLE)) {
  1985. SetVisible(pwndChild, SV_UNSET);
  1986. }
  1987. UnlinkWindow(pwndChild, pwnd);
  1988. /*
  1989. * Set the state as destroyed so any z-ordering events will be ignored.
  1990. * We cannot NULL out the owner field until WM_NCDESTROY is send or
  1991. * apps like Rumba fault (they call GetParent after every message)
  1992. */
  1993. SetWF(pwndChild, WFDESTROYED);
  1994. /*
  1995. * If the window belongs to another thread, post
  1996. * an event to let it know it should be destroyed.
  1997. * Otherwise, free the window.
  1998. */
  1999. pti = GETPTI(pwndChild);
  2000. if (pti != ptiCurrent) {
  2001. PostEventMessage(pti, pti->pq, QEVENT_DESTROYWINDOW,
  2002. NULL, 0,
  2003. (WPARAM)HWq(pwndChild), 0);
  2004. ThreadUnlock(&tlpwndChild);
  2005. } else {
  2006. /*
  2007. * FreeWindow performs a ThreadUnlock.
  2008. */
  2009. xxxFreeWindow(pwndChild, &tlpwndChild);
  2010. }
  2011. }
  2012. }
  2013. /***************************************************************************\
  2014. * UnlockNotifyWindow
  2015. *
  2016. * Walk down a menu and unlock all notify windows.
  2017. *
  2018. * History:
  2019. * 18-May-1994 JimA Created.
  2020. \***************************************************************************/
  2021. VOID UnlockNotifyWindow(
  2022. PMENU pmenu)
  2023. {
  2024. PITEM pItem;
  2025. int i;
  2026. /*
  2027. * Go down the item list and unlock submenus.
  2028. */
  2029. pItem = pmenu->rgItems;
  2030. for (i = pmenu->cItems; i--; ++pItem) {
  2031. if (pItem->spSubMenu != NULL)
  2032. UnlockNotifyWindow(pItem->spSubMenu);
  2033. }
  2034. Unlock(&pmenu->spwndNotify);
  2035. }
  2036. /***************************************************************************\
  2037. * xxxFreeWindow
  2038. *
  2039. * History:
  2040. * 19-Oct-1990 DarrinM Ported from Win 3.0 sources.
  2041. \***************************************************************************/
  2042. VOID xxxFreeWindow(
  2043. PWND pwnd,
  2044. PTL ptlpwndFree)
  2045. {
  2046. PDCE *ppdce;
  2047. PDCE pdce;
  2048. UINT uDCERelease;
  2049. PMENU pmenu;
  2050. PQMSG pqmsg;
  2051. PPCLS ppcls;
  2052. WORD fnid;
  2053. TL tlpdesk;
  2054. PWINDOWSTATION pwinsta = _GetProcessWindowStation(NULL);
  2055. PTHREADINFO pti = PtiCurrent();
  2056. PPROCESSINFO ppi;
  2057. PMONITOR pMonitor;
  2058. TL tlpMonitor;
  2059. UNREFERENCED_PARAMETER(ptlpwndFree);
  2060. CheckLock(pwnd);
  2061. /*
  2062. * If the pwnd is any of the global shell-related windows,
  2063. * then we need to unlock them from the deskinfo.
  2064. */
  2065. if (pwnd->head.rpdesk != NULL) {
  2066. if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndShell)
  2067. Unlock(&pwnd->head.rpdesk->pDeskInfo->spwndShell);
  2068. if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndBkGnd)
  2069. Unlock(&pwnd->head.rpdesk->pDeskInfo->spwndBkGnd);
  2070. if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndTaskman)
  2071. Unlock(&pwnd->head.rpdesk->pDeskInfo->spwndTaskman);
  2072. if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndProgman)
  2073. Unlock(&pwnd->head.rpdesk->pDeskInfo->spwndProgman);
  2074. if (TestWF(pwnd,WFSHELLHOOKWND)) {
  2075. _DeregisterShellHookWindow(pwnd);
  2076. }
  2077. if (TestWF(pwnd, WFMSGBOX)) {
  2078. pwnd->head.rpdesk->pDeskInfo->cntMBox--;
  2079. ClrWF(pwnd, WFMSGBOX);
  2080. }
  2081. }
  2082. /*
  2083. * First, if this handle has been marked for destruction, that means it
  2084. * is possible that the current thread is not its owner! (meaning we're
  2085. * being called from a handle unlock call). In this case, set the owner
  2086. * to be the current thread so inter-thread send messages don't occur.
  2087. */
  2088. if (HMIsMarkDestroy(pwnd))
  2089. HMChangeOwnerThread(pwnd, pti);
  2090. /*
  2091. * Blow away the children.
  2092. *
  2093. * DestroyAllChildren() will still destroy windows created by other
  2094. * threads! This needs to be looked at more closely: the ultimate
  2095. * "right" thing to do is not to destroy these windows but just
  2096. * unlink them.
  2097. */
  2098. xxxFW_DestroyAllChildren(pwnd);
  2099. xxxSendMessage(pwnd, WM_NCDESTROY, 0, 0L);
  2100. pMonitor = _MonitorFromWindow(pwnd, MONITOR_DEFAULTTOPRIMARY);
  2101. ThreadLockAlwaysWithPti(pti, pMonitor, &tlpMonitor);
  2102. xxxRemoveFullScreen(pwnd, pMonitor);
  2103. ThreadUnlock(&tlpMonitor);
  2104. /*
  2105. * If this is one of the built in controls which hasn't been cleaned
  2106. * up yet, do it now. If it lives in the kernel, call the function
  2107. * directly, otherwise call back to the client. Even if the control
  2108. * is sub- or super-classed, use the window procs associated with
  2109. * the function id.
  2110. */
  2111. fnid = GETFNID(pwnd);
  2112. if ((fnid >= FNID_WNDPROCSTART) && !(pwnd->fnid & FNID_CLEANEDUP_BIT)) {
  2113. if (fnid <= FNID_WNDPROCEND) {
  2114. FNID(fnid)(pwnd, WM_FINALDESTROY, 0, 0, 0);
  2115. } else if (fnid <= FNID_CONTROLEND && !(pti->TIF_flags & TIF_INCLEANUP)) {
  2116. CallClientWorkerProc(pwnd,
  2117. WM_FINALDESTROY,
  2118. 0,
  2119. 0,
  2120. (PROC)FNID_TO_CLIENT_PFNWORKER(fnid));
  2121. }
  2122. pwnd->fnid |= FNID_CLEANEDUP_BIT;
  2123. }
  2124. pwnd->fnid |= FNID_DELETED_BIT;
  2125. /*
  2126. * Check to clear the most recently active window in owned list.
  2127. */
  2128. if (pwnd->spwndOwner && (pwnd->spwndOwner->spwndLastActive == pwnd)) {
  2129. Lock(&(pwnd->spwndOwner->spwndLastActive), pwnd->spwndOwner);
  2130. }
  2131. /*
  2132. * The windowstation may be NULL if we are destroying a desktop
  2133. * or windowstation. If this is the case, this thread will not
  2134. * be using the clipboard.
  2135. */
  2136. if (pwinsta != NULL) {
  2137. if (pwnd == pwinsta->spwndClipOpen) {
  2138. Unlock(&pwinsta->spwndClipOpen);
  2139. pwinsta->ptiClipLock = NULL;
  2140. }
  2141. if (pwnd == pwinsta->spwndClipViewer) {
  2142. Unlock(&pwinsta->spwndClipViewer);
  2143. }
  2144. }
  2145. if (IS_IME_ENABLED() && pwnd == pti->spwndDefaultIme)
  2146. Unlock(&pti->spwndDefaultIme);
  2147. if (pwnd == pti->pq->spwndFocus)
  2148. Unlock(&pti->pq->spwndFocus);
  2149. if (pwnd == pti->pq->spwndActivePrev)
  2150. Unlock(&pti->pq->spwndActivePrev);
  2151. if (pwnd == gspwndActivate)
  2152. Unlock(&gspwndActivate);
  2153. if (pwnd->head.rpdesk != NULL) {
  2154. if (pwnd == pwnd->head.rpdesk->spwndForeground)
  2155. Unlock(&pwnd->head.rpdesk->spwndForeground);
  2156. if (pwnd == pwnd->head.rpdesk->spwndTray)
  2157. Unlock(&pwnd->head.rpdesk->spwndTray);
  2158. if (pwnd == pwnd->head.rpdesk->spwndTrack) {
  2159. /*
  2160. * Remove tooltip, if any
  2161. */
  2162. if (GETPDESK(pwnd)->dwDTFlags & DF_TOOLTIPSHOWING) {
  2163. PWND pwndTooltip = GETPDESK(pwnd)->spwndTooltip;
  2164. TL tlpwndTooltip;
  2165. ThreadLockAlways(pwndTooltip, &tlpwndTooltip);
  2166. xxxResetTooltip((PTOOLTIPWND)pwndTooltip);
  2167. ThreadUnlock(&tlpwndTooltip);
  2168. }
  2169. Unlock(&pwnd->head.rpdesk->spwndTrack);
  2170. pwnd->head.rpdesk->dwDTFlags &= ~DF_MOUSEMOVETRK;
  2171. }
  2172. }
  2173. if (pwnd == pti->pq->spwndCapture)
  2174. xxxReleaseCapture();
  2175. if (FAnyShadows()) {
  2176. if (TestCF(pwnd, CFDROPSHADOW)) {
  2177. xxxRemoveShadow(pwnd);
  2178. } else if (pwnd->pcls->atomClassName == gatomShadow) {
  2179. CleanupShadow(pwnd);
  2180. }
  2181. }
  2182. /*
  2183. * This window won't be needing any more input.
  2184. */
  2185. if (pwnd == gspwndMouseOwner)
  2186. Unlock(&gspwndMouseOwner);
  2187. /*
  2188. * It also won't have any mouse cursors over it.
  2189. */
  2190. if (pwnd == gspwndCursor)
  2191. Unlock(&gspwndCursor);
  2192. DestroyWindowsTimers(pwnd);
  2193. DestroyWindowsHotKeys(pwnd);
  2194. /*
  2195. * Make sure this window has no pending sent messages.
  2196. */
  2197. ClearSendMessages(pwnd);
  2198. /*
  2199. * Remove the associated GDI sprite.
  2200. */
  2201. if (TestWF(pwnd, WEFLAYERED)) {
  2202. UnsetLayeredWindow(pwnd);
  2203. }
  2204. if (TestWF(pwnd, WEFCOMPOSITED)) {
  2205. UnsetRedirectedWindow(pwnd, REDIRECT_COMPOSITED);
  2206. }
  2207. #ifdef REDIRECTION
  2208. if (TestWF(pwnd, WEFEXTREDIRECTED)) {
  2209. UnsetRedirectedWindow(pwnd, REDIRECT_EXTREDIRECTED);
  2210. }
  2211. #endif // REDIRECTION
  2212. /*
  2213. * Blow away any update region lying around.
  2214. */
  2215. if (NEEDSPAINT(pwnd)) {
  2216. DecPaintCount(pwnd);
  2217. DeleteMaybeSpecialRgn(pwnd->hrgnUpdate);
  2218. pwnd->hrgnUpdate = NULL;
  2219. ClrWF(pwnd, WFINTERNALPAINT);
  2220. }
  2221. /*
  2222. * Decrememt queue's syncpaint count if necessary.
  2223. */
  2224. if (NEEDSSYNCPAINT(pwnd)) {
  2225. ClrWF(pwnd, WFSENDNCPAINT);
  2226. ClrWF(pwnd, WFSENDERASEBKGND);
  2227. }
  2228. /*
  2229. * Clear both flags to ensure that the window is removed
  2230. * from the hung redraw list.
  2231. */
  2232. ClearHungFlag(pwnd, WFREDRAWIFHUNG);
  2233. ClearHungFlag(pwnd, WFREDRAWFRAMEIFHUNG);
  2234. /*
  2235. * If there is a WM_QUIT message in this app's message queue, call
  2236. * PostQuitMessage() (this happens if the app posts itself a quit message.
  2237. * WinEdit2.0 posts a quit to a window while receiving the WM_DESTROY
  2238. * for that window - it works because we need to do a PostQuitMessage()
  2239. * automatically for this thread.
  2240. */
  2241. if (pti->mlPost.pqmsgRead != NULL) {
  2242. /*
  2243. * try to get rid of WM_DDE_ACK too.
  2244. */
  2245. if ((pqmsg = FindQMsg(pti,
  2246. &(pti->mlPost),
  2247. pwnd,
  2248. WM_QUIT,
  2249. WM_QUIT, TRUE)) != NULL) {
  2250. _PostQuitMessage((int)pqmsg->msg.wParam);
  2251. }
  2252. }
  2253. if (!TestwndChild(pwnd) && pwnd->spmenu != NULL) {
  2254. pmenu = (PMENU)pwnd->spmenu;
  2255. if (UnlockWndMenu(pwnd, &pwnd->spmenu))
  2256. _DestroyMenu(pmenu);
  2257. }
  2258. if (pwnd->spmenuSys != NULL) {
  2259. pmenu = (PMENU)pwnd->spmenuSys;
  2260. if (pmenu != pwnd->head.rpdesk->spmenuDialogSys) {
  2261. if (UnlockWndMenu(pwnd, &pwnd->spmenuSys)) {
  2262. _DestroyMenu(pmenu);
  2263. }
  2264. } else {
  2265. UnlockWndMenu(pwnd, &pwnd->spmenuSys);
  2266. }
  2267. }
  2268. /*
  2269. * If it was using either of the desktop system menus, unlock it
  2270. */
  2271. if (pwnd->head.rpdesk != NULL) {
  2272. if (pwnd->head.rpdesk->spmenuSys != NULL &&
  2273. pwnd == pwnd->head.rpdesk->spmenuSys->spwndNotify) {
  2274. UnlockNotifyWindow(pwnd->head.rpdesk->spmenuSys);
  2275. } else if (pwnd->head.rpdesk->spmenuDialogSys != NULL &&
  2276. pwnd == pwnd->head.rpdesk->spmenuDialogSys->spwndNotify) {
  2277. UnlockNotifyWindow(pwnd->head.rpdesk->spmenuDialogSys);
  2278. }
  2279. }
  2280. /*
  2281. * Tell Gdi that the window is going away.
  2282. */
  2283. if (gcountPWO != 0) {
  2284. PVOID pwo = InternalRemoveProp(pwnd, PROP_WNDOBJ, TRUE);
  2285. if (pwo != NULL) {
  2286. GreLockDisplay(gpDispInfo->hDev);
  2287. GreDeleteWnd(pwo);
  2288. gcountPWO--;
  2289. GreUnlockDisplay(gpDispInfo->hDev);
  2290. }
  2291. }
  2292. #ifdef HUNGAPP_GHOSTING
  2293. /*
  2294. * RemoveGhost handles the case when pwnd is the hung window that has a
  2295. * corresponding ghost window and the case when pwnd is the ghost itself.
  2296. */
  2297. RemoveGhost(pwnd);
  2298. #endif // HUNGAPP_GHOSTING
  2299. /*
  2300. * Scan the DC cache to find any DC's for this window. If any are there,
  2301. * then invalidate them. We don't need to worry about calling SpbCheckDC
  2302. * because the window has been hidden by this time.
  2303. */
  2304. for (ppdce = &gpDispInfo->pdceFirst; *ppdce != NULL; ) {
  2305. pdce = *ppdce;
  2306. if (pdce->DCX_flags & DCX_INVALID) {
  2307. goto NextEntry;
  2308. }
  2309. if ((pdce->pwndOrg == pwnd) || (pdce->pwndClip == pwnd)) {
  2310. if (!(pdce->DCX_flags & DCX_CACHE)) {
  2311. if (TestCF(pwnd, CFCLASSDC)) {
  2312. GreLockDisplay(gpDispInfo->hDev);
  2313. if (pdce->DCX_flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
  2314. DeleteHrgnClip(pdce);
  2315. MarkDCEInvalid(pdce);
  2316. pdce->pwndOrg = NULL;
  2317. pdce->pwndClip = NULL;
  2318. pdce->hrgnClip = NULL;
  2319. /*
  2320. * Remove the vis rgn since it is still owned - if we did
  2321. * not, gdi would not be able to clean up properly if the
  2322. * app that owns this vis rgn exist while the vis rgn is
  2323. * still selected.
  2324. */
  2325. GreSelectVisRgn(pdce->hdc, NULL, SVR_DELETEOLD);
  2326. GreUnlockDisplay(gpDispInfo->hDev);
  2327. } else if (TestCF(pwnd, CFOWNDC)) {
  2328. DestroyCacheDC(ppdce, pdce->hdc);
  2329. } else {
  2330. UserAssert(FALSE);
  2331. }
  2332. } else {
  2333. /*
  2334. * If the DC is checked out, release it before
  2335. * we invalidate. Note, that if this process is exiting
  2336. * and it has a dc checked out, gdi is going to destroy that
  2337. * dc. We need to similarly remove that dc from the dc cache.
  2338. * This is not done here, but in the exiting code.
  2339. *
  2340. * The return for ReleaseDC() could fail, which would
  2341. * indicate a delayed-free (DCE_NUKE).
  2342. */
  2343. uDCERelease = DCE_RELEASED;
  2344. if (pdce->DCX_flags & DCX_INUSE) {
  2345. uDCERelease = ReleaseCacheDC(pdce->hdc, FALSE);
  2346. } else if (!GreSetDCOwner(pdce->hdc, OBJECT_OWNER_NONE)) {
  2347. uDCERelease = DCE_NORELEASE;
  2348. }
  2349. if (uDCERelease != DCE_FREED) {
  2350. if (uDCERelease == DCE_NORELEASE) {
  2351. /*
  2352. * We either could not release this dc or could not set
  2353. * its owner. In either case it means some other thread
  2354. * is actively using it. Since it is not too useful if
  2355. * the window it is calculated for is gone, mark it as
  2356. * INUSE (so we don't give it out again) and as
  2357. * DESTROYTHIS (so we just get rid of it since it is
  2358. * easier to do this than to release it back into the
  2359. * cache). The W32PF_OWNERDCCLEANUP bit means "look for
  2360. * DESTROYTHIS flags and destroy that dc", and the bit
  2361. * gets looked at in various strategic execution paths.
  2362. */
  2363. pdce->DCX_flags = DCX_DESTROYTHIS | DCX_INUSE | DCX_CACHE;
  2364. pti->ppi->W32PF_Flags |= W32PF_OWNDCCLEANUP;
  2365. } else {
  2366. /*
  2367. * We either released the DC or changed its owner
  2368. * successfully. Mark the entry as invalid so it can
  2369. * be given out again.
  2370. */
  2371. MarkDCEInvalid(pdce);
  2372. pdce->hrgnClip = NULL;
  2373. }
  2374. /*
  2375. * We shouldn't reference this window anymore. Setting
  2376. * these to NULL here will make sure that even if we were
  2377. * not able to release the DC here, we won't return this
  2378. * window from one of the DC matching functions.
  2379. */
  2380. pdce->pwndOrg = NULL;
  2381. pdce->pwndClip = NULL;
  2382. /*
  2383. * Remove the visrgn since it is still owned - if we did
  2384. * not, gdi would not be able to clean up properly if the
  2385. * app that owns this visrgn exist while the visrgn is
  2386. * still selected.
  2387. */
  2388. GreLockDisplay(gpDispInfo->hDev);
  2389. GreSelectVisRgn(pdce->hdc, NULL, SVR_DELETEOLD);
  2390. GreUnlockDisplay(gpDispInfo->hDev);
  2391. }
  2392. }
  2393. }
  2394. /*
  2395. * Step to the next DC. If the DC was deleted, there
  2396. * is no need to calculate address of the next entry.
  2397. */
  2398. if (pdce == *ppdce)
  2399. NextEntry:
  2400. ppdce = &pdce->pdceNext;
  2401. }
  2402. /*
  2403. * Clean up the spb that may still exist - like child window spb's.
  2404. */
  2405. if (pwnd == gspwndLockUpdate) {
  2406. FreeSpb(FindSpb(pwnd));
  2407. Unlock(&gspwndLockUpdate);
  2408. gptiLockUpdate = NULL;
  2409. }
  2410. if (TestWF(pwnd, WFHASSPB)) {
  2411. FreeSpb(FindSpb(pwnd));
  2412. }
  2413. /*
  2414. * Blow away the window clipping region. If the window is maximized, don't
  2415. * blow away the monitor region. If the window is the desktop, don't blow
  2416. * away the screen region.
  2417. */
  2418. if ( pwnd->hrgnClip != NULL &&
  2419. !TestWF(pwnd, WFMAXFAKEREGIONAL) &&
  2420. GETFNID(pwnd) != FNID_DESKTOP) {
  2421. GreDeleteObject(pwnd->hrgnClip);
  2422. pwnd->hrgnClip = NULL;
  2423. }
  2424. /*
  2425. * Clean up any memory allocated for scroll bars...
  2426. */
  2427. if (pwnd->pSBInfo) {
  2428. DesktopFree(pwnd->head.rpdesk, (HANDLE)(pwnd->pSBInfo));
  2429. pwnd->pSBInfo = NULL;
  2430. }
  2431. /*
  2432. * Free any callback handles associated with this window.
  2433. * This is done outside of DeleteProperties because of the special
  2434. * nature of callback handles as opposed to normal memory handles
  2435. * allocated for a thread.
  2436. */
  2437. /*
  2438. * Blow away the title
  2439. */
  2440. if (pwnd->strName.Buffer != NULL) {
  2441. DesktopFree(pwnd->head.rpdesk, pwnd->strName.Buffer);
  2442. pwnd->strName.Buffer = NULL;
  2443. pwnd->strName.Length = 0;
  2444. }
  2445. /*
  2446. * Blow away any properties connected to the window.
  2447. */
  2448. if (pwnd->ppropList != NULL) {
  2449. TL tlpDdeConv;
  2450. PDDECONV pDdeConv;
  2451. PDDEIMP pddei;
  2452. /*
  2453. * Get rid of any icon properties.
  2454. */
  2455. DestroyWindowSmIcon(pwnd);
  2456. InternalRemoveProp(pwnd, MAKEINTATOM(gpsi->atomIconProp), PROPF_INTERNAL);
  2457. pDdeConv = (PDDECONV)_GetProp(pwnd, PROP_DDETRACK, PROPF_INTERNAL);
  2458. if (pDdeConv != NULL) {
  2459. ThreadLockAlwaysWithPti(pti, pDdeConv, &tlpDdeConv);
  2460. xxxDDETrackWindowDying(pwnd, pDdeConv);
  2461. ThreadUnlock(&tlpDdeConv);
  2462. }
  2463. pddei = (PDDEIMP)InternalRemoveProp(pwnd, PROP_DDEIMP, PROPF_INTERNAL);
  2464. if (pddei != NULL) {
  2465. pddei->cRefInit = 0;
  2466. if (pddei->cRefConv == 0) {
  2467. /*
  2468. * If this is not 0 it is referenced by one or more DdeConv
  2469. * structures so DON'T free it yet!
  2470. */
  2471. UserFreePool(pddei);
  2472. }
  2473. }
  2474. }
  2475. /*
  2476. * Unlock everything that the window references.
  2477. * After we have sent the WM_DESTROY and WM_NCDESTROY message we
  2478. * can unlock & NULL the owner field so no other windows get z-ordered
  2479. * relative to this window. Rhumba faults if we NULL it before the
  2480. * destroy. (It calls GetParent after every message).
  2481. *
  2482. * We special-case the spwndParent window. In this case, if the
  2483. * window being destroyed is a desktop window, unlock the parent.
  2484. * Otherwise, we lock in the desktop-window as the parent so that
  2485. * if we aren't freed in this function, we will ensure that we
  2486. * won't fault when doing things like clipping-calculations. We'll
  2487. * unlock this once we know we're truly going to free this window.
  2488. */
  2489. if (pwnd->head.rpdesk != NULL &&
  2490. pwnd != pwnd->head.rpdesk->pDeskInfo->spwnd) {
  2491. Lock(&pwnd->spwndParent, pwnd->head.rpdesk->pDeskInfo->spwnd);
  2492. } else {
  2493. Unlock(&pwnd->spwndParent);
  2494. }
  2495. Unlock(&pwnd->spwndChild);
  2496. Unlock(&pwnd->spwndOwner);
  2497. Unlock(&pwnd->spwndLastActive);
  2498. /*
  2499. * Decrement the Window Reference Count in the Class structure.
  2500. */
  2501. DereferenceClass(pwnd);
  2502. /*
  2503. * Mark the object for destruction before this final unlock. This way
  2504. * the WM_FINALDESTROY will get sent if this is the last thread lock.
  2505. * We're currently destroying this window, so don't allow unlock recursion
  2506. * at this point (this is what HANDLEF_INDESTROY will do for us).
  2507. */
  2508. HMMarkObjectDestroy(pwnd);
  2509. HMPheFromObject(pwnd)->bFlags |= HANDLEF_INDESTROY;
  2510. /*
  2511. * Unlock the window... This shouldn't return FALSE because HANDLEF_DESTROY
  2512. * is set, but just in case... if it isn't around anymore, return because
  2513. * pwnd is invalid.
  2514. */
  2515. if (!ThreadUnlock(ptlpwndFree)) {
  2516. return;
  2517. }
  2518. /*
  2519. * Try to free the object. The object won't free if it is locked - but
  2520. * it will be marked for destruction. If the window is locked, change
  2521. * it's wndproc to xxxDefWindowProc().
  2522. *
  2523. * HMMarkObjectDestroy() will clear the HANDLEF_INDESTROY flag if the
  2524. * object isn't about to go away (so it can be destroyed again!)
  2525. */
  2526. if (HMMarkObjectDestroy(pwnd)) {
  2527. /*
  2528. * Delete the window's property list. Wait until now in case some
  2529. * thread keeps a property pointer around across a callback.
  2530. */
  2531. if (pwnd->ppropList != NULL) {
  2532. DeleteProperties(pwnd);
  2533. }
  2534. #if DBG
  2535. /*
  2536. * If we find the window is visible at the time we free it, then
  2537. * somehow the app was made visible on a callback (we hide it
  2538. * during xxxDestroyWindow(). This screws up our vis-window
  2539. * count for the thread, so we need to assert it.
  2540. */
  2541. if (TestWF(pwnd, WFINDESTROY) && TestWF(pwnd, WFVISIBLE))
  2542. RIPMSG1(RIP_WARNING, "xxxFreeWindow: Window should not be visible (pwnd == %#p)", pwnd);
  2543. #endif
  2544. pti->cWindows--;
  2545. /*
  2546. * Since we're freeing the memory for this window, we need
  2547. * to unlock the parent (which is the desktop for zombie windows).
  2548. */
  2549. Unlock(&pwnd->spwndParent);
  2550. ThreadLockDesktop(pti, pwnd->head.rpdesk, &tlpdesk, LDLT_FN_FREEWINDOW);
  2551. HMFreeObject(pwnd);
  2552. ThreadUnlockDesktop(pti, &tlpdesk, LDUT_FN_FREEWINDOW);
  2553. return;
  2554. }
  2555. /*
  2556. * Turn this into an object that the app won't see again - turn
  2557. * it into an icon title window - the window is still totally
  2558. * valid and useable by any structures that has this window locked.
  2559. */
  2560. pwnd->lpfnWndProc = xxxDefWindowProc;
  2561. if (pwnd->head.rpdesk)
  2562. ppi = pwnd->head.rpdesk->rpwinstaParent->pTerm->ptiDesktop->ppi;
  2563. else
  2564. ppi = PpiCurrent();
  2565. ppcls = GetClassPtr(gpsi->atomSysClass[ICLS_ICONTITLE], ppi, hModuleWin);
  2566. UserAssert(ppcls);
  2567. pwnd->pcls = *ppcls;
  2568. /*
  2569. * Since pwnd is marked as destroyed, there should be no client-side
  2570. * code which can validate it. So we do not need to search for a clone
  2571. * class of the right desktop -- just use the base class and bump the
  2572. * WndReferenceCount. This also helps if we are in a low-memory situation
  2573. * and cannot alloc another clone.
  2574. */
  2575. pwnd->pcls->cWndReferenceCount++;
  2576. SetWF(pwnd, WFSERVERSIDEPROC);
  2577. /*
  2578. * Clear the palette bit so that WM_PALETTECHANGED will not be sent
  2579. * again when the window is finally destroyed.
  2580. */
  2581. ClrWF(pwnd, WFHASPALETTE);
  2582. /*
  2583. * Clear its child bits so no code assumes that if the child bit
  2584. * is set, it has a parent. Change spmenu to NULL - it is only
  2585. * non-zero if this was child.
  2586. */
  2587. ClrWF(pwnd, WFTYPEMASK);
  2588. SetWF(pwnd, WFTILED);
  2589. pwnd->spmenu = NULL;
  2590. }
  2591. /***************************************************************************\
  2592. * UnlinkWindow
  2593. *
  2594. * History:
  2595. * 19-Oct-1990 DarrinM Ported from Win 3.0 sources.
  2596. \***************************************************************************/
  2597. VOID UnlinkWindow(
  2598. PWND pwnd,
  2599. PWND pwndParent)
  2600. {
  2601. if (pwndParent->spwndChild == pwnd) {
  2602. UserAssert(pwnd->spwndPrev == NULL);
  2603. Lock(&pwndParent->spwndChild, pwnd->spwndNext);
  2604. } else if (pwnd->spwndPrev != NULL) {
  2605. Lock(&pwnd->spwndPrev->spwndNext, pwnd->spwndNext);
  2606. }
  2607. if (pwnd->spwndNext != NULL) {
  2608. Lock(&pwnd->spwndNext->spwndPrev, pwnd->spwndPrev);
  2609. Unlock(&pwnd->spwndNext);
  2610. }
  2611. Unlock(&pwnd->spwndPrev);
  2612. #if DBG
  2613. VerifyWindowLink(pwnd, pwndParent, FALSE);
  2614. #endif
  2615. }
  2616. /***************************************************************************\
  2617. * DestroyCacheDCEntries
  2618. *
  2619. * Destroys all cache dc entries currently in use by this thread.
  2620. *
  2621. * 24-Feb-1992 ScottLu Created.
  2622. \***************************************************************************/
  2623. VOID DestroyCacheDCEntries(
  2624. PTHREADINFO pti)
  2625. {
  2626. PDCE *ppdce;
  2627. PDCE pdce;
  2628. /*
  2629. * Before any window destruction occurs, we need to destroy any dcs
  2630. * in use in the dc cache. When a dc is checked out, it is marked owned,
  2631. * which makes gdi's process cleanup code delete it when a process
  2632. * goes away. We need to similarly destroy the cache entry of any dcs
  2633. * in use by the exiting process.
  2634. */
  2635. for (ppdce = &gpDispInfo->pdceFirst; *ppdce != NULL; ) {
  2636. /*
  2637. * If the dc owned by this thread, remove it from the cache. Because
  2638. * DestroyCacheEntry destroys gdi objects, it is important that
  2639. * USER be called first in process destruction ordering.
  2640. *
  2641. * Only destroy this dc if it is a cache dc, because if it is either
  2642. * an owndc or a classdc, it will be destroyed for us when we destroy
  2643. * the window (for owndcs) or destroy the class (for classdcs).
  2644. */
  2645. pdce = *ppdce;
  2646. if (pti == pdce->ptiOwner) {
  2647. if (pdce->DCX_flags & DCX_CACHE)
  2648. DestroyCacheDC(ppdce, pdce->hdc);
  2649. }
  2650. /*
  2651. * Step to the next DC. If the DC was deleted, there's no need to
  2652. * calculate address of the next entry.
  2653. */
  2654. if (pdce == *ppdce) {
  2655. ppdce = &pdce->pdceNext;
  2656. }
  2657. }
  2658. }
  2659. /***************************************************************************\
  2660. * PatchThreadWindows
  2661. *
  2662. * This patches a thread's windows so that their window procs point to
  2663. * server only windowprocs. This is used for cleanup so that app aren't
  2664. * called back while the system is cleaning up after them.
  2665. *
  2666. * 24-Feb-1992 ScottLu Created.
  2667. \***************************************************************************/
  2668. VOID PatchThreadWindows(
  2669. PTHREADINFO pti)
  2670. {
  2671. PHE pheT;
  2672. PHE pheMax;
  2673. PWND pwnd;
  2674. /*
  2675. * First do any preparation work: windows need to be "patched" so that
  2676. * their window procs point to server only windowprocs, for example.
  2677. */
  2678. pheMax = &gSharedInfo.aheList[giheLast];
  2679. for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
  2680. /*
  2681. * Make sure this object is a window, it hasn't been marked for
  2682. * destruction, and that it is owned by this thread.
  2683. */
  2684. if (pheT->bType != TYPE_WINDOW)
  2685. continue;
  2686. if (pheT->bFlags & HANDLEF_DESTROY) {
  2687. continue;
  2688. }
  2689. if ((PTHREADINFO)pheT->pOwner != pti) {
  2690. continue;
  2691. }
  2692. /*
  2693. * Don't patch the window based on the class it was created from -
  2694. * because apps can sometimes sub-class a class - make a random class,
  2695. * then call ButtonWndProc with windows of that class by using
  2696. * the CallWindowProc() api. So patch the wndproc based on what
  2697. * wndproc this window has been calling.
  2698. */
  2699. pwnd = (PWND)pheT->phead;
  2700. if ((pwnd->fnid >= (WORD)FNID_WNDPROCSTART) &&
  2701. (pwnd->fnid <= (WORD)FNID_WNDPROCEND)) {
  2702. pwnd->lpfnWndProc = STOCID(pwnd->fnid);
  2703. if (pwnd->lpfnWndProc == NULL) {
  2704. pwnd->lpfnWndProc = xxxDefWindowProc;
  2705. }
  2706. } else {
  2707. pwnd->lpfnWndProc = xxxDefWindowProc;
  2708. }
  2709. /*
  2710. * This is a server side window now...
  2711. */
  2712. SetWF(pwnd, WFSERVERSIDEPROC);
  2713. ClrWF(pwnd, WFANSIPROC);
  2714. }
  2715. }