Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

createw.c File Reference

#include "precomp.h"

Go to the source code of this file.

Functions

BOOL WantImeWindow (IN PWND pwndParent, IN PWND pwnd)
PWND xxxCreateWindowEx (DWORD dwExStyle, PLARGE_STRING cczpstrClass, PLARGE_STRING cczpstrName, DWORD style, int x, int y, int cx, int cy, PWND pwndParent, PMENU pMenu, HANDLE hInstance, LPVOID lpCreateParams, DWORD dwExpWinVerAndFlags)
void SetTiledRect (PWND pwnd, LPRECT lprc, PMONITOR pMonitor)
void xxxAdjustSize (PWND pwnd, LPINT lpcx, LPINT lpcy)
void LinkWindow (PWND pwnd, PWND pwndInsert, PWND pwndParent)
BOOL xxxDestroyWindow (PWND pwnd)
void xxxDW_DestroyOwnedWindows (PWND pwndParent)
void xxxDW_SendDestroyMessages (PWND pwnd)
void xxxFW_DestroyAllChildren (PWND pwnd)
VOID UnlockNotifyWindow (PMENU pmenu)
VOID xxxFreeWindow (PWND pwnd, PTL ptlpwndFree)
VOID UnlinkWindow (PWND pwndUnlink, PWND pwndParent)
VOID DestroyCacheDCEntries (PTHREADINFO pti)
VOID PatchThreadWindows (PTHREADINFO pti)


Function Documentation

VOID DestroyCacheDCEntries PTHREADINFO  pti  ) 
 

Definition at line 2923 of file createw.c.

References tagDCE::DCX_flags, DestroyCacheDC(), gpDispInfo, tagDCE::hdc, NULL, tagDISPLAYINFO::pdceFirst, tagDCE::pdceNext, tagDCE::ptiOwner, and VOID().

Referenced by CleanupGDI(), and DestroyThreadsObjects().

02925 { 02926 PDCE *ppdce; 02927 PDCE pdce; 02928 /* 02929 * Before any window destruction occurs, we need to destroy any dcs 02930 * in use in the dc cache. When a dc is checked out, it is marked owned, 02931 * which makes gdi's process cleanup code delete it when a process 02932 * goes away. We need to similarly destroy the cache entry of any dcs 02933 * in use by the exiting process. 02934 */ 02935 for (ppdce = &gpDispInfo->pdceFirst; *ppdce != NULL; ) { 02936 02937 /* 02938 * If the dc owned by this thread, remove it from the cache. Because 02939 * DestroyCacheEntry destroys gdi objects, it is important that 02940 * USER be called first in process destruction ordering. 02941 * 02942 * Only destroy this dc if it is a cache dc, because if it is either 02943 * an owndc or a classdc, it will be destroyed for us when we destroy 02944 * the window (for owndcs) or destroy the class (for classdcs). 02945 */ 02946 pdce = *ppdce; 02947 if (pti == pdce->ptiOwner) { 02948 02949 if (pdce->DCX_flags & DCX_CACHE) 02950 DestroyCacheDC(ppdce, pdce->hdc); 02951 } 02952 02953 /* 02954 * Step to the next DC. If the DC was deleted, there 02955 * is no need to calculate address of the next entry. 02956 */ 02957 if (pdce == *ppdce) 02958 ppdce = &pdce->pdceNext; 02959 } 02960 }

void LinkWindow PWND  pwnd,
PWND  pwndInsert,
PWND  pwndParent
 

Definition at line 1478 of file createw.c.

References tagCLS::atomClassName, tagSERVERINFO::atomSysClass, CFIME, FALSE, FSwpTopmost(), gpsi, ICLS_IME, Lock, NULL, tagWND::pcls, PWND_BOTTOM, PWND_TOP, PWNDDESKTOP, PWNDMESSAGE, tagWND::spwndChild, tagWND::spwndNext, tagWND::spwndParent, TestCF, TestWF, TrackLayeredZorder(), TRUE, WEFLAYERED, WEFTOPMOST, WFBOTTOMMOST, WFDESTROYED, and WFTOGGLETOPMOST.

Referenced by ImeSetTopmost(), xxxCreateDesktop(), xxxCreateWindowEx(), xxxSetParent(), and zzzChangeStates().

01482 { 01483 if (pwndParent->spwndChild == pwnd) { 01484 RIPMSG0(RIP_WARNING, "Attempting to link a window to itself"); 01485 return; 01486 } 01487 UserAssert(pwnd != pwndInsert); 01488 UserAssert((pwnd->spwndParent == NULL) || (pwnd->spwndParent == pwndParent)); 01489 01490 if (pwndInsert == PWND_TOP) { 01491 01492 /* 01493 * We are at the top of the list. 01494 */ 01495 LinkTop: 01496 #if DBG 01497 /* 01498 * If the first child is topmost, so must be pwnd, but only for top-level windows. 01499 * 01500 * IME or IME related windows are the exceptions, because ImeSetTopmost() and its fellow 01501 * do most of the relinking by its own: when LinkWindow() is called, it's possible TOPMOST flags 01502 * are left in intermediate state. By the time the all window relinking finishes, TOPMOST 01503 * flags have been taken care of and they are just fine. 01504 */ 01505 if (pwndParent == PWNDDESKTOP(pwndParent) && 01506 pwndParent->spwndChild && 01507 FSwpTopmost(pwndParent->spwndChild) && 01508 pwndParent != PWNDMESSAGE(pwndParent) && 01509 // Check if the target is IME related window 01510 !TestCF(pwnd, CFIME) && pwnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]) { 01511 01512 /* 01513 * There are few cases that cause the z-ordering code to leave the WFTOGGLETOPMOST bit set. 01514 * One is when SWP_NOOWNERZORDER is used when changing the topmost state of a window; 01515 * in this case, ZOrderByOwner2 doesn't add ownees to the psmwp list, still SetTopMost 01516 * sets the bit on all the ownees. 01517 * Another case is when SetWindowPos gets re-entered on the same window. 01518 * It's too late to attempt to fix this ancient behavior (2/24/99) so let's turn off 01519 * the assert for now. 01520 */ 01521 if (!FSwpTopmost(pwnd)) { 01522 RIPMSG1(RIP_WARNING, "LinkWindow pwnd:%p is not FSwpTopmost", pwnd); 01523 } 01524 } 01525 #endif 01526 01527 Lock(&pwnd->spwndNext, pwndParent->spwndChild); 01528 Lock(&(pwndParent->spwndChild), pwnd); 01529 } else { 01530 if (pwndInsert == PWND_BOTTOM) { 01531 01532 /* 01533 * Find bottom-most window. 01534 */ 01535 if (((pwndInsert = pwndParent->spwndChild) == NULL) || 01536 TestWF(pwndInsert, WFBOTTOMMOST)) 01537 goto LinkTop; 01538 01539 /* 01540 * Since we know (ahem) that there's only one bottommost window, 01541 * we can't possibly insert after it. Either we're inserting 01542 * the bottomost window, in which case it's not in the linked 01543 * list currently, or we're inserting some other window. 01544 */ 01545 01546 while (pwndInsert->spwndNext != NULL) { 01547 if (TestWF(pwndInsert->spwndNext, WFBOTTOMMOST)) { 01548 #if DBG 01549 UserAssert(pwnd != pwndInsert->spwndNext); 01550 if (TestWF(pwnd, WFBOTTOMMOST)) 01551 UserAssert(FALSE); 01552 #endif 01553 break; 01554 } 01555 01556 pwndInsert = pwndInsert->spwndNext; 01557 } 01558 } 01559 01560 UserAssert(pwnd != pwndInsert); 01561 UserAssert(pwnd != pwndInsert->spwndNext); 01562 UserAssert(!TestWF(pwndInsert, WFDESTROYED)); 01563 UserAssert(!TestWF(pwnd, WEFTOPMOST) || TestWF(pwndInsert, WEFTOPMOST) || TestWF(pwnd, WFTOGGLETOPMOST) || (pwndParent != PWNDDESKTOP(pwndInsert))); 01564 UserAssert(pwnd->spwndParent == pwndInsert->spwndParent); 01565 01566 Lock(&pwnd->spwndNext, pwndInsert->spwndNext); 01567 Lock(&pwndInsert->spwndNext, pwnd); 01568 } 01569 01570 if (TestWF(pwnd, WEFLAYERED)) 01571 TrackLayeredZorder(pwnd); 01572 01573 #if DBG 01574 VerifyWindowLink (pwnd, pwndParent, TRUE); 01575 #endif 01576 01577 }

VOID PatchThreadWindows PTHREADINFO  pti  ) 
 

Definition at line 2972 of file createw.c.

References tagSHAREDINFO::aheList, _HANDLEENTRY::bFlags, _HANDLEENTRY::bType, ClrWF, FNID_WNDPROCEND, FNID_WNDPROCSTART, giheLast, gSharedInfo, HANDLEF_DESTROY, tagWND::head, tagWND::lpfnWndProc, NULL, tagDESKTOP::pDeskInfo, _HANDLEENTRY::phead, _HANDLEENTRY::pOwner, PTHROBJHEAD, tagTHREADINFO::rpdesk, SetWF, tagDESKTOPINFO::spwnd, tagDESKTOP::spwndMenu, STOCID, TYPE_WINDOW, VOID(), WFANSIPROC, WFSERVERSIDEPROC, and xxxDefWindowProc().

Referenced by xxxDestroyThreadInfo().

02974 { 02975 PHE pheT; 02976 PHE pheMax; 02977 PWND pwnd; 02978 02979 /* 02980 * First do any preparation work: windows need to be "patched" so that 02981 * their window procs point to server only windowprocs, for example. 02982 */ 02983 pheMax = &gSharedInfo.aheList[giheLast]; 02984 for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) { 02985 02986 /* 02987 * Make sure this object is a window, it hasn't been marked for 02988 * destruction, and that it is owned by this thread. 02989 */ 02990 if (pheT->bType != TYPE_WINDOW) 02991 continue; 02992 02993 if (pheT->bFlags & HANDLEF_DESTROY) 02994 continue; 02995 02996 if ((PTHREADINFO)pheT->pOwner != pti) 02997 continue; 02998 02999 /* 03000 * don't patch the shared menu window 03001 */ 03002 if (pti->rpdesk && (PHEAD)pti->rpdesk->spwndMenu == pheT->phead) { 03003 03004 ((PTHROBJHEAD)pheT->phead)->pti = pti->rpdesk->pDeskInfo->spwnd->head.pti; 03005 pheT->pOwner = pti->rpdesk->pDeskInfo->spwnd->head.pti; 03006 03007 continue; 03008 } 03009 03010 /* 03011 * Don't patch the window based on the class it was created from - 03012 * because apps can sometimes sub-class a class - make a random class, 03013 * then call ButtonWndProc with windows of that class by using 03014 * the CallWindowProc() api. So patch the wndproc based on what 03015 * wndproc this window has been calling. 03016 */ 03017 pwnd = (PWND)pheT->phead; 03018 03019 if ((pwnd->fnid >= (WORD)FNID_WNDPROCSTART) && 03020 (pwnd->fnid <= (WORD)FNID_WNDPROCEND)) { 03021 03022 pwnd->lpfnWndProc = STOCID(pwnd->fnid); 03023 03024 if (pwnd->lpfnWndProc == NULL) 03025 pwnd->lpfnWndProc = xxxDefWindowProc; 03026 03027 } else { 03028 03029 pwnd->lpfnWndProc = xxxDefWindowProc; 03030 } 03031 03032 /* 03033 * This is a server side window now... 03034 */ 03035 SetWF(pwnd, WFSERVERSIDEPROC); 03036 ClrWF(pwnd, WFANSIPROC); 03037 } 03038 }

void SetTiledRect PWND  pwnd,
LPRECT  lprc,
PMONITOR  pMonitor
 

Definition at line 1333 of file createw.c.

References tagMONITOR::cWndStack, GetRealClientRect(), GRC_MINWNDS, MultDiv, PWNDDESKTOP, and SYSMET.

Referenced by xxxCreateWindowEx().

01337 { 01338 POINT pt; 01339 RECT rcT; 01340 01341 UserAssert(pMonitor->cWndStack >= 0); 01342 01343 /* 01344 * Get available desktop area, minus minimized spacing area. 01345 */ 01346 GetRealClientRect(PWNDDESKTOP(pwnd), &rcT, GRC_MINWNDS, pMonitor); 01347 01348 /* 01349 * Normalized rectangle is 3/4 width, 3/4 height of desktop area. We 01350 * offset it based on the value of giwndStack for cascading. 01351 */ 01352 01353 /* 01354 * We want the left edge of the new window to align with the 01355 * right edge of the old window's system menu. And we want the 01356 * top edge of the new window to align with the bottom edge of the 01357 * selected caption area (caption height - cyBorder) of the old 01358 * window. 01359 */ 01360 pt.x = pMonitor->cWndStack * (SYSMET(CXSIZEFRAME) + SYSMET(CXSIZE)); 01361 pt.y = pMonitor->cWndStack * (SYSMET(CYSIZEFRAME) + SYSMET(CYSIZE)); 01362 01363 /* 01364 * If below upper top left 1/4 of free area, reset. 01365 */ 01366 if ( (pt.x > ((rcT.right-rcT.left) / 4)) || 01367 (pt.y > ((rcT.bottom-rcT.top) / 4)) ) { 01368 01369 pMonitor->cWndStack = 0; 01370 pt.x = 0; 01371 pt.y = 0; 01372 } 01373 01374 /* 01375 * Get starting position 01376 */ 01377 pt.x += rcT.left; 01378 pt.y += rcT.top; 01379 01380 lprc->left = pt.x; 01381 lprc->top = pt.y; 01382 lprc->right = pt.x + MultDiv(rcT.right-rcT.left, 3, 4); 01383 lprc->bottom = pt.y + MultDiv(rcT.bottom-rcT.top, 3, 4); 01384 01385 /* 01386 * Increment the count of stacked windows. 01387 */ 01388 pMonitor->cWndStack++; 01389 }

VOID UnlinkWindow PWND  pwndUnlink,
PWND  pwndParent
 

Definition at line 2867 of file createw.c.

References FALSE, Lock, NULL, tagWND::spwndChild, tagWND::spwndNext, tagWND::spwndParent, Unlock, and VOID().

Referenced by ImeSetTopmost(), xxxDestroyWindow(), xxxFW_DestroyAllChildren(), xxxSetParent(), and zzzChangeStates().

02870 { 02871 PWND pwnd; 02872 02873 pwnd = pwndParent->spwndChild; 02874 02875 if (pwnd == pwndUnlink) { 02876 Lock(&(pwndParent->spwndChild), pwndUnlink->spwndNext); 02877 Unlock(&pwndUnlink->spwndNext); 02878 02879 #if DBG 02880 VerifyWindowLink (pwnd, pwndParent, FALSE); 02881 #endif 02882 02883 return; 02884 } 02885 02886 while (pwnd != NULL) { 02887 UserAssert(pwnd->spwndParent == pwndParent); 02888 if (pwnd->spwndNext == pwndUnlink) { 02889 Lock(&(pwnd->spwndNext), pwndUnlink->spwndNext); 02890 Unlock(&pwndUnlink->spwndNext); 02891 02892 #if DBG 02893 VerifyWindowLink (pwnd, pwndParent, FALSE); 02894 #endif 02895 return; 02896 } 02897 02898 pwnd = pwnd->spwndNext; 02899 } 02900 02901 /* 02902 * We should never get here unless the window isn't in the list! 02903 */ 02904 RIPMSG1(RIP_WARNING, 02905 "Unlinking previously unlinked window %#p\n", 02906 pwndUnlink); 02907 02908 #if DBG 02909 VerifyWindowLink (pwnd, pwndParent, FALSE); 02910 #endif 02911 02912 return; 02913 }

VOID UnlockNotifyWindow PMENU  pmenu  ) 
 

Definition at line 2192 of file createw.c.

References tagMENU::cItems, NULL, tagMENU::rgItems, tagITEM::spSubMenu, tagMENU::spwndNotify, Unlock, and VOID().

Referenced by xxxFreeWindow().

02194 { 02195 PITEM pItem; 02196 int i; 02197 02198 /* 02199 * Go down the item list and unlock submenus. 02200 */ 02201 pItem = pmenu->rgItems; 02202 for (i = pmenu->cItems; i--; ++pItem) { 02203 02204 if (pItem->spSubMenu != NULL) 02205 UnlockNotifyWindow(pItem->spSubMenu); 02206 } 02207 02208 Unlock(&pmenu->spwndNotify); 02209 }

BOOL WantImeWindow IN PWND  pwndParent,
IN PWND  pwnd
 

Definition at line 1287 of file createw.c.

References BOOL, tagWINDOWSTATION::dwWSF_Flags, FALSE, tagWND::head, NULL, PtiCurrent, tagDESKTOP::rpwinstaParent, tagWND::spwndParent, TestWF, TIF_DISABLEIME, TRUE, WFSERVERSIDEPROC, and WSF_NOIO.

Referenced by xxxCreateWindowEx().

01288 { 01289 PDESKTOP pdesk; 01290 01291 UserAssert(pwnd); 01292 01293 if (PtiCurrent()->TIF_flags & TIF_DISABLEIME) { 01294 return FALSE; 01295 } 01296 if (TestWF(pwnd, WFSERVERSIDEPROC)) { 01297 return FALSE; 01298 } 01299 01300 pdesk = pwnd->head.rpdesk; 01301 if (pdesk == NULL || pdesk->rpwinstaParent == NULL) { 01302 return FALSE; 01303 } 01304 01305 // Check whether pwnd's desktop has I/O. 01306 if (pdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO) { 01307 return FALSE; 01308 } 01309 01310 // Check if the owner window is message-only window. 01311 if (pwndParent) { 01312 PWND pwndT = pwndParent; 01313 01314 while (pwndT && pdesk == pwndT->head.rpdesk) { 01315 if (pwndT == pdesk->spwndMessage) { 01316 return FALSE; 01317 } 01318 pwndT = pwndT->spwndParent; 01319 } 01320 } 01321 01322 return TRUE; 01323 }

void xxxAdjustSize PWND  pwnd,
LPINT  lpcx,
LPINT  lpcy
 

Definition at line 1401 of file createw.c.

References CheckLock, max, min, TestWF, TestwndTiled, WFMINIMIZED, WFSIZEBOX, and xxxInitSendValidateMinMaxInfo().

Referenced by xxxCreateWindowEx(), and xxxDefWindowProc().

01405 { 01406 POINT ptmin, 01407 ptmax; 01408 MINMAXINFO mmi; 01409 01410 CheckLock(pwnd); 01411 01412 /* 01413 * If this window is sizeable or if this window is tiled, check size 01414 */ 01415 if (TestwndTiled(pwnd) || TestWF(pwnd, WFSIZEBOX)) { 01416 01417 /* 01418 * Get size info from pwnd 01419 */ 01420 xxxInitSendValidateMinMaxInfo(pwnd, &mmi); 01421 01422 if (TestWF(pwnd, WFMINIMIZED)) { 01423 ptmin = mmi.ptReserved; 01424 ptmax = mmi.ptMaxSize; 01425 } else { 01426 ptmin = mmi.ptMinTrackSize; 01427 ptmax = mmi.ptMaxTrackSize; 01428 } 01429 01430 // 01431 // Make sure we're less than the max, and greater than the min 01432 // 01433 *lpcx = max(ptmin.x, min(*lpcx, ptmax.x)); 01434 *lpcy = max(ptmin.y, min(*lpcy, ptmax.y)); 01435 } 01436 }

PWND xxxCreateWindowEx DWORD  dwExStyle,
PLARGE_STRING  cczpstrClass,
PLARGE_STRING  cczpstrName,
DWORD  style,
int  x,
int  y,
int  cx,
int  cy,
PWND  pwndParent,
PMENU  pMenu,
HANDLE  hInstance,
LPVOID  lpCreateParams,
DWORD  dwExpWinVerAndFlags
 

Definition at line 33 of file createw.c.

References _GetDesktopWindow(), _MonitorFromWindow(), tagTHREADINFO::amdesk, ASSERT, tagCLS::atomClassName, tagSERVERINFO::atomSysClass, BOOL, _LARGE_STRING::Buffer, _LARGE_UNICODE_STRING::Buffer, CalcForegroundInsertAfter(), tagWND::cbwndExtra, CFCLASSDC, CFIME, CFNOCLOSE, CFOWNDC, CheckLock, _CLIENTINFO::CI_flags, CI_INPUTCONTEXT_REINIT, ClrWF, CopyRect, CreateCacheDC(), CREATESTRUCTEX, CSF_ANSIPROC, tagCLS::CSF_flags, CSF_SERVERSIDEPROC, tagPROCESSINFO::cThreads, CW2_USEDEFAULT, tagTHREADINFO::cWindows, tagMONITOR::cWndStack, tagSIZERECT::cx, cy, tagSIZERECT::cy, DF_DESKWNDDESTROYED, DF_DESTROYED, DF_DYING, DIALOGCLASS, tagDESKTOP::dwDTFlags, tagUSERSTARTUPINFO::dwFlags, tagPROCESSINFO::dwHotkey, DWORD, DWP_SetHotKey(), tagUSERSTARTUPINFO::dwX, tagUSERSTARTUPINFO::dwXSize, tagUSERSTARTUPINFO::dwY, tagUSERSTARTUPINFO::dwYSize, FALSE, FWINABLE, gaOleMainThreadWndClass, GetAppCompatFlags(), GetClassPtr(), GetPrimaryMonitor(), GETPTI, GetTopLevelWindow(), GETTOPMOSTINSERTAFTER, gpsi, tagTHREADINFO::hdesk, tagWND::head, tagWND::hImc, tagKL::hkl, HMAllocObject(), HMFreeObject(), tagPROCESSINFO::hMonitor, HW, HWq, ICLS_BUTTON, ICLS_COMBOBOX, ICLS_COMBOLISTBOX, ICLS_DIALOG, ICLS_EDIT, ICLS_IME, ICLS_LISTBOX, ICLS_MDICLIENT, ICLS_STATIC, Is310Compat, Is400Compat, Is500Compat, IS_IME_ENABLED, IS_PTR, IsHooked, IsWinEventNotifyDeferredOK, L, LARGE_STRING, LinkWindow(), Lock, LockWndMenu(), tagWND::lpfnWndProc, MapClientNeuterToClientPfn(), MaskWF, MINMAX_KEEPHIDDEN, NeedsWindowEdge(), NULL, NULL_HIMC, tagTHREADINFO::pClientInfo, tagWND::pcls, tagCLS::pdce, PLARGE_STRING, tagTHREADINFO::ppi, PtiCurrent, PtoH, PTR_TO_ID, PUDF_ANIMATE, PWND_BOTTOM, PWND_TOP, PWNDDESKTOP, PWNDMESSAGE, tagWND::rcClient, tagMONITOR::rcMonitor, tagWND::rcWindow, RECTFromSIZERECT(), ReferenceClass(), RETURN_IF_ACCESS_DENIED, RevalidateHwnd, tagTHREADINFO::rpdesk, RtlInitLargeAnsiString(), RtlInitUnicodeStringOrId(), SetMinimize(), SetTiledRect(), SetVisible(), SetWF, SIZERECT, SMIN_CLEAR, tagTHREADINFO::spDefaultImc, tagTHREADINFO::spklActive, tagWND::spmenu, tagTHREADINFO::spwndDefaultIme, tagWND::spwndLastActive, tagWND::spwndOwner, tagWND::spwndParent, tagWND::strName, SV_UNSET, TEST_PUDF, TestCF, TestCF2, TestWF, TestwndChild, TestwndPopup, TestwndTiled, ThreadLock, ThreadLockAlwaysWithPti, ThreadLockWithPti, ThreadUnlock, TIF_16BIT, tagTHREADINFO::TIF_flags, TIF_INCLEANUP, TRUE, TYPE_WINDOW, UINT, UserFindAtom(), tagPROCESSINFO::usi, ValidateHmonitor(), ValidateOwnerDepth(), ValidateParentDepth(), WantImeWindow(), WEFAPPWINDOW, WEFNOPARENTNOTIFY, WEFTOOLWINDOW, WEFTOPMOST, WEFWINDOWEDGE, WFALWAYSSENDNCPAINT, WFANSICREATOR, WFANSIPROC, WFBORDER, WFCAPTION, WFCHILD, WFCLIPCHILDREN, WFCLIPSIBLINGS, WFDESTROYED, WFISINITIALIZED, WFMAXIMIZED, WFMINIMIZED, WFOLDUI, WFSENDSIZEMOVE, WFSERVERSIDEPROC, WFTITLESET, WFTYPEMASK, WFVISIBLE, WFWIN31COMPAT, WFWIN40COMPAT, WFWIN50COMPAT, WHF_CBT, WNDPROC_PWND, WS_EX_ANSICREATOR, tagSIZERECT::x, xxxAdjustSize(), xxxCallHook(), xxxCheckFullScreen(), xxxClientLoadMenu(), xxxClientWOWGetProcModule(), xxxCreateClassSmIcon(), xxxCreateDefaultImeWindow(), xxxDeleteMenu(), xxxDestroyWindow(), xxxFreeWindow(), xxxGetSystemMenu(), xxxMinMaximize(), xxxSendMessage(), xxxSendSizeMessage(), xxxSetLayeredWindow(), xxxShowWindow(), xxxWindowEvent(), tagSIZERECT::y, and zzzAttachThreadInput().

Referenced by NtUserCreateWindowEx(), xxxCreateDefaultImeWindow(), xxxCreateDesktop(), xxxCreateWindowStation(), xxxCsDdeInitialize(), xxxMNOpenHierarchy(), xxxNextWindow(), xxxOldNextWindow(), and xxxTrackPopupMenuEx().

00047 { 00048 /* 00049 * The buffers for Class and Name may be client memory, and access 00050 * to those buffers must be protected. 00051 */ 00052 UINT mask = 0; 00053 BOOL fChild; 00054 BOOL fDefPos = FALSE; 00055 BOOL fStartup = FALSE; 00056 PCLS pcls; 00057 PPCLS ppcls; 00058 RECT rc; 00059 int dx, dy; 00060 SIZERECT src; 00061 int sw = SW_SHOW; 00062 PWND pwnd; 00063 PWND pwndZOrder, pwndHardError; 00064 CREATESTRUCTEX csex; 00065 PDESKTOP pdesk; 00066 ATOM atomT; 00067 PTHREADINFO ptiCurrent; 00068 TL tlpwnd; 00069 TL tlpwndParent; 00070 TL tlpwndParentT; 00071 BOOL fLockParent = FALSE; 00072 WORD wWFAnsiCreator = 0; 00073 DWORD dw; 00074 DWORD dwMinMax; 00075 PMONITOR pMonitor; 00076 BOOL fTiled; 00077 #ifdef USE_MIRRORING 00078 DWORD dwLayout; 00079 #endif 00080 00081 CheckLock(pwndParent); 00082 UserAssert(IsWinEventNotifyDeferredOK()); 00083 00084 /* 00085 * For Edit Controls (including those in comboboxes), we must know whether 00086 * the App used an ANSI or a Unicode CreateWindow call. This is passed in 00087 * with the private WS_EX_ANSICREATOR dwExStyle bit, but we MUST NOT leave 00088 * out this bit in the window's dwExStyle! Transfer to the internal window 00089 * flag WFANSICREATOR immediately. 00090 */ 00091 if (dwExStyle & WS_EX_ANSICREATOR) { 00092 wWFAnsiCreator = WFANSICREATOR; 00093 dwExStyle &= ~WS_EX_ANSICREATOR; 00094 } 00095 00096 ptiCurrent = PtiCurrent(); 00097 /* 00098 * If this thread has already been in xxxDestroyThreadInfo, then this window 00099 * is probably going to end up with a bogus pti. 00100 */ 00101 UserAssert(!(ptiCurrent->TIF_flags & TIF_INCLEANUP)); 00102 pdesk = ptiCurrent->rpdesk; 00103 00104 /* 00105 * If a parent window is specified, make sure it's on the 00106 * same desktop. 00107 */ 00108 if (pwndParent != NULL && pwndParent->head.rpdesk != pdesk) { 00109 RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, ""); 00110 return NULL; 00111 } 00112 00113 /* 00114 * Set a flag to indicate whther a it is a child window 00115 */ 00116 fChild = ((HIWORD(style) & MaskWF(WFTYPEMASK)) == MaskWF(WFCHILD)); 00117 00118 #ifdef USE_MIRRORING 00119 /* 00120 00121 00122 The WS_EX_LAYOUT_RTL flag is set if, 00123 00124 1- WS_EX_LAYOUT_RTL set in dwExStyle parameter of the CreateWindow call. 00125 2- If the window is created from DialogBox class, then it can't inherit from its parent 00126 and it has to specify WS_EX_LAYOUTRTL explicitly to enable mirroring on it. 00127 3- If the window is an owned window then the window is left to right layout and the algorithm terminates. 00128 (An owned window is one created with an HWND passed in the hWndParent paremeter to CreateWindow(Ex), 00129 but without the WS_CHILD flag present in it's styles. 00130 4- If the window is a child window, and it's parent is right to left layout, 00131 and it's parent does not have the WS_EX_NOINHERIT_LAYOUT flag set in it's extended styles, 00132 then the window is right to left layout and the algorithm terminates. 00133 5- If the hWndParent parameter to Createwindow(Ex) was NULL, and the process calling CreateWindow(Ex) has called 00134 SetProcessDefaultLayout(LAYOUT_RTL), then the window is right to left layout and the algorithm terminates. 00135 6- In all other cases, the layout is left to right. 00136 */ 00137 00138 if (!(dwExStyle & WS_EX_LAYOUTRTL)) { 00139 if (pwndParent != NULL) { 00140 if (fChild && TestWF(pwndParent, WEFLAYOUTRTL) && !TestWF(pwndParent, WEFNOINHERITLAYOUT)) { 00141 dwExStyle |= WS_EX_LAYOUTRTL; 00142 } 00143 } else if (!(!IS_PTR(cczpstrClass) && (PTR_TO_ID(cczpstrClass) == PTR_TO_ID(DIALOGCLASS)))) { 00144 if ((_GetProcessDefaultLayout(&dwLayout)) && (dwLayout & LAYOUT_RTL)) { 00145 dwExStyle |= WS_EX_LAYOUTRTL; 00146 } 00147 } 00148 } 00149 #endif 00150 /* 00151 * Ensure that we can create the window. If there is no desktop 00152 * yet, assume that this will be the root desktop window and allow 00153 * the creation. 00154 */ 00155 if (ptiCurrent->hdesk) { 00156 RETURN_IF_ACCESS_DENIED( 00157 ptiCurrent->amdesk, DESKTOP_CREATEWINDOW, NULL); 00158 } 00159 00160 if (fChild) { 00161 00162 /* 00163 * Don't allow child windows without a parent handle. 00164 */ 00165 if (pwndParent == NULL) { 00166 RIPERR0(ERROR_TLW_WITH_WSCHILD, RIP_VERBOSE, ""); 00167 return NULL; 00168 } 00169 00170 if (!ValidateParentDepth(NULL, pwndParent)) { 00171 RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Exceeded nested children limit"); 00172 return NULL; 00173 } 00174 } 00175 00176 /* 00177 * Make sure we can get the window class. 00178 */ 00179 if (IS_PTR(cczpstrClass)) { 00180 /* 00181 * UserFindAtom protects access of the string. 00182 */ 00183 atomT = UserFindAtom(cczpstrClass->Buffer); 00184 } else 00185 atomT = PTR_TO_ID(cczpstrClass); 00186 00187 if (atomT == 0) { 00188 CantFindClassMessageAndFail: 00189 #if DBG 00190 if (IS_PTR(cczpstrClass)) { 00191 try { 00192 RIPMSG1(RIP_WARNING, 00193 "Couldn't find class string %ws", 00194 cczpstrClass->Buffer); 00195 00196 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00197 } 00198 } else { 00199 RIPMSG1(RIP_WARNING, 00200 "Couldn't find class atom %lx", 00201 cczpstrClass); 00202 } 00203 #endif 00204 00205 RIPERR0(ERROR_CANNOT_FIND_WND_CLASS, RIP_VERBOSE, ""); 00206 return NULL; 00207 } 00208 00209 /* 00210 * First scan the private classes. If we don't find the class there 00211 * scan the public classes. If we don't find it there, fail. 00212 */ 00213 ppcls = GetClassPtr(atomT, ptiCurrent->ppi, hInstance); 00214 if (ppcls == NULL) { 00215 goto CantFindClassMessageAndFail; 00216 } 00217 00218 pcls = *ppcls; 00219 00220 if (NeedsWindowEdge(style, dwExStyle, Is400Compat(dwExpWinVerAndFlags))) { 00221 dwExStyle |= WS_EX_WINDOWEDGE; 00222 } else { 00223 dwExStyle &= ~WS_EX_WINDOWEDGE; 00224 } 00225 00226 /* 00227 * Allocate memory for regular windows. 00228 */ 00229 pwnd = HMAllocObject( 00230 ptiCurrent, pdesk, TYPE_WINDOW, sizeof(WND) + pcls->cbwndExtra); 00231 00232 if (pwnd == NULL) { 00233 RIPERR0(ERROR_OUTOFMEMORY, 00234 RIP_WARNING, 00235 "Out of pool in xxxCreateWindowEx"); 00236 00237 return NULL; 00238 } 00239 00240 /* 00241 * Stuff in the pq, class pointer, and window style. 00242 */ 00243 pwnd->pcls = pcls; 00244 pwnd->style = style & ~WS_VISIBLE; 00245 #ifdef REDIRECTION 00246 pwnd->ExStyle = dwExStyle & ~(WS_EX_LAYERED | WS_EX_REDIRECTED); 00247 #else 00248 pwnd->ExStyle = dwExStyle & ~WS_EX_LAYERED; 00249 #endif // REDIRECTION 00250 pwnd->cbwndExtra = pcls->cbwndExtra; 00251 00252 00253 /* 00254 * Increment the Window Reference Count in the Class structure 00255 * Because xxxFreeWindow() decrements the count, incrementing has 00256 * to be done now. Incase of error, xxxFreeWindow() will decrement it. 00257 */ 00258 if (!ReferenceClass(pcls, pwnd)) { 00259 HMFreeObject(pwnd); 00260 goto CantFindClassMessageAndFail; 00261 } 00262 00263 /* 00264 * Button control doesn't need input context. Other windows 00265 * will associate with the default input context. 00266 */ 00267 if (atomT == gpsi->atomSysClass[ICLS_BUTTON]) { 00268 pwnd->hImc = NULL_HIMC; 00269 } else { 00270 pwnd->hImc = (HIMC)PtoH(ptiCurrent->spDefaultImc); 00271 } 00272 00273 /* 00274 * Update the window count. Doing this now will ensure that if 00275 * the creation fails, xxxFreeWindow will keep the window count 00276 * correct. 00277 */ 00278 ptiCurrent->cWindows++; 00279 00280 /* 00281 * Get the class from the window because ReferenceClass may have 00282 * cloned the class. 00283 */ 00284 pcls = pwnd->pcls; 00285 00286 /* 00287 * This is a replacement for the &lpCreateParams stuff that used to 00288 * pass a pointer directly to the parameters on the stack. This 00289 * step must be done AFTER referencing the class because we 00290 * may use the ANSI class name. 00291 */ 00292 RtlZeroMemory(&csex, sizeof(csex)); 00293 csex.cs.dwExStyle = dwExStyle; 00294 csex.cs.hInstance = hInstance; 00295 00296 if (!IS_PTR(cczpstrClass)) { 00297 csex.cs.lpszClass = (LPWSTR)cczpstrClass; 00298 } else { 00299 if (wWFAnsiCreator) { 00300 csex.cs.lpszClass = (LPWSTR)pcls->lpszAnsiClassName; 00301 if (IS_PTR(csex.cs.lpszClass)) { 00302 RtlInitLargeAnsiString( 00303 (PLARGE_ANSI_STRING)&csex.strClass, 00304 (LPSTR)csex.cs.lpszClass, 00305 (UINT)-1); 00306 } 00307 } else { 00308 csex.cs.lpszClass = cczpstrClass->Buffer; 00309 csex.strClass = *cczpstrClass; 00310 } 00311 } 00312 00313 if (cczpstrName != NULL) { 00314 csex.cs.lpszName = cczpstrName->Buffer; 00315 csex.strName = *cczpstrName; 00316 } 00317 csex.cs.style = style; 00318 csex.cs.x = x; 00319 csex.cs.y = y; 00320 csex.cs.cx = cx; 00321 csex.cs.cy = cy; 00322 csex.cs.hwndParent = HW(pwndParent); 00323 00324 /* 00325 * If pMenu is non-NULL and the window is not a child, pMenu must 00326 * be a menu. 00327 * Child windows get their UIState bits from their parent. Top level ones 00328 * remain with the default cleared bits. 00329 * 00330 * The below test is equivalent to TestwndChild(). 00331 */ 00332 if (fChild) { 00333 csex.cs.hMenu = (HMENU)pMenu; 00334 00335 pwnd->ExStyle |= pwndParent->ExStyle & (WS_EXP_FOCUSHIDDEN | WS_EXP_ACCELHIDDEN); 00336 #if WS_EXP_ACCELHIDDEN != 0x40000000 00337 #error Fix UISTATE bits copying if you moved the UISTATE bits from ExStyle 00338 #endif 00339 00340 } else { 00341 csex.cs.hMenu = PtoH(pMenu); 00342 } 00343 00344 csex.cs.lpCreateParams = lpCreateParams; 00345 00346 /* 00347 * ThreadLock: we are going to be doing multiple callbacks here. 00348 */ 00349 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd); 00350 00351 /* 00352 * set the parent to be the desktop window (if exists) 00353 * before any callback. This way we'll always have a 00354 * pointer on spwndParent 00355 */ 00356 if (pwnd->head.rpdesk) { 00357 Lock(&(pwnd->spwndParent), PWNDMESSAGE(pwnd)); 00358 } 00359 00360 /* 00361 * Create the class small icon if there isn't one since we are in context 00362 * and we are creating a window from this class... 00363 */ 00364 if (pcls->spicn && !pcls->spicnSm) { 00365 xxxCreateClassSmIcon(pcls); 00366 } 00367 00368 /* 00369 * Store the instance handle and window proc address. We do this earlier 00370 * than Windows because they have a bug were a message can be sent 00371 * but lpfnWndProc is not set (3986 CBT WM_CREATE not allowed.) 00372 */ 00373 pwnd->hModule = hInstance; 00374 00375 /* 00376 * Get rid of EditWndProc plain. 00377 */ 00378 pwnd->lpfnWndProc = (WNDPROC_PWND)MapClientNeuterToClientPfn(pcls, 0, wWFAnsiCreator); 00379 00380 /* 00381 * If this window class has a server-side window procedure, mark 00382 * it as such. If the app subclasses it later with an app-side proc 00383 * then this mark will be removed. 00384 */ 00385 if (pcls->CSF_flags & CSF_SERVERSIDEPROC) { 00386 SetWF(pwnd, WFSERVERSIDEPROC); 00387 UserAssert(!(pcls->CSF_flags & CSF_ANSIPROC)); 00388 } 00389 00390 /* 00391 * If this window was created with an ANSI CreateWindow*() call, mark 00392 * it as such so edit controls will be created correctly. (A combobox 00393 * will be able to pass the WFANSICREATOR bit on to its edit control) 00394 */ 00395 SetWF(pwnd, wWFAnsiCreator); 00396 00397 /* 00398 * If this window belongs to an ANSI class or it is a WFANSICREATOR 00399 * control, then mark it as an ANSI window 00400 */ 00401 if ((pcls->CSF_flags & CSF_ANSIPROC) || 00402 (wWFAnsiCreator && 00403 ((atomT == gpsi->atomSysClass[ICLS_BUTTON]) || 00404 (atomT == gpsi->atomSysClass[ICLS_COMBOBOX]) || 00405 (atomT == gpsi->atomSysClass[ICLS_COMBOLISTBOX]) || 00406 (atomT == gpsi->atomSysClass[ICLS_DIALOG]) || 00407 (atomT == gpsi->atomSysClass[ICLS_EDIT]) || 00408 (atomT == gpsi->atomSysClass[ICLS_LISTBOX]) || 00409 (atomT == gpsi->atomSysClass[ICLS_MDICLIENT]) || 00410 (atomT == gpsi->atomSysClass[ICLS_IME]) || 00411 (atomT == gpsi->atomSysClass[ICLS_STATIC])))) { 00412 SetWF(pwnd, WFANSIPROC); 00413 } 00414 00415 /* 00416 * If a 3.1-compatible application is creating the window, set this 00417 * bit to enable various backward-compatibility hacks. 00418 * 00419 * If it's not 3.1 compatible, see if we need to turn on the PixieHack 00420 * (see wmupdate.c for more info on this) 00421 */ 00422 00423 dw = GetAppCompatFlags(ptiCurrent); 00424 00425 if (dw & GACF_RANDOM3XUI) { 00426 SetWF(pwnd, WFOLDUI); 00427 00428 dwExStyle &= 0x0000003f; 00429 csex.cs.dwExStyle &= 0x0000003f; 00430 } 00431 00432 pwnd->hMod16 = ((ptiCurrent->TIF_flags & TIF_16BIT) && !TestWF(pwnd, WFSERVERSIDEPROC))? xxxClientWOWGetProcModule(pwnd->lpfnWndProc):0; 00433 if (Is310Compat(dwExpWinVerAndFlags)) { 00434 SetWF(pwnd, WFWIN31COMPAT); 00435 if (Is400Compat(dwExpWinVerAndFlags)) { 00436 SetWF(pwnd, WFWIN40COMPAT); 00437 if (Is500Compat(dwExpWinVerAndFlags)) { 00438 SetWF(pwnd, WFWIN50COMPAT); 00439 } 00440 } 00441 } else if (dw & GACF_ALWAYSSENDNCPAINT) { 00442 SetWF(pwnd, WFALWAYSSENDNCPAINT); 00443 } 00444 00445 /* 00446 * Inform the CBT hook that a window is being created. Pass it the 00447 * CreateParams and the window handle that the new one will be inserted 00448 * after. The CBT hook handler returns TRUE to prevent the window 00449 * from being created. It can also modify the CREATESTRUCT info, which 00450 * will affect the size, parent, and position of the window. 00451 * Defaultly position non-child windows at the top of their list. 00452 */ 00453 00454 if (IsHooked(ptiCurrent, WHF_CBT)) { 00455 CBT_CREATEWND cbt; 00456 00457 /* 00458 * Use the extended createstruct so the hook thunk can 00459 * handle the strings correctly. 00460 */ 00461 cbt.lpcs = (LPCREATESTRUCT)&csex; 00462 cbt.hwndInsertAfter = HWND_TOP; 00463 00464 if ((BOOL)xxxCallHook(HCBT_CREATEWND, (WPARAM)HWq(pwnd), 00465 (LPARAM)&cbt, WH_CBT)) { 00466 00467 goto MemError; 00468 } else { 00469 /* 00470 * The CreateHook may have modified some parameters so write them 00471 * out (in Windows 3.1 we used to write directly to the variables 00472 * on the stack). 00473 */ 00474 00475 x = csex.cs.x; 00476 y = csex.cs.y; 00477 cx = csex.cs.cx; 00478 cy = csex.cs.cy; 00479 00480 if (!IS_PTR(cbt.hwndInsertAfter)) 00481 pwndZOrder = (PWND)cbt.hwndInsertAfter; 00482 else 00483 pwndZOrder = RevalidateHwnd(cbt.hwndInsertAfter); 00484 } 00485 } else { 00486 pwndZOrder = (PWND)HWND_TOP; 00487 } 00488 00489 if (!(fTiled = TestwndTiled(pwnd))) { 00490 00491 /* 00492 * CW_USEDEFAULT is only valid for tiled and overlapped windows. 00493 * Don't let it be used. 00494 */ 00495 if (x == CW_USEDEFAULT || x == CW2_USEDEFAULT) { 00496 x = 0; 00497 y = 0; 00498 } 00499 00500 if (cx == CW_USEDEFAULT || cx == CW2_USEDEFAULT) { 00501 cx = 0; 00502 cy = 0; 00503 } 00504 } 00505 00506 /* 00507 * Make local copies of these parameters. 00508 */ 00509 src.x = x; 00510 src.y = y; 00511 src.cx = cx; 00512 src.cy = cy; 00513 00514 /* 00515 * Position Child Windows 00516 */ 00517 if (fChild = (BOOL)TestwndChild(pwnd)) { 00518 00519 /* 00520 * Child windows are offset from the parent's origin. 00521 */ 00522 UserAssert(pwndParent); 00523 if (pwndParent != PWNDDESKTOP(pwnd)) { 00524 src.x += pwndParent->rcClient.left; 00525 src.y += pwndParent->rcClient.top; 00526 } 00527 00528 /* 00529 * Defaultly position child windows at bottom of their list. 00530 */ 00531 pwndZOrder = PWND_BOTTOM; 00532 } 00533 00534 /* 00535 * Position Tiled Windows 00536 */ 00537 00538 /* 00539 * Is this a Tiled/Overlapping window? 00540 */ 00541 if (fTiled) { 00542 00543 /* 00544 * Force the WS_CLIPSIBLINGS window style and add a caption and 00545 * a border. 00546 */ 00547 SetWF(pwnd, WFCLIPSIBLINGS); 00548 mask = MaskWF(WFCAPTION) | MaskWF(WFBORDER); 00549 00550 // 00551 // We add on a raised edge since IF the person had passed in WS_CAPTION, 00552 // and didn't specify any 3D borders, we would've added it on to the 00553 // style bits above. 00554 // 00555 00556 if (TestWF(pwnd, WFWIN40COMPAT)) { 00557 // if (!TestWF(pwnd, WEFEDGEMASK)) 00558 SetWF(pwnd, WEFWINDOWEDGE); 00559 } 00560 00561 /* 00562 * Set bit that will force size message to be sent at SHOW time. 00563 */ 00564 SetWF(pwnd, WFSENDSIZEMOVE); 00565 00566 /* 00567 * Here is how the "tiled" window initial positioning works... 00568 * If the app is a 1.0x app, then we use our standard "stair step" 00569 * default positioning scheme. Otherwise, we check the x & cx 00570 * parameters. If either of these == CW_USEDEFAULT then use the 00571 * default position/size, otherwise use the position/size they 00572 * specified. If not using default position, use SW_SHOW for the 00573 * xxxShowWindow() parameter, otherwise use the y parameter given. 00574 * 00575 * In 32-bit world, CW_USEDEFAULT is 0x80000000, but apps still 00576 * store word-oriented values either in dialog templates or 00577 * in their own structures. So CreateWindow still recognizes the 00578 * 16 bit equivalent, which is 0x8000, CW2_USEDEFAULT. The original 00579 * is changed because parameters to CreateWindow() are 32 bit 00580 * values, which can cause sign extention, or weird results if 00581 * 16 bit math assumptions are being made, etc. 00582 */ 00583 00584 /* 00585 * Default to passing the y parameter to xxxShowWindow(). 00586 */ 00587 if (x == CW_USEDEFAULT || x == CW2_USEDEFAULT) { 00588 00589 /* 00590 * If the y value is not CW_USEDEFAULT, use it as a SW_* command. 00591 */ 00592 if (src.y != CW_USEDEFAULT && src.y != CW2_USEDEFAULT) { 00593 sw = src.y; 00594 } 00595 } 00596 00597 00598 /* 00599 * Allow the shell to tell us what monitor to run this app on 00600 */ 00601 pMonitor = NULL; 00602 if ( x == CW_USEDEFAULT || 00603 x == CW2_USEDEFAULT || 00604 cx == CW_USEDEFAULT || 00605 cx == CW2_USEDEFAULT) { 00606 00607 if (ptiCurrent->ppi->hMonitor) { 00608 pMonitor = ValidateHmonitor(ptiCurrent->ppi->hMonitor); 00609 } else if (pwndParent) { 00610 pMonitor = _MonitorFromWindow(pwndParent, MONITOR_DEFAULTTONEAREST); 00611 } 00612 } 00613 00614 if (!pMonitor) { 00615 pMonitor = GetPrimaryMonitor(); 00616 } 00617 00618 SetTiledRect(pwnd, &rc, pMonitor); 00619 00620 /* 00621 * Did the app ask for default positioning? 00622 */ 00623 if (x == CW_USEDEFAULT || x == CW2_USEDEFAULT) { 00624 00625 /* 00626 * Use default positioning. 00627 */ 00628 if (ptiCurrent->ppi->usi.dwFlags & STARTF_USEPOSITION ) { 00629 fStartup = TRUE; 00630 x = src.x = ptiCurrent->ppi->usi.dwX; 00631 y = src.y = ptiCurrent->ppi->usi.dwY; 00632 } else { 00633 x = src.x = rc.left; 00634 y = src.y = rc.top; 00635 } 00636 fDefPos = TRUE; 00637 00638 } else { 00639 00640 /* 00641 * Use the apps specified positioning. Undo the "stacking" 00642 * effect caused by SetTiledRect(). 00643 */ 00644 if (pMonitor->cWndStack) { 00645 pMonitor->cWndStack--; 00646 } 00647 } 00648 00649 /* 00650 * Did the app ask for default sizing? 00651 */ 00652 if (src.cx == CW_USEDEFAULT || src.cx == CW2_USEDEFAULT) { 00653 00654 /* 00655 * Use default sizing. 00656 */ 00657 if (ptiCurrent->ppi->usi.dwFlags & STARTF_USESIZE) { 00658 fStartup = TRUE; 00659 src.cx = ptiCurrent->ppi->usi.dwXSize; 00660 src.cy = ptiCurrent->ppi->usi.dwYSize; 00661 } else { 00662 src.cx = rc.right - x; 00663 src.cy = rc.bottom - y; 00664 } 00665 fDefPos = TRUE; 00666 00667 } else if (fDefPos) { 00668 /* 00669 * The app wants default positioning but not default sizing. 00670 * Make sure that it's still entirely visible by moving the 00671 * window. 00672 */ 00673 dx = (src.x + src.cx) - pMonitor->rcMonitor.right; 00674 dy = (src.y + src.cy) - pMonitor->rcMonitor.bottom; 00675 if (dx > 0) { 00676 x -= dx; 00677 src.x = x; 00678 if (src.x < pMonitor->rcMonitor.left) { 00679 src.x = x = pMonitor->rcMonitor.left; 00680 } 00681 } 00682 00683 if (dy > 0) { 00684 y -= dy; 00685 src.y = y; 00686 if (src.y < pMonitor->rcMonitor.top) { 00687 src.y = y = pMonitor->rcMonitor.top; 00688 } 00689 } 00690 } 00691 } 00692 00693 /* 00694 * If we have used any startup postitions, turn off the startup 00695 * info so we don't use it again. 00696 */ 00697 if (fStartup) { 00698 ptiCurrent->ppi->usi.dwFlags &= 00699 ~(STARTF_USESIZE | STARTF_USEPOSITION); 00700 } 00701 00702 /* 00703 * Position Popup Windows 00704 */ 00705 00706 if (TestwndPopup(pwnd)) { 00707 // LATER: Why is this test necessary? Can one create a popup desktop? 00708 if (pwnd != _GetDesktopWindow()) { 00709 00710 /* 00711 * Force the clipsiblings/overlap style. 00712 */ 00713 SetWF(pwnd, WFCLIPSIBLINGS); 00714 } 00715 } 00716 00717 /* 00718 * Shove in those default style bits. 00719 */ 00720 *(((WORD *)&pwnd->style) + 1) |= mask; 00721 00722 /* 00723 * Menu/SysMenu Stuff 00724 */ 00725 00726 /* 00727 * If there is no menu handle given and it's not a child window but 00728 * there is a class menu, use the class menu. 00729 */ 00730 if (pMenu == NULL && !fChild && (pcls->lpszMenuName != NULL)) { 00731 UNICODE_STRING strMenuName; 00732 00733 RtlInitUnicodeStringOrId(&strMenuName, pcls->lpszMenuName); 00734 pMenu = xxxClientLoadMenu(pcls->hModule, &strMenuName); 00735 csex.cs.hMenu = PtoH(pMenu); 00736 00737 /* 00738 * This load fails if the caller does not have DESKTOP_CREATEMENU 00739 * permission but that's ok they will just get a window without a menu 00740 */ 00741 } 00742 00743 /* 00744 * Store the menu handle. 00745 */ 00746 if (TestwndChild(pwnd)) { 00747 00748 /* 00749 * It's an id in this case. 00750 */ 00751 pwnd->spmenu = pMenu; 00752 } else { 00753 00754 /* 00755 * It's a real handle in this case. 00756 */ 00757 LockWndMenu(pwnd, &pwnd->spmenu, pMenu); 00758 } 00759 00760 // LATER does this work? 00761 /* 00762 * Delete the Close menu item if directed. 00763 */ 00764 if (TestCF(pwnd, CFNOCLOSE)) { 00765 00766 /* 00767 * Do this by position since the separator does not have an ID. 00768 */ 00769 // LATER mikeke why is xxxGetSystemMenu() returning NULL? 00770 pMenu = xxxGetSystemMenu(pwnd, FALSE); 00771 if (pMenu != NULL) { 00772 TL tlpMenu; 00773 00774 ThreadLock(pMenu, &tlpMenu); 00775 xxxDeleteMenu(pMenu, 5, MF_BYPOSITION); 00776 xxxDeleteMenu(pMenu, 5, MF_BYPOSITION); 00777 ThreadUnlock(&tlpMenu); 00778 } 00779 } 00780 00781 /* 00782 * Parent/Owner Stuff 00783 */ 00784 00785 /* 00786 * If this isn't a child window, reset the Owner/Parent info. 00787 */ 00788 if (!fChild) { 00789 Lock(&(pwnd->spwndLastActive), pwnd); 00790 if ((pwndParent != NULL) && 00791 (pwndParent != pwndParent->head.rpdesk->spwndMessage) && 00792 (pwndParent != pwndParent->head.rpdesk->pDeskInfo->spwnd)) { 00793 00794 PWND pwndOwner = GetTopLevelWindow(pwndParent); 00795 00796 if (!ValidateOwnerDepth(pwnd, pwndOwner)) { 00797 RIPERR1(ERROR_INVALID_PARAMETER, 00798 RIP_WARNING, 00799 "Exceeded nested owner limit for pwnd %#p", 00800 pwnd); 00801 goto MemError; 00802 } 00803 00804 #if DBG 00805 if (pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) { 00806 UserAssert(!TestCF(pwndOwner, CFIME)); 00807 } 00808 #endif 00809 Lock(&(pwnd->spwndOwner), pwndOwner); 00810 if (pwnd->spwndOwner && TestWF(pwnd->spwndOwner, WEFTOPMOST)) { 00811 00812 /* 00813 * If this window's owner is a topmost window, then it has to 00814 * be one also since a window must be above its owner. 00815 */ 00816 SetWF(pwnd, WEFTOPMOST); 00817 } 00818 00819 /* 00820 * If this is a owner window on another thread, share input 00821 * state so this window gets z-ordered correctly. 00822 */ 00823 if (atomT != gpsi->atomSysClass[ICLS_IME] && 00824 pwnd->spwndOwner != NULL && 00825 GETPTI(pwnd->spwndOwner) != ptiCurrent) { 00826 /* 00827 * No need to DeferWinEventNotify() here: pwnd and pwndParent 00828 * are locked and because we called ReferenceClass(pcls, pwnd), 00829 * pcls is safe until xxxFreeWindow(pwnd). (IanJa) 00830 */ 00831 zzzAttachThreadInput(ptiCurrent, GETPTI(pwnd->spwndOwner), TRUE); 00832 } 00833 00834 } else { 00835 pwnd->spwndOwner = NULL; 00836 } 00837 00838 #if DBG 00839 if (ptiCurrent->rpdesk != NULL) { 00840 UserAssert(!(ptiCurrent->rpdesk->dwDTFlags & (DF_DESTROYED | DF_DESKWNDDESTROYED | DF_DYING))); 00841 } 00842 #endif 00843 if ((pwndParent == NULL) || 00844 (pwndParent != pwndParent->head.rpdesk->spwndMessage)) { 00845 pwndParent = _GetDesktopWindow(); 00846 00847 ThreadLockWithPti(ptiCurrent, pwndParent, &tlpwndParent); 00848 fLockParent = TRUE; 00849 } 00850 } 00851 00852 /* 00853 * Store backpointer to parent. 00854 */ 00855 Lock(&(pwnd->spwndParent), pwndParent); 00856 00857 /* 00858 * Final Window Positioning 00859 */ 00860 00861 if (!TestWF(pwnd, WFWIN31COMPAT)) { 00862 /* 00863 * BACKWARD COMPATIBILITY HACK 00864 * 00865 * In 3.0, CS_PARENTDC overrides WS_CLIPCHILDREN and WS_CLIPSIBLINGS, 00866 * but only if the parent is not WS_CLIPCHILDREN. 00867 * This behavior is required by PowerPoint and Charisma, among others. 00868 */ 00869 if ((pcls->style & CS_PARENTDC) && 00870 !TestWF(pwndParent, WFCLIPCHILDREN)) { 00871 #if DBG 00872 if (TestWF(pwnd, WFCLIPCHILDREN)) 00873 RIPMSG0(RIP_WARNING, "WS_CLIPCHILDREN overridden by CS_PARENTDC"); 00874 if (TestWF(pwnd, WFCLIPSIBLINGS)) 00875 RIPMSG0(RIP_WARNING, "WS_CLIPSIBLINGS overridden by CS_PARENTDC"); 00876 #endif 00877 ClrWF(pwnd, (WFCLIPCHILDREN | WFCLIPSIBLINGS)); 00878 } 00879 } 00880 00881 /* 00882 * If this is a child window being created in a parent window 00883 * of a different thread, but not on the desktop, attach their 00884 * input streams together. [windows with WS_CHILD can be created 00885 * on the desktop, that's why we check both the style bits 00886 * and the parent window.] 00887 */ 00888 if (TestwndChild(pwnd) && (pwndParent != PWNDDESKTOP(pwnd)) && 00889 (ptiCurrent != GETPTI(pwndParent))) { 00890 /* 00891 * No need to DeferWinEventNotify() - there is an xxx call just below 00892 */ 00893 zzzAttachThreadInput(ptiCurrent, GETPTI(pwndParent), TRUE); 00894 } 00895 00896 /* 00897 * Make sure the window is between the minimum and maximum sizes. 00898 */ 00899 00900 /* 00901 * HACK ALERT! 00902 * This sends WM_GETMINMAXINFO to a (tiled or sizable) window before 00903 * it has been created (before it is sent WM_NCCREATE). 00904 * Maybe some app expects this, so we nustn't reorder the messages. 00905 */ 00906 xxxAdjustSize(pwnd, &src.cx, &src.cy); 00907 00908 /* 00909 * check for a window being created full screen 00910 * 00911 * Note the check for a non-NULL pdeskParent -- this is important for CreateWindowStation 00912 */ 00913 if ( pwnd->head.rpdesk != NULL && 00914 !TestWF(pwnd, WFCHILD) && 00915 !TestWF(pwnd, WEFTOOLWINDOW)) { 00916 00917 xxxCheckFullScreen(pwnd, &src); 00918 } 00919 00920 if (src.cx < 0) { 00921 RIPMSG1(RIP_WARNING, "xxxCreateWindowEx: adjusted cx in pwnd %#p", pwnd); 00922 src.cx = 0; 00923 } 00924 00925 if (src.cy < 0) { 00926 RIPMSG1(RIP_WARNING, "xxxCreateWindowEx: adjusted cy in pwnd %#p", pwnd); 00927 src.cy = 0; 00928 } 00929 00930 /* 00931 * Calculate final window dimensions... 00932 */ 00933 RECTFromSIZERECT(&pwnd->rcWindow, &src); 00934 00935 if (dwExStyle & WS_EX_LAYERED) { 00936 if (!xxxSetLayeredWindow(pwnd, FALSE)) { 00937 goto MemError; 00938 } 00939 } 00940 00941 #ifdef REDIRECTION 00942 if (dwExStyle & WS_EX_REDIRECTED) { 00943 if (!SetRedirectedWindow(pwnd)) { 00944 goto MemError; 00945 } 00946 } 00947 #endif // REDIRECTION 00948 00949 if (TestCF2(pcls, CFOWNDC) || 00950 (TestCF2(pcls, CFCLASSDC) && pcls->pdce == NULL)) { 00951 if (NULL == CreateCacheDC(pwnd, DCX_OWNDC, NULL)) { 00952 00953 RIPMSG1(RIP_WARNING, "xxxCreateWindowEx: pwnd %#p failed to create cached DC", 00954 pwnd); 00955 00956 goto MemError; 00957 } 00958 } 00959 00960 /* 00961 * Update the create struct now that we've modified some passed in 00962 * parameters. 00963 */ 00964 csex.cs.x = x; 00965 csex.cs.y = y; 00966 csex.cs.cx = cx; 00967 csex.cs.cy = cy; 00968 00969 /* 00970 * Send a NCCREATE message to the window. 00971 */ 00972 if (!xxxSendMessage(pwnd, WM_NCCREATE, 0L, (LPARAM)&csex)) { 00973 00974 MemError: 00975 00976 #if DBG 00977 if (!IS_PTR(cczpstrClass)) { 00978 RIPMSG2(RIP_WARNING, 00979 (pwndParent) ? 00980 "xxxCreateWindowEx failed, Class=%#.4x, ID=%d" : 00981 "xxxCreateWindowEx failed, Class=%#.4x", 00982 PTR_TO_ID(cczpstrClass), 00983 (LONG_PTR) pMenu); 00984 } else { 00985 RIPMSG2(RIP_WARNING, 00986 (pwndParent) ? 00987 "xxxCreateWindowEx failed, Class=\"%s\", ID=%d" : 00988 "xxxCreateWindowEx failed, Class=\"%s\"", 00989 pcls->lpszAnsiClassName, 00990 (LONG_PTR) pMenu); 00991 } 00992 #endif 00993 00994 if (fLockParent) 00995 ThreadUnlock(&tlpwndParent); 00996 00997 /* 00998 * Set the state as destroyed so any z-ordering events will be ignored. 00999 * We cannot NULL out the owner field until WM_NCDESTROY is send or 01000 * apps like Rumba fault (they call GetParent after every message) 01001 */ 01002 SetWF(pwnd, WFDESTROYED); 01003 01004 /* 01005 * Unset the visible flag so we don't think in xxxDestroyWindow that 01006 * this window is visible 01007 */ 01008 if (TestWF(pwnd, WFVISIBLE)) { 01009 SetVisible(pwnd, SV_UNSET); 01010 } 01011 01012 /* 01013 * FreeWindow performs a ThreadUnlock. 01014 */ 01015 xxxFreeWindow(pwnd, &tlpwnd); 01016 01017 return NULL; 01018 } 01019 01020 /* 01021 * WM_NCCREATE processing may have changed the window text. Change 01022 * the CREATESTRUCT to point to the real window text. 01023 * 01024 * MSMoney needs this because it clears the window and we need to 01025 * reflect the new name back into the cs structure. 01026 * A better thing to do would be to have a pointer to the CREATESTRUCT 01027 * within the window itself so that DefWindowProc can change the 01028 * the window name in the CREATESTRUCT to point to the real name and 01029 * this funky check is no longer needed. 01030 * 01031 * DefSetText converts a pointer to NULL to a NULL title so 01032 * we don't want to over-write cs.lpszName if it was a pointer to 01033 * a NULL string and pName is NULL. Approach Database for Windows creates 01034 * windows with a pointer to NULL and then accesses the pointer later 01035 * during WM_CREATE 01036 */ 01037 if (TestWF(pwnd, WFTITLESET)) 01038 if (!(csex.strName.Buffer != NULL && csex.strName.Length == 0 && 01039 pwnd->strName.Buffer == NULL)) { 01040 csex.cs.lpszName = pwnd->strName.Buffer; 01041 RtlCopyMemory(&csex.strName, &pwnd->strName, sizeof(LARGE_STRING)); 01042 } 01043 01044 /* 01045 * The Window is now officially "created." Change the relevant global 01046 * stuff. 01047 */ 01048 01049 01050 /* 01051 * Create per thread default IME window. 01052 */ 01053 if (IS_IME_ENABLED() && ptiCurrent->spwndDefaultIme == NULL) { 01054 /* 01055 * Avoid creating the default IME window to any of message only windows 01056 * or windows on no I/O desktop. 01057 */ 01058 if (WantImeWindow(pwndParent, pwnd)) { 01059 // 01060 // Make sure we are not creating a window for Ole, 01061 // for it does not pump messages even though 01062 // they creates a window. 01063 // 01064 UserAssert(gaOleMainThreadWndClass != atomT); 01065 01066 Lock(&(ptiCurrent->spwndDefaultIme), 01067 xxxCreateDefaultImeWindow(pwnd, atomT, hInstance)); 01068 01069 01070 /* 01071 * If keybaord layout is switched but Imm activation was skipped 01072 * while spwndDefaultIme was gone, do the activation now. 01073 */ 01074 #if _DBG 01075 if (ptiCurrent->spDefaultImc == NULL) { 01076 RIPMSG1(RIP_WARNING, "xxxCreateWindowEx: ptiCurrent(%08p)->spDefaultImc is NULL.", ptiCurrent); 01077 } 01078 ASSERT(ptiCurrent->pClientInfo); 01079 #endif 01080 01081 if (ptiCurrent->spwndDefaultIme && (ptiCurrent->pClientInfo->CI_flags & CI_INPUTCONTEXT_REINIT)) { 01082 01083 TL tlpwndIme; 01084 01085 TAGMSG1(DBGTAG_IMM, "xxxCreateDefaultImeWindow: ptiCurrent(%08p)->spDefaultImc->fNeedClientImcActivate is set.", ptiCurrent); 01086 /* 01087 * Make this client side callback to force the input context 01088 * is re-initialized appropriately. 01089 * (keyboard layout has been changed since this thread was taking 01090 * a nap while with no window but still was GUI thread) 01091 * see raid #294964 01092 */ 01093 ThreadLock(ptiCurrent->spwndDefaultIme, &tlpwndIme); 01094 xxxSendMessage(ptiCurrent->spwndDefaultIme, WM_IME_SYSTEM, (WPARAM)IMS_ACTIVATETHREADLAYOUT, (LPARAM)ptiCurrent->spklActive->hkl); 01095 01096 // Reset the flag. 01097 ptiCurrent->pClientInfo->CI_flags &= ~CI_INPUTCONTEXT_REINIT; 01098 01099 ThreadUnlock(&tlpwndIme); 01100 } 01101 } 01102 else { 01103 RIPMSG0(RIP_VERBOSE, "xxxCreateWindowEx: default IME window is not created."); 01104 } 01105 } 01106 01107 01108 /* 01109 * Update the Parent/Child linked list. 01110 */ 01111 if (pwndParent != NULL) { 01112 if (!fChild && (pwndParent != pwndParent->head.rpdesk->spwndMessage)) { 01113 01114 /* 01115 * If this is a top-level window, and it's not part of the 01116 * topmost pile of windows, then we have to make sure it 01117 * doesn't go on top of any of the topmost windows. 01118 * 01119 * If he's trying to put the window on the top, or trying 01120 * to insert it after one of the topmost windows, insert 01121 * it after the last topmost window in the pile. 01122 */ 01123 if (!TestWF(pwnd, WEFTOPMOST)) { 01124 if (pwndZOrder == PWND_TOP || 01125 TestWF(pwndZOrder, WEFTOPMOST)) { 01126 pwndZOrder = CalcForegroundInsertAfter(pwnd); 01127 } 01128 } else { 01129 pwndHardError = GETTOPMOSTINSERTAFTER(pwnd); 01130 if (pwndHardError != NULL) { 01131 pwndZOrder = pwndHardError; 01132 } 01133 } 01134 } 01135 01136 LinkWindow(pwnd, pwndZOrder, pwndParent); 01137 } 01138 01139 /* 01140 * Message Sending 01141 */ 01142 01143 /* 01144 * Send a NCCALCSIZE message to the window and have it return the official 01145 * size of its client area. 01146 */ 01147 01148 #ifdef USE_MIRRORING 01149 if (fChild && TestWF(pwndParent, WEFLAYOUTRTL)) { 01150 cx = pwnd->rcWindow.right - pwnd->rcWindow.left; 01151 pwnd->rcWindow.right = pwndParent->rcClient.right - (pwnd->rcWindow.left - pwndParent->rcClient.left); 01152 pwnd->rcWindow.left = pwnd->rcWindow.right - cx; 01153 } 01154 #endif 01155 01156 CopyRect(&rc, &pwnd->rcWindow); 01157 xxxSendMessage(pwnd, WM_NCCALCSIZE, 0L, (LPARAM)&rc); 01158 pwnd->rcClient = rc; 01159 01160 /* 01161 * Send a CREATE message to the window. 01162 */ 01163 if (xxxSendMessage(pwnd, WM_CREATE, 0L, (LPARAM)&csex) == -1L) { 01164 #if DBG 01165 if (!IS_PTR(cczpstrClass)) { 01166 RIPMSG1(RIP_WARNING, 01167 "CreateWindow() send of WM_CREATE failed, Class = 0x%x", 01168 PTR_TO_ID(cczpstrClass)); 01169 } else { 01170 RIPMSG1(RIP_WARNING, 01171 "CreateWindow() send of WM_CREATE failed, Class = \"%s\"", 01172 pcls->lpszAnsiClassName); 01173 } 01174 #endif 01175 if (fLockParent) 01176 ThreadUnlock(&tlpwndParent); 01177 01178 if (ThreadUnlock(&tlpwnd)) 01179 xxxDestroyWindow(pwnd); 01180 01181 return NULL; 01182 } 01183 01184 SetWF(pwnd, WFISINITIALIZED); /* Flag that the window is created. 01185 WoW uses this bit to determine that 01186 an fnid of 0 really means 0. */ 01187 01188 /* 01189 * Notify anyone who is listening that the window is created. Do this 01190 * before we size/move/max/min/show it so that event observers can count 01191 * on getting notifications for those things also. 01192 * 01193 * But do this AFTER WM_CREATE is sent. The window and its data will not 01194 * be fully initialized until then. Since the purpose of an event is to 01195 * let watchers turn around and do querying, we want their queries to 01196 * succeed and not fault. 01197 */ 01198 if (FWINABLE()) { 01199 xxxWindowEvent(EVENT_OBJECT_CREATE, pwnd, OBJID_WINDOW, INDEXID_OBJECT, 0); 01200 } 01201 01202 /* 01203 * If this is a Tiled/Overlapped window, don't send size or move msgs yet. 01204 */ 01205 if (!TestWF(pwnd, WFSENDSIZEMOVE)) { 01206 xxxSendSizeMessage(pwnd, SIZENORMAL); 01207 01208 if (pwndParent != NULL && PWNDDESKTOP(pwnd) != pwndParent) { 01209 rc.left -= pwndParent->rcClient.left; 01210 rc.top -= pwndParent->rcClient.top; 01211 } 01212 01213 xxxSendMessage(pwnd, WM_MOVE, 0L, MAKELONG(rc.left, rc.top)); 01214 } 01215 01216 /* 01217 * Min/Max Stuff 01218 */ 01219 01220 /* 01221 * If app specified either min/max style, then we must call our minmax 01222 * code to get it all set up correctly so that when the show is done, 01223 * the window is displayed right. 01224 */ 01225 dwMinMax = MINMAX_KEEPHIDDEN | TEST_PUDF(PUDF_ANIMATE); 01226 if (TestWF(pwnd, WFMINIMIZED)) { 01227 SetMinimize(pwnd, SMIN_CLEAR); 01228 xxxMinMaximize(pwnd, SW_SHOWMINNOACTIVE, dwMinMax); 01229 } else if (TestWF(pwnd, WFMAXIMIZED)) { 01230 ClrWF(pwnd, WFMAXIMIZED); 01231 xxxMinMaximize(pwnd, SW_SHOWMAXIMIZED, dwMinMax); 01232 } 01233 01234 /* 01235 * Send notification if child 01236 */ 01237 01238 // LATER 15-Aug-1991 mikeke 01239 // pointer passed as a word here 01240 01241 if (fChild && !TestWF(pwnd, WEFNOPARENTNOTIFY) && 01242 (pwnd->spwndParent != NULL)) { 01243 ThreadLockAlwaysWithPti(ptiCurrent, pwnd->spwndParent, &tlpwndParentT); 01244 xxxSendMessage(pwnd->spwndParent, WM_PARENTNOTIFY, 01245 MAKELONG(WM_CREATE, PTR_TO_ID(pwnd->spmenu)), (LPARAM)HWq(pwnd)); 01246 ThreadUnlock(&tlpwndParentT); 01247 } 01248 01249 /* 01250 * Show the Window 01251 */ 01252 if (style & WS_VISIBLE) { 01253 xxxShowWindow(pwnd, sw | TEST_PUDF(PUDF_ANIMATE)); 01254 } 01255 01256 /* 01257 * Try and set the application's hot key. Use the Win95 logic of 01258 * looking for the first tiled and/or APPWINDOW to be created by 01259 * this process. 01260 */ 01261 if (TestwndTiled(pwnd) || TestWF(pwnd, WEFAPPWINDOW)) { 01262 if (ptiCurrent->ppi->dwHotkey) { 01263 /* 01264 * Ignore hot keys for WowExe the first thread of a wow process. 01265 */ 01266 if (!(ptiCurrent->TIF_flags & TIF_16BIT) || (ptiCurrent->ppi->cThreads > 1)) { 01267 #ifdef LATER 01268 /* 01269 * Win95 sets the hot key directly, we on the other hand send 01270 * a WM_SETHOTKEY message to the app. Which is right? 01271 */ 01272 DWP_SetHotKey(pwnd, ptiCurrent->ppi->dwHotkey); 01273 #else 01274 xxxSendMessage(pwnd, WM_SETHOTKEY, ptiCurrent->ppi->dwHotkey, 0); 01275 #endif 01276 ptiCurrent->ppi->dwHotkey = 0; 01277 } 01278 } 01279 } 01280 01281 if (fLockParent) 01282 ThreadUnlock(&tlpwndParent); 01283 01284 return ThreadUnlock(&tlpwnd); 01285 }

BOOL xxxDestroyWindow PWND  pwnd  ) 
 

Definition at line 1591 of file createw.c.

References tagCLS::atomClassName, tagSERVERINFO::atomSysClass, AW_SKIP, AW_TRY, BOOL, CFIME, CheckLock, DWORD, DWP_SetHotKey(), FALSE, tagMENUSTATE::fModelessMenu, FWINABLE, GetpMenuState(), GETPTI, ghwndSwitch, gpqForeground, gpsi, tagWND::head, HMChangeOwnerThread(), HMIsMarkDestroy, HMPheFromObject, HWq, ICLS_IME, ImeCanDestroyDefIME(), ImeCanDestroyDefIMEforChild(), IS_IME_ENABLED, IsHooked, IsTrayWindow(), Lock, MNEndMenuStateNotify(), NULL, tagWND::pcls, tagMENUSTATE::pGlobalPopupMenu, PostShellHookMessages(), tagTHREADINFO::pq, PsGetCurrentThread, PtiCurrent, PtoHq, PTR_TO_ID, PUDF_ANIMATE, PWNDDESKTOP, tagWND::rcWindow, SetVisible(), SetWF, tagWND::spmenu, tagQ::spwndActive, tagTHREADINFO::spwndDefaultIme, tagQ::spwndFocus, tagWND::spwndLastActive, tagPOPUPMENU::spwndNotify, tagWND::spwndOwner, tagWND::spwndParent, SV_UNSET, TEST_PUDF, TestCF, TestWF, TestwndChild, ThreadLockAlwaysWithPti, ThreadLockWithPti, ThreadUnlock, TIF_DISABLEHOOKS, tagTHREADINFO::TIF_flags, TIF_INCLEANUP, TRUE, UINT, UnlinkWindow(), Unlock, WEF_USEPWNDTHREAD, WEFNOPARENTNOTIFY, WFCHILD, WFDESTROYED, WFHASPALETTE, WFINDESTROY, WFPOPUP, WFVISIBLE, WHF_CBT, xxxActivateWindow(), xxxCallHook(), xxxDW_DestroyOwnedWindows(), xxxDW_SendDestroyMessages(), xxxEndMenu(), xxxFlushPalette(), xxxFocusSetInputContext(), xxxFreeWindow(), xxxRedrawWindow(), xxxSendMessage(), xxxSetWindowPos(), xxxShowWindow(), xxxWindowEvent(), zzzAttachThreadInput(), and zzzInternalDestroyCaret().

Referenced by NtUserDestroyWindow(), NtUserDisableThreadIme(), xxxCancelCoolSwitch(), xxxCreateDesktop(), xxxCreateWindowEx(), xxxDefWindowProc(), xxxDesktopThread(), xxxDestroyThreadDDEObject(), xxxDW_DestroyOwnedWindows(), xxxEndMenu(), xxxMNCancel(), xxxMNCloseHierarchy(), xxxMNOpenHierarchy(), xxxProcessEventMessage(), and xxxTrackPopupMenuEx().

01593 { 01594 PMENUSTATE pMenuState, pmnsEnd; 01595 PTHREADINFO pti = PtiCurrent(); 01596 TL tlpwnd; 01597 PWND pwndFocus; 01598 TL tlpwndFocus; 01599 TL tlpwndParent; 01600 BOOL fAlreadyDestroyed; 01601 DWORD dwDisableHooks; 01602 01603 dwDisableHooks = 0; 01604 ThreadLockWithPti(pti, pwnd, &tlpwnd); 01605 01606 /* 01607 * First, if this handle has been marked for destruction, that means it 01608 * is possible that the current thread is not its owner! (meaning we're 01609 * being called from a handle unlock call). In this case, set the owner 01610 * to be the current thread so inter-thread send messages occur. 01611 */ 01612 fAlreadyDestroyed = HMIsMarkDestroy(pwnd); 01613 if (fAlreadyDestroyed) { 01614 /* 01615 * UserAssert(dwInAtomicOperation > 0); 01616 * This Assert ensures that we are here only because of an unlock 01617 * on a previously destroyed window. We BEGIN/ENDATOMICHCHECK in 01618 * HMDestroyUnlockedObject to ensure we don't leave the crit sect 01619 * unexpectedly, which gives us dwInAtomicCheck > 0. We set 01620 * TIF_DISABLEHOOKS to prevent a callback in Unlock 01621 * However, it is currently possible destroy the same window handle 01622 * twice, since we don't (yet) fail to revalidate zombie handles: 01623 * GerardoB may change this, at which time we should probably restore 01624 * this Assert, and test #76902 (close winmsd.exe) again. (preventing 01625 * hooks in a second destroy of a zombie window should be OK) - IanJa 01626 */ 01627 // UserAssert(dwInAtomicOperation > 0); 01628 01629 if (HMPheFromObject(pwnd)->pOwner != pti) { 01630 UserAssert(PsGetCurrentThread()->Tcb.Win32Thread); 01631 HMChangeOwnerThread(pwnd, pti); 01632 } 01633 dwDisableHooks = pti->TIF_flags & TIF_DISABLEHOOKS; 01634 pti->TIF_flags |= TIF_DISABLEHOOKS; 01635 } else { 01636 /* 01637 * Ensure that we can destroy the window. JIMA: no other process or thread 01638 * should be able to destroy any other process or thread's window. 01639 */ 01640 if (pti != GETPTI(pwnd)) { 01641 RIPERR0(ERROR_ACCESS_DENIED, 01642 RIP_WARNING, 01643 "Access denied in xxxDestroyWindow"); 01644 01645 goto FalseReturn; 01646 } 01647 } 01648 01649 /* 01650 * First ask the CBT hook if we can destroy this window. 01651 * If this object has already been destroyed OR this thread is currently 01652 * in cleanup mode, *do not* make any callbacks via hooks to the client 01653 * process. 01654 */ 01655 if (!fAlreadyDestroyed && !(pti->TIF_flags & TIF_INCLEANUP) && 01656 IsHooked(pti, WHF_CBT)) { 01657 if (xxxCallHook(HCBT_DESTROYWND, (WPARAM)HWq(pwnd), 0, WH_CBT)) { 01658 goto FalseReturn; 01659 } 01660 } 01661 01662 /* 01663 * If the window we are destroying is in menu mode, end the menu 01664 */ 01665 pMenuState = GetpMenuState(pwnd); 01666 if ((pMenuState != NULL) 01667 && (pwnd == pMenuState->pGlobalPopupMenu->spwndNotify)) { 01668 01669 MNEndMenuStateNotify(pMenuState); 01670 /* 01671 * Signal all states to end. The window(s) will be unlocked when 01672 * the menu exits; we cannot unlock it now because the menu 01673 * code could fault. 01674 */ 01675 pmnsEnd = pMenuState; 01676 do { 01677 UserAssert(pwnd == pMenuState->pGlobalPopupMenu->spwndNotify); 01678 pMenuState->fInsideMenuLoop = FALSE; 01679 pMenuState = pMenuState->pmnsPrev; 01680 } while (pMenuState != NULL) ; 01681 01682 /* 01683 * All states have been signaled to exit, so once we callback 01684 * we cannot count on pmnsEnd->pmnsPrev to be valid. Thus 01685 * we simply end the current menu here and let the others go 01686 * on their own. No state points to pwnd anymore so that 01687 * should be OK. 01688 */ 01689 if (!pmnsEnd->fModelessMenu) { 01690 xxxEndMenu(pmnsEnd); 01691 } 01692 } 01693 01694 if (ghwndSwitch == HWq(pwnd)) 01695 ghwndSwitch = NULL; 01696 01697 if (!TestWF(pwnd, WFCHILD) && (pwnd->spwndOwner == NULL)) { 01698 01699 if (TestWF(pwnd, WFHASPALETTE)) { 01700 xxxFlushPalette(pwnd); 01701 } 01702 } 01703 01704 /* 01705 * Disassociate thread state if this is top level and owned by a different 01706 * thread. This is done to begin with so these windows z-order together. 01707 */ 01708 if (pwnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME] && 01709 !TestwndChild(pwnd) && pwnd->spwndOwner != NULL && 01710 GETPTI(pwnd->spwndOwner) != GETPTI(pwnd)) { 01711 /* 01712 * No need to zzzDeferWinEventNotify() - there is an xxx call just below 01713 */ 01714 zzzAttachThreadInput(GETPTI(pwnd), GETPTI(pwnd->spwndOwner), FALSE); 01715 } 01716 01717 /* 01718 * If we are a child window without the WS_NOPARENTNOTIFY style, send 01719 * the appropriate notification message. 01720 * 01721 * NOTE: Although it would appear that we are illegally cramming a 01722 * a WORD (WM_DESTROY) and a DWORD (pwnd->spmenu) into a single LONG 01723 * (wParam) this isn't really the case because we first test if this 01724 * is a child window. The pMenu field in a child window is really 01725 * the window's id and only the LOWORD is significant. 01726 */ 01727 if (TestWF(pwnd, WFCHILD) && !TestWF(pwnd, WEFNOPARENTNOTIFY) && 01728 pwnd->spwndParent != NULL) { 01729 01730 ThreadLockAlwaysWithPti(pti, pwnd->spwndParent, &tlpwndParent); 01731 xxxSendMessage(pwnd->spwndParent, WM_PARENTNOTIFY, 01732 MAKELONG(WM_DESTROY, PTR_TO_ID(pwnd->spmenu)), (LPARAM)HWq(pwnd)); 01733 ThreadUnlock(&tlpwndParent); 01734 } 01735 01736 /* 01737 * Mark this window as beginning the destroy process. This is necessary 01738 * to prevent window-management calls such as ShowWindow or SetWindowPos 01739 * from coming in and changing the visible-state of the window 01740 * once we hide it. Otherwise, if the app attempts to make it 01741 * visible, then we can get our vis-rgns screwed up once we truely 01742 * destroy the window. 01743 * 01744 * Don't mark the mother desktop with this bit. The xxxSetWindowPos() 01745 * will fail for this window, and thus possibly cause an assertion 01746 * in the xxxFreeWindow() call when we check for the visible-bit. 01747 */ 01748 if (pwnd->spwndParent && (pwnd->spwndParent->head.rpdesk != NULL)) 01749 SetWF(pwnd, WFINDESTROY); 01750 01751 /* 01752 * Hide the window. 01753 */ 01754 if (TestWF(pwnd, WFVISIBLE)) { 01755 if (TestWF(pwnd, WFCHILD)) { 01756 xxxShowWindow(pwnd, SW_HIDE | TEST_PUDF(PUDF_ANIMATE)); 01757 } else { 01758 01759 /* 01760 * Hide this window without activating anyone else. 01761 */ 01762 xxxSetWindowPos(pwnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | 01763 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | 01764 (fAlreadyDestroyed ? SWP_DEFERDRAWING : 0)); 01765 } 01766 01767 /* 01768 * Under low memory conditions, the above attempt to hide could fail. 01769 */ 01770 if (TestWF(pwnd, WFVISIBLE)) { 01771 RIPMSG0(RIP_WARNING, "xxxDestroyWindow: normal hide failed"); 01772 SetVisible(pwnd, SV_UNSET); 01773 01774 /* 01775 * Invalidate windows below so they redraw properly. 01776 */ 01777 xxxRedrawWindow(NULL, &pwnd->rcWindow, NULL, RDW_INVALIDATE | 01778 RDW_ERASE | RDW_ALLCHILDREN); 01779 01780 } 01781 } else if (IsTrayWindow(pwnd)) { 01782 PostShellHookMessages(HSHELL_WINDOWDESTROYED, 01783 (LPARAM)PtoHq( pwnd )); 01784 } 01785 01786 /* 01787 * Destroy any owned windows. 01788 */ 01789 if (!TestWF(pwnd, WFCHILD)) { 01790 xxxDW_DestroyOwnedWindows(pwnd); 01791 01792 /* 01793 * And remove the window hot-key, if it has one 01794 */ 01795 DWP_SetHotKey(pwnd, 0); 01796 } 01797 01798 /* 01799 * If the window has already been destroyed, don't muck with 01800 * activation because we may already be in the middle of 01801 * an activation event. Changing activation now may cause us 01802 * to leave our critical section while holding the display lock. 01803 * This will result in a deadlock if another thread gets the 01804 * critical section before we do and attempts to lock the 01805 * display. 01806 */ 01807 if (!fAlreadyDestroyed) { 01808 PWND pwndActivate = NULL; 01809 TL tlpwndActivate; 01810 UINT cmdActivate; 01811 01812 /* 01813 * If hiding the active window, activate someone else. 01814 * This call is strategically located after DestroyOwnedWindows() so we 01815 * don't end up activating our owner window. 01816 * 01817 * If the window is a popup, try to activate his creator not the top 01818 * window in the Z list. 01819 */ 01820 if (pwnd == pti->pq->spwndActive) { 01821 if (TestWF(pwnd, WFPOPUP) && pwnd->spwndOwner) { 01822 pwndActivate = pwnd->spwndOwner; 01823 cmdActivate = AW_TRY; 01824 01825 } else { 01826 pwndActivate = pwnd; 01827 cmdActivate = AW_SKIP; 01828 } 01829 } else if ((pti->pq->spwndActive == NULL) && (gpqForeground == pti->pq)) { 01830 pwndActivate = pwnd; 01831 cmdActivate = AW_SKIP; 01832 } 01833 01834 if (pwndActivate) { 01835 ThreadLockAlwaysWithPti(pti, pwndActivate, &tlpwndActivate); 01836 01837 if (!xxxActivateWindow(pwndActivate, cmdActivate) || 01838 ((cmdActivate == AW_SKIP) && (pwnd == pti->pq->spwndActive))) { 01839 if ((cmdActivate == AW_SKIP) || (pwnd == pti->pq->spwndActive)) { 01840 Unlock(&pti->pq->spwndActive); 01841 pwndFocus = Unlock(&pti->pq->spwndFocus); 01842 if (IS_IME_ENABLED() && pwndFocus != NULL) { 01843 ThreadLockAlwaysWithPti(pti, pwndFocus, &tlpwndFocus); 01844 xxxFocusSetInputContext(pwndFocus, FALSE, FALSE); 01845 ThreadUnlock(&tlpwndFocus); 01846 } 01847 if (FWINABLE() && (pti->pq == gpqForeground)) { 01848 xxxWindowEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, 01849 INDEXID_CONTAINER, 0); 01850 xxxWindowEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, 01851 INDEXID_CONTAINER, WEF_USEPWNDTHREAD); 01852 } 01853 zzzInternalDestroyCaret(); 01854 } 01855 } 01856 01857 ThreadUnlock(&tlpwndActivate); 01858 } 01859 } 01860 01861 /* 01862 * fix last active popup 01863 */ 01864 { 01865 PWND pwndOwner = pwnd->spwndOwner; 01866 01867 if (pwndOwner != NULL) { 01868 while (pwndOwner->spwndOwner != NULL) { 01869 pwndOwner = pwndOwner->spwndOwner; 01870 } 01871 01872 if (pwnd == pwndOwner->spwndLastActive) { 01873 Lock(&(pwndOwner->spwndLastActive), pwnd->spwndOwner); 01874 } 01875 } 01876 } 01877 01878 if (!fAlreadyDestroyed) { 01879 /* 01880 * Note we do this BEFORE telling the app the window is dying. Note also 01881 * that we do NOT loop through the children generating DESTROY events. 01882 * DESTROY of a parent implies DESTROY of all children (see #71846 - IanJa) 01883 */ 01884 if (FWINABLE() && !TestWF(pwnd, WFDESTROYED)) { 01885 xxxWindowEvent(EVENT_OBJECT_DESTROY, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, 0); 01886 } 01887 01888 /* 01889 * Send destroy messages before the WindowLockStart in case 01890 * he tries to destroy windows as a result. 01891 */ 01892 xxxDW_SendDestroyMessages(pwnd); 01893 } 01894 01895 /* 01896 * Check the owner of IME window again. 01897 * If thread is destroying, don't bother to check. 01898 */ 01899 if (IS_IME_ENABLED() && !(pti->TIF_flags & TIF_INCLEANUP) && 01900 pti->spwndDefaultIme != NULL && 01901 !TestCF(pwnd, CFIME) && 01902 pwnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]) { 01903 01904 if (fAlreadyDestroyed) { 01905 RIPMSG2(RIP_VERBOSE, "xxxDestroyWindow: in final destruction of %#p, ime=%#p", 01906 pwnd, pti->spwndDefaultIme); 01907 } else { 01908 if (!TestWF(pwnd, WFCHILD)) { 01909 if (ImeCanDestroyDefIME(pti->spwndDefaultIme, pwnd)) { 01910 TAGMSG1(DBGTAG_IMM, "xxxDestroyWindow: destroying (1) the default IME window=%p", pti->spwndDefaultIme); 01911 xxxDestroyWindow(pti->spwndDefaultIme); 01912 } 01913 } 01914 else if (pwnd->spwndParent != NULL) { 01915 if (ImeCanDestroyDefIMEforChild(pti->spwndDefaultIme, pwnd)) { 01916 TAGMSG1(DBGTAG_IMM, "xxxDestroyWindow: destroying (2) the default IME window=%p", pti->spwndDefaultIme); 01917 xxxDestroyWindow(pti->spwndDefaultIme); 01918 } 01919 } 01920 } 01921 } 01922 01923 if ((pwnd->spwndParent != NULL) && !fAlreadyDestroyed) { 01924 01925 /* 01926 * TestwndChild() on checks to WFCHILD bit. Make sure this 01927 * window wasn't SetParent()'ed to the desktop as well. 01928 */ 01929 if (TestwndChild(pwnd) && (pwnd->spwndParent != PWNDDESKTOP(pwnd)) && 01930 (GETPTI(pwnd) != GETPTI(pwnd->spwndParent))) { 01931 /* 01932 * pwnd is threadlocked, so no need to DeferWinEventNotify() 01933 */ 01934 CheckLock(pwnd); 01935 zzzAttachThreadInput(GETPTI(pwnd), GETPTI(pwnd->spwndParent), FALSE); 01936 } 01937 01938 UnlinkWindow(pwnd, pwnd->spwndParent); 01939 } 01940 01941 /* 01942 * This in intended to check for a case where we destroy the window, 01943 * but it's still listed as the active-window in the queue. This 01944 * could cause problems in window-activation (see xxxActivateThisWindow) 01945 * where we attempt to activate another window and in the process, try 01946 * to deactivate this window (bad). 01947 */ 01948 #if DBG 01949 if (pwnd == pti->pq->spwndActive) { 01950 RIPMSG1(RIP_WARNING, "xxxDestroyWindow: pwnd == pti->pq->spwndActive (%#p)", pwnd); 01951 } 01952 #endif 01953 01954 /* 01955 * Set the state as destroyed so any z-ordering events will be ignored. 01956 * We cannot NULL out the owner field until WM_NCDESTROY is send or 01957 * apps like Rumba fault (they call GetParent after every message) 01958 */ 01959 SetWF(pwnd, WFDESTROYED); 01960 01961 /* 01962 * FreeWindow performs a ThreadUnlock. 01963 */ 01964 01965 xxxFreeWindow(pwnd, &tlpwnd); 01966 01967 if (fAlreadyDestroyed) { 01968 pti->TIF_flags = (pti->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks; 01969 } 01970 return TRUE; 01971 01972 FalseReturn: 01973 if (fAlreadyDestroyed) { 01974 pti->TIF_flags = (pti->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks; 01975 } 01976 ThreadUnlock(&tlpwnd); 01977 return FALSE; 01978 }

void xxxDW_DestroyOwnedWindows PWND  pwndParent  ) 
 

Definition at line 1989 of file createw.c.

References CheckLock, GETPTI, tagWND::head, IS_IME_ENABLED, NULL, tagDESKTOP::pDeskInfo, tagDESKTOPINFO::spwnd, tagWND::spwndChild, tagWND::spwndNext, tagWND::spwndOwner, TIF_INCLEANUP, Unlock, and xxxDestroyWindow().

Referenced by xxxDestroyWindow().

01991 { 01992 PWND pwnd, pwndDesktop; 01993 PDESKTOP pdeskParent; 01994 PWND pwndDefaultIme = GETPTI(pwndParent)->spwndDefaultIme; 01995 01996 CheckLock(pwndParent); 01997 01998 if ((pdeskParent = pwndParent->head.rpdesk) == NULL) 01999 return; 02000 pwndDesktop = pdeskParent->pDeskInfo->spwnd; 02001 02002 /* 02003 * During shutdown, the desktop owner window will be 02004 * destroyed. In this case, pwndDesktop will be NULL. 02005 */ 02006 if (pwndDesktop == NULL) 02007 return; 02008 02009 pwnd = pwndDesktop->spwndChild; 02010 02011 while (pwnd != NULL) { 02012 if (pwnd->spwndOwner == pwndParent) { 02013 /* 02014 * We don't destroy the IME window here 02015 * unless the thread is doing cleanup. 02016 */ 02017 if (IS_IME_ENABLED() && !(GETPTI(pwndParent)->TIF_flags & TIF_INCLEANUP) && 02018 pwnd == pwndDefaultIme) { 02019 Unlock(&pwnd->spwndOwner); 02020 pwnd = pwnd->spwndNext; 02021 continue; 02022 } 02023 02024 /* 02025 * If the window doesn't get destroyed, set its owner to NULL. 02026 * A good example of this is trying to destroy a window created 02027 * by another thread or process, but there are other cases. 02028 */ 02029 if (!xxxDestroyWindow(pwnd)) { 02030 Unlock(&pwnd->spwndOwner); 02031 } 02032 02033 /* 02034 * Start the search over from the beginning since the app could 02035 * have caused other windows to be created or activation/z-order 02036 * changes. 02037 */ 02038 pwnd = pwndDesktop->spwndChild; 02039 } else { 02040 pwnd = pwnd->spwndNext; 02041 } 02042 } 02043 }

void xxxDW_SendDestroyMessages PWND  pwnd  ) 
 

Definition at line 2053 of file createw.c.

References _GetProcessWindowStation(), CheckLock, DisownClipboard(), L, NULL, PtiCurrent, tagWND::spwndChild, tagWINDOWSTATION::spwndClipOwner, tagWND::spwndNext, ThreadLock, ThreadLockAlways, ThreadUnlock, xxxCheckFocus(), and xxxSendMessage().

Referenced by xxxDestroyWindow().

02055 { 02056 PWND pwndChild; 02057 PWND pwndNext; 02058 TL tlpwndNext; 02059 TL tlpwndChild; 02060 PWINDOWSTATION pwinsta; 02061 02062 CheckLock(pwnd); 02063 02064 /* 02065 * Be sure the window gets any resulting messages before being destroyed. 02066 */ 02067 xxxCheckFocus(pwnd); 02068 02069 pwinsta = _GetProcessWindowStation(NULL); 02070 if (pwinsta != NULL && pwnd == pwinsta->spwndClipOwner) { 02071 /* 02072 * Pass along the pwnd which is the reason we are dis'ing the clipboard. 02073 * We want to later make sure the owner is still this window after we make callbacks 02074 * and clear the owner 02075 */ 02076 DisownClipboard(pwnd); 02077 } 02078 02079 /* 02080 * Send the WM_DESTROY message. 02081 */ 02082 #if _DBG 02083 if (pwnd == PtiCurrent()->spwndDefaultIme) { 02084 TAGMSG2(DBGTAG_IMM, "xxxDW_SendDestroyMessages: sending WM_DESTROY message to def IME=%p, pti=%p", pwnd, PtiCurrent()); 02085 } 02086 #endif 02087 xxxSendMessage(pwnd, WM_DESTROY, 0L, 0L); 02088 02089 /* 02090 * Now send destroy message to all children of pwnd. 02091 * Enumerate down (pwnd->spwndChild) and sideways (pwnd->spwndNext). 02092 * We do it this way because parents often assume that child windows still 02093 * exist during WM_DESTROY message processing. 02094 */ 02095 pwndChild = pwnd->spwndChild; 02096 02097 while (pwndChild != NULL) { 02098 02099 pwndNext = pwndChild->spwndNext; 02100 02101 ThreadLock(pwndNext, &tlpwndNext); 02102 02103 ThreadLockAlways(pwndChild, &tlpwndChild); 02104 xxxDW_SendDestroyMessages(pwndChild); 02105 ThreadUnlock(&tlpwndChild); 02106 pwndChild = pwndNext; 02107 02108 /* 02109 * The unlock may nuke the next window. If so, get out. 02110 */ 02111 if (!ThreadUnlock(&tlpwndNext)) 02112 break; 02113 } 02114 02115 xxxCheckFocus(pwnd); 02116 }

VOID xxxFreeWindow PWND  pwnd,
PTL  ptlpwndFree
 

Definition at line 2218 of file createw.c.

References _DeregisterShellHookWindow(), _DestroyMenu(), _GetProcessWindowStation(), _GetProp(), _MonitorFromWindow(), _PostQuitMessage(), tagSERVERINFO::atomIconProp, tagSERVERINFO::atomSysClass, _LARGE_UNICODE_STRING::Buffer, CallClientWorkerProc, CFCLASSDC, CFOWNDC, CheckLock, ClearHungFlag(), ClearSendMessages(), ClrWF, tagDDEIMP::cRefConv, tagDDEIMP::cRefInit, tagTHREADINFO::cWindows, tagCLS::cWndReferenceCount, DCE_FREED, DCE_NORELEASE, DCE_RELEASED, tagDCE::DCX_flags, DecPaintCount(), DeleteHrgnClip(), DeleteMaybeSpecialRgn(), DeleteProperties(), DereferenceClass(), DesktopFree, DestroyCacheDC(), DestroyWindowsHotKeys(), DestroyWindowSmIcon(), DestroyWindowsTimers(), DF_MOUSEMOVETRK, DF_TOOLTIPSHOWING, FALSE, FindQMsg(), FindSpb(), FNID, FNID_CLEANEDUP_BIT, FNID_CONTROLEND, FNID_DELETED_BIT, FNID_DESKTOP, FNID_TO_CLIENT_PFNWORKER, FNID_WNDPROCEND, FNID_WNDPROCSTART, FreeSpb(), gcountPWO, GetClassPtr(), GETFNID, GETPDESK, gpDispInfo, gpsi, gptiLockUpdate, gspwndActivate, gspwndCursor, gspwndLockUpdate, gspwndMouseOwner, HANDLEF_INDESTROY, tagDCE::hdc, tagDISPLAYINFO::hDev, tagWND::head, HMChangeOwnerThread(), HMFreeObject(), HMIsMarkDestroy, HMMarkObjectDestroy(), hModuleWin, HMPheFromObject, tagDCE::hrgnClip, tagWND::hrgnClip, tagWND::hrgnUpdate, ICLS_ICONTITLE, InternalRemoveProp(), IS_IME_ENABLED, L, _LARGE_UNICODE_STRING::Length, Lock, tagWND::lpfnWndProc, MAKEINTATOM, MarkDCEInvalid(), tagTHREADINFO::mlPost, tagQMSG::msg, NEEDSPAINT, NEEDSSYNCPAINT, NULL, tagWND::pcls, tagDISPLAYINFO::pdceFirst, tagDCE::pdceNext, PDDECONV, PDDEIMP, tagTHREADINFO::ppi, PpiCurrent, tagWND::ppropList, tagTHREADINFO::pq, tagMLIST::pqmsgRead, PROP_DDEIMP, PROP_DDETRACK, PROP_WNDOBJ, PROPF_INTERNAL, tagWND::pSBInfo, tagWINDOWSTATION::ptiClipLock, PtiCurrent, PTL, PTOOLTIPWND, tagDCE::pwndClip, tagDCE::pwndOrg, ReleaseCacheDC(), SetWF, tagWND::spmenu, tagWND::spmenuSys, tagQ::spwndActivePrev, tagQ::spwndCapture, tagWND::spwndChild, tagWINDOWSTATION::spwndClipOpen, tagWINDOWSTATION::spwndClipViewer, tagTHREADINFO::spwndDefaultIme, tagQ::spwndFocus, tagWND::spwndLastActive, tagWND::spwndOwner, tagWND::spwndParent, tagWND::strName, TestCF, TestWF, TestwndChild, ThreadLockAlways, ThreadLockAlwaysWithPti, ThreadLockDesktop, ThreadUnlock, ThreadUnlockDesktop, tagTHREADINFO::TIF_flags, TIF_INCLEANUP, TRUE, UINT, Unlock, UnlockNotifyWindow(), UnlockWndMenu(), UnsetLayeredWindow(), VOID(), WEFLAYERED, WFHASPALETTE, WFHASSPB, WFINDESTROY, WFINTERNALPAINT, WFMAXFAKEREGIONAL, WFMSGBOX, WFREDRAWFRAMEIFHUNG, WFREDRAWIFHUNG, WFSENDERASEBKGND, WFSENDNCPAINT, WFSERVERSIDEPROC, WFSHELLHOOKWND, WFTILED, WFTYPEMASK, WFVISIBLE, xxxDDETrackWindowDying(), xxxDefWindowProc(), xxxFW_DestroyAllChildren(), xxxReleaseCapture(), xxxRemoveFullScreen(), xxxResetTooltip(), and xxxSendMessage().

Referenced by xxxCreateWindowEx(), xxxDestroyWindow(), xxxFW_DestroyAllChildren(), and xxxProcessEventMessage().

02221 { 02222 PDCE *ppdce; 02223 PDCE pdce; 02224 UINT uDCERelease; 02225 PMENU pmenu; 02226 PQMSG pqmsg; 02227 PPCLS ppcls; 02228 WORD fnid; 02229 TL tlpdesk; 02230 PWINDOWSTATION pwinsta = _GetProcessWindowStation(NULL); 02231 PTHREADINFO pti = PtiCurrent(); 02232 PPROCESSINFO ppi; 02233 PMONITOR pMonitor; 02234 TL tlpMonitor; 02235 02236 UNREFERENCED_PARAMETER(ptlpwndFree); 02237 02238 CheckLock(pwnd); 02239 02240 /* 02241 * If the pwnd is any of the global shell-related windows, 02242 * then we need to unlock them from the deskinfo. 02243 */ 02244 if (pwnd->head.rpdesk != NULL) { 02245 if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndShell) 02246 Unlock(&pwnd->head.rpdesk->pDeskInfo->spwndShell); 02247 if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndBkGnd) 02248 Unlock(&pwnd->head.rpdesk->pDeskInfo->spwndBkGnd); 02249 if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndTaskman) 02250 Unlock(&pwnd->head.rpdesk->pDeskInfo->spwndTaskman); 02251 if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndProgman) 02252 Unlock(&pwnd->head.rpdesk->pDeskInfo->spwndProgman); 02253 if (TestWF(pwnd,WFSHELLHOOKWND)) { 02254 _DeregisterShellHookWindow(pwnd); 02255 } 02256 02257 if (TestWF(pwnd, WFMSGBOX)) { 02258 pwnd->head.rpdesk->pDeskInfo->cntMBox--; 02259 ClrWF(pwnd, WFMSGBOX); 02260 } 02261 } 02262 02263 /* 02264 * First, if this handle has been marked for destruction, that means it 02265 * is possible that the current thread is not its owner! (meaning we're 02266 * being called from a handle unlock call). In this case, set the owner 02267 * to be the current thread so inter-thread send messages don't occur. 02268 */ 02269 if (HMIsMarkDestroy(pwnd)) 02270 HMChangeOwnerThread(pwnd, pti); 02271 02272 /* 02273 * Blow away the children. 02274 * 02275 * DestroyAllChildren() will still destroy windows created by other 02276 * threads! This needs to be looked at more closely: the ultimate 02277 * "right" thing to do is not to destroy these windows but just 02278 * unlink them. 02279 */ 02280 xxxFW_DestroyAllChildren(pwnd); 02281 xxxSendMessage(pwnd, WM_NCDESTROY, 0, 0L); 02282 02283 pMonitor = _MonitorFromWindow(pwnd, MONITOR_DEFAULTTOPRIMARY); 02284 ThreadLockAlwaysWithPti(pti, pMonitor, &tlpMonitor); 02285 xxxRemoveFullScreen(pwnd, pMonitor); 02286 ThreadUnlock(&tlpMonitor); 02287 02288 /* 02289 * If this is one of the built in controls which hasn't been cleaned 02290 * up yet, do it now. If it lives in the kernel, call the function 02291 * directly, otherwise call back to the client. Even if the control 02292 * is sub- or super-classed, use the window procs associated with 02293 * the function id. 02294 */ 02295 fnid = GETFNID(pwnd); 02296 if ((fnid >= FNID_WNDPROCSTART) && !(pwnd->fnid & FNID_CLEANEDUP_BIT)) { 02297 02298 if (fnid <= FNID_WNDPROCEND) { 02299 02300 FNID(fnid)(pwnd, WM_FINALDESTROY, 0, 0, 0); 02301 02302 } else if (fnid <= FNID_CONTROLEND && !(pti->TIF_flags & TIF_INCLEANUP)) { 02303 02304 CallClientWorkerProc(pwnd, 02305 WM_FINALDESTROY, 02306 0, 02307 0, 02308 (PROC)FNID_TO_CLIENT_PFNWORKER(fnid)); 02309 } 02310 02311 pwnd->fnid |= FNID_CLEANEDUP_BIT; 02312 } 02313 02314 pwnd->fnid |= FNID_DELETED_BIT; 02315 02316 /* 02317 * Check to clear the most recently active window in owned list. 02318 */ 02319 if (pwnd->spwndOwner && (pwnd->spwndOwner->spwndLastActive == pwnd)) { 02320 Lock(&(pwnd->spwndOwner->spwndLastActive), pwnd->spwndOwner); 02321 } 02322 02323 /* 02324 * The windowstation may be NULL if we are destroying a desktop 02325 * or windowstation. If this is the case, this thread will not 02326 * be using the clipboard. 02327 */ 02328 if (pwinsta != NULL) { 02329 02330 if (pwnd == pwinsta->spwndClipOpen) { 02331 Unlock(&pwinsta->spwndClipOpen); 02332 pwinsta->ptiClipLock = NULL; 02333 } 02334 02335 if (pwnd == pwinsta->spwndClipViewer) { 02336 Unlock(&pwinsta->spwndClipViewer); 02337 } 02338 } 02339 02340 if (IS_IME_ENABLED() && pwnd == pti->spwndDefaultIme) 02341 Unlock(&pti->spwndDefaultIme); 02342 02343 if (pwnd == pti->pq->spwndFocus) 02344 Unlock(&pti->pq->spwndFocus); 02345 02346 if (pwnd == pti->pq->spwndActivePrev) 02347 Unlock(&pti->pq->spwndActivePrev); 02348 02349 if (pwnd == gspwndActivate) 02350 Unlock(&gspwndActivate); 02351 02352 if (pwnd->head.rpdesk != NULL) { 02353 02354 if (pwnd == pwnd->head.rpdesk->spwndForeground) 02355 Unlock(&pwnd->head.rpdesk->spwndForeground); 02356 02357 if (pwnd == pwnd->head.rpdesk->spwndTray) 02358 Unlock(&pwnd->head.rpdesk->spwndTray); 02359 02360 if (pwnd == pwnd->head.rpdesk->spwndTrack) { 02361 /* 02362 * Remove tooltip, if any 02363 */ 02364 if (GETPDESK(pwnd)->dwDTFlags & DF_TOOLTIPSHOWING) { 02365 PWND pwndTooltip = GETPDESK(pwnd)->spwndTooltip; 02366 TL tlpwndTooltip; 02367 02368 ThreadLockAlways(pwndTooltip, &tlpwndTooltip); 02369 xxxResetTooltip((PTOOLTIPWND)pwndTooltip); 02370 ThreadUnlock(&tlpwndTooltip); 02371 } 02372 02373 Unlock(&pwnd->head.rpdesk->spwndTrack); 02374 pwnd->head.rpdesk->dwDTFlags &= ~DF_MOUSEMOVETRK; 02375 } 02376 } 02377 02378 if (pwnd == pti->pq->spwndCapture) 02379 xxxReleaseCapture(); 02380 02381 /* 02382 * This window won't be needing any more input. 02383 */ 02384 if (pwnd == gspwndMouseOwner) 02385 Unlock(&gspwndMouseOwner); 02386 02387 /* 02388 * It also won't have any mouse cursors over it. 02389 */ 02390 if (pwnd == gspwndCursor) 02391 Unlock(&gspwndCursor); 02392 02393 DestroyWindowsTimers(pwnd); 02394 DestroyWindowsHotKeys(pwnd); 02395 02396 /* 02397 * Make sure this window has no pending sent messages. 02398 */ 02399 ClearSendMessages(pwnd); 02400 02401 /* 02402 * Remove the associated GDI sprite. 02403 */ 02404 if (TestWF(pwnd, WEFLAYERED)) { 02405 UnsetLayeredWindow(pwnd); 02406 } 02407 02408 #ifdef REDIRECTION 02409 if (TestWF(pwnd, WEFREDIRECTED)) { 02410 UnsetRedirectedWindow(pwnd); 02411 } 02412 #endif // REDIRECTION 02413 02414 /* 02415 * Blow away any update region lying around. 02416 */ 02417 if (NEEDSPAINT(pwnd)) { 02418 02419 DecPaintCount(pwnd); 02420 02421 DeleteMaybeSpecialRgn(pwnd->hrgnUpdate); 02422 pwnd->hrgnUpdate = NULL; 02423 ClrWF(pwnd, WFINTERNALPAINT); 02424 } 02425 02426 /* 02427 * Decrememt queue's syncpaint count if necessary. 02428 */ 02429 if (NEEDSSYNCPAINT(pwnd)) { 02430 ClrWF(pwnd, WFSENDNCPAINT); 02431 ClrWF(pwnd, WFSENDERASEBKGND); 02432 } 02433 02434 /* 02435 * Clear both flags to ensure that the window is removed 02436 * from the hung redraw list. 02437 */ 02438 ClearHungFlag(pwnd, WFREDRAWIFHUNG); 02439 ClearHungFlag(pwnd, WFREDRAWFRAMEIFHUNG); 02440 02441 /* 02442 * If there is a WM_QUIT message in this app's message queue, call 02443 * PostQuitMessage() (this happens if the app posts itself a quit message. 02444 * WinEdit2.0 posts a quit to a window while receiving the WM_DESTROY 02445 * for that window - it works because we need to do a PostQuitMessage() 02446 * automatically for this thread. 02447 */ 02448 if (pti->mlPost.pqmsgRead != NULL) { 02449 02450 /* 02451 * try to get rid of WM_DDE_ACK too. 02452 */ 02453 if ((pqmsg = FindQMsg(pti, 02454 &(pti->mlPost), 02455 pwnd, 02456 WM_QUIT, 02457 WM_QUIT, TRUE)) != NULL) { 02458 02459 _PostQuitMessage((int)pqmsg->msg.wParam); 02460 } 02461 } 02462 02463 if (!TestwndChild(pwnd) && pwnd->spmenu != NULL) { 02464 pmenu = (PMENU)pwnd->spmenu; 02465 if (UnlockWndMenu(pwnd, &pwnd->spmenu)) 02466 _DestroyMenu(pmenu); 02467 } 02468 02469 if (pwnd->spmenuSys != NULL) { 02470 pmenu = (PMENU)pwnd->spmenuSys; 02471 if (pmenu != pwnd->head.rpdesk->spmenuDialogSys) { 02472 if (UnlockWndMenu(pwnd, &pwnd->spmenuSys)) { 02473 _DestroyMenu(pmenu); 02474 } 02475 } else { 02476 UnlockWndMenu(pwnd, &pwnd->spmenuSys); 02477 } 02478 } 02479 02480 /* 02481 * If it was using either of the desktop system menus, unlock it 02482 */ 02483 if (pwnd->head.rpdesk != NULL) { 02484 if (pwnd->head.rpdesk->spmenuSys != NULL && 02485 pwnd == pwnd->head.rpdesk->spmenuSys->spwndNotify) { 02486 02487 UnlockNotifyWindow(pwnd->head.rpdesk->spmenuSys); 02488 } else if (pwnd->head.rpdesk->spmenuDialogSys != NULL && 02489 pwnd == pwnd->head.rpdesk->spmenuDialogSys->spwndNotify) { 02490 02491 UnlockNotifyWindow(pwnd->head.rpdesk->spmenuDialogSys); 02492 } 02493 02494 } 02495 02496 02497 /* 02498 * Tell Gdi that the window is going away. 02499 */ 02500 if (gcountPWO != 0) { 02501 PVOID pwo = InternalRemoveProp(pwnd, PROP_WNDOBJ, TRUE); 02502 if (pwo != NULL) { 02503 GreLockDisplay(gpDispInfo->hDev); 02504 GreDeleteWnd(pwo); 02505 gcountPWO--; 02506 GreUnlockDisplay(gpDispInfo->hDev); 02507 } 02508 } 02509 02510 #ifdef HUNGAPP_GHOSTING 02511 02512 /* 02513 * RemoveGhost handles the case when pwnd is the hung window that has a 02514 * corresponding ghost window and the case when pwnd is the ghost itself. 02515 */ 02516 RemoveGhost(pwnd); 02517 02518 #endif // HUNGAPP_GHOSTING 02519 02520 /* 02521 * Scan the DC cache to find any DC's for this window. If any are there, 02522 * then invalidate them. We don't need to worry about calling SpbCheckDC 02523 * because the window has been hidden by this time. 02524 */ 02525 for (ppdce = &gpDispInfo->pdceFirst; *ppdce != NULL; ) { 02526 02527 pdce = *ppdce; 02528 if (pdce->DCX_flags & DCX_INVALID) { 02529 goto NextEntry; 02530 } 02531 02532 if ((pdce->pwndOrg == pwnd) || (pdce->pwndClip == pwnd)) { 02533 02534 if (!(pdce->DCX_flags & DCX_CACHE)) { 02535 02536 if (TestCF(pwnd, CFCLASSDC)) { 02537 02538 GreLockDisplay(gpDispInfo->hDev); 02539 02540 if (pdce->DCX_flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) 02541 DeleteHrgnClip(pdce); 02542 02543 MarkDCEInvalid(pdce); 02544 pdce->pwndOrg = NULL; 02545 pdce->pwndClip = NULL; 02546 pdce->hrgnClip = NULL; 02547 02548 /* 02549 * Remove the vis rgn since it is still owned - if we did 02550 * not, gdi would not be able to clean up properly if the 02551 * app that owns this vis rgn exist while the vis rgn is 02552 * still selected. 02553 */ 02554 GreSelectVisRgn(pdce->hdc, NULL, SVR_DELETEOLD); 02555 GreUnlockDisplay(gpDispInfo->hDev); 02556 02557 } else if (TestCF(pwnd, CFOWNDC)) { 02558 DestroyCacheDC(ppdce, pdce->hdc); 02559 } else { 02560 UserAssert(FALSE); 02561 } 02562 02563 } else { 02564 02565 /* 02566 * If the DC is checked out, release it before 02567 * we invalidate. Note, that if this process is exiting 02568 * and it has a dc checked out, gdi is going to destroy that 02569 * dc. We need to similarly remove that dc from the dc cache. 02570 * This is not done here, but in the exiting code. 02571 * 02572 * The return for ReleaseDC() could fail, which would 02573 * indicate a delayed-free (DCE_NUKE). 02574 */ 02575 uDCERelease = DCE_RELEASED; 02576 02577 if (pdce->DCX_flags & DCX_INUSE) { 02578 uDCERelease = ReleaseCacheDC(pdce->hdc, FALSE); 02579 } else if (!GreSetDCOwner(pdce->hdc, OBJECT_OWNER_NONE)) { 02580 uDCERelease = DCE_NORELEASE; 02581 } 02582 02583 if (uDCERelease != DCE_FREED) { 02584 02585 if (uDCERelease == DCE_NORELEASE) { 02586 02587 /* 02588 * We either could not release this dc or could not set 02589 * its owner. In either case it means some other thread 02590 * is actively using it. Since it is not too useful if 02591 * the window it is calculated for is gone, mark it as 02592 * INUSE (so we don't give it out again) and as 02593 * DESTROYTHIS (so we just get rid of it since it is 02594 * easier to do this than to release it back into the 02595 * cache). The W32PF_OWNERDCCLEANUP bit means "look for 02596 * DESTROYTHIS flags and destroy that dc", and the bit 02597 * gets looked at in various strategic execution paths. 02598 */ 02599 pdce->DCX_flags = DCX_DESTROYTHIS | DCX_INUSE | DCX_CACHE; 02600 pti->ppi->W32PF_Flags |= W32PF_OWNDCCLEANUP; 02601 02602 } else { 02603 02604 /* 02605 * We either released the DC or changed its owner 02606 * successfully. Mark the entry as invalid so it can 02607 * be given out again. 02608 */ 02609 MarkDCEInvalid(pdce); 02610 pdce->hrgnClip = NULL; 02611 } 02612 02613 /* 02614 * We shouldn't reference this window anymore. Setting 02615 * these to NULL here will make sure that even if we were 02616 * not able to release the DC here, we won't return this 02617 * window from one of the DC matching functions. 02618 */ 02619 pdce->pwndOrg = NULL; 02620 pdce->pwndClip = NULL; 02621 02622 /* 02623 * Remove the visrgn since it is still owned - if we did 02624 * not, gdi would not be able to clean up properly if the 02625 * app that owns this visrgn exist while the visrgn is 02626 * still selected. 02627 */ 02628 GreLockDisplay(gpDispInfo->hDev); 02629 GreSelectVisRgn(pdce->hdc, NULL, SVR_DELETEOLD); 02630 GreUnlockDisplay(gpDispInfo->hDev); 02631 } 02632 } 02633 } 02634 02635 /* 02636 * Step to the next DC. If the DC was deleted, there 02637 * is no need to calculate address of the next entry. 02638 */ 02639 if (pdce == *ppdce) 02640 NextEntry: 02641 ppdce = &pdce->pdceNext; 02642 } 02643 02644 /* 02645 * Clean up the spb that may still exist - like child window spb's. 02646 */ 02647 if (pwnd == gspwndLockUpdate) { 02648 FreeSpb(FindSpb(pwnd)); 02649 Unlock(&gspwndLockUpdate); 02650 gptiLockUpdate = NULL; 02651 } 02652 02653 if (TestWF(pwnd, WFHASSPB)) { 02654 FreeSpb(FindSpb(pwnd)); 02655 } 02656 02657 /* 02658 * Blow away the window clipping region. If the window is maximized, don't 02659 * blow away the monitor region. If the window is the desktop, don't blow 02660 * away the screen region. 02661 */ 02662 if ( pwnd->hrgnClip != NULL && 02663 !TestWF(pwnd, WFMAXFAKEREGIONAL) && 02664 GETFNID(pwnd) != FNID_DESKTOP) { 02665 02666 GreDeleteObject(pwnd->hrgnClip); 02667 pwnd->hrgnClip = NULL; 02668 } 02669 02670 /* 02671 * Clean up any memory allocated for scroll bars... 02672 */ 02673 if (pwnd->pSBInfo) { 02674 DesktopFree(pwnd->head.rpdesk, (HANDLE)(pwnd->pSBInfo)); 02675 pwnd->pSBInfo = NULL; 02676 } 02677 02678 /* 02679 * Free any callback handles associated with this window. 02680 * This is done outside of DeleteProperties because of the special 02681 * nature of callback handles as opposed to normal memory handles 02682 * allocated for a thread. 02683 */ 02684 02685 /* 02686 * Blow away the title 02687 */ 02688 if (pwnd->strName.Buffer != NULL) { 02689 DesktopFree(pwnd->head.rpdesk, pwnd->strName.Buffer); 02690 pwnd->strName.Buffer = NULL; 02691 pwnd->strName.Length = 0; 02692 } 02693 02694 /* 02695 * Blow away any properties connected to the window. 02696 */ 02697 if (pwnd->ppropList != NULL) { 02698 TL tlpDdeConv; 02699 PDDECONV pDdeConv; 02700 PDDEIMP pddei; 02701 02702 /* 02703 * Get rid of any icon properties. 02704 */ 02705 DestroyWindowSmIcon(pwnd); 02706 InternalRemoveProp(pwnd, MAKEINTATOM(gpsi->atomIconProp), PROPF_INTERNAL); 02707 02708 pDdeConv = (PDDECONV)_GetProp(pwnd, PROP_DDETRACK, PROPF_INTERNAL); 02709 if (pDdeConv != NULL) { 02710 ThreadLockAlwaysWithPti(pti, pDdeConv, &tlpDdeConv); 02711 xxxDDETrackWindowDying(pwnd, pDdeConv); 02712 ThreadUnlock(&tlpDdeConv); 02713 } 02714 pddei = (PDDEIMP)InternalRemoveProp(pwnd, PROP_DDEIMP, PROPF_INTERNAL); 02715 if (pddei != NULL) { 02716 pddei->cRefInit = 0; 02717 if (pddei->cRefConv == 0) { 02718 /* 02719 * If this is not 0 it is referenced by one or more DdeConv 02720 * structures so DON'T free it yet! 02721 */ 02722 UserFreePool(pddei); 02723 } 02724 } 02725 } 02726 02727 /* 02728 * Unlock everything that the window references. 02729 * After we have sent the WM_DESTROY and WM_NCDESTROY message we 02730 * can unlock & NULL the owner field so no other windows get z-ordered 02731 * relative to this window. Rhumba faults if we NULL it before the 02732 * destroy. (It calls GetParent after every message). 02733 * 02734 * We special-case the spwndParent window. In this case, if the 02735 * window being destroyed is a desktop window, unlock the parent. 02736 * Otherwise, we lock in the desktop-window as the parent so that 02737 * if we aren't freed in this function, we will ensure that we 02738 * won't fault when doing things like clipping-calculations. We'll 02739 * unlock this once we know we're truly going to free this window. 02740 */ 02741 if (pwnd->head.rpdesk != NULL && 02742 pwnd != pwnd->head.rpdesk->pDeskInfo->spwnd) 02743 Lock(&pwnd->spwndParent, pwnd->head.rpdesk->pDeskInfo->spwnd); 02744 else 02745 Unlock(&pwnd->spwndParent); 02746 02747 Unlock(&pwnd->spwndChild); 02748 Unlock(&pwnd->spwndOwner); 02749 Unlock(&pwnd->spwndLastActive); 02750 02751 /* 02752 * Decrement the Window Reference Count in the Class structure. 02753 */ 02754 DereferenceClass(pwnd); 02755 02756 /* 02757 * Mark the object for destruction before this final unlock. This way 02758 * the WM_FINALDESTROY will get sent if this is the last thread lock. 02759 * We're currently destroying this window, so don't allow unlock recursion 02760 * at this point (this is what HANDLEF_INDESTROY will do for us). 02761 */ 02762 HMMarkObjectDestroy(pwnd); 02763 HMPheFromObject(pwnd)->bFlags |= HANDLEF_INDESTROY; 02764 02765 /* 02766 * Unlock the window... This shouldn't return FALSE because HANDLEF_DESTROY 02767 * is set, but just in case... if it isn't around anymore, return because 02768 * pwnd is invalid. 02769 */ 02770 if (!ThreadUnlock(ptlpwndFree)) 02771 return; 02772 02773 /* 02774 * Try to free the object. The object won't free if it is locked - but 02775 * it will be marked for destruction. If the window is locked, change 02776 * it's wndproc to xxxDefWindowProc(). 02777 * 02778 * HMMarkObjectDestroy() will clear the HANDLEF_INDESTROY flag if the 02779 * object isn't about to go away (so it can be destroyed again!) 02780 */ 02781 pwnd->pcls = NULL; 02782 if (HMMarkObjectDestroy(pwnd)) { 02783 02784 /* 02785 * Delete the window's property list. Wait until now in case some 02786 * thread keeps a property pointer around across a callback. 02787 */ 02788 if (pwnd->ppropList != NULL) { 02789 DeleteProperties(pwnd); 02790 } 02791 02792 #if DBG 02793 /* 02794 * If we find the window is visible at the time we free it, then 02795 * somehow the app was made visible on a callback (we hide it 02796 * during xxxDestroyWindow(). This screws up our vis-window 02797 * count for the thread, so we need to assert it. 02798 */ 02799 if (TestWF(pwnd, WFINDESTROY) && TestWF(pwnd, WFVISIBLE)) 02800 RIPMSG1(RIP_ERROR, "xxxFreeWindow: Window should not be visible (pwnd == %#p)", pwnd); 02801 #endif 02802 02803 pti->cWindows--; 02804 02805 /* 02806 * Since we're freeing the memory for this window, we need 02807 * to unlock the parent (which is the desktop for zombie windows). 02808 */ 02809 Unlock(&pwnd->spwndParent); 02810 02811 ThreadLockDesktop(pti, pwnd->head.rpdesk, &tlpdesk, LDLT_FN_FREEWINDOW); 02812 HMFreeObject(pwnd); 02813 ThreadUnlockDesktop(pti, &tlpdesk, LDUT_FN_FREEWINDOW); 02814 return; 02815 } 02816 02817 /* 02818 * Turn this into an object that the app won't see again - turn 02819 * it into an icon title window - the window is still totally 02820 * valid and useable by any structures that has this window locked. 02821 */ 02822 pwnd->lpfnWndProc = xxxDefWindowProc; 02823 if (pwnd->head.rpdesk) 02824 ppi = pwnd->head.rpdesk->rpwinstaParent->pTerm->ptiDesktop->ppi; 02825 else 02826 ppi = PpiCurrent(); 02827 ppcls = GetClassPtr(gpsi->atomSysClass[ICLS_ICONTITLE], ppi, hModuleWin); 02828 02829 UserAssert(ppcls); 02830 pwnd->pcls = *ppcls; 02831 02832 /* 02833 * Since pwnd is marked as destroyed, there should be no client-side 02834 * code which can validate it. So we do not need to search for a clone 02835 * class of the right desktop -- just use the base class and bump the 02836 * WndReferenceCount. This also helps if we are in a low-memory situation 02837 * and cannot alloc another clone. 02838 */ 02839 02840 pwnd->pcls->cWndReferenceCount++; 02841 02842 SetWF(pwnd, WFSERVERSIDEPROC); 02843 02844 /* 02845 * Clear the palette bit so that WM_PALETTECHANGED will not be sent 02846 * again when the window is finally destroyed. 02847 */ 02848 ClrWF(pwnd, WFHASPALETTE); 02849 02850 /* 02851 * Clear its child bits so no code assumes that if the child bit 02852 * is set, it has a parent. Change spmenu to NULL - it is only 02853 * non-zero if this was child. 02854 */ 02855 ClrWF(pwnd, WFTYPEMASK); 02856 SetWF(pwnd, WFTILED); 02857 pwnd->spmenu = NULL; 02858 }

void xxxFW_DestroyAllChildren PWND  pwnd  ) 
 

Definition at line 2126 of file createw.c.

References CheckLock, GETPTI, HWq, NULL, PostEventMessage(), tagTHREADINFO::pq, PtiCurrent, QEVENT_DESTROYWINDOW, SetVisible(), SetWF, tagWND::spwndChild, SV_UNSET, TestWF, ThreadLockAlwaysWithPti, ThreadUnlock, UnlinkWindow(), WFDESTROYED, WFVISIBLE, and xxxFreeWindow().

Referenced by xxxFreeWindow().

02128 { 02129 PWND pwndChild; 02130 TL tlpwndChild; 02131 PTHREADINFO pti; 02132 PTHREADINFO ptiCurrent = PtiCurrent(); 02133 02134 CheckLock(pwnd); 02135 02136 while (pwnd->spwndChild != NULL) { 02137 pwndChild = pwnd->spwndChild; 02138 02139 /* 02140 * ThreadLock prior to the unlink in case pwndChild 02141 * is already marked as destroyed. 02142 */ 02143 ThreadLockAlwaysWithPti(ptiCurrent, pwndChild, &tlpwndChild); 02144 02145 /* 02146 * Propagate the VISIBLE flag. We need to do this so that 02147 * when a child window gets destroyed we don't try to hide it 02148 * if the WFVISIBLE flag is set. 02149 */ 02150 if (TestWF(pwndChild, WFVISIBLE)) { 02151 SetVisible(pwndChild, SV_UNSET); 02152 } 02153 02154 UnlinkWindow(pwndChild, pwnd); 02155 02156 /* 02157 * Set the state as destroyed so any z-ordering events will be ignored. 02158 * We cannot NULL out the owner field until WM_NCDESTROY is send or 02159 * apps like Rumba fault (they call GetParent after every message) 02160 */ 02161 SetWF(pwndChild, WFDESTROYED); 02162 02163 /* 02164 * If the window belongs to another thread, post 02165 * an event to let it know it should be destroyed. 02166 * Otherwise, free the window. 02167 */ 02168 pti = GETPTI(pwndChild); 02169 if (pti != ptiCurrent) { 02170 PostEventMessage(pti, pti->pq, QEVENT_DESTROYWINDOW, 02171 NULL, 0, 02172 (WPARAM)HWq(pwndChild), 0); 02173 ThreadUnlock(&tlpwndChild); 02174 } else { 02175 /* 02176 * FreeWindow performs a ThreadUnlock. 02177 */ 02178 xxxFreeWindow(pwndChild, &tlpwndChild); 02179 } 02180 } 02181 }


Generated on Sat May 15 19:43:18 2004 for test by doxygen 1.3.7