test: createw.c Source File

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

# createw.c

Go to the documentation of this file.

    00001 /****************************** Module Header ******************************\
    00002 * Module Name: createw.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * Contains xxxCreateWindow, xxxDestroyWindow and a few close friends.
    00007 *
    00008 * Note that during creation or deletion, the window is locked so that
    00009 *   it can't be deleted recursively
    00010 *
    00011 * History:
    00012 * 19-Oct-1990 DarrinM   Created.
    00013 * 11-Feb-1991 JimA      Added access checks.
    00014 * 19-Feb-1991 MikeKe    Added Revalidation code
    00015 * 20-Jan-1992 IanJa     ANSI/UNICODE neutralization
    00016 \***************************************************************************/
    00017
    00018 #include "precomp.h"
    00019 #pragma hdrstop
    00020
    00021 BOOL WantImeWindow(IN PWND pwndParent, IN PWND pwnd);
    00022
    00023 /***************************************************************************\
    00024 * xxxCreateWindowEx (API)
    00025 *
    00026 * History:
    00027 * 10-18-90 darrinm      Ported from Win 3.0 sources.
    00028 * 02-07-91 DavidPe      Added Win 3.1 WH_CBT support.
    00029 * 02-11-91 JimA         Added access checks.
    00030 * 04-11-92 ChandanC     Added initialization of WOW words
    00031 \***************************************************************************/
    00032
    00033 PWND xxxCreateWindowEx(
    00034     DWORD         dwExStyle,
    00035     PLARGE_STRING cczpstrClass,
    00036     PLARGE_STRING cczpstrName,
    00037     DWORD         style,
    00038     int           x,
    00039     int           y,
    00040     int           cx,
    00041     int           cy,
    00042     PWND          pwndParent,
    00043     PMENU         pMenu,
    00044     HANDLE        hInstance,
    00045     LPVOID        lpCreateParams,
    00046     DWORD         dwExpWinVerAndFlags)
    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 }
    01286
    01287 BOOL WantImeWindow(IN PWND pwndParent, IN PWND pwnd)
    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 }
    01324
    01325
    01326 /***************************************************************************\
    01327 * SetTiledRect
    01328 *
    01329 * History:
    01330 * 10-19-90 darrinm      Ported from Win 3.0 sources.
    01331 \***************************************************************************/
    01332
    01333 void SetTiledRect(
    01334     PWND        pwnd,
    01335     LPRECT      lprc,
    01336     PMONITOR    pMonitor)
    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 }
    01390
    01391
    01392 /***************************************************************************\
    01393 * xxxAdjustSize
    01394 *
    01395 * Make sure that *lpcx and *lpcy are within the legal limits.
    01396 *
    01397 * History:
    01398 * 10-19-90 darrinm      Ported from Win 3.0 sources.
    01399 \***************************************************************************/
    01400
    01401 void xxxAdjustSize(
    01402     PWND pwnd,
    01403     LPINT lpcx,
    01404     LPINT lpcy)
    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 }
    01437
    01438 #if DBG
    01439 /***************************************************************************\
    01440 * VerifyWindowLink
    01441 *
    01442 * History:
    01443 * 10/28/96 GerardoB     Added
    01444 \***************************************************************************/
    01445 void VerifyWindowLink (PWND pwnd, PWND pwndParent, BOOL fLink)
    01446 {
    01447     BOOL fFirstFound = FALSE;
    01448     BOOL fInFound = FALSE;
    01449     PWND pwndNext = pwndParent->spwndChild;
    01450     PWND pwndFirst = pwndNext;
    01451
    01452     while (pwndNext != NULL) {
    01453         if (pwndFirst == pwndNext) {
    01454             if (fFirstFound) {
    01455                 RIPMSG1(RIP_ERROR, "Loop in %#p spwndNext chain", pwnd);
    01456                 return;
    01457             } else {
    01458                 fFirstFound = TRUE;
    01459             }
    01460         }
    01461
    01462         if (pwndNext == pwnd) fInFound = TRUE;
    01463         pwndNext = pwndNext->spwndNext;
    01464     }
    01465
    01466     if (fLink && !fInFound) {
    01467         RIPMSG1(RIP_ERROR, "%#p not found in spwndNext chain", pwnd);
    01468     }
    01469 }
    01470 #endif
    01471
    01472 /***************************************************************************\
    01473 * LinkWindow
    01474 *
    01475 * History:
    01476 \***************************************************************************/
    01477
    01478 void LinkWindow(
    01479     PWND pwnd,
    01480     PWND pwndInsert,
    01481     PWND pwndParent)
    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 }
    01578
    01579
    01580 /***************************************************************************\
    01581 * xxxDestroyWindow (API)
    01582 *
    01583 * Destroy the specified window. The window passed in is not thread locked.
    01584 *
    01585 * History:
    01586 * 10-20-90 darrinm      Ported from Win 3.0 sources.
    01587 * 02-07-91 DavidPe      Added Win 3.1 WH_CBT support.
    01588 * 02-11-91 JimA         Added access checks.
    01589 \***************************************************************************/
    01590
    01591 BOOL xxxDestroyWindow(
    01592     PWND pwnd)
    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 }
    01979
    01980
    01981 /***************************************************************************\
    01982 * xxxDW_DestroyOwnedWindows
    01983 *
    01984 * History:
    01985 * 10-20-90 darrinm      Ported from Win 3.0 sources.
    01986 * 07-22-91 darrinm      Re-ported from Win 3.1 sources.
    01987 \***************************************************************************/
    01988
    01989 void xxxDW_DestroyOwnedWindows(
    01990     PWND pwndParent)
    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 }
    02044
    02045
    02046 /***************************************************************************\
    02047 * xxxDW_SendDestroyMessages
    02048 *
    02049 * History:
    02050 * 10-20-90 darrinm      Ported from Win 3.0 sources.
    02051 \***************************************************************************/
    02052
    02053 void xxxDW_SendDestroyMessages(
    02054     PWND pwnd)
    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 }
    02117
    02118
    02119 /***************************************************************************\
    02120 * xxxFW_DestroyAllChildren
    02121 *
    02122 * History:
    02123 * 11-06-90 darrinm      Ported from Win 3.0 sources.
    02124 \***************************************************************************/
    02125
    02126 void xxxFW_DestroyAllChildren(
    02127     PWND pwnd)
    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 }
    02182
    02183 /***************************************************************************\
    02184 * UnlockNotifyWindow
    02185 *
    02186 * Walk down a menu and unlock all notify windows.
    02187 *
    02188 * History:
    02189 * 18-May-1994 JimA      Created.
    02190 \***************************************************************************/
    02191
    02192 VOID UnlockNotifyWindow(
    02193     PMENU pmenu)
    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 }
    02210
    02211 /***************************************************************************\
    02212 * xxxFreeWindow
    02213 *
    02214 * History:
    02215 * 19-Oct-1990 DarrinM   Ported from Win 3.0 sources.
    02216 \***************************************************************************/
    02217
    02218 VOID xxxFreeWindow(
    02219     PWND pwnd,
    02220     PTL  ptlpwndFree)
    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 }
    02859
    02860 /***************************************************************************\
    02861 * UnlinkWindow
    02862 *
    02863 * History:
    02864 * 19-Oct-1990 DarrinM   Ported from Win 3.0 sources.
    02865 \***************************************************************************/
    02866
    02867 VOID UnlinkWindow(
    02868     PWND pwndUnlink,
    02869     PWND pwndParent)
    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 }
    02914
    02915 /***************************************************************************\
    02916 * DestroyCacheDCEntries
    02917 *
    02918 * Destroys all cache dc entries currently in use by this thread.
    02919 *
    02920 * 24-Feb-1992 ScottLu   Created.
    02921 \***************************************************************************/
    02922
    02923 VOID DestroyCacheDCEntries(
    02924     PTHREADINFO pti)
    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 }
    02961
    02962 /***************************************************************************\
    02963 * PatchThreadWindows
    02964 *
    02965 * This patches a thread's windows so that their window procs point to
    02966 * server only windowprocs. This is used for cleanup so that app aren't
    02967 * called back while the system is cleaning up after them.
    02968 *
    02969 * 24-Feb-1992 ScottLu   Created.
    02970 \***************************************************************************/
    02971
    02972 VOID PatchThreadWindows(
    02973     PTHREADINFO pti)
    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 }