Skip to content

Commit d958a24

Browse files
authored
[NTUSER][USER32_APITEST] Support ShowWindow.SW_FORCEMINIMIZE (reactos#8261)
One more step to support ghost windows. JIRA issue: CORE-19671 - Add IntForceMinimizeWindow helper function. - Use IntForceMinimizeWindow in co_WinPosShowWindow function. - Enhance ShowWindow testcase in user32_apitest. - Add mask to the return value of GetWindowLong.
1 parent 6ebf15d commit d958a24

File tree

3 files changed

+205
-5
lines changed

3 files changed

+205
-5
lines changed

modules/rostests/apitests/user32/ShowWindow.c

Lines changed: 164 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
* PROJECT: ReactOS API tests
33
* LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
44
* PURPOSE: Tests for ShowWindow
5-
* COPYRIGHT: Copyright 2021 Katayama Hirofumi MZ <[email protected]>
5+
* COPYRIGHT: Copyright 2021-2025 Katayama Hirofumi MZ <[email protected]>
66
*/
77

88
#include "precomp.h"
9+
#include <versionhelpers.h>
910

1011
typedef struct TEST_ENTRY
1112
{
@@ -164,7 +165,7 @@ WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
164165
return 0;
165166
}
166167

167-
START_TEST(ShowWindow)
168+
static VOID Test_ShowWindow_Main(VOID)
168169
{
169170
WNDCLASSA wc;
170171
UINT iTest;
@@ -181,3 +182,164 @@ START_TEST(ShowWindow)
181182
DoTestEntry(&s_entries[iTest]);
182183
}
183184
}
185+
186+
#define RED RGB(255, 0, 0)
187+
188+
static COLORREF CheckColor(VOID)
189+
{
190+
HDC hDC = GetDC(NULL);
191+
COLORREF color = GetPixel(hDC, 100, 100);
192+
ReleaseDC(NULL, hDC);
193+
return color;
194+
}
195+
196+
static DWORD WINAPI
197+
ForceMinimizeThreadFunc(LPVOID arg)
198+
{
199+
BOOL ret;
200+
HWND hwnd = (HWND)arg;
201+
DWORD style, exstyle;
202+
203+
Sleep(100);
204+
ok_long(CheckColor(), RED);
205+
206+
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, WS_EX_MAKEVISIBLEWHENUNGHOSTED);
207+
ret = ShowWindow(hwnd, SW_FORCEMINIMIZE);
208+
Sleep(100);
209+
ok(ret != FALSE, "ret was FALSE\n");
210+
ok(CheckColor() != RED, "Color was red\n");
211+
style = GetWindowLongPtrW(hwnd, GWL_STYLE);
212+
if (IsWindowsVistaOrGreater())
213+
ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP | WS_MINIMIZE | WS_VISIBLE), "style was 0x%08lX\n", style);
214+
else
215+
ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP), "style was 0x%08lX\n", style);
216+
exstyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
217+
ok_long(exstyle, 0);
218+
219+
ShowWindow(hwnd, SW_MINIMIZE);
220+
Sleep(100);
221+
ok(CheckColor() != RED, "Color was red\n");
222+
223+
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, WS_EX_MAKEVISIBLEWHENUNGHOSTED);
224+
ret = ShowWindow(hwnd, SW_FORCEMINIMIZE);
225+
Sleep(100);
226+
ok(ret != FALSE, "ret was FALSE\n");
227+
ok(CheckColor() != RED, "Color was red\n");
228+
style = GetWindowLongPtrW(hwnd, GWL_STYLE);
229+
ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP | WS_MINIMIZE | WS_VISIBLE), "style was 0x%08lX\n", style);
230+
exstyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
231+
ok_long(exstyle, 0);
232+
233+
ShowWindow(hwnd, SW_SHOWNORMAL);
234+
Sleep(100);
235+
ok_long(CheckColor(), RED);
236+
237+
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, WS_EX_MAKEVISIBLEWHENUNGHOSTED);
238+
ret = ShowWindow(hwnd, SW_FORCEMINIMIZE);
239+
Sleep(100);
240+
ok(ret != FALSE, "ret was FALSE\n");
241+
ok(CheckColor() != RED, "Color was red\n");
242+
style = GetWindowLongPtrW(hwnd, GWL_STYLE);
243+
if (IsWindowsVistaOrGreater())
244+
ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP | WS_MINIMIZE | WS_VISIBLE), "style was 0x%08lX\n", style);
245+
else
246+
ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP), "style was 0x%08lX\n", style);
247+
exstyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
248+
ok_long(exstyle, 0);
249+
250+
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, WS_EX_MAKEVISIBLEWHENUNGHOSTED);
251+
ret = ShowWindow(hwnd, SW_FORCEMINIMIZE);
252+
Sleep(100);
253+
if (IsWindowsVistaOrGreater())
254+
ok(ret != FALSE, "ret was FALSE\n");
255+
else
256+
ok_bool_false(ret, "Return was");
257+
ok(CheckColor() != RED, "Color was red\n");
258+
style = GetWindowLongPtrW(hwnd, GWL_STYLE);
259+
if (IsWindowsVistaOrGreater())
260+
ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP | WS_MINIMIZE | WS_VISIBLE), "style was 0x%08lX\n", style);
261+
else
262+
ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP), "style was 0x%08lX\n", style);
263+
exstyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
264+
ok_long(exstyle, 0);
265+
266+
PostMessageW(hwnd, WM_CLOSE, 0, 0);
267+
return 0;
268+
}
269+
270+
static LRESULT CALLBACK
271+
ForceMinimizeWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
272+
{
273+
switch (uMsg)
274+
{
275+
case WM_DESTROY:
276+
PostQuitMessage(0);
277+
break;
278+
default:
279+
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
280+
}
281+
return 0;
282+
}
283+
284+
static VOID
285+
Test_WS_FORCEMINIMIZE_Sub(HBRUSH hbr)
286+
{
287+
WNDCLASSW wc;
288+
HWND hwnd;
289+
DWORD style;
290+
HINSTANCE hInstance = GetModuleHandleW(NULL);
291+
DWORD dwThreadId;
292+
HANDLE hThread;
293+
MSG msg;
294+
295+
ZeroMemory(&wc, sizeof(wc));
296+
wc.lpfnWndProc = ForceMinimizeWndProc;
297+
wc.hInstance = hInstance;
298+
wc.hIcon = LoadIconW(NULL, (PCWSTR)IDI_APPLICATION);
299+
wc.hCursor = LoadCursorW(NULL, (PCWSTR)IDC_ARROW);
300+
wc.hbrBackground = hbr;
301+
wc.lpszClassName = L"SW_FORCEMINIMIZE";
302+
if (!RegisterClassW(&wc))
303+
{
304+
skip("RegisterClassW failed\n");
305+
return;
306+
}
307+
308+
style = WS_POPUP | WS_VISIBLE;
309+
hwnd = CreateWindowExW(0, L"SW_FORCEMINIMIZE", L"SW_FORCEMINIMIZE", style,
310+
50, 50, 100, 100, NULL, NULL, hInstance, NULL);
311+
if (!hwnd)
312+
{
313+
skip("CreateWindowExW failed\n");
314+
return;
315+
}
316+
317+
hThread = CreateThread(NULL, 0, ForceMinimizeThreadFunc, hwnd, 0, &dwThreadId);
318+
if (!hThread)
319+
{
320+
skip("CreateThread failed\n");
321+
DestroyWindow(hwnd);
322+
return;
323+
}
324+
CloseHandle(hThread);
325+
326+
while (GetMessageW(&msg, NULL, 0, 0))
327+
{
328+
TranslateMessage(&msg);
329+
DispatchMessageW(&msg);
330+
}
331+
}
332+
333+
static VOID
334+
Test_WS_FORCEMINIMIZE()
335+
{
336+
HBRUSH hbr = CreateSolidBrush(RED);
337+
Test_WS_FORCEMINIMIZE_Sub(hbr);
338+
DeleteObject(hbr);
339+
}
340+
341+
START_TEST(ShowWindow)
342+
{
343+
Test_ShowWindow_Main();
344+
Test_WS_FORCEMINIMIZE();
345+
}

win32ss/user/ntuser/winpos.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,9 +2586,36 @@ co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
25862586
return SwpFlags;
25872587
}
25882588

2589+
// SW_FORCEMINIMIZE
2590+
void IntForceMinimizeWindow(PWND pWnd)
2591+
{
2592+
HRGN hRgn;
2593+
PREGION pRgn;
2594+
2595+
if ((pWnd->style & (WS_MINIMIZE | WS_VISIBLE)) != WS_VISIBLE)
2596+
return;
2597+
2598+
if (pWnd->state & WNDS_DESTROYED)
2599+
return;
2600+
2601+
pWnd->ExStyle &= ~WS_EX_MAKEVISIBLEWHENUNGHOSTED;
2602+
2603+
IntSetStyle(pWnd, 0, WS_VISIBLE);
2604+
2605+
// Invalidate and redraw the window region
2606+
hRgn = GreCreateRectRgnIndirect(&pWnd->rcWindow);
2607+
pRgn = REGION_LockRgn(hRgn);
2608+
co_UserRedrawWindow(UserGetDesktopWindow(), NULL, pRgn, RDW_ALLCHILDREN | RDW_ERASE | RDW_INVALIDATE);
2609+
REGION_UnlockRgn(pRgn);
2610+
GreDeleteObject(hRgn);
2611+
2612+
// Activate the other window if necessary
2613+
if (pWnd->spwndParent == pWnd->head.rpdesk->pDeskInfo->spwnd)
2614+
co_WinPosActivateOtherWindow(pWnd);
2615+
}
2616+
25892617
/*
25902618
ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits!
2591-
Win: xxxShowWindow
25922619
*/
25932620
BOOLEAN FASTCALL
25942621
co_WinPosShowWindow(PWND Wnd, INT Cmd)
@@ -2661,7 +2688,10 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
26612688
break;
26622689
}
26632690

2664-
case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2691+
case SW_FORCEMINIMIZE:
2692+
IntForceMinimizeWindow(Wnd);
2693+
return WasVisible;
2694+
26652695
case SW_SHOWMINNOACTIVE:
26662696
Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
26672697
/* Fall through. */

win32ss/user/user32/windows/class.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,14 @@ GetClassWord(
10771077
return retvalue;
10781078
}
10791079

1080+
#define PUBLIC_EXSTYLE ( \
1081+
WS_EX_NOACTIVATE | WS_EX_COMPOSITED | WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT | \
1082+
WS_EX_LAYERED | WS_EX_APPWINDOW | WS_EX_STATICEDGE | WS_EX_CONTROLPARENT | \
1083+
WS_EX_LEFTSCROLLBAR | WS_EX_RTLREADING | WS_EX_RIGHT | WS_EX_CONTEXTHELP | \
1084+
WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_MDICHILD | \
1085+
WS_EX_TRANSPARENT | WS_EX_ACCEPTFILES | WS_EX_TOPMOST | WS_EX_NOPARENTNOTIFY | \
1086+
WS_EX_DRAGDETECT | WS_EX_DLGMODALFRAME \
1087+
)
10801088

10811089
LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
10821090
{
@@ -1116,7 +1124,7 @@ LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
11161124
{
11171125
case GWLP_USERDATA: retvalue = wndPtr->dwUserData; break;
11181126
case GWL_STYLE: retvalue = wndPtr->style; break;
1119-
case GWL_EXSTYLE: retvalue = wndPtr->ExStyle; break;
1127+
case GWL_EXSTYLE: retvalue = (wndPtr->ExStyle & PUBLIC_EXSTYLE); break;
11201128
case GWLP_ID: retvalue = wndPtr->IDMenu; break;
11211129
case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hModule; break;
11221130
#if 0

0 commit comments

Comments
 (0)