diff --git a/modules/rostests/apitests/user32/ShowWindow.c b/modules/rostests/apitests/user32/ShowWindow.c index 832688b938e..53c52c0e189 100644 --- a/modules/rostests/apitests/user32/ShowWindow.c +++ b/modules/rostests/apitests/user32/ShowWindow.c @@ -2,10 +2,11 @@ * PROJECT: ReactOS API tests * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) * PURPOSE: Tests for ShowWindow - * COPYRIGHT: Copyright 2021 Katayama Hirofumi MZ + * COPYRIGHT: Copyright 2021-2025 Katayama Hirofumi MZ */ #include "precomp.h" +#include typedef struct TEST_ENTRY { @@ -164,7 +165,7 @@ WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return 0; } -START_TEST(ShowWindow) +static VOID Test_ShowWindow_Main(VOID) { WNDCLASSA wc; UINT iTest; @@ -181,3 +182,164 @@ START_TEST(ShowWindow) DoTestEntry(&s_entries[iTest]); } } + +#define RED RGB(255, 0, 0) + +static COLORREF CheckColor(VOID) +{ + HDC hDC = GetDC(NULL); + COLORREF color = GetPixel(hDC, 100, 100); + ReleaseDC(NULL, hDC); + return color; +} + +static DWORD WINAPI +ForceMinimizeThreadFunc(LPVOID arg) +{ + BOOL ret; + HWND hwnd = (HWND)arg; + DWORD style, exstyle; + + Sleep(100); + ok_long(CheckColor(), RED); + + SetWindowLongPtrW(hwnd, GWL_EXSTYLE, WS_EX_MAKEVISIBLEWHENUNGHOSTED); + ret = ShowWindow(hwnd, SW_FORCEMINIMIZE); + Sleep(100); + ok(ret != FALSE, "ret was FALSE\n"); + ok(CheckColor() != RED, "Color was red\n"); + style = GetWindowLongPtrW(hwnd, GWL_STYLE); + if (IsWindowsVistaOrGreater()) + ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP | WS_MINIMIZE | WS_VISIBLE), "style was 0x%08lX\n", style); + else + ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP), "style was 0x%08lX\n", style); + exstyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); + ok_long(exstyle, 0); + + ShowWindow(hwnd, SW_MINIMIZE); + Sleep(100); + ok(CheckColor() != RED, "Color was red\n"); + + SetWindowLongPtrW(hwnd, GWL_EXSTYLE, WS_EX_MAKEVISIBLEWHENUNGHOSTED); + ret = ShowWindow(hwnd, SW_FORCEMINIMIZE); + Sleep(100); + ok(ret != FALSE, "ret was FALSE\n"); + ok(CheckColor() != RED, "Color was red\n"); + style = GetWindowLongPtrW(hwnd, GWL_STYLE); + ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP | WS_MINIMIZE | WS_VISIBLE), "style was 0x%08lX\n", style); + exstyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); + ok_long(exstyle, 0); + + ShowWindow(hwnd, SW_SHOWNORMAL); + Sleep(100); + ok_long(CheckColor(), RED); + + SetWindowLongPtrW(hwnd, GWL_EXSTYLE, WS_EX_MAKEVISIBLEWHENUNGHOSTED); + ret = ShowWindow(hwnd, SW_FORCEMINIMIZE); + Sleep(100); + ok(ret != FALSE, "ret was FALSE\n"); + ok(CheckColor() != RED, "Color was red\n"); + style = GetWindowLongPtrW(hwnd, GWL_STYLE); + if (IsWindowsVistaOrGreater()) + ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP | WS_MINIMIZE | WS_VISIBLE), "style was 0x%08lX\n", style); + else + ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP), "style was 0x%08lX\n", style); + exstyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); + ok_long(exstyle, 0); + + SetWindowLongPtrW(hwnd, GWL_EXSTYLE, WS_EX_MAKEVISIBLEWHENUNGHOSTED); + ret = ShowWindow(hwnd, SW_FORCEMINIMIZE); + Sleep(100); + if (IsWindowsVistaOrGreater()) + ok(ret != FALSE, "ret was FALSE\n"); + else + ok_bool_false(ret, "Return was"); + ok(CheckColor() != RED, "Color was red\n"); + style = GetWindowLongPtrW(hwnd, GWL_STYLE); + if (IsWindowsVistaOrGreater()) + ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP | WS_MINIMIZE | WS_VISIBLE), "style was 0x%08lX\n", style); + else + ok((style & (WS_POPUP | WS_MINIMIZE | WS_VISIBLE)) == (WS_POPUP), "style was 0x%08lX\n", style); + exstyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); + ok_long(exstyle, 0); + + PostMessageW(hwnd, WM_CLOSE, 0, 0); + return 0; +} + +static LRESULT CALLBACK +ForceMinimizeWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + return 0; +} + +static VOID +Test_WS_FORCEMINIMIZE_Sub(HBRUSH hbr) +{ + WNDCLASSW wc; + HWND hwnd; + DWORD style; + HINSTANCE hInstance = GetModuleHandleW(NULL); + DWORD dwThreadId; + HANDLE hThread; + MSG msg; + + ZeroMemory(&wc, sizeof(wc)); + wc.lpfnWndProc = ForceMinimizeWndProc; + wc.hInstance = hInstance; + wc.hIcon = LoadIconW(NULL, (PCWSTR)IDI_APPLICATION); + wc.hCursor = LoadCursorW(NULL, (PCWSTR)IDC_ARROW); + wc.hbrBackground = hbr; + wc.lpszClassName = L"SW_FORCEMINIMIZE"; + if (!RegisterClassW(&wc)) + { + skip("RegisterClassW failed\n"); + return; + } + + style = WS_POPUP | WS_VISIBLE; + hwnd = CreateWindowExW(0, L"SW_FORCEMINIMIZE", L"SW_FORCEMINIMIZE", style, + 50, 50, 100, 100, NULL, NULL, hInstance, NULL); + if (!hwnd) + { + skip("CreateWindowExW failed\n"); + return; + } + + hThread = CreateThread(NULL, 0, ForceMinimizeThreadFunc, hwnd, 0, &dwThreadId); + if (!hThread) + { + skip("CreateThread failed\n"); + DestroyWindow(hwnd); + return; + } + CloseHandle(hThread); + + while (GetMessageW(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } +} + +static VOID +Test_WS_FORCEMINIMIZE() +{ + HBRUSH hbr = CreateSolidBrush(RED); + Test_WS_FORCEMINIMIZE_Sub(hbr); + DeleteObject(hbr); +} + +START_TEST(ShowWindow) +{ + Test_ShowWindow_Main(); + Test_WS_FORCEMINIMIZE(); +} diff --git a/win32ss/user/ntuser/winpos.c b/win32ss/user/ntuser/winpos.c index da895726b7a..1fb5bda74af 100644 --- a/win32ss/user/ntuser/winpos.c +++ b/win32ss/user/ntuser/winpos.c @@ -2586,9 +2586,36 @@ co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos) return SwpFlags; } +// SW_FORCEMINIMIZE +void IntForceMinimizeWindow(PWND pWnd) +{ + HRGN hRgn; + PREGION pRgn; + + if ((pWnd->style & (WS_MINIMIZE | WS_VISIBLE)) != WS_VISIBLE) + return; + + if (pWnd->state & WNDS_DESTROYED) + return; + + pWnd->ExStyle &= ~WS_EX_MAKEVISIBLEWHENUNGHOSTED; + + IntSetStyle(pWnd, 0, WS_VISIBLE); + + // Invalidate and redraw the window region + hRgn = GreCreateRectRgnIndirect(&pWnd->rcWindow); + pRgn = REGION_LockRgn(hRgn); + co_UserRedrawWindow(UserGetDesktopWindow(), NULL, pRgn, RDW_ALLCHILDREN | RDW_ERASE | RDW_INVALIDATE); + REGION_UnlockRgn(pRgn); + GreDeleteObject(hRgn); + + // Activate the other window if necessary + if (pWnd->spwndParent == pWnd->head.rpdesk->pDeskInfo->spwnd) + co_WinPosActivateOtherWindow(pWnd); +} + /* ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits! - Win: xxxShowWindow */ BOOLEAN FASTCALL co_WinPosShowWindow(PWND Wnd, INT Cmd) @@ -2661,7 +2688,10 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd) break; } - case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */ + case SW_FORCEMINIMIZE: + IntForceMinimizeWindow(Wnd); + return WasVisible; + case SW_SHOWMINNOACTIVE: Swp |= SWP_NOACTIVATE | SWP_NOZORDER; /* Fall through. */ diff --git a/win32ss/user/user32/windows/class.c b/win32ss/user/user32/windows/class.c index 4092936d731..c2c64e9166c 100644 --- a/win32ss/user/user32/windows/class.c +++ b/win32ss/user/user32/windows/class.c @@ -1077,6 +1077,14 @@ GetClassWord( return retvalue; } +#define PUBLIC_EXSTYLE ( \ + WS_EX_NOACTIVATE | WS_EX_COMPOSITED | WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT | \ + WS_EX_LAYERED | WS_EX_APPWINDOW | WS_EX_STATICEDGE | WS_EX_CONTROLPARENT | \ + WS_EX_LEFTSCROLLBAR | WS_EX_RTLREADING | WS_EX_RIGHT | WS_EX_CONTEXTHELP | \ + WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_MDICHILD | \ + WS_EX_TRANSPARENT | WS_EX_ACCEPTFILES | WS_EX_TOPMOST | WS_EX_NOPARENTNOTIFY | \ + WS_EX_DRAGDETECT | WS_EX_DLGMODALFRAME \ +) LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode ) { @@ -1116,7 +1124,7 @@ LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode ) { case GWLP_USERDATA: retvalue = wndPtr->dwUserData; break; case GWL_STYLE: retvalue = wndPtr->style; break; - case GWL_EXSTYLE: retvalue = wndPtr->ExStyle; break; + case GWL_EXSTYLE: retvalue = (wndPtr->ExStyle & PUBLIC_EXSTYLE); break; case GWLP_ID: retvalue = wndPtr->IDMenu; break; case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hModule; break; #if 0