From 45743b4d9fb792d836e502c01f07a75a1814a602 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 3 Mar 2016 11:10:21 +0300 Subject: [PATCH] d3drm: Implement AddDestroyCallback/DeleteDestroyCallback for a viewport. Signed-off-by: Nikolay Sivov Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard --- 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 3d5255f7b01..62ad5b924d3 100644 --- a/dlls/d3drm/d3drm_main.c +++ b/dlls/d3drm/d3drm_main.c @@ -18,13 +18,14 @@ */ #include -#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 5703560200b..34cd913cc74 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 23193bf1d75..77b4d5950d3 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 CDECL 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 CDECL 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 e092559d5c8..98ea582412d 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;