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