Henri Verbeet : wined3d: Don' t unregister a window unless the window proc is what we expect it to be.
Alexandre Julliard
julliard at winehq.org
Wed Nov 10 11:09:41 CST 2010
Module: wine
Branch: master
Commit: 7a354177b38c9451c938389576890a14d5c543fa
URL: http://source.winehq.org/git/wine.git/?a=commit;h=7a354177b38c9451c938389576890a14d5c543fa
Author: Henri Verbeet <hverbeet at codeweavers.com>
Date: Wed Nov 10 10:53:04 2010 +0100
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 82fdedf..a8535a3 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 0e44702..8cc2828 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 */
More information about the wine-cvs
mailing list