diff --git a/win32ss/include/ntuser.h b/win32ss/include/ntuser.h index 7e09af4896f..783d4e0c32a 100644 --- a/win32ss/include/ntuser.h +++ b/win32ss/include/ntuser.h @@ -1670,7 +1670,7 @@ enum SimpleCallRoutines TWOPARAM_ROUTINE_WOWCLEANUP }; -DWORD +DWORD_PTR NTAPI NtUserCallHwnd( HWND hWnd, diff --git a/win32ss/user/ntuser/defwnd.c b/win32ss/user/ntuser/defwnd.c index 368105afc42..dba5c7b567b 100644 --- a/win32ss/user/ntuser/defwnd.c +++ b/win32ss/user/ntuser/defwnd.c @@ -495,6 +495,58 @@ DefWndGetIcon(PWND pWnd, WPARAM wParam, LPARAM lParam) return (LRESULT)hIconRet; } +PWND FASTCALL +DWP_GetEnabledPopup(PWND pWnd) +{ + PWND pwndNode1; + PTHREADINFO pti = pWnd->head.pti, ptiNode; + BOOL bFoundNullNode = FALSE; + + for (pwndNode1 = pWnd->spwndNext; pwndNode1 != pWnd; ) + { + if (!pwndNode1) /* NULL detected? */ + { + if (bFoundNullNode) + return NULL; + bFoundNullNode = TRUE; + /* Retry with parent's first child (once only) */ + pwndNode1 = pWnd->spwndParent->spwndChild; + continue; + } + + /* + * 1. We want to detect the window that owns the same input target of pWnd. + * 2. For non-16-bit apps, we need to check the two threads' input queues to + * see whether they are the same, while for 16-bit apps it's sufficient to + * only check the thread info pointers themselves (ptiNode and pti). + * See also: + * https://devblogs.microsoft.com/oldnewthing/20060221-09/?p=32203 + * https://github.com/reactos/reactos/pull/7700#discussion_r1939435931 + */ + ptiNode = pwndNode1->head.pti; + if ((!(pti->TIF_flags & TIF_16BIT) && ptiNode->MessageQueue == pti->MessageQueue) || + ((pti->TIF_flags & TIF_16BIT) && ptiNode == pti)) + { + DWORD style = pwndNode1->style; + if ((style & WS_VISIBLE) && !(style & WS_DISABLED)) /* Visible and enabled? */ + { + /* Does pwndNode1 have a pWnd as an ancestor? */ + PWND pwndNode2; + for (pwndNode2 = pwndNode1->spwndOwner; pwndNode2; + pwndNode2 = pwndNode2->spwndOwner) + { + if (pwndNode2 == pWnd) + return pwndNode1; + } + } + } + + pwndNode1 = pwndNode1->spwndNext; + } + + return NULL; +} + VOID FASTCALL DefWndScreenshot(PWND pWnd) { diff --git a/win32ss/user/ntuser/simplecall.c b/win32ss/user/ntuser/simplecall.c index fa7ee28d857..6a433ed7120 100644 --- a/win32ss/user/ntuser/simplecall.c +++ b/win32ss/user/ntuser/simplecall.c @@ -706,7 +706,7 @@ NtUserCallHwndOpt( return hWnd; } -DWORD +DWORD_PTR APIENTRY NtUserCallHwnd( HWND hWnd, @@ -755,6 +755,17 @@ NtUserCallHwnd( UserLeave(); return FALSE; } + + case HWND_ROUTINE_DWP_GETENABLEDPOPUP: + { + PWND pWnd; + UserEnterShared(); + pWnd = UserGetWindowObject(hWnd); + if (pWnd) + pWnd = DWP_GetEnabledPopup(pWnd); + UserLeave(); + return (DWORD_PTR)pWnd; + } } STUB; diff --git a/win32ss/user/ntuser/userfuncs.h b/win32ss/user/ntuser/userfuncs.h index 740607530a4..f282344ab56 100644 --- a/win32ss/user/ntuser/userfuncs.h +++ b/win32ss/user/ntuser/userfuncs.h @@ -161,6 +161,7 @@ LRESULT NC_HandleNCRButtonDown( PWND wnd, WPARAM wParam, LPARAM lParam ); HBRUSH FASTCALL DefWndControlColor(HDC hDC,UINT ctlType); BOOL UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down); BOOL UserPaintCaption(PWND pWnd, INT Flags); +PWND FASTCALL DWP_GetEnabledPopup(PWND pWnd); /************** LAYERED **************/ diff --git a/win32ss/user/ntuser/window.c b/win32ss/user/ntuser/window.c index 55df7d52b4c..9f8d669e3e8 100644 --- a/win32ss/user/ntuser/window.c +++ b/win32ss/user/ntuser/window.c @@ -428,7 +428,7 @@ IntGetWindow(HWND hWnd, break; default: - Wnd = NULL; + EngSetLastError(ERROR_INVALID_GW_COMMAND); break; } diff --git a/win32ss/user/user32/include/ntwrapper.h b/win32ss/user/user32/include/ntwrapper.h index 67b67de6ed9..067077890ed 100644 --- a/win32ss/user/user32/include/ntwrapper.h +++ b/win32ss/user/user32/include/ntwrapper.h @@ -725,22 +725,22 @@ EXTINLINE VOID NtUserxNotifyWinEvent(HWND hWnd, PVOID ne) EXTINLINE DWORD NtUserxGetWindowContextHelpId(HWND hwnd) { - return NtUserCallHwnd(hwnd, HWND_ROUTINE_GETWNDCONTEXTHLPID); + return (DWORD)NtUserCallHwnd(hwnd, HWND_ROUTINE_GETWNDCONTEXTHLPID); } EXTINLINE BOOL NtUserxDeregisterShellHookWindow(HWND hWnd) { - return NtUserCallHwnd(hWnd, HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW); + return (BOOL)NtUserCallHwnd(hWnd, HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW); } EXTINLINE BOOL NtUserxRegisterShellHookWindow(HWND hWnd) { - return NtUserCallHwnd(hWnd, HWND_ROUTINE_REGISTERSHELLHOOKWINDOW); + return (BOOL)NtUserCallHwnd(hWnd, HWND_ROUTINE_REGISTERSHELLHOOKWINDOW); } EXTINLINE BOOL NtUserxSetMessageBox(HWND hWnd) { - return NtUserCallHwnd(hWnd, HWND_ROUTINE_SETMSGBOX); + return (BOOL)NtUserCallHwnd(hWnd, HWND_ROUTINE_SETMSGBOX); } EXTINLINE VOID NtUserxClearWindowState(PWND pWnd, UINT Flag) diff --git a/win32ss/user/user32/windows/window.c b/win32ss/user/user32/windows/window.c index dfe06a349c5..e7468f8a91c 100644 --- a/win32ss/user/user32/windows/window.c +++ b/win32ss/user/user32/windows/window.c @@ -1141,9 +1141,19 @@ GetWindow(HWND hWnd, FoundWnd = DesktopPtrToUser(FoundWnd->spwndNext); break; - default: - Wnd = NULL; + case GW_ENABLEDPOPUP: + { + PWND pwndPopup = (PWND)NtUserCallHwnd(hWnd, HWND_ROUTINE_DWP_GETENABLEDPOPUP); + if (pwndPopup) + FoundWnd = DesktopPtrToUser(pwndPopup); break; + } + + default: + { + UserSetLastError(ERROR_INVALID_GW_COMMAND); + break; + } } if (FoundWnd != NULL)