[PATCH 2/2 v2] d3drm: Implement AddDestroyCallback/DeleteDestroyCallback for a viewport

Nikolay Sivov nsivov at codeweavers.com
Thu Mar 3 02:10:21 CST 2016


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---

v2: fixed names, removed cast that's not needed, tests for Viewport2.

 dlls/d3drm/d3drm_main.c    | 70 ++++++++++++++++++++++++++++++++--
 dlls/d3drm/d3drm_private.h |  8 ++++
 dlls/d3drm/tests/d3drm.c   | 95 ++++++++++++++++++++++++++++++++++++++++++++++
 dlls/d3drm/viewport.c      | 29 +++++++++-----
 4 files changed, 190 insertions(+), 12 deletions(-)

diff --git a/dlls/d3drm/d3drm_main.c b/dlls/d3drm/d3drm_main.c
index 3d5255f..62ad5b9 100644
--- a/dlls/d3drm/d3drm_main.c
+++ b/dlls/d3drm/d3drm_main.c
@@ -18,13 +18,14 @@
  */
 
 #include <stdarg.h>
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
 #include "d3d.h"
+
+#include "dxfile.h"
 #include "initguid.h"
 #include "d3drm.h"
 
+#include "d3drm_private.h"
+#include "wine/list.h"
 
 /***********************************************************************
  *		DllMain  (D3DRM.@)
@@ -41,3 +42,66 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved)
     }
     return TRUE;
 }
+
+void d3drm_object_init(struct d3drm_object *object)
+{
+    object->ref = 1;
+    object->appdata = 0;
+    list_init(&object->destroy_callbacks);
+}
+
+struct destroy_callback
+{
+    struct list entry;
+    D3DRMOBJECTCALLBACK cb;
+    void *ctx;
+};
+
+HRESULT d3drm_object_add_destroy_callback(struct d3drm_object *object, D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    struct destroy_callback *callback;
+
+    if (!cb)
+        return D3DRMERR_BADVALUE;
+
+    callback = HeapAlloc(GetProcessHeap(), 0, sizeof(*callback));
+    if (!callback)
+        return E_OUTOFMEMORY;
+
+    callback->cb = cb;
+    callback->ctx = ctx;
+
+    list_add_head(&object->destroy_callbacks, &callback->entry);
+    return D3DRM_OK;
+}
+
+HRESULT d3drm_object_delete_destroy_callback(struct d3drm_object *object, D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    struct destroy_callback *callback, *callback2;
+
+    if (!cb)
+        return D3DRMERR_BADVALUE;
+
+    LIST_FOR_EACH_ENTRY_SAFE(callback, callback2, &object->destroy_callbacks, struct destroy_callback, entry)
+    {
+        if (callback->cb == cb && callback->ctx == ctx)
+        {
+            list_remove(&callback->entry);
+            HeapFree(GetProcessHeap(), 0, callback);
+        }
+    }
+
+    return D3DRM_OK;
+}
+
+void d3drm_object_cleanup(IDirect3DRMObject *iface, struct d3drm_object *object)
+{
+    struct destroy_callback *callback, *callback2;
+
+    LIST_FOR_EACH_ENTRY_SAFE(callback, callback2, &object->destroy_callbacks, struct destroy_callback, entry)
+    {
+        callback->cb(iface, callback->ctx);
+        list_remove(&callback->entry);
+        HeapFree(GetProcessHeap(), 0, callback);
+    }
+}
diff --git a/dlls/d3drm/d3drm_private.h b/dlls/d3drm/d3drm_private.h
index 5703560..34cd913 100644
--- a/dlls/d3drm/d3drm_private.h
+++ b/dlls/d3drm/d3drm_private.h
@@ -24,13 +24,21 @@
 #include "d3drm.h"
 #include "dxfile.h"
 
+#include "wine/list.h"
+
 struct d3drm_device;
 struct d3drm_object
 {
     LONG ref;
     DWORD appdata;
+    struct list destroy_callbacks;
 };
 
+void d3drm_object_init(struct d3drm_object *object) DECLSPEC_HIDDEN;
+HRESULT d3drm_object_add_destroy_callback(struct d3drm_object *object, D3DRMOBJECTCALLBACK cb, void *ctx) DECLSPEC_HIDDEN;
+HRESULT d3drm_object_delete_destroy_callback(struct d3drm_object *object, D3DRMOBJECTCALLBACK cb, void *ctx) DECLSPEC_HIDDEN;
+void d3drm_object_cleanup(IDirect3DRMObject *iface, struct d3drm_object *object) DECLSPEC_HIDDEN;
+
 HRESULT d3drm_device_create(struct d3drm_device **out) DECLSPEC_HIDDEN;
 IDirect3DRMDevice *IDirect3DRMDevice_from_impl(struct d3drm_device *device) DECLSPEC_HIDDEN;
 IDirect3DRMDevice2 *IDirect3DRMDevice2_from_impl(struct d3drm_device *device) DECLSPEC_HIDDEN;
diff --git a/dlls/d3drm/tests/d3drm.c b/dlls/d3drm/tests/d3drm.c
index 23193bf..4c73714 100644
--- a/dlls/d3drm/tests/d3drm.c
+++ b/dlls/d3drm/tests/d3drm.c
@@ -1212,8 +1212,31 @@ static void test_Frame(void)
     IDirect3DRM_Release(d3drm);
 }
 
+struct destroy_context
+{
+    IDirect3DRMObject *obj;
+    int called;
+};
+
+static void destroy_callback(IDirect3DRMObject *obj, void *arg)
+{
+    struct destroy_context *ctxt = arg;
+    ok(ctxt->called == 1 || ctxt->called == 2, "got called counter %d\n", ctxt->called);
+    ok(obj == ctxt->obj, "called with %p, expected %p\n", obj, ctxt->obj);
+    ctxt->called++;
+}
+
+static void destroy_callback1(IDirect3DRMObject *obj, void *arg)
+{
+    struct destroy_context *ctxt = (struct destroy_context*)arg;
+    ok(ctxt->called == 0, "got called counter %d\n", ctxt->called);
+    ok(obj == ctxt->obj, "called with %p, expected %p\n", obj, ctxt->obj);
+    ctxt->called++;
+}
+
 static void test_Viewport(void)
 {
+    struct destroy_context context;
     IDirectDrawClipper *pClipper;
     HRESULT hr;
     IDirect3DRM *d3drm;
@@ -1299,7 +1322,79 @@ static void test_Viewport(void)
     ok(data == 1, "got %x\n", data);
     IDirect3DRMViewport2_Release(viewport2);
 
+    /* destroy callback */
+    context.called = 0;
+    hr = IDirect3DRMViewport_QueryInterface(viewport, &IID_IDirect3DRMObject, (void**)&context.obj);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+    IDirect3DRMObject_Release(context.obj);
+
+    hr = IDirect3DRMViewport_AddDestroyCallback(viewport, NULL, &context);
+    ok(hr == D3DRMERR_BADVALUE, "expected D3DRMERR_BADVALUE (hr = %x)\n", hr);
+
+    hr = IDirect3DRMViewport_AddDestroyCallback(viewport, destroy_callback, &context);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+
+    /* same callback added twice */
+    hr = IDirect3DRMViewport_AddDestroyCallback(viewport, destroy_callback, &context);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+
+    hr = IDirect3DRMViewport_DeleteDestroyCallback(viewport, destroy_callback1, NULL);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+
+    hr = IDirect3DRMViewport_DeleteDestroyCallback(viewport, destroy_callback1, &context);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+
+    /* add one more */
+    hr = IDirect3DRMViewport_AddDestroyCallback(viewport, destroy_callback1, &context);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+
+    hr = IDirect3DRMViewport_DeleteDestroyCallback(viewport, NULL, NULL);
+    ok(hr == D3DRMERR_BADVALUE, "expected D3DRM_BADVALUE (hr = %x)\n", hr);
+
+    context.called = 0;
     IDirect3DRMViewport_Release(viewport);
+    ok(context.called == 3, "got %d, expected 3\n", context.called);
+
+    /* destroy from Viewport2 */
+    hr = IDirect3DRM_CreateViewport(d3drm, device, frame, rc.left, rc.top, rc.right, rc.bottom, &viewport);
+    ok(hr == D3DRM_OK, "Cannot get IDirect3DRMViewport interface (hr = %x)\n", hr);
+
+    hr = IDirect3DRMViewport_QueryInterface(viewport, &IID_IDirect3DRMViewport2, (void**)&viewport2);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+    IDirect3DRMViewport_Release(viewport);
+
+    context.called = 0;
+    hr = IDirect3DRMViewport2_QueryInterface(viewport2, &IID_IDirect3DRMObject, (void**)&context.obj);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+    IDirect3DRMObject_Release(context.obj);
+
+    hr = IDirect3DRMViewport2_AddDestroyCallback(viewport2, NULL, &context);
+    ok(hr == D3DRMERR_BADVALUE, "expected D3DRMERR_BADVALUE (hr = %x)\n", hr);
+
+    hr = IDirect3DRMViewport2_AddDestroyCallback(viewport2, destroy_callback, &context);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+
+    /* same callback added twice */
+    hr = IDirect3DRMViewport2_AddDestroyCallback(viewport2, destroy_callback, &context);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+
+    hr = IDirect3DRMViewport2_DeleteDestroyCallback(viewport2, destroy_callback1, NULL);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+
+    hr = IDirect3DRMViewport2_DeleteDestroyCallback(viewport2, destroy_callback1, &context);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+
+    /* add one more */
+    hr = IDirect3DRMViewport2_AddDestroyCallback(viewport2, destroy_callback1, &context);
+    ok(hr == D3DRM_OK, "expected D3DRM_OK (hr = %x)\n", hr);
+
+    hr = IDirect3DRMViewport2_DeleteDestroyCallback(viewport2, NULL, NULL);
+    ok(hr == D3DRMERR_BADVALUE, "expected D3DRM_BADVALUE (hr = %x)\n", hr);
+
+    context.called = 0;
+    IDirect3DRMViewport2_Release(viewport2);
+    ok(context.called == 3, "got %d, expected 3\n", context.called);
+
     IDirect3DRMFrame_Release(frame);
     IDirect3DRMDevice_Release(device);
     IDirectDrawClipper_Release(pClipper);
diff --git a/dlls/d3drm/viewport.c b/dlls/d3drm/viewport.c
index e092559..98ea582 100644
--- a/dlls/d3drm/viewport.c
+++ b/dlls/d3drm/viewport.c
@@ -95,7 +95,10 @@ static ULONG WINAPI d3drm_viewport1_Release(IDirect3DRMViewport *iface)
     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
 
     if (!refcount)
+    {
+        d3drm_object_cleanup((IDirect3DRMObject*)iface, &viewport->obj);
         HeapFree(GetProcessHeap(), 0, viewport);
+    }
 
     return refcount;
 }
@@ -111,17 +114,21 @@ static HRESULT WINAPI d3drm_viewport1_Clone(IDirect3DRMViewport *iface,
 static HRESULT WINAPI d3drm_viewport1_AddDestroyCallback(IDirect3DRMViewport *iface,
         D3DRMOBJECTCALLBACK cb, void *ctx)
 {
-    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
 
-    return E_NOTIMPL;
+    TRACE("iface %p, cb %p, ctx %p\n", iface, cb, ctx);
+
+    return IDirect3DRMViewport2_AddDestroyCallback(&viewport->IDirect3DRMViewport2_iface, cb, ctx);
 }
 
 static HRESULT WINAPI d3drm_viewport1_DeleteDestroyCallback(IDirect3DRMViewport *iface,
         D3DRMOBJECTCALLBACK cb, void *ctx)
 {
-    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
 
-    return E_NOTIMPL;
+    TRACE("iface %p, cb %p, ctx %p\n", iface, cb, ctx);
+
+    return IDirect3DRMViewport2_DeleteDestroyCallback(&viewport->IDirect3DRMViewport2_iface, cb, ctx);
 }
 
 static HRESULT WINAPI d3drm_viewport1_SetAppData(IDirect3DRMViewport *iface, DWORD data)
@@ -468,17 +475,21 @@ static HRESULT WINAPI d3drm_viewport2_Clone(IDirect3DRMViewport2 *iface,
 static HRESULT WINAPI d3drm_viewport2_AddDestroyCallback(IDirect3DRMViewport2 *iface,
         D3DRMOBJECTCALLBACK cb, void *ctx)
 {
-    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
 
-    return E_NOTIMPL;
+    TRACE("iface %p, cb %p, ctx %p\n", iface, cb, ctx);
+
+    return d3drm_object_add_destroy_callback(&viewport->obj, cb, ctx);
 }
 
 static HRESULT WINAPI d3drm_viewport2_DeleteDestroyCallback(IDirect3DRMViewport2 *iface,
         D3DRMOBJECTCALLBACK cb, void *ctx)
 {
-    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
 
-    return E_NOTIMPL;
+    TRACE("iface %p, cb %p, ctx %p\n", iface, cb, ctx);
+
+    return d3drm_object_delete_destroy_callback(&viewport->obj, cb, ctx);
 }
 
 static HRESULT WINAPI d3drm_viewport2_SetAppData(IDirect3DRMViewport2 *iface, DWORD data)
@@ -829,7 +840,7 @@ HRESULT Direct3DRMViewport_create(REFIID riid, IUnknown **out)
 
     object->IDirect3DRMViewport_iface.lpVtbl = &d3drm_viewport1_vtbl;
     object->IDirect3DRMViewport2_iface.lpVtbl = &d3drm_viewport2_vtbl;
-    object->obj.ref = 1;
+    d3drm_object_init(&object->obj);
 
     if (IsEqualGUID(riid, &IID_IDirect3DRMViewport2))
         *out = (IUnknown *)&object->IDirect3DRMViewport2_iface;
-- 
2.7.0




More information about the wine-patches mailing list