[PATCH] winex11: Don't pump messages in ChangeDisplaySettings (v2).

Stefan Dösinger stefan at codeweavers.com
Thu Apr 16 06:39:53 CDT 2015


Version 2: Filter DEVMODE flags to make the testbot happy. Supersedes
patch 110792.

This is for bug 38394. During the handling of a focus loss on game exit,
ChangeDisplaySettings calls SendMessage and causes a game-internal
message to be delivered to the game's wndproc. The wndproc destroys the
ddraw object, which causes a segfault in wined3d when control is
returned to it.

Moving the call that sends WM_DISPLAYCHANGE is necessary because
otherwise the two SendMessageTimeout calls will deadlock. Replacing SMTO
with PostMessage in the desktop thread is not an option because this
message is delivered to the calling thread's windows before
ChangeDisplaySettings returns.

I cannot put the new test into test_WM_DISPLAYCHANGE because this test
has a message loop running in a separate thread.
---
 dlls/user32/tests/sysparams.c | 81 +++++++++++++++++++++++++++++++++++++++++++
 dlls/winex11.drv/desktop.c    |  7 ++--
 2 files changed, 85 insertions(+), 3 deletions(-)

diff --git a/dlls/user32/tests/sysparams.c b/dlls/user32/tests/sysparams.c
index 31d1a8e..ae62b5f 100644
--- a/dlls/user32/tests/sysparams.c
+++ b/dlls/user32/tests/sysparams.c
@@ -164,6 +164,7 @@ static int change_last_param;
 static int last_bpp;
 static BOOL displaychange_ok = FALSE, displaychange_test_active = FALSE;
 static HANDLE displaychange_sem = 0;
+static BOOL wm_user_received;
 
 static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam,
                                               LPARAM lParam )
@@ -212,6 +213,10 @@ static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam
         PostQuitMessage( 0 );
         break;
 
+    case WM_USER:
+        wm_user_received = TRUE;
+        break;
+
     /* drop through */
     default:
         return( DefWindowProcA( hWnd, msg, wParam, lParam ) );
@@ -2898,6 +2903,80 @@ static void test_GetSysColorBrush(void)
         win_skip("COLOR_MENUBAR unsupported\n");
 }
 
+static DWORD WINAPI displaychange_test_thread(void *param)
+{
+    SendNotifyMessageA(ghTestWnd, WM_USER, 0, 0);
+    return 0;
+}
+
+static void test_displaychange_message(void)
+{
+    DEVMODEA mode, startmode;
+    LONG change_ret;
+    DWORD tid, wait_ret;
+    HANDLE thread;
+    MSG msg;
+    unsigned int i = 0;
+    DWORD width = 0, height;
+
+    if (!pChangeDisplaySettingsExA)
+    {
+        win_skip("ChangeDisplaySettingsExA is not available\n");
+        return;
+    }
+
+    memset(&startmode, 0, sizeof(startmode));
+    startmode.dmSize = sizeof(startmode);
+    EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &startmode);
+
+    memset(&mode, 0, sizeof(mode));
+    mode.dmSize = sizeof(mode);
+    while (EnumDisplaySettingsA(NULL, i++, &mode))
+    {
+        if (mode.dmPelsWidth != startmode.dmPelsWidth || mode.dmPelsHeight != startmode.dmPelsHeight)
+        {
+            width = mode.dmPelsWidth;
+            height = mode.dmPelsHeight;
+            break;
+        }
+    }
+    if (!width)
+    {
+        skip("Cound not find a mode different from the startup mode\n");
+        return;
+    }
+    memset(&mode, 0, sizeof(mode));
+    mode.dmSize = sizeof(mode);
+    mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+    mode.dmPelsWidth = width;
+    mode.dmPelsHeight = height;
+
+    displaychange_sem = CreateSemaphoreW(NULL, 0, 1, NULL);
+
+    wm_user_received = FALSE;
+    thread = CreateThread(NULL, 0, displaychange_test_thread, NULL, 0, &tid);
+    ok(thread != NULL, "CreateThread failed\n");
+    wait_ret = WaitForSingleObject(thread, INFINITE);
+    ok(wait_ret == WAIT_OBJECT_0, "Waiting for the thread to finish timed out\n");
+
+    displaychange_ok = TRUE;
+    change_ret = ChangeDisplaySettingsExA(NULL, &mode, NULL, CDS_FULLSCREEN, NULL);
+    ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsEx failed, %d\n", change_ret);
+    ok(!wm_user_received, "Received WM_USER, did not expect it\n");
+    wait_ret = WaitForSingleObject(displaychange_sem, 0);
+    ok(wait_ret == WAIT_OBJECT_0, "Expected WM_DISPLAYCHANGE, did not receive it\n");
+
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE));
+    ok(wm_user_received, "Expected WM_USER, did not receive it\n");
+
+    displaychange_ok = TRUE;
+    change_ret = pChangeDisplaySettingsExA(NULL, &startmode, NULL, 0, NULL);
+    ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsEx failed, %d\n", change_ret);
+
+    CloseHandle(displaychange_sem);
+    displaychange_sem = 0;
+}
+
 START_TEST(sysparams)
 {
     int argc;
@@ -2948,6 +3027,8 @@ START_TEST(sysparams)
     ghTestWnd = CreateWindowA( "SysParamsTestClass", "Test System Parameters Application",
                                WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, hInstance, NULL );
 
+    test_displaychange_message();
+
     hThread = CreateThread( NULL, 0, SysParamsThreadFunc, 0, 0, &dwThreadId );
     assert( hThread );
     CloseHandle( hThread );
diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c
index 603e19f..2eb673e 100644
--- a/dlls/winex11.drv/desktop.c
+++ b/dlls/winex11.drv/desktop.c
@@ -267,7 +267,10 @@ void X11DRV_resize_desktop( unsigned int width, unsigned int height )
 
     if (GetWindowThreadProcessId( hwnd, NULL ) != GetCurrentThreadId())
     {
-        SendMessageW( hwnd, WM_X11DRV_RESIZE_DESKTOP, 0, MAKELPARAM( width, height ) );
+        SendMessageTimeoutW( hwnd, WM_X11DRV_RESIZE_DESKTOP, 0,
+                             MAKELPARAM( width, height ), SMTO_BLOCK, ~0U, NULL );
+        SendMessageTimeoutW( HWND_BROADCAST, WM_DISPLAYCHANGE, screen_bpp, MAKELPARAM( width, height ),
+                             SMTO_BLOCK | SMTO_ABORTIFHUNG, 2000, NULL );
     }
     else
     {
@@ -278,8 +281,6 @@ void X11DRV_resize_desktop( unsigned int width, unsigned int height )
                       resize_data.new_virtual_rect.bottom - resize_data.new_virtual_rect.top,
                       SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE );
         ungrab_clipping_window();
-        SendMessageTimeoutW( HWND_BROADCAST, WM_DISPLAYCHANGE, screen_bpp,
-                             MAKELPARAM( width, height ), SMTO_ABORTIFHUNG, 2000, NULL );
     }
 
     EnumWindows( update_windows_on_desktop_resize, (LPARAM)&resize_data );
-- 
2.3.4




More information about the wine-patches mailing list