static BOOL FASTCALL co_IntSetForegroundAndFocusWindow(PWND Wnd, PWND FocusWindow, BOOL MouseActivate) { HWND hWnd = Wnd->head.h; HWND hWndPrev = NULL; HWND hWndFocus = FocusWindow->head.h; HWND hWndFocusPrev = NULL; PUSER_MESSAGE_QUEUE PrevForegroundQueue; ASSERT_REFS_CO(Wnd); TRACE("IntSetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd, hWndFocus, MouseActivate ? "TRUE" : "FALSE"); if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD) { TRACE("Failed - Child\n"); return FALSE; } if (0 == (Wnd->style & WS_VISIBLE) && Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess) { TRACE("Failed - Invisible\n"); return FALSE; } PrevForegroundQueue = IntGetFocusMessageQueue(); if (PrevForegroundQueue != 0) { hWndPrev = PrevForegroundQueue->ActiveWindow; hWndFocusPrev = PrevForegroundQueue->FocusWindow; } if (hWndPrev == hWnd) { TRACE("Failed - Same\n"); return TRUE; } /* FIXME: Call hooks. */ co_IntSendDeactivateMessages(hWndPrev, hWnd); co_IntSendKillFocusMessages(hWndFocusPrev, hWndFocus); IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue); if (Wnd->head.pti->MessageQueue) { Wnd->head.pti->MessageQueue->ActiveWindow = hWnd; } if (FocusWindow->head.pti->MessageQueue) { FocusWindow->head.pti->MessageQueue->FocusWindow = hWndFocus; } if (PrevForegroundQueue != Wnd->head.pti->MessageQueue) { /* FIXME: Send WM_ACTIVATEAPP to all thread windows. */ } co_IntSendSetFocusMessages(hWndFocusPrev, hWndFocus); co_IntSendActivateMessages(hWndPrev, hWnd, MouseActivate); return TRUE; }
/* MSDN: The system restricts which processes can set the foreground window. A process can set the foreground window only if one of the following conditions is true: * The process is the foreground process. * The process was started by the foreground process. * The process received the last input event. * There is no foreground process. * The foreground process is being debugged. * The foreground is not locked (see LockSetForegroundWindow). * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo). * No menus are active. */ static BOOL FASTCALL co_IntSetForegroundAndFocusWindow( _In_ PWND Wnd, _In_ BOOL MouseActivate) { HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL; HWND hWndPrev = NULL; PWND pWndPrev = NULL; PUSER_MESSAGE_QUEUE PrevForegroundQueue; PTHREADINFO pti; BOOL fgRet = FALSE, Ret = FALSE; if (Wnd) ASSERT_REFS_CO(Wnd); //ERR("SetForegroundAndFocusWindow(%x, %s)\n", hWnd, (MouseActivate ? "TRUE" : "FALSE")); PrevForegroundQueue = IntGetFocusMessageQueue(); // Use this active desktop. pti = PsGetCurrentThreadWin32Thread(); if (PrevForegroundQueue) { // Same Window Q as foreground just do active. if (Wnd && Wnd->head.pti->MessageQueue == PrevForegroundQueue) { //ERR("Same Window Q as foreground just do active.\n"); if (pti->MessageQueue == PrevForegroundQueue) { // Same WQ and TQ go active. //ERR("Same WQ and TQ go active.\n"); Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE); } else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd) { // Same WQ and it is active. //ERR("Same WQ and it is active.\n"); Ret = TRUE; } else { // Same WQ as FG but not the same TQ send active. //ERR("Same WQ as FG but not the same TQ send active.\n"); co_IntSendMessage(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate ); Ret = TRUE; } return Ret; } hWndPrev = PrevForegroundQueue->spwndActive ? UserHMGetHandle(PrevForegroundQueue->spwndActive) : 0; pWndPrev = PrevForegroundQueue->spwndActive; } if ( (( !IsFGLocked() || pti->ppi == gppiInputProvider ) && ( CanForceFG(pti->ppi) || pti->TIF_flags & (TIF_SYSTEMTHREAD|TIF_CSRSSTHREAD|TIF_ALLOWFOREGROUNDACTIVATE) )) || pti->ppi == ppiScrnSaver ) { //ToggleFGActivate(pti); // win.c line 2662 fail if (Wnd) { IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue); gptiForeground = Wnd->head.pti; //ERR("Set Foreground pti 0x%p Q 0x%p hWnd 0x%p\n",Wnd->head.pti, Wnd->head.pti->MessageQueue,Wnd->head.h); } else { IntSetFocusMessageQueue(NULL); gptiForeground = NULL; //ERR("Set Foreground pti 0x0 Q 0x0 hWnd 0x0\n"); } /* Henri Verbeet, What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the other thread after we already changed the foreground window back to our own window. */ //ERR("SFAFW: 1\n"); FindRemoveAsyncMsg(Wnd, 0); // Do this to fix test_SFW todos! fgRet = TRUE; } // Fix FG Bounce with regedit. if (hWndPrev != hWnd ) { if (PrevForegroundQueue && fgRet && PrevForegroundQueue->spwndActive) { //ERR("SFGW: Send NULL to 0x%x\n",hWndPrev); if (pti->MessageQueue == PrevForegroundQueue) { //ERR("SFGW: TI same as Prev TI\n"); co_IntSetActiveWindow(NULL, FALSE, TRUE, FALSE); } else if (pWndPrev) { //ERR("SFGW Deactivate: TI not same as Prev TI\n"); // No real reason to wait here. co_IntSendMessageNoWait(hWndPrev, WM_ASYNC_SETACTIVEWINDOW, 0, 0 ); } } } if (!Wnd) return FALSE; // Always return false. if (pti->MessageQueue == Wnd->head.pti->MessageQueue) { //ERR("Same PQ and WQ go active.\n"); Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE); } else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd) { //ERR("Same Active and Wnd.\n"); Ret = TRUE; } else { //ERR("Activate Not same PQ and WQ and Wnd.\n"); co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate ); Ret = TRUE; } return Ret && fgRet; }
NTSTATUS FASTCALL UserAttachThreadInput(PTHREADINFO ptiFrom, PTHREADINFO ptiTo, BOOL fAttach) { MSG msg; PATTACHINFO pai; /* Can not be the same thread. */ if (ptiFrom == ptiTo) return STATUS_INVALID_PARAMETER; /* Do not attach to system threads or between different desktops. */ if (ptiFrom->TIF_flags & TIF_DONTATTACHQUEUE || ptiTo->TIF_flags & TIF_DONTATTACHQUEUE || ptiFrom->rpdesk != ptiTo->rpdesk) return STATUS_ACCESS_DENIED; /* MSDN Note: Keyboard and mouse events received by both threads are processed by the thread specified by the idAttachTo. */ /* If Attach set, allocate and link. */ if (fAttach) { pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), USERTAG_ATTACHINFO); if (!pai) return STATUS_NO_MEMORY; pai->paiNext = gpai; pai->pti1 = ptiFrom; pai->pti2 = ptiTo; gpai = pai; paiCount++; ERR("Attach Allocated! ptiFrom 0x%p ptiTo 0x%p paiCount %d\n",ptiFrom,ptiTo,paiCount); if (ptiTo->MessageQueue != ptiFrom->MessageQueue) { ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel; // FIXME: conditions? if (ptiTo->MessageQueue == gpqForeground) { ERR("ptiTo is Foreground\n"); } else { ERR("ptiTo NOT Foreground\n"); } if (ptiFrom->MessageQueue == gpqForeground) { ERR("ptiFrom is Foreground\n"); ptiTo->MessageQueue->spwndActive = ptiFrom->MessageQueue->spwndActive; ptiTo->MessageQueue->spwndFocus = ptiFrom->MessageQueue->spwndFocus; ptiTo->MessageQueue->CursorObject = ptiFrom->MessageQueue->CursorObject; ptiTo->MessageQueue->spwndCapture = ptiFrom->MessageQueue->spwndCapture; ptiTo->MessageQueue->QF_flags ^= ((ptiTo->MessageQueue->QF_flags ^ ptiFrom->MessageQueue->QF_flags) & QF_CAPTURELOCKED); ptiTo->MessageQueue->CaretInfo = ptiFrom->MessageQueue->CaretInfo; IntSetFocusMessageQueue(NULL); IntSetFocusMessageQueue(ptiTo->MessageQueue); gptiForeground = ptiTo; } else { ERR("ptiFrom NOT Foreground\n"); } MsqDestroyMessageQueue(ptiFrom); ptiFrom->MessageQueue = ptiTo->MessageQueue; ptiFrom->MessageQueue->cThreads++; ERR("ptiTo S Share count %d\n", ptiFrom->MessageQueue->cThreads); IntReferenceMessageQueue(ptiTo->MessageQueue); } else { ERR("Attach Threads are already associated!\n"); } } else /* If clear, unlink and free it. */ { BOOL Hit = FALSE; PATTACHINFO *ppai; if (!gpai) return STATUS_INVALID_PARAMETER; /* Search list and free if found or return false. */ ppai = &gpai; while (*ppai != NULL) { if ( (*ppai)->pti2 == ptiTo && (*ppai)->pti1 == ptiFrom ) { pai = *ppai; /* Remove it from the list */ *ppai = (*ppai)->paiNext; ExFreePoolWithTag(pai, USERTAG_ATTACHINFO); paiCount--; Hit = TRUE; break; } ppai = &((*ppai)->paiNext); } if (!Hit) return STATUS_INVALID_PARAMETER; ERR("Attach Free! ptiFrom 0x%p ptiTo 0x%p paiCount %d\n",ptiFrom,ptiTo,paiCount); if (ptiTo->MessageQueue == ptiFrom->MessageQueue) { if (gptiForeground == ptiFrom) { ERR("ptiTo is now pti FG.\n"); // MessageQueue foreground is set so switch threads. gptiForeground = ptiTo; } ptiTo->MessageQueue->cThreads--; ERR("ptiTo E Share count %d\n", ptiTo->MessageQueue->cThreads); ASSERT(ptiTo->MessageQueue->cThreads >= 1); IntDereferenceMessageQueue(ptiTo->MessageQueue); ptiFrom->MessageQueue = MsqCreateMessageQueue(ptiFrom); ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel; } else { ERR("Detaching Threads are not associated!\n"); } } /* Note that key state, which can be ascertained by calls to the GetKeyState or GetKeyboardState function, is reset after a call to AttachThreadInput. ATM which one? */ RtlCopyMemory(ptiTo->MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState)); /* Generate mouse move message */ msg.message = WM_MOUSEMOVE; msg.wParam = UserGetMouseButtonsState(); msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y); msg.pt = gpsi->ptCursor; co_MsqInsertMouseMessage(&msg, 0, 0, TRUE); return STATUS_SUCCESS; }