[PATCH 5/6] d3d9/tests: Port test_wndproc to d3d9ex (v2).

Stefan Dösinger stefan at codeweavers.com
Wed Oct 1 08:50:29 CDT 2014


v2: Don't test wparam of WM_ACTIVATE during creation.
---
 dlls/d3d9/tests/d3d9ex.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 353 insertions(+), 5 deletions(-)

diff --git a/dlls/d3d9/tests/d3d9ex.c b/dlls/d3d9/tests/d3d9ex.c
index 0309013..c8e7c69 100644
--- a/dlls/d3d9/tests/d3d9ex.c
+++ b/dlls/d3d9/tests/d3d9ex.c
@@ -420,7 +420,6 @@ static void test_get_adapter_displaymode_ex(void)
     D3DDISPLAYMODE mode;
     D3DDISPLAYMODEEX mode_ex;
     D3DDISPLAYROTATION rotation;
-    HANDLE hdll;
     DEVMODEA startmode;
     LONG retval;
 
@@ -447,10 +446,6 @@ static void test_get_adapter_displaymode_ex(void)
        hr);
     ok(d3d9 != NULL && d3d9 != (void *) 0xdeadbeef,
        "QueryInterface returned interface %p, expected != NULL && != 0xdeadbeef\n", d3d9);
-    /* change displayorientation*/
-    hdll = GetModuleHandleA("user32.dll");
-    pEnumDisplaySettingsExA = (void*)GetProcAddress(hdll, "EnumDisplaySettingsExA");
-    pChangeDisplaySettingsExA = (void*)GetProcAddress(hdll, "ChangeDisplaySettingsExA");
 
     if (!pEnumDisplaySettingsExA || !pChangeDisplaySettingsExA) goto out;
 
@@ -1331,8 +1326,356 @@ done:
     DestroyWindow(window);
 }
 
+/* try to make sure pending X events have been processed before continuing */
+static void flush_events(void)
+{
+    MSG msg;
+    int diff = 200;
+    int min_timeout = 100;
+    DWORD time = GetTickCount() + diff;
+
+    while (diff > 0)
+    {
+        if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
+        while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+        diff = time - GetTickCount();
+    }
+}
+
+static HWND filter_messages;
+
+enum message_window
+{
+    DEVICE_WINDOW,
+    FOCUS_WINDOW,
+};
+
+struct message
+{
+    UINT message;
+    enum message_window window;
+    BOOL check_wparam;
+    WPARAM expect_wparam;
+};
+
+static const struct message *expect_messages;
+static HWND device_window, focus_window;
+
+struct wndproc_thread_param
+{
+    HWND dummy_window;
+    HANDLE window_created;
+    HANDLE test_finished;
+    BOOL running_in_foreground;
+};
+
+static LRESULT CALLBACK test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
+{
+    if (filter_messages && filter_messages == hwnd)
+    {
+        if (message != WM_DISPLAYCHANGE && message != WM_IME_NOTIFY)
+            todo_wine ok( 0, "Received unexpected message %#x for window %p.\n", message, hwnd);
+    }
+
+    if (expect_messages)
+    {
+        HWND w;
+
+        switch (expect_messages->window)
+        {
+            case DEVICE_WINDOW:
+                w = device_window;
+                break;
+
+            case FOCUS_WINDOW:
+                w = focus_window;
+                break;
+
+            default:
+                w = NULL;
+                break;
+        };
+
+
+        if (hwnd == w && expect_messages->message == message)
+        {
+            if (expect_messages->check_wparam)
+                ok(wparam == expect_messages->expect_wparam,
+                        "Got unexpected wparam %lx for message %x, expected %lx.\n",
+                        wparam, message, expect_messages->expect_wparam);
+
+            ++expect_messages;
+        }
+    }
+
+    return DefWindowProcA(hwnd, message, wparam, lparam);
+}
+
+static DWORD WINAPI wndproc_thread(void *param)
+{
+    struct wndproc_thread_param *p = param;
+    DWORD res;
+    BOOL ret;
+
+    p->dummy_window = CreateWindowA("d3d9_test_wndproc_wc", "d3d9_test",
+            WS_MAXIMIZE | WS_VISIBLE | WS_CAPTION, 0, 0, 200, 200, 0, 0, 0, 0);
+    p->running_in_foreground = SetForegroundWindow(p->dummy_window);
+
+    ret = SetEvent(p->window_created);
+    ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
+
+    for (;;)
+    {
+        MSG msg;
+
+        while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+        res = WaitForSingleObject(p->test_finished, 100);
+        if (res == WAIT_OBJECT_0) break;
+        if (res != WAIT_TIMEOUT)
+        {
+            ok(0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
+            break;
+        }
+    }
+
+    DestroyWindow(p->dummy_window);
+
+    return 0;
+}
+
+static void test_wndproc(void)
+{
+    struct wndproc_thread_param thread_params;
+    IDirect3DDevice9Ex *device;
+    WNDCLASSA wc = {0};
+    IDirect3D9Ex *d3d9;
+    HANDLE thread;
+    LONG_PTR proc;
+    ULONG ref;
+    DWORD res, tid;
+    HWND tmp;
+    D3DPRESENT_PARAMETERS present_parameters = {0};
+    DEVMODEA devmode, orig_mode;
+    BOOL ret;
+    D3DDISPLAYMODEEX mode;
+    HRESULT hr;
+
+    static const struct message create_messages[] =
+    {
+        {WM_WINDOWPOSCHANGING,  FOCUS_WINDOW,   FALSE,  0},
+        /* Do not test wparam here. If device creation succeeds,
+         * wparam is WA_ACTIVE. If device creation fails (testbot)
+         * wparam is set to WA_INACTIVE on some Windows versions. */
+        {WM_ACTIVATE,           FOCUS_WINDOW,   FALSE,  0},
+        {WM_SETFOCUS,           FOCUS_WINDOW,   FALSE,  0},
+        {0,                     0,              FALSE,  0},
+    };
+    static const struct message focus_loss_messages[] =
+    {
+        {WM_ACTIVATE,           FOCUS_WINDOW,   TRUE,   WA_INACTIVE},
+        {WM_DISPLAYCHANGE,      DEVICE_WINDOW,  FALSE,  0},
+        /* WM_DISPLAYCHANGE is sent to the focus window too, but the order is
+         * not deterministic. */
+        {WM_WINDOWPOSCHANGING,  DEVICE_WINDOW,  FALSE,  0},
+        /* Windows sends WM_ACTIVATE to the device window, indicating that
+         * SW_SHOWMINIMIZED is used instead of SW_MINIMIZE. Yet afterwards
+         * the foreground and focus window are NULL. On Wine SW_SHOWMINIMIZED
+         * leaves the device window active, breaking re-activation in the
+         * lost device test.
+         * {WM_ACTIVATE,           DEVICE_WINDOW,  TRUE,   0x200000 | WA_ACTIVE}, */
+        {WM_WINDOWPOSCHANGED,   DEVICE_WINDOW,  FALSE,  0},
+        {WM_SIZE,               DEVICE_WINDOW,  TRUE,   SIZE_MINIMIZED},
+        {WM_ACTIVATEAPP,        FOCUS_WINDOW,   TRUE,   FALSE},
+        /* WM_ACTIVATEAPP is sent to the device window too, but the order is
+         * not deterministic. It may be sent after the focus window handling
+         * or before. */
+        {0,                     0,              FALSE,  0},
+    };
+
+    memset(&orig_mode, 0, sizeof(orig_mode));
+    orig_mode.dmSize = sizeof(orig_mode);
+    ret = pEnumDisplaySettingsExA(NULL, ENUM_CURRENT_SETTINGS, &orig_mode, 0);
+    ok(ret, "Failed to get display mode.\n");
+
+    if (FAILED(pDirect3DCreate9Ex(D3D_SDK_VERSION, &d3d9)))
+        return;
+
+    wc.lpfnWndProc = test_proc;
+    wc.lpszClassName = "d3d9_test_wndproc_wc";
+    ok(RegisterClassA(&wc), "Failed to register window class.\n");
+
+    thread_params.window_created = CreateEventA(NULL, FALSE, FALSE, NULL);
+    ok(!!thread_params.window_created, "CreateEvent failed, last error %#x.\n", GetLastError());
+    thread_params.test_finished = CreateEventA(NULL, FALSE, FALSE, NULL);
+    ok(!!thread_params.test_finished, "CreateEvent failed, last error %#x.\n", GetLastError());
+
+    focus_window = CreateWindowA("d3d9_test_wndproc_wc", "d3d9_test",
+            WS_MAXIMIZE | WS_VISIBLE | WS_CAPTION, 0, 0, orig_mode.dmPelsWidth, orig_mode.dmPelsHeight, 0, 0, 0, 0);
+    device_window = CreateWindowA("d3d9_test_wndproc_wc", "d3d9_test",
+            WS_MAXIMIZE | WS_VISIBLE | WS_CAPTION, 0, 0, orig_mode.dmPelsWidth, orig_mode.dmPelsHeight, 0, 0, 0, 0);
+    thread = CreateThread(NULL, 0, wndproc_thread, &thread_params, 0, &tid);
+    ok(!!thread, "Failed to create thread, last error %#x.\n", GetLastError());
+
+    res = WaitForSingleObject(thread_params.window_created, INFINITE);
+    ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
+
+    proc = GetWindowLongPtrA(device_window, GWLP_WNDPROC);
+    ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
+            (LONG_PTR)test_proc, proc);
+    proc = GetWindowLongPtrA(focus_window, GWLP_WNDPROC);
+    ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
+            (LONG_PTR)test_proc, proc);
+
+    trace("device_window %p, focus_window %p, dummy_window %p.\n",
+            device_window, focus_window, thread_params.dummy_window);
+
+    tmp = GetFocus();
+    ok(tmp == device_window, "Expected focus %p, got %p.\n", device_window, tmp);
+    if (thread_params.running_in_foreground)
+    {
+        tmp = GetForegroundWindow();
+        ok(tmp == thread_params.dummy_window, "Expected foreground window %p, got %p.\n",
+                thread_params.dummy_window, tmp);
+    }
+    else
+        skip("Not running in foreground, skip foreground window test\n");
+
+    flush_events();
+
+    expect_messages = create_messages;
+
+    present_parameters.Windowed = FALSE;
+    present_parameters.hDeviceWindow = device_window;
+    present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    present_parameters.BackBufferWidth = 640;
+    present_parameters.BackBufferHeight = 480;
+    present_parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
+    mode.Size = sizeof(mode);
+    mode.Width = 640;
+    mode.Height = 480;
+    mode.RefreshRate = 0;
+    mode.Format = D3DFMT_A8R8G8B8;
+    mode.ScanLineOrdering = 0;
+    if (FAILED(IDirect3D9Ex_CreateDeviceEx(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, focus_window,
+            D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &mode, &device)))
+    {
+        skip("Failed to create a D3D device, skipping tests.\n");
+        goto done;
+    }
+
+    ok(!expect_messages->message, "Expected message %#x for window %#x, but didn't receive it.\n",
+            expect_messages->message, expect_messages->window);
+    expect_messages = NULL;
+
+    if (0) /* Disabled until we can make this work in a reliable way on Wine. */
+    {
+        tmp = GetFocus();
+        ok(tmp == focus_window, "Expected focus %p, got %p.\n", focus_window, tmp);
+        tmp = GetForegroundWindow();
+        ok(tmp == focus_window, "Expected foreground window %p, got %p.\n", focus_window, tmp);
+    }
+    SetForegroundWindow(focus_window);
+    flush_events();
+
+    proc = GetWindowLongPtrA(device_window, GWLP_WNDPROC);
+    ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
+            (LONG_PTR)test_proc, proc);
+
+    proc = GetWindowLongPtrA(focus_window, GWLP_WNDPROC);
+    ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
+            (LONG_PTR)test_proc, proc);
+
+    filter_messages = NULL;
+    expect_messages = focus_loss_messages;
+    SetForegroundWindow(GetDesktopWindow());
+    ok(!expect_messages->message, "Expected message %#x for window %#x, but didn't receive it.\n",
+            expect_messages->message, expect_messages->window);
+    expect_messages = NULL;
+    tmp = GetFocus();
+    ok(tmp != device_window, "The device window is active.\n");
+    ok(tmp != focus_window, "The focus window is active.\n");
+
+    memset(&devmode, 0, sizeof(devmode));
+    devmode.dmSize = sizeof(devmode);
+    ret = pEnumDisplaySettingsExA(NULL, ENUM_CURRENT_SETTINGS, &devmode, 0);
+    ok(ret, "Failed to get display mode.\n");
+    ok(devmode.dmPelsWidth == orig_mode.dmPelsWidth, "Got unexpect width %u.\n", devmode.dmPelsWidth);
+    ok(devmode.dmPelsHeight == orig_mode.dmPelsHeight, "Got unexpect height %u.\n", devmode.dmPelsHeight);
+
+    proc = GetWindowLongPtrA(device_window, GWLP_WNDPROC);
+    ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
+            (LONG_PTR)test_proc, proc);
+
+    proc = GetWindowLongPtrA(focus_window, GWLP_WNDPROC);
+    ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
+            (LONG_PTR)test_proc, proc);
+
+    /* For some reason I have to minimize and restore the focus window,
+     * otherwise native d3d9 fails device::reset. This may be related
+     * to the WM_ACTIVATE message during focus loss. */
+    ShowWindow(focus_window, SW_MINIMIZE);
+    ShowWindow(focus_window, SW_RESTORE);
+    SetForegroundWindow(focus_window);
+    flush_events();
+
+    filter_messages = focus_window;
+    hr = reset_device(device, device_window, FALSE);
+    ok(SUCCEEDED(hr), "Failed to reset device, hr %#x.\n", hr);
+
+    ref = IDirect3DDevice9_Release(device);
+    ok(ref == 0, "The device was not properly freed: refcount %u.\n", ref);
+
+    proc = GetWindowLongPtrA(focus_window, GWLP_WNDPROC);
+    ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
+            (LONG_PTR)test_proc, proc);
+
+    device = create_device(focus_window, focus_window, FALSE);
+    if (!device)
+    {
+        skip("Failed to create a D3D device, skipping tests.\n");
+        goto done;
+    }
+
+    ref = IDirect3DDevice9_Release(device);
+    ok(ref == 0, "The device was not properly freed: refcount %u.\n", ref);
+
+    device = create_device(device_window, focus_window, FALSE);
+    if (!device)
+    {
+        skip("Failed to create a D3D device, skipping tests.\n");
+        goto done;
+    }
+
+    proc = SetWindowLongPtrA(focus_window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
+    ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
+            (LONG_PTR)test_proc, proc);
+
+    ref = IDirect3DDevice9_Release(device);
+    ok(ref == 0, "The device was not properly freed: refcount %u.\n", ref);
+
+    proc = GetWindowLongPtrA(focus_window, GWLP_WNDPROC);
+    ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
+            (LONG_PTR)DefWindowProcA, proc);
+
+done:
+    filter_messages = NULL;
+    IDirect3D9_Release(d3d9);
+
+    SetEvent(thread_params.test_finished);
+    WaitForSingleObject(thread, INFINITE);
+    CloseHandle(thread_params.test_finished);
+    CloseHandle(thread_params.window_created);
+    CloseHandle(thread);
+
+    DestroyWindow(device_window);
+    DestroyWindow(focus_window);
+    UnregisterClassA("d3d9_test_wndproc_wc", GetModuleHandleA(NULL));
+}
+
 START_TEST(d3d9ex)
 {
+    HANDLE user32_handle;
+
     d3d9_handle = LoadLibraryA("d3d9.dll");
     if (!d3d9_handle)
     {
@@ -1346,6 +1689,10 @@ START_TEST(d3d9ex)
         return;
     }
 
+    user32_handle = GetModuleHandleA("user32.dll");
+    pEnumDisplaySettingsExA = (void*)GetProcAddress(user32_handle, "EnumDisplaySettingsExA");
+    pChangeDisplaySettingsExA = (void*)GetProcAddress(user32_handle, "ChangeDisplaySettingsExA");
+
     test_qi_base_to_ex();
     test_qi_ex_to_base();
     test_swapchain_get_displaymode_ex();
@@ -1357,4 +1704,5 @@ START_TEST(d3d9ex)
     test_vidmem_accounting();
     test_user_memory_getdc();
     test_lost_device();
+    test_wndproc();
 }
-- 
1.8.5.5




More information about the wine-patches mailing list