Example #1
0
BOOL _ShowWindowAsync(
    PWND pwnd,
    int cmdShow)
{
    return PostEventMessage(GETPTI(pwnd), GETPTI(pwnd)->pq, QEVENT_SHOWWINDOW,
                            NULL, 0,(DWORD)HWq(pwnd),
                            MAKELONG(cmdShow, gfAnimate));
}
Example #2
0
PWND InternalDoPaint(
    PWND        pwnd,
    PTHREADINFO ptiCurrent)
{
    PWND pwndT;

    /*
     * Enumerate all windows, top-down, looking for one that
     * needs repainting.  Skip windows of other tasks.
     */
    for ( ; pwnd != NULL; pwnd = pwnd->spwndNext) {

        if (GETPTI(pwnd) == ptiCurrent) {

            if (NEEDSPAINT(pwnd)) {

                /*
                 * If this window is transparent, we don't want to
                 * send it a WM_PAINT until all its siblings below it
                 * have been repainted.  If we find an unpainted sibling
                 * below, return it instead.
                 */
                if (TestWF(pwnd, WEFTRANSPARENT)) {

                    pwndT = pwnd;
                    while ((pwndT = pwndT->spwndNext) != NULL) {

                        /*
                         * Make sure sibling window belongs to same app
                         */
                        if ((GETPTI(pwndT) == ptiCurrent) && NEEDSPAINT(pwndT)) {

                            if (TestWF(pwndT, WEFTRANSPARENT))
                                continue;

                            return pwndT;
                        }
                    }
                }

                return pwnd;
            }
        }

        if (pwnd->spwndChild &&
            (pwndT = InternalDoPaint(pwnd->spwndChild, ptiCurrent))) {

            return pwndT;
        }
    }

    return pwnd;
}
Example #3
0
/***************************************************************************\
*
* _GetListBoxInfo()
*
* Currently returns back the # of items per column.  There is no way to get
* or calculate this info any other way in a multicolumn list.
*
* For now, no structure is returned. If we ever need one more thing, make one.
*
* Since I have to run on multiple platforms, I can't define a message.
* To do so would require that
*     * I make changes to the thunk table
*     * I make sure the 32-bit define doesn't collide with some NT new msg
*     * I use a different value on Win '95 vs Memphis due to additions
*     * I test apps extensively since many of them pass on bogus valued
*         messages to the listbox handler which checks to see if they
*         are in range.  In other words, any value I pick is probably
*         going to flake out MSVC++ 4.0.
*
*  Ergo an API instead.
*
\***************************************************************************/
DWORD WINAPI
_GetListBoxInfo(PWND pwnd)
{
    PCLS    pcls;
    DWORD   dwRet = 0;
    BOOL    fOtherProcess;

    /*
     * Make sure it is a combobox or a dropdown
     */
    pcls = pwnd->pcls;
    if ((pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) &&
            (GETFNID(pwnd) != FNID_LISTBOX)) {
        RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "pwnd %#p is not a listbox", pwnd);
        return 0;
    }

    if (fOtherProcess = (GETPTI(pwnd)->ppi != PpiCurrent())) {
        KeAttachProcess(&GETPTI(pwnd)->ppi->Process->Pcb);
    }

    try {
        PLBIV   ccxPlbSnap;

        /*
         * Snap and probe the pointer to the LBIV, since it is client-side.
         */
        ccxPlbSnap = ((PLBWND)pwnd)->pLBIV;
        if (!ccxPlbSnap) {
            goto errorexit;
        }
        ProbeForRead(ccxPlbSnap, sizeof(LBIV), DATAALIGN);

        if (ccxPlbSnap->fMultiColumn) {
            dwRet = ccxPlbSnap->itemsPerColumn;
        } else {
            dwRet = ccxPlbSnap->cMac;
        }
    } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
        dwRet = 0;
    }

errorexit:
    if (fOtherProcess) {
        KeDetachProcess();
    }

    return dwRet;
}
Example #4
0
PWND xxxSetCapture(
    PWND pwnd)
{
    PQ   pq;
    PWND pwndCaptureOld;
    HWND hwndCaptureOld;

    pq = (PQ)PtiCurrent()->pq;

    /*
     * Don't allow the app to set capture to a window
     * from another queue.
     */
    if ((pwnd != NULL) && GETPTI(pwnd)->pq != pq)
        return NULL;

    /*
     * If full screen capture don't allow any other capture
     */
    if (gspwndScreenCapture)
        return NULL;

    pwndCaptureOld = pq->spwndCapture;
    hwndCaptureOld = HW(pwndCaptureOld);

    xxxCapture(PtiCurrent(), pwnd, CLIENT_CAPTURE);

    if (hwndCaptureOld != NULL) {

        if (RevalidateHwnd(hwndCaptureOld))
            return pwndCaptureOld;
    }

    return NULL;
}
Example #5
0
BOOL FCallerOk(
    PWND pwnd)
{
    PTHREADINFO pti = PtiCurrent();

    if ((GETPTI(pwnd)->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) &&
            !(pti->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD))) {
        return FALSE;
    }

    if (GETPTI(pwnd)->pEThread->Cid.UniqueProcess == gpidLogon &&
            pti->pEThread->Cid.UniqueProcess != gpidLogon) {
        return FALSE;
    }

    return TRUE;
}
Example #6
0
VOID IncPaintCount(
    PWND pwnd)
{
    PTHREADINFO pti = GETPTI(pwnd);

    if (pti->cPaintsReady++ == 0)
        SetWakeBit(pti, QS_PAINT);
}
Example #7
0
VOID DecPaintCount(
    PWND pwnd)
{
    PTHREADINFO pti = GETPTI(pwnd);

    if (--pti->cPaintsReady == 0) {
        pti->pcti->fsWakeBits   &= ~QS_PAINT;
        pti->pcti->fsChangeBits &= ~QS_PAINT;
    }
}
Example #8
0
/***************************************************************************\
* MNEndMenuStateNotify
*
* spwndNotify might have been created by a thread other than the one
*  the menu mode is running on. If this is the case, this function
*  NULLs out pMenuState for the thread that owns spwndNotify.
*
* 05-21-96 GerardoB Created
\***************************************************************************/
void MNEndMenuStateNotify (PMENUSTATE pMenuState)
{
    PTHREADINFO ptiNotify;

    if (pMenuState->pGlobalPopupMenu->spwndNotify != NULL) {
        ptiNotify = GETPTI(pMenuState->pGlobalPopupMenu->spwndNotify);
        if (ptiNotify != pMenuState->ptiMenuStateOwner) {
            UserAssert(ptiNotify->pMenuState == pMenuState);
            ptiNotify->pMenuState = NULL;
        }
    }
}
Example #9
0
/***************************************************************************\
* xxxMessageEvent
*
* Description:  Called when a hooked DDE message is sent or posted.  flags
*   specifies the applicable MF_ flag.  This is called in the server side
*   context of the sender or poster which may or may not be a DDEML process.
*   pdmhd contains DDE data extracted and copied from the client side.
*
* History:
* 12-1-91   sanfords    Created.
\***************************************************************************/
VOID xxxMessageEvent(
PWND pwndTo,
UINT message,
WPARAM wParam,
LPARAM lParam,
DWORD flag,
PDDEML_MSG_HOOK_DATA pdmhd)
{
    PEVENT_PACKET pep;
    PWND pwndFrom;
    TL tlpep;
    PTHREADINFO pti;

    CheckCritIn();

    pep = (PEVENT_PACKET)UserAllocPoolWithQuota(sizeof(EVENT_PACKET) -
            sizeof(DWORD) + sizeof(MONMSGSTRUCT), TAG_DDE8);
    if (pep == NULL) {
        return;
    }
    pep->EventType = flag;
    pep->fSense = TRUE;
    pep->cbEventData = sizeof(MONMSGSTRUCT);
#define pmsgs ((MONMSGSTRUCT *)&pep->Data)
    pmsgs->cb = sizeof(MONMSGSTRUCT);
    pmsgs->hwndTo = PtoH(pwndTo);
    pmsgs->dwTime = NtGetTickCount();

    pwndFrom = RevalidateHwnd((HWND)wParam);
    if (pwndFrom != NULL) {
        pmsgs->hTask = GETPTI(pwndFrom)->pEThread->Cid.UniqueThread;
    } else {
        pmsgs->hTask = 0;
    }

    pmsgs->wMsg = message;
    pmsgs->wParam = wParam;
    pmsgs->lParam = lParam;
    if (pdmhd != NULL) {
        pmsgs->dmhd = *pdmhd;
    }
#undef pmsgs
    pti = PtiCurrent();
    ThreadLockPool(pti, pep, &tlpep);
    xxxCsEvent(pep, sizeof(MONMSGSTRUCT));
    ThreadUnlockAndFreePool(pti, &tlpep);
}
Example #10
0
/***************************************************************************\
* xxxCancelMouseMoveTracking
*
* History
* 12/07/96 GerardoB  Created
\***************************************************************************/
void xxxCancelMouseMoveTracking (DWORD dwDTFlags, PWND pwndTrack, int htEx, DWORD dwDTCancel)
{

    CheckLock(pwndTrack);
    /*
     * Hottracking
     */
    if ((dwDTFlags & DF_HOTTRACKING) && (dwDTCancel & DF_HOTTRACKING)) {
        /*
         * The current state must be owned by the current queue.
         * Otherwise, we're about to do an inter-queue cancelation.
         */
        UserAssert(PtiCurrent()->pq == GETPTI(pwndTrack)->pq);

        xxxHotTrack(pwndTrack, htEx, FALSE);
    }

    /*
     * Tooltips
     */
    if ((dwDTFlags & DF_TOOLTIPSHOWING) && (dwDTCancel & DF_TOOLTIP)) {
        PTOOLTIPWND pttwnd = (PTOOLTIPWND)PWNDTOOLTIP(pwndTrack);
        TL tlpwnd;

        ThreadLockAlways(pttwnd, &tlpwnd);
        xxxResetTooltip(pttwnd);
        ThreadUnlock(&tlpwnd);
    }

    /*
     * Mouse Leave
     */
    if ((dwDTFlags & DF_TRACKMOUSELEAVE) && (dwDTCancel & DF_TRACKMOUSELEAVE)) {
        _PostMessage(pwndTrack,
                     ((htEx == HTCLIENT) ? WM_MOUSELEAVE : WM_NCMOUSELEAVE),
                     0, 0);
    }

    /*
     * Mouse Hover
     */
    if ((dwDTFlags & DF_TRACKMOUSEHOVER) && (dwDTCancel & DF_TRACKMOUSEHOVER)) {
        _KillSystemTimer(pwndTrack, IDSYS_MOUSEHOVER);
    }
}
Example #11
0
void xxxClientShutdown(
    PWND pwnd,
    DWORD wParam,
    DWORD lParam)
{
    PBWL pbwl;
    PTHREADINFO ptiT;
    BOOL fExit;

    /*
     * Build a list of windows first.
     */
    fExit = TRUE;
    ptiT = GETPTI(pwnd);

    /*
     * If the request was cancelled, then do nothing.
     */
    if (ptiT->TIF_flags & TIF_SHUTDOWNCOMPLETE) {
        return;
    }

    if ((pbwl = BuildHwndList(ptiT->rpdesk->pDeskInfo->spwnd->spwndChild,
            BWL_ENUMLIST, ptiT)) == NULL) {
        /*
         * Can't allocate memory to notify this thread's windows of shutdown.
         */
        goto SafeExit;
    }

    if (wParam & WMCS_QUERYEND) {
        fExit = xxxClientShutdown2(pbwl, WM_QUERYENDSESSION, wParam);
    } else {
        xxxClientShutdown2(pbwl, WM_ENDSESSION, wParam);
        fExit = TRUE;
    }

    FreeHwndList(pbwl);

SafeExit:
    ptiT->TIF_flags |= (TIF_SHUTDOWNCOMPLETE | (fExit ? TIF_ALLOWSHUTDOWN : 0));
}
Example #12
0
VOID SetDialogPointer(PWND pwnd, LONG_PTR lPtr) {

    if ((pwnd->cbwndExtra < DLGWINDOWEXTRA)
            || TestWF(pwnd, WFSERVERSIDEPROC)
            || (PpiCurrent() != GETPTI(pwnd)->ppi)) {
        RIPMSG1(RIP_WARNING, "SetDialogPointer: Unexpected pwnd:%#p", pwnd);
        return;
    }

    ((PDIALOG)pwnd)->pdlg = (PDLG)lPtr;

    if (lPtr == 0) {
        pwnd->fnid |= FNID_CLEANEDUP_BIT;
        ClrWF(pwnd, WFDIALOGWINDOW);
    } else {
        if (pwnd->fnid == 0) {
            pwnd->fnid = FNID_DIALOG;
        }
        SetWF(pwnd, WFDIALOGWINDOW);
    }


}
Example #13
0
VOID xxxInternalDoSyncPaint(
    PWND  pwnd,
    DWORD flags)
{
    CheckLock(pwnd);

    /*
     * Do the paint for this window.
     */
    xxxSimpleDoSyncPaint(pwnd);

    /*
     * Normally we like to enumerate all of this window's children and have
     * them erase their backgrounds synchronously.  However, this is a bad
     * thing to do if the window is NOT CLIPCHLIDREN.  Here's the scenario
     * we want to to avoid:
     *
     * 1) Window 'A' is invalidated
     * 2) 'A' erases itself (or not, doesn't matter)
     * 3) 'A's children are enumerated and they erase themselves.
     * 4) 'A' paints over its children (remember, 'A' isn't CLIPCHILDREN)
     * 5) 'A's children paint but their backgrounds aren't their ERASEBKND
     *    color (because 'A' painted over them) and everything looks like
     *    dirt.
     */
    if ((flags & DSP_ALLCHILDREN) ||
        ((flags & DSP_ENUMCLIPPEDCHILDREN) && TestWF(pwnd, WFCLIPCHILDREN))) {

        TL   tlpwnd;
        PBWL pbwl;
        HWND *phwnd;

        if (pbwl = BuildHwndList(pwnd->spwndChild, BWL_ENUMLIST, NULL)) {

            PTHREADINFO ptiCurrent = PtiCurrent();
            HWND        hwnd;

            /*
             * If the client dies during a callback, the hwnd list
             * will be freed in xxxDestroyThreadInfo.
             */
            for (phwnd = pbwl->rghwnd; (hwnd = *phwnd) != (HWND)1; phwnd++) {

                if (hwnd == NULL)
                    continue;

                if ((pwnd = (PWND)RevalidateHwnd(hwnd)) == NULL)
                    continue;

                /*
                 * Note: testing if a window is a child automatically
                 * excludes the desktop window.
                 */
                if (TestWF(pwnd, WFCHILD) && (ptiCurrent != GETPTI(pwnd))) {

                    /*
                     * Don't cause any more intertask sendmessages cause it
                     * does bad things to cbt's windowproc hooks.  (Due to
                     * SetParent allowing child windows in the topwindow
                     * hierarchy.
                     */
                    continue;
                }

                /*
                 * Note that we pass only certain bits down as we recurse:
                 * the other bits pertain to the current window only.
                 */
                ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
                xxxInternalDoSyncPaint(pwnd, flags);
                ThreadUnlock(&tlpwnd);
            }

            FreeHwndList(pbwl);
        }
    }
}
Example #14
0
VOID xxxSimpleDoSyncPaint(
    PWND pwnd)
{
    HRGN  hrgnUpdate;
    DWORD flags = 0;

    CheckLock(pwnd);

    /*
     * Since we're taking care of the frame drawing, we can consider
     * this WM_PAINT message processed.
     */
    ClrWF(pwnd, WFPAINTNOTPROCESSED);

    /*
     * Make copies of these flags, because their state might
     * change after we send a message, and we don't want
     * to "lose" them.
     */
    if (TestWF(pwnd, WFSENDNCPAINT))
        flags |= DSP_FRAME;

    if (TestWF(pwnd, WFSENDERASEBKGND))
        flags |= DSP_ERASE;

    if (flags & (DSP_ERASE | DSP_FRAME)) {

        if (!TestWF(pwnd, WFVISIBLE)) {

            /*
             * If there is no update region, just clear the bits.
             */
            ClrWF(pwnd, WFSENDNCPAINT);
            ClrWF(pwnd, WFSENDERASEBKGND);
            ClrWF(pwnd, WFPIXIEHACK);
            ClrWF(pwnd, WFERASEBKGND);
            ClearHungFlag(pwnd, WFREDRAWIFHUNG);

        } else {

            PTHREADINFO ptiCurrent = PtiCurrent();

            /*
             * If there is no update region, we don't have to
             * do any erasing, but we may need to send an NCPAINT.
             */
            if (pwnd->hrgnUpdate == NULL) {
                ClrWF(pwnd, WFSENDERASEBKGND);
                ClrWF(pwnd, WFERASEBKGND);
                flags &= ~DSP_ERASE;
            }

            /*
             * Only mess with windows owned by the current thread.
             * NOTE: This means that WM_NCPAINT and WM_ERASEBKGND are
             *       only sent intra-thread.
             */
            if (GETPTI(pwnd) == ptiCurrent) {

                hrgnUpdate = GetNCUpdateRgn(pwnd, TRUE);

                if (flags & DSP_FRAME) {

                    /*
                     * If the message got sent before we got here then do
                     * nothing.
                     */
                    if (TestWF(pwnd, WFSENDNCPAINT))
                        xxxSendNCPaint(pwnd, hrgnUpdate);
                }

                if (flags & DSP_ERASE) {

                    if (TestWF(pwnd, WFSENDNCPAINT)) {
                        /*
                         * If we got another invalidate during the NCPAINT
                         * callback get the new update region
                         */
                        DeleteMaybeSpecialRgn(hrgnUpdate);
                        hrgnUpdate = GetNCUpdateRgn(pwnd, FALSE);
                    }

                    /*
                     * If the message got sent before we got here
                     * (e.g.: an UpdateWindow() inside WM_NCPAINT handler,
                     * for example), don't do anything.
                     *
                     * WINPROJ.EXE (version 1.0) calls UpdateWindow() in
                     * the WM_NCPAINT handlers for its subclassed listboxes
                     * in the open dialog.
                     */
                    if (TestWF(pwnd, WFSENDERASEBKGND)) {
                        ClrWF(pwnd, WFSENDERASEBKGND);
                        ClrWF(pwnd, WFERASEBKGND);
                        xxxSendEraseBkgnd(pwnd, NULL, hrgnUpdate);
                    }

                    /*
                     * The erase and frame operation has occured. Clear the
                     * WFREDRAWIFHUNG bit here. We don't want to clear it until we
                     * know the erase and frame has occured, so we know we always
                     * have a consistent looking window.
                     */
                    ClearHungFlag(pwnd, WFREDRAWIFHUNG);
                }

                DeleteMaybeSpecialRgn(hrgnUpdate);

            } else if (!TestwndChild(pwnd)                         &&
                       (pwnd != grpdeskRitInput->pDeskInfo->spwnd) &&
                       FHungApp(GETPTI(pwnd), CMSHUNGAPPTIMEOUT)   &&
                       TestWF(pwnd, WFREDRAWIFHUNG)) {

                ClearHungFlag(pwnd, WFREDRAWIFHUNG);
                xxxRedrawHungWindow(pwnd, NULL);
            }
        }
    }
}
Example #15
0
BOOL xxxSendEraseBkgnd(
    PWND pwnd,
    HDC  hdcBeginPaint,
    HRGN hrgnUpdate)
{
    PTHREADINFO ptiCurrent;
    BOOL        fErased;
    HDC         hdc;

    CheckLock(pwnd);

    /*
     * For minimized dudes in win3.1, we would've sent an
     * WM_ICONERASEBKGND and cleared the erase bit.  Now that min
     * windows in 4.0 are all nonclient, don't bother erasing at
     * all.  Pretend like we did.
     *
     * NOTE:
     * For < 4.0 windows, we may have to send a fake WM_ICONERASEKBGND
     * to keep 'em happy.  Saves time not to though.  Getting a DC and
     * sending the message ain't speedy.
     */
    if ((hrgnUpdate == NULL) || TestWF(pwnd, WFMINIMIZED))
        return FALSE;

    /*
     * If a DC to use was not passed in, get one.
     * We want one clipped to this window's update region.
     */
    if (hdcBeginPaint == NULL) {

       hdc = _GetDCEx(pwnd,
                      hrgnUpdate,
                      DCX_USESTYLE | DCX_INTERSECTRGN | DCX_NODELETERGN);
    } else {

        hdc = hdcBeginPaint;
    }

    /*
     * If we're send the WM_ERASEBKGND to another process
     * we need to change the DC owner.
     *
     * We'd like to change the owner to pwnd->pti->idProcess, but
     * GDI won't let us assign ownership back to ourselves later.
     */
    ptiCurrent = PtiCurrent();

    if (GETPTI(pwnd)->ppi != ptiCurrent->ppi)
        GreSetDCOwner(hdc, OBJECT_OWNER_PUBLIC);

    /*
     * Send the event to the window.  This contains the DC clipped to
     * the update-region.
     */
    fErased = (BOOL)xxxSendMessage(pwnd, WM_ERASEBKGND, (WPARAM)hdc, 0L);

    /*
     * If we've changed the DC owner, change it back to
     * the current process.
     */
    if (GETPTI(pwnd)->ppi != ptiCurrent->ppi)
        GreSetDCOwner(hdc, OBJECT_OWNER_CURRENT);

    /*
     * If the WM_ERASEBKGND message did not erase the
     * background, then set this flag to let BeginPaint()
     * know to ask the caller to do it via the fErase
     * flag in the PAINTSTRUCT.
     */
    if (!fErased) {
        SetWF(pwnd, WFERASEBKGND);
        if (!TestWF(pwnd, WFWIN31COMPAT))
            SetWF(pwnd, WFSENDERASEBKGND);
    }

    /*
     * If we got a cache DC in this routine, release it.
     */
    if (hdcBeginPaint == NULL) {
        ReleaseCacheDC(hdc, TRUE);
    }

    return fErased;
}
Example #16
0
/***************************************************************************\
*
* _GetComboBoxInfo()
*
* This returns combobox information for either a combo or its dropdown
* list.
*
\***************************************************************************/
BOOL WINAPI
_GetComboBoxInfo(PWND pwnd, PCOMBOBOXINFO pcbi)
{
    PCLS    pcls;
    COMBOBOXINFO cbi = {
        sizeof cbi,
    };
    BOOL fOtherProcess;
    BOOL bRetval = FALSE;
    WORD wWindowType = 0;

    /*
     * Make sure it is a combobox or a dropdown
     */
    pcls = pwnd->pcls;


    if ((GETFNID(pwnd) == FNID_COMBOBOX) ||
            (pcls->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX])) {
        wWindowType = FNID_COMBOBOX;
    } else if ((GETFNID(pwnd) == FNID_COMBOLISTBOX) ||
            (pcls->atomClassName == gpsi->atomSysClass[ICLS_COMBOLISTBOX])) {
        wWindowType = FNID_COMBOLISTBOX;
    } else {
        RIPERR1(ERROR_WINDOW_NOT_COMBOBOX, RIP_WARNING,
                "pwnd %#p not a combobox or dropdown", pwnd);
        return FALSE;
    }

    /*
     * Validate combo structure
     */
    if (pcbi->cbSize != sizeof(COMBOBOXINFO)) {
        RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "COMBOBOXINFO.cbSize %d is wrong", pcbi->cbSize);
        return FALSE;
    }

    if (fOtherProcess = (GETPTI(pwnd)->ppi != PpiCurrent())) {
        KeAttachProcess(&GETPTI(pwnd)->ppi->Process->Pcb);
    }

    try {
        PCBOX ccxPcboxSnap;
        PWND  ccxPwndSnap;
        HWND  ccxHwndSnap;

        /*
         * Snap and probe the CBOX structure, since it is client side.
         */
        if (wWindowType == FNID_COMBOBOX) {
            ccxPcboxSnap = ((PCOMBOWND)pwnd)->pcbox;
        } else {
            PLBIV ccxPlbSnap;
            /*
             * If this is a listbox, we must snap and probe the LBIV structure
             * in order to get to the CBOX structure.
             */
            ccxPlbSnap = ((PLBWND)pwnd)->pLBIV;
            if (!ccxPlbSnap) {
                goto errorexit;
            }
            ProbeForRead(ccxPlbSnap, sizeof(LBIV), DATAALIGN);
            ccxPcboxSnap = ccxPlbSnap->pcbox;
        }
        if (!ccxPcboxSnap) {
            goto errorexit;
        }
        ProbeForRead(ccxPcboxSnap, sizeof(CBOX), DATAALIGN);

        /*
         * Get the combo information now
         */

        /*
         * Snap and probe the client side pointer to the Combo window
         */
        ccxPwndSnap = ccxPcboxSnap->spwnd;
        ProbeForRead(ccxPwndSnap, sizeof(HEAD), DATAALIGN);
        cbi.hwndCombo = HWCCX(ccxPwndSnap);

        /*
         * Snap & probe the client side pointer to the Edit window.
         * To compare spwndEdit and pwnd, we should compare handles
         * since spwndEdit is a client-side address and pwnd is a
         * kernel-mode address,
         */

        ccxPwndSnap = ccxPcboxSnap->spwndEdit;
        /*
         * If combobox is not fully initialized and spwndEdit is NULL,
         * we should fail.
         */
        ProbeForRead(ccxPwndSnap, sizeof(HEAD), DATAALIGN);
        ccxHwndSnap = HWCCX(ccxPwndSnap);
        if (ccxHwndSnap == HW(pwnd)) {
            /*
             * ComboBox doesn't have Edit control.
             */
            cbi.hwndItem = NULL;
        } else {
            cbi.hwndItem = HWCCX(ccxPwndSnap);
        }

        /*
         * Snap and probe the client side pointer to the List window
         */
        ccxPwndSnap = ccxPcboxSnap->spwndList;
        /*
         * If combobox is not fully initialized and spwndList is NULL,
         * we should fail.
         */
        ProbeForRead(ccxPwndSnap, sizeof(HEAD), DATAALIGN);
        cbi.hwndList = HWCCX(ccxPwndSnap);

        /*
         * Snap the rest of the combo information.
         * We don't need to probe any of these, since there are no more indirections.
         */
        cbi.rcItem = ccxPcboxSnap->editrc;
        cbi.rcButton = ccxPcboxSnap->buttonrc;

        /*
         * Button state
         */
        cbi.stateButton = 0;
        if (ccxPcboxSnap->CBoxStyle == CBS_SIMPLE) {
            cbi.stateButton |= STATE_SYSTEM_INVISIBLE;
        }
        if (ccxPcboxSnap->fButtonPressed) {
            cbi.stateButton |= STATE_SYSTEM_PRESSED;
        }
    } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
        goto errorexit;
    }

    *pcbi = cbi;
    bRetval = TRUE;

errorexit:
    if (fOtherProcess) {
        KeDetachProcess();
    }
    return bRetval;
}
Example #17
0
VOID xxxCapture(
    PTHREADINFO pti,
    PWND        pwnd,
    UINT        code)
{
    if ((gspwndScreenCapture == NULL) ||
        (code == FULLSCREEN_CAPTURE) ||
        ((pwnd == NULL) && (code == NO_CAP_CLIENT) && (pti->pq != GETPTI(gspwndScreenCapture)->pq))) {

        PQ   pq;
        PWND pwndCaptureOld = NULL;

        if (code == FULLSCREEN_CAPTURE) {
            if (pwnd) {

                Lock(&gspwndScreenCapture, pwnd);

                /*
                 * We're going full screen so clear the mouse owner
                 */
                Unlock(&gspwndMouseOwner);

            } else {

                Unlock(&gspwndScreenCapture);
            }
        }

        /*
         * Internal capture works like Win 3.1 capture unlike the NT capture
         * which can be lost if the user clicks down on another application
         */
        if (code == CLIENT_CAPTURE_INTERNAL) {
            Lock(&gspwndInternalCapture, pwnd);
            code = CLIENT_CAPTURE;
        }

        /*
         * Free the internal capture if the app (thread) that did the internal
         * capture is freeing the capture.
         */
        if ((code == NO_CAP_CLIENT) &&
            gspwndInternalCapture   &&
            (pti == GETPTI(gspwndInternalCapture))) {

            Unlock(&gspwndInternalCapture);
        }

        if ((pq = pti->pq) != NULL) {

            /*
             * Make consistent picture of mouse tracking stuff for apps
             */
            if ((pq->spwndLastMouseMessage != NULL) &&
                    ((pwnd == pq->spwndLastMouseMessage) &&
                     (code != CLIENT_CAPTURE)) ||
                    ((pq->spwndCapture == pq->spwndLastMouseMessage) &&
                     (pq->codeCapture != CLIENT_CAPTURE))) {
                ResetMouseTracking(pq, NULL);
            }

            pwndCaptureOld = pq->spwndCapture;
            Lock(&pq->spwndCapture, pwnd);
            pq->codeCapture = code;
        }

        /*
         * If there was a capture window and we're releasing it, post
         * a WM_MOUSEMOVE to the window we're over so they can know about
         * the current mouse position.
         */
        if ((pwnd == NULL) && (pwndCaptureOld != NULL))
            SetFMouseMoved();

        /*
         * New for win95 - send  WM_CAPTURECHANGED.
         *
         * The FNID_DELETED_BIT is set in xxxFreeWindow which means we
         * DON'T want to send the message.
         */
        if (pwndCaptureOld                        &&
            TestWF(pwndCaptureOld, WFWIN40COMPAT) &&
            !(pwndCaptureOld->fnid & FNID_DELETED_BIT)) {

            TL tlpwnd;

            ThreadLock(pwndCaptureOld, &tlpwnd);
            xxxSendMessageCallback(pwndCaptureOld,
                    WM_CAPTURECHANGED,
                    FALSE,
                    (LPARAM)HW(pwnd),
                    NULL,
                    0,
                    FALSE);
            ThreadUnlock(&tlpwnd);
        }
    }
}
Example #18
0
void xxxTrackMouseMove(PWND pwnd, int htEx, UINT message)
{
    BOOL fNewpwndTrack;
    DWORD dwDTCancel = 0;
    TL tlpwnd;
    LPWSTR pstr;
    PDESKTOP pdesk = PtiCurrent()->rpdesk;
    PTHREADINFO ptiTrack;


#if DBG
    /*
     * Let's warn if this function gets reenterd so we can make sure
     * nothing bad will follow. This should be a rare situation.
     * Look in gptiReEntered to find out who is already here.
     */
    static UINT gcReEntered = 0;
    static PTHREADINFO gptiReEntered;
    if(gcReEntered++ != 0){
      RIPMSG2(RIP_WARNING, "Reentered xxxTrackMouseMove; previous thread was %#p, current thread is %#p", gptiReEntered, PtiCurrent());
    }
    gptiReEntered = PtiCurrent();

    CheckLock(pwnd);

    /*
     * We must be on an interactive window station.
     */
    if (pdesk->rpwinstaParent != NULL &&
            pdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO) {
        RIPMSG0(RIP_ERROR, "Can't use tooltips on non-interactive winsta");
    }

     {
        static POINT pt = {0, 0};

#ifdef UNDONE
        /*
         * We might have taken a guess on the hit test (see FindNCHitEx)
         *  so if we're at the same point and same window, something
         *  might be fishy
         */
        if ((pt.x == gpsi->ptCursor.x)
                    && (pt.y == gpsi->ptCursor.y)
                    && (pdesk->spwndTrack == pwnd)) {
            RIPMSG1(RIP_WARNING, "xxxTrackMouseMove: Same point & window. %#p", pwnd);
        }
#endif

        /*
         * Something is supposed to have changed or we're wasting time
         */
        UserAssert((pt.x != gpsi->ptCursor.x)
                    || (pt.y != gpsi->ptCursor.y)
                    || (pdesk->spwndTrack != pwnd)
                    || (pdesk->htEx != htEx)
                    || (message != WM_MOUSEMOVE));
        /*
         * Remember last tracked point
         */
        pt = gpsi->ptCursor;
     }
    /*
     * pwnd is supposed to be on the current thread and queue
     */
    UserAssert(PtiCurrent() == GETPTI(pwnd));
    UserAssert(PtiCurrent()->pq == GETPTI(pwnd)->pq);
#endif

    /*
     * Have we switched windows?
     */
    fNewpwndTrack = (pdesk->spwndTrack != pwnd);
    /*
     * If no tracking is taking place, just go set the new
     *  tracking state
     */
    if (!(pdesk->dwDTFlags & DF_MOUSEMOVETRK)) {
        goto SetNewState;
    }
    /*
     * Potentially while we leave the critical section below in
     * xxxCancelMouseMoveTracking, spwndTrack could be destroyed and unlocked
     * and then we go and create the tooltip. This would mean that
     * DF_TOOLTIPACTIVE (part of DF_MOUSEMOVETRK test above) would be set,
     * but pdesk->spwndTrack would be NULL and we can AV dereferencing
     * pdesk->spwndTrack below. Prevent this by making the check here.
     */
    if (pdesk->spwndTrack == NULL) {
        goto SetNewState;
    }

    /*
     * Nuke hottracking and deactivate tooltip state, if any.
     * Do it sychronously if we're tracking on the current queue;
     *  Otherwise, post an event and let it happen later.
     */
    ptiTrack = GETPTI(pdesk->spwndTrack);
    if  (PtiCurrent()->pq == ptiTrack->pq) {
        dwDTCancel |= DF_HOTTRACKING;
    } else if (pdesk->dwDTFlags & (DF_HOTTRACKING | DF_TOOLTIPACTIVE)) {
        PostEventMessage(ptiTrack, ptiTrack->pq,
                        QEVENT_CANCELMOUSEMOVETRK,
                        pdesk->spwndTrack,
                        pdesk->dwDTFlags,
                        pdesk->htEx, DF_HOTTRACKING);
       /*
        * Paranoid assertion. If we're switching queues, we must
        *  be switching windows. Did we just go through
        *  ReattachThreads?
        */
        UserAssert(pwnd != pdesk->spwndTrack);
        pdesk->dwDTFlags &= ~(DF_HOTTRACKING | DF_TOOLTIPACTIVE);
    }
    /*
     * If we're on the client area or the user clicked,
     *  nuke the tooltip (if any).
     * Since we might want to re-show the tooltip, we don't nuke it
     *  now if we swichted windows (we'll nuke it later if needed)
     */
    if ((htEx == HTCLIENT) || (message != WM_MOUSEMOVE)) {
        dwDTCancel |= DF_TOOLTIPACTIVE;
    }
    /*
     * If we switched windows or crossed client/nonclinet boundaries,
     *  end track mouse leave/hover.
     */
    if (fNewpwndTrack || ((pdesk->htEx == HTCLIENT) ^ (htEx == HTCLIENT))) {
        dwDTCancel |= DF_TRACKMOUSEEVENT;
    }
    /*
     * Cancel whatever is active and needs to go away
     */
    ThreadLockAlways(pdesk->spwndTrack, &tlpwnd);
    xxxCancelMouseMoveTracking(pdesk->dwDTFlags,
                           pdesk->spwndTrack,
                           pdesk->htEx,
                           dwDTCancel);
    ThreadUnlock(&tlpwnd);
    pdesk->dwDTFlags &= ~dwDTCancel;



SetNewState:
    /*
     * Hottracking/tooltip on mouse move if on NC hitest and enabled
     */
    if ((htEx != HTCLIENT) && (message == WM_MOUSEMOVE) && TestEffectUP(HOTTRACKING)) {
        /*
         * Hottrack the new hit test area
         */
        if (xxxHotTrack(pwnd, htEx, TRUE)) {
            pdesk->dwDTFlags |= DF_HOTTRACKING;
        }

        /*
         * Remove/set the tool tip.
         * We always do this synchronously because it doesn't mess
         *  with pwnd's or spwnTrack's queue
         */
        if ((pstr = IsTooltipHittest(pwnd, LOWORD(htEx))) != NULL) {
            PTOOLTIPWND pttwnd = (PTOOLTIPWND)pdesk->spwndTooltip;
            ThreadLockAlways(pttwnd, &tlpwnd);
            xxxCreateTooltip(pttwnd, pstr);
            ThreadUnlock(&tlpwnd);
            pdesk->dwDTFlags |= DF_TOOLTIP;
        } else  {
            PTOOLTIPWND pttwnd = (PTOOLTIPWND)pdesk->spwndTooltip;
            ThreadLockAlways(pttwnd, &tlpwnd);
            xxxResetTooltip(pttwnd);
            ThreadUnlock(&tlpwnd);
        }
    } /* if (htEx != HTCLIENT) */


    ValidateThreadLocks(NULL, PtiCurrent()->ptl, (ULONG_PTR)&pwnd, TRUE);

    /*
     * Update new track window if needed.
     */
    if (fNewpwndTrack) {
        PWND pwndActivate;

         Lock(&pdesk->spwndTrack, pwnd);
        /*
         * Active window tracking.
         * If there is non-zero timeout, get the window we're supposed to activate
         *  and set the timer. Otherwise, set the queue flag so
         *  xxxActiveWindowTracking can do its thing.
         */
         if ((message == WM_MOUSEMOVE) && TestUP(ACTIVEWINDOWTRACKING)) {
             if (UP(ACTIVEWNDTRKTIMEOUT) != 0) {
                 pwndActivate = GetActiveTrackPwnd(pwnd, NULL);
                 if (pwndActivate != NULL) {
                     InternalSetTimer(pwndActivate, IDSYS_WNDTRACKING,
                                     UP(ACTIVEWNDTRKTIMEOUT),
                                     xxxSystemTimerProc, TMRF_SYSTEM);
                 }
             } else {
                 PtiCurrent()->pq->QF_flags |= QF_ACTIVEWNDTRACKING;
             } /* if (TestUP(ACTIVEWNDTRKZORDER)) */
         } /* if (TestUP(ACTIVEWINDOWTRACKING)) */

    }

    /*
     * Save new hit test code
     */
    pdesk->htEx = htEx;

#if DBG
    --gcReEntered;
#endif
}
Example #19
0
BOOL _RegisterHotKey(
    PWND pwnd,
    int id,
    UINT fsModifiers,
    UINT vk)
{
    PHOTKEY phk;
    BOOL fKeysExist;
    PTHREADINFO ptiCurrent;
    PWINDOWSTATION pwinsta = _GetProcessWindowStation(NULL);

    ptiCurrent = PtiCurrent();

    /*
     * Blow it off if the caller is not the windowstation init thread
     * and doesn't have the proper access rights
     */
    if (grpwinstaList && !CheckWinstaWriteAttributesAccess()) {
        return FALSE;
    }

    /*
     * Can't register hotkey for a window of another queue.
     * Return FALSE in this case.
     */
    if ((pwnd != PWND_FOCUS) && (pwnd != PWND_INPUTOWNER)) {
        if (GETPTI(pwnd) != ptiCurrent) {
            RIPERR0(ERROR_WINDOW_OF_OTHER_THREAD, RIP_VERBOSE, "");
            return FALSE;
        }
    }

    phk = FindHotKey(ptiCurrent, pwnd, id, fsModifiers, vk, FALSE, &fKeysExist);

    /*
     * If the keys have already been registered, return FALSE.
     */
    if (fKeysExist) {
        RIPERR0(ERROR_HOTKEY_ALREADY_REGISTERED, RIP_VERBOSE, "");
        return FALSE;
    }

    if (phk == NULL) {
        /*
         * This hotkey doesn't exist yet.
         */
        phk = (PHOTKEY)UserAllocPool(sizeof(HOTKEY), TAG_HOTKEY);

        /*
         * If the allocation failed, bail out.
         */
        if (phk == NULL) {
            return FALSE;
        }

        phk->pti = ptiCurrent;

        if ((pwnd != PWND_FOCUS) && (pwnd != PWND_INPUTOWNER)) {
            phk->spwnd = NULL;
            Lock(&phk->spwnd, pwnd);
        } else {
            phk->spwnd = pwnd;
        }
        phk->fsModifiers = fsModifiers;
        phk->vk = vk;
        phk->id = id;

        /*
         * Link the new hotkey to the front of the list.
         */
        phk->phkNext = gphkFirst;
        gphkFirst = phk;

    } else {

        /*
         * Hotkey already exists, reset the keys.
         */
        phk->fsModifiers = fsModifiers;
        phk->vk = vk;
    }

    return TRUE;
}
Example #20
0
/***************************************************************************\
*
*  SetShellWindow()
*
*  Returns true if shell window is successfully set.  Note that we return
*  FALSE if a shell window already exists.  I.E., this works on a first
*  come, first serve basis.
*
*  We also do NOT allow child windows to be shell windows.  Other than that,
*  it's up to the caller to size her window appropriately.
*
*  The pwndBkGnd is provided for the explorer shell.  Since the shellwnd
*  and the window which does the drawing of background wallpapers are
*  different, we need to provide means by which we can draw directly on
*  the background window during hung-app drawing.  The pwnd and pwndBkGnd
*  will be identical if called through the SetShellWindow() api.
*
*
\***************************************************************************/
BOOL xxxSetShellWindow(PWND pwnd, PWND pwndBkGnd)
{
    PTHREADINFO  ptiCurrent = PtiCurrent();
    PDESKTOPINFO pdeskinfo = GETDESKINFO(ptiCurrent);

    PPROCESSINFO ppiShellProcess;

    UserAssert(pwnd);

    /*
     * Fail the call if another shell window exists
     */
    if (pdeskinfo->spwndShell != NULL)
        return(FALSE);

    /*
     * The shell window must be
     *      (1) Top-level
     *      (2) Unowned
     *      (3) Not topmost
     */
    if (TestwndChild(pwnd)             ||
            (pwnd->spwndOwner != NULL) ||
            TestWF(pwnd, WEFTOPMOST)) {

        RIPMSG0(RIP_WARNING, "xxxSetShellWindow: Invalid type of window");
        return(FALSE);
    }

    /*
     * Chicago has a totally different input model which has special code
     * that checks for Ctrl-Esc and sends it to the shell.  We can get
     * the same functionality, without totally re-writing our input model
     * by just automatically installing the Ctrl-Esc as a hotkey for the
     * shell window.  The hotkey delivery code has a special case which
     * turns this into a WM_SYSCOMMAND message instead of a WM_HOTKEY
     * message.
     *
     * We don't both checking for failure.  Somebody could already have
     * a Ctrl-Esc handler installed.
     */
    _RegisterHotKey(pwnd,SC_TASKLIST,MOD_CONTROL,VK_ESCAPE);

    /*
     * This is the shell window wright.
     * So get the process id for the shell.
     */
    ppiShellProcess = GETPTI(pwnd)->ppi;

    /*
     * Set the shell process id to the desktop only if it's the first instance
     */
    if ((ppiShellProcess != NULL) && (pdeskinfo->ppiShellProcess == NULL)) {
        pdeskinfo->ppiShellProcess = ppiShellProcess;
    }

    Lock(&pdeskinfo->spwndShell, pwnd);
    Lock(&pdeskinfo->spwndBkGnd, pwndBkGnd);

    /*
     * Push window to bottom of stack.
     */
    SetWF(pdeskinfo->spwndShell, WFBOTTOMMOST);
    xxxSetWindowPos(pdeskinfo->spwndShell,
                    PWND_BOTTOM,
                    0,
                    0,
                    0,
                    0,
                    SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

    return(TRUE);
}
Example #21
0
VOID DoQueuedSyncPaint(
    PWND        pwnd,
    DWORD       flags,
    PTHREADINFO pti)
{
    PTHREADINFO ptiPwnd = GETPTI(pwnd);

    if ((ptiPwnd != pti)          &&
        TestWF(pwnd, WFSENDNCPAINT)    &&
        TestWF(pwnd, WFSENDERASEBKGND) &&
        TestWF(pwnd, WFVISIBLE)) {

        PSMS psms = ptiPwnd->psmsReceiveList;

        /*
         * If this window already has a WM_SYNCPAINT queue'd up, then there's
         * no need to send another one.  Also protects our heap from getting
         * chewed up.
         */
        while (psms != NULL) {

            if ((psms->message == WM_SYNCPAINT) && (psms->spwnd == pwnd)) {
                break;
            }

            psms = psms->psmsReceiveNext;
        }

        if (psms == NULL) {
            /*
             * This will give this message the semantics of a notify
             * message (sendmessage no wait), without calling back
             * the WH_CALLWNDPROC hook. We don't want to do that
             * because that'll let all these processes with invalid
             * windows to process paint messages before they process
             * "synchronous" erasing or framing needs.
             *
             * Hi word of wParam must be zero or wow will drop it
             *
             * LATER mikeke
             * Do we need to send down the flags with DWP_ERASE and DSP_FRAME
             * in it?
             */
            UserAssert(HIWORD(flags) == 0);
            QueueNotifyMessage(pwnd, WM_SYNCPAINT, flags, 0);

            /*
             * Set our syncpaint-pending flag, since we queued one up.  This
             * will be used to check when we validate-parents for windows
             * without clipchildren.
             */
            SetWF(pwnd, WFSYNCPAINTPENDING);
        }

        /*
         * If we posted a WM_SYNCPAINT for a top-level window that is not
         * of the current thread we're done; we'll pick up the children
         * when we process the message for real.  If we're the desktop
         * however make sure we get all it children.
         */
        if (pwnd != PWNDDESKTOP(pwnd))
            return;
    }

    /*
     * Normally we like to enumerate all of this window's children and have
     * them erase their backgrounds synchronously.  However, this is a bad
     * thing to do if the window is NOT CLIPCHLIDREN.  Here's the scenario
     * we want to to avoid:
     *
     * 1.  Window 'A' is invalidated
     * 2.  'A' erases itself (or not, doesn't matter)
     * 3.  'A's children are enumerated and they erase themselves.
     * 4.  'A' paints over its children (remember, 'A' isn't CLIPCHILDREN)
     * 5.  'A's children paint but their backgrounds aren't their ERASEBKND
     *    color (because 'A' painted over them) and everything looks like
     *    dirt.
     */
    if ((flags & DSP_ALLCHILDREN) ||
        ((flags & DSP_ENUMCLIPPEDCHILDREN) && TestWF(pwnd, WFCLIPCHILDREN))) {

        PWND pwndT;

        for (pwndT = pwnd->spwndChild; pwndT; pwndT = pwndT->spwndNext) {

            /*
             * Don't cause any more intertask sendmessages cause it does
             * bad things to cbt's windowproc hooks.  (Due to SetParent
             * allowing child windows in the topwindow hierarchy.
             * The child bit also catches the desktop window; we want to
             */
            if (TestWF(pwndT, WFCHILD) && (pti != GETPTI(pwndT)))
                continue;

            /*
             * Note that we pass only certain bits down as we recurse:
             * the other bits pertain to the current window only.
             */
            DoQueuedSyncPaint(pwndT, flags, pti);
        }
    }
}
Example #22
0
/***************************************************************************\
* xxxMNStartMenuState
*
* This function is called when the menu bar is about to be activated (the
*  app's main menu). It makes sure that the threads involved are not in
*  menu mode already, finds the owner/notification window, initializes
*  pMenuState and sends the WM_ENTERMENULOOP message.
* It successful, it returns a pointer to a pMenuState. If so, the caller
*  must call MNEndMenuState when done.
*
* History:
* 4-25-91 Mikehar       Port for 3.1 merge
* 5-20-96 GerardoB      Renamed and changed (Old name: xxxMNGetPopup)
\***************************************************************************/
PMENUSTATE xxxMNStartMenuState(PWND pwnd)
{
    PPOPUPMENU ppopupmenu;
    PTHREADINFO ptiCurrent, ptiNotify;
    PMENUSTATE pMenuState;
    TL tlpwnd;

    CheckLock(pwnd);

    /*
     * Bail if the current thread is already in menu mode
     */
    ptiCurrent = PtiCurrent();
    if (ptiCurrent->pMenuState != NULL) {
        return NULL;
    }

    /*
     * If the window doesn't have any children, return pwndActive.
     */
    if (!TestwndChild(pwnd)) {
        pwnd = GETPTI(pwnd)->pq->spwndActive;
    } else {

        /*
         * Search up the parents for a window with a System Menu.
         */
        while (TestwndChild(pwnd)) {
            if (TestWF(pwnd, WFSYSMENU))
                break;
            pwnd = pwnd->spwndParent;
        }
    }

    if (pwnd == NULL) {
        return NULL;
    }

    if (!TestwndChild(pwnd) && (pwnd->spmenu != NULL)) {
        goto hasmenu;
    }

    if (!TestWF(pwnd, WFSYSMENU)) {
        return NULL;
    }

hasmenu:
    /*
     * If the owner/notification window was created by another thread,
     *  make sure that it's not in menu mode already
     * This can happen if PtiCurrent() is attached to other threads, one of
     *  which created pwnd.
     */
    ptiNotify = GETPTI(pwnd);
    if (ptiNotify->pMenuState != NULL) {
        return NULL;
    }

    /*
     * Allocate ppoupmenu and pMenuState
     */
    ppopupmenu = MNAllocPopup(FALSE);
    if (ppopupmenu == NULL) {
        return NULL;
    }

    pMenuState = MNAllocMenuState(ptiCurrent, ptiNotify, ppopupmenu);
    if (pMenuState == NULL) {
        MNFreePopup(ppopupmenu);
        return NULL;
    }

    ppopupmenu->fIsMenuBar = TRUE;
    ppopupmenu->fHasMenuBar = TRUE;
    Lock(&(ppopupmenu->spwndNotify), pwnd);
    ppopupmenu->posSelectedItem = MFMWFP_NOITEM;
    Lock(&(ppopupmenu->spwndPopupMenu), pwnd);
    ppopupmenu->ppopupmenuRoot = ppopupmenu;

    /*
     * Notify the app we are entering menu mode.  wParam is always 0 since this
     * procedure will only be called for menu bar menus not TrackPopupMenu
     * menus.
     */
    ThreadLockAlways(pwnd, &tlpwnd);
    xxxSendMessage(pwnd, WM_ENTERMENULOOP, 0, 0L);
    ThreadUnlock(&tlpwnd);

    return pMenuState;
}
Example #23
0
/*****************************************************************************\
*
*  GetGUIThreadInfo()
*
*  This gets GUI information out of context.  If you pass in a NULL thread ID,
*  we will get the 'global' information, using the foreground thread.  This
*  is guaranteed to be the real active window, focus window, etc.  Yes, you
*  could do it yourself by calling GetForegroundWindow, getting the thread ID
*  of that window via GetWindowThreadProcessId, then passing the ID into
*  GetGUIThreadInfo().  However, that takes three calls and aside from being
*  a pain, anything could happen in the middle.  So passing in NULL gets
*  you stuff in one call and hence also works right.
*
*  This function returns FALSE if the thread doesn't have a queue or the
*  thread ID is bogus.
*
\*****************************************************************************/
BOOL WINAPI
_GetGUIThreadInfo(PTHREADINFO pti, PGUITHREADINFO pgui)
{
    PQ pq;

    /*
     * Validate threadinfo structure
     */
    if (pgui->cbSize != sizeof(GUITHREADINFO)) {
        RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "GUITHREADINFO.cbSize %d is wrong", pgui->cbSize);
        return FALSE;
    }

    /*
     * Is this a valid initialized GUI thread?
     */
    if (pti != NULL) {
        if ((pq = pti->pq) == NULL) {
            // does this ever happen?
            RIPMSG1(RIP_ERROR, "GetGUIThreadInfo: No queue for pti %lx", pti);
            return FALSE;
        }
    } else {
        /*
         * Use the foreground queue. To get menu state information we must also
         * figure out the right pti.  This matches _GetForegroundWindow() logic.
         */
        if ((pq = gpqForeground) == NULL) {
            // this does sometimes happen...
            RIPMSG0(RIP_WARNING, "GetGUIThreadInfo: No foreground queue");
            return FALSE;
        }

        if (pq->spwndActive && (GETPTI(pq->spwndActive)->pq == pq)) {
            pti = GETPTI(pq->spwndActive);
            if (PtiCurrentShared()->rpdesk != pti->rpdesk) {
                RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Foreground window on different desktop");
                return FALSE;
            }
        }
    }

    UserAssert(pq != NULL);

    /*
     * For C2 security, verify that pq and pti are on the current thread's desktop.
     * We can't directly determine which desktop pq belongs to, but we can at
     * least ensure that any caret info we return is not from another desktop
     */
    if (pq->caret.spwnd &&
            (GETPTI(pq->caret.spwnd)->rpdesk != PtiCurrentShared()->rpdesk)) {
        RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Foreground caret on different desktop");
        return FALSE;
    }
    if (pti && (pti->rpdesk != PtiCurrentShared()->rpdesk)) {
        RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Foreground thread on different desktop");
        return FALSE;
    }

    pgui->flags        = 0;
    pgui->hwndMoveSize = NULL;
    pgui->hwndMenuOwner = NULL;

    /*
     * Get Menu information from the THREADINFO
     */
    if (pti != NULL) {
        if (pti->pmsd && !pti->pmsd->fTrackCancelled && pti->pmsd->spwnd) {
            pgui->flags |= GUI_INMOVESIZE;
            pgui->hwndMoveSize = HWq(pti->pmsd->spwnd);
        }

        if (pti->pMenuState && pti->pMenuState->pGlobalPopupMenu) {
            pgui->flags |= GUI_INMENUMODE;

            if (pti->pMenuState->pGlobalPopupMenu->fHasMenuBar) {
                if (pti->pMenuState->pGlobalPopupMenu->fIsSysMenu) {
                    pgui->flags |= GUI_SYSTEMMENUMODE;
                }
            } else {
                pgui->flags |= GUI_POPUPMENUMODE;
            }

            if (pti->pMenuState->pGlobalPopupMenu->spwndNotify)
                pgui->hwndMenuOwner = HWq(pti->pMenuState->pGlobalPopupMenu->spwndNotify);
        }
    }

    /*
     * Get the rest of the information from the queue
     */
    pgui->hwndActive   = HW(pq->spwndActive);
    pgui->hwndFocus    = HW(pq->spwndFocus);
    pgui->hwndCapture  = HW(pq->spwndCapture);

    pgui->hwndCaret    = NULL;

    if (pq->caret.spwnd) {
        pgui->hwndCaret = HWq(pq->caret.spwnd);

        /*
         * These coords are always relative to the client of hwndCaret
         * of course.
         */
        pgui->rcCaret.left   = pq->caret.x;
        pgui->rcCaret.right  = pgui->rcCaret.left + pq->caret.cx;
        pgui->rcCaret.top    = pq->caret.y;
        pgui->rcCaret.bottom = pgui->rcCaret.top + pq->caret.cy;

        if (pq->caret.iHideLevel == 0)
            pgui->flags |= GUI_CARETBLINKING;
    } else if (pti && (pti->ppi->W32PF_Flags & W32PF_CONSOLEHASFOCUS)) {
        /*
         * The thread is running in the console window with focus. Pull
         * out the info from the console pseudo caret.
         */
        pgui->hwndCaret = pti->rpdesk->cciConsole.hwnd;
        pgui->rcCaret = pti->rpdesk->cciConsole.rc;
    } else {
        SetRectEmpty(&pgui->rcCaret);
    }

    return TRUE;
}