From 7a354177b38c9451c938389576890a14d5c543fa Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Wed, 10 Nov 2010 10:53:04 +0100 Subject: [PATCH] wined3d: Don't unregister a window unless the window proc is what we expect it to be. In particular, if we'd unregister a window when the application replaced our window proc, but still forwards to us, we'd create a loop when we register the same window again later. --- dlls/ddraw/tests/d3d.c | 84 ++++++++++++++++++++++++++++++++++++- dlls/wined3d/wined3d_main.c | 52 ++++++++++++++--------- 2 files changed, 115 insertions(+), 21 deletions(-) diff --git a/dlls/ddraw/tests/d3d.c b/dlls/ddraw/tests/d3d.c index 82fdedf29d..a8535a37cd 100644 --- a/dlls/ddraw/tests/d3d.c +++ b/dlls/ddraw/tests/d3d.c @@ -3263,9 +3263,9 @@ static LRESULT CALLBACK test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM static void test_wndproc(void) { + LONG_PTR proc, ddraw_proc; IDirectDraw7 *ddraw7; WNDCLASSA wc = {0}; - LONG_PTR proc; HWND window; HRESULT hr; ULONG ref; @@ -3356,7 +3356,87 @@ static void test_wndproc(void) (LONG_PTR)test_proc, proc); /* The original window proc is only restored by ddraw if the current - * window proc matches the one ddraw set. */ + * window proc matches the one ddraw set. This also affects switching + * from DDSCL_NORMAL to DDSCL_EXCLUSIVE. */ + hr = pDirectDrawCreateEx(NULL, (void **)&ddraw7, &IID_IDirectDraw7, NULL); + if (FAILED(hr)) + { + skip("Failed to create IDirectDraw7 object (%#x), skipping tests.\n", hr); + return; + } + + proc = GetWindowLongPtrA(window, GWLP_WNDPROC); + ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n", + (LONG_PTR)test_proc, proc); + + hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr); + if (FAILED(hr)) + { + IDirectDraw7_Release(ddraw7); + goto done; + } + + proc = GetWindowLongPtrA(window, GWLP_WNDPROC); + ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n", + (LONG_PTR)test_proc, proc); + ddraw_proc = proc; + + hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_NORMAL); + ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr); + if (FAILED(hr)) + { + IDirectDraw7_Release(ddraw7); + goto done; + } + + proc = GetWindowLongPtrA(window, GWLP_WNDPROC); + ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n", + (LONG_PTR)test_proc, proc); + + hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr); + if (FAILED(hr)) + { + IDirectDraw7_Release(ddraw7); + goto done; + } + + proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA); + ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n", + (LONG_PTR)test_proc, proc); + + hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_NORMAL); + ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr); + if (FAILED(hr)) + { + IDirectDraw7_Release(ddraw7); + goto done; + } + + proc = GetWindowLongPtrA(window, GWLP_WNDPROC); + ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n", + (LONG_PTR)DefWindowProcA, proc); + + hr = IDirectDraw7_SetCooperativeLevel(ddraw7, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr); + if (FAILED(hr)) + { + IDirectDraw7_Release(ddraw7); + goto done; + } + + proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)ddraw_proc); + ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n", + (LONG_PTR)DefWindowProcA, proc); + + ref = IDirectDraw7_Release(ddraw7); + ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref); + + proc = GetWindowLongPtrA(window, GWLP_WNDPROC); + ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n", + (LONG_PTR)test_proc, proc); + hr = pDirectDrawCreateEx(NULL, (void **)&ddraw7, &IID_IDirectDraw7, NULL); if (FAILED(hr)) { diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c index 0e4470274d..8cc2828db7 100644 --- a/dlls/wined3d/wined3d_main.c +++ b/dlls/wined3d/wined3d_main.c @@ -467,35 +467,49 @@ BOOL wined3d_register_window(HWND window, IWineD3DDeviceImpl *device) void wined3d_unregister_window(HWND window) { - unsigned int i; + struct wined3d_wndproc *entry, *last; + LONG_PTR proc; wined3d_mutex_lock(); - for (i = 0; i < wndproc_table.count; ++i) + + if (!(entry = wined3d_find_wndproc(window))) { - if (wndproc_table.entries[i].window == window) - { - struct wined3d_wndproc *entry = &wndproc_table.entries[i]; - struct wined3d_wndproc *last = &wndproc_table.entries[--wndproc_table.count]; + wined3d_mutex_unlock(); + ERR("Window %p is not registered with wined3d.\n", window); + return; + } - if (entry->unicode) - { - if (GetWindowLongPtrW(window, GWLP_WNDPROC) == (LONG_PTR)wined3d_wndproc) - SetWindowLongPtrW(window, GWLP_WNDPROC, (LONG_PTR)entry->proc); - } - else - { - if (GetWindowLongPtrA(window, GWLP_WNDPROC) == (LONG_PTR)wined3d_wndproc) - SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)entry->proc); - } - if (entry != last) *entry = *last; + if (entry->unicode) + { + proc = GetWindowLongPtrW(window, GWLP_WNDPROC); + if (proc != (LONG_PTR)wined3d_wndproc) + { wined3d_mutex_unlock(); + WARN("Not unregistering window %p, window proc %#lx doesn't match wined3d window proc %p.\n", + window, proc, wined3d_wndproc); + return; + } + SetWindowLongPtrW(window, GWLP_WNDPROC, (LONG_PTR)entry->proc); + } + else + { + proc = GetWindowLongPtrA(window, GWLP_WNDPROC); + if (proc != (LONG_PTR)wined3d_wndproc) + { + wined3d_mutex_unlock(); + WARN("Not unregistering window %p, window proc %#lx doesn't match wined3d window proc %p.\n", + window, proc, wined3d_wndproc); return; } + + SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)entry->proc); } - wined3d_mutex_unlock(); - ERR("Window %p is not registered with wined3d.\n", window); + last = &wndproc_table.entries[--wndproc_table.count]; + if (entry != last) *entry = *last; + + wined3d_mutex_unlock(); } /* At process attach */ -- 2.32.0.93.g670b81a890