[NTUSER][USER32] Support GetWindow.GW_ENABLEDPOPUP (#7700)

JIRA issue: CORE-6920
- Make the return value of
  NtUserCallHwnd a DWORD_PTR.
- Add DWP_GetEnabledPopup
  helper function in
  win32ss/user/ntuser/defwnd.c.
- Add code to NtUserCallHwnd for
  HWND_ROUTINE_DWP_GETENABLEDPOPUP.
- Add code to GetWindow for
  GW_ENABLEDPOPUP.
- Set last error in GetWindow and
  IntGetWindow.
This commit is contained in:
Katayama Hirofumi MZ 2025-02-07 07:31:08 +09:00 committed by GitHub
parent 2d8a2944ba
commit 22577aed85
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 83 additions and 9 deletions

View file

@ -1670,7 +1670,7 @@ enum SimpleCallRoutines
TWOPARAM_ROUTINE_WOWCLEANUP TWOPARAM_ROUTINE_WOWCLEANUP
}; };
DWORD DWORD_PTR
NTAPI NTAPI
NtUserCallHwnd( NtUserCallHwnd(
HWND hWnd, HWND hWnd,

View file

@ -495,6 +495,58 @@ DefWndGetIcon(PWND pWnd, WPARAM wParam, LPARAM lParam)
return (LRESULT)hIconRet; 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 VOID FASTCALL
DefWndScreenshot(PWND pWnd) DefWndScreenshot(PWND pWnd)
{ {

View file

@ -706,7 +706,7 @@ NtUserCallHwndOpt(
return hWnd; return hWnd;
} }
DWORD DWORD_PTR
APIENTRY APIENTRY
NtUserCallHwnd( NtUserCallHwnd(
HWND hWnd, HWND hWnd,
@ -755,6 +755,17 @@ NtUserCallHwnd(
UserLeave(); UserLeave();
return FALSE; 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; STUB;

View file

@ -161,6 +161,7 @@ LRESULT NC_HandleNCRButtonDown( PWND wnd, WPARAM wParam, LPARAM lParam );
HBRUSH FASTCALL DefWndControlColor(HDC hDC,UINT ctlType); HBRUSH FASTCALL DefWndControlColor(HDC hDC,UINT ctlType);
BOOL UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down); BOOL UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down);
BOOL UserPaintCaption(PWND pWnd, INT Flags); BOOL UserPaintCaption(PWND pWnd, INT Flags);
PWND FASTCALL DWP_GetEnabledPopup(PWND pWnd);
/************** LAYERED **************/ /************** LAYERED **************/

View file

@ -428,7 +428,7 @@ IntGetWindow(HWND hWnd,
break; break;
default: default:
Wnd = NULL; EngSetLastError(ERROR_INVALID_GW_COMMAND);
break; break;
} }

View file

@ -725,22 +725,22 @@ EXTINLINE VOID NtUserxNotifyWinEvent(HWND hWnd, PVOID ne)
EXTINLINE DWORD NtUserxGetWindowContextHelpId(HWND hwnd) EXTINLINE DWORD NtUserxGetWindowContextHelpId(HWND hwnd)
{ {
return NtUserCallHwnd(hwnd, HWND_ROUTINE_GETWNDCONTEXTHLPID); return (DWORD)NtUserCallHwnd(hwnd, HWND_ROUTINE_GETWNDCONTEXTHLPID);
} }
EXTINLINE BOOL NtUserxDeregisterShellHookWindow(HWND hWnd) EXTINLINE BOOL NtUserxDeregisterShellHookWindow(HWND hWnd)
{ {
return NtUserCallHwnd(hWnd, HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW); return (BOOL)NtUserCallHwnd(hWnd, HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW);
} }
EXTINLINE BOOL NtUserxRegisterShellHookWindow(HWND hWnd) EXTINLINE BOOL NtUserxRegisterShellHookWindow(HWND hWnd)
{ {
return NtUserCallHwnd(hWnd, HWND_ROUTINE_REGISTERSHELLHOOKWINDOW); return (BOOL)NtUserCallHwnd(hWnd, HWND_ROUTINE_REGISTERSHELLHOOKWINDOW);
} }
EXTINLINE BOOL NtUserxSetMessageBox(HWND hWnd) 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) EXTINLINE VOID NtUserxClearWindowState(PWND pWnd, UINT Flag)

View file

@ -1141,11 +1141,21 @@ GetWindow(HWND hWnd,
FoundWnd = DesktopPtrToUser(FoundWnd->spwndNext); FoundWnd = DesktopPtrToUser(FoundWnd->spwndNext);
break; break;
default: case GW_ENABLEDPOPUP:
Wnd = NULL; {
PWND pwndPopup = (PWND)NtUserCallHwnd(hWnd, HWND_ROUTINE_DWP_GETENABLEDPOPUP);
if (pwndPopup)
FoundWnd = DesktopPtrToUser(pwndPopup);
break; break;
} }
default:
{
UserSetLastError(ERROR_INVALID_GW_COMMAND);
break;
}
}
if (FoundWnd != NULL) if (FoundWnd != NULL)
Ret = UserHMGetHandle(FoundWnd); Ret = UserHMGetHandle(FoundWnd);
} }