[v2 PATCH 2/3] d2d1: Added support for ID2D1GdiInteropRenderTarget interface

Nikolay Sivov nsivov at codeweavers.com
Sun Feb 12 13:14:58 CST 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/d2d1/bitmap_render_target.c |   4 +
 dlls/d2d1/d2d1_private.h         |   1 +
 dlls/d2d1/dc_render_target.c     |   4 +
 dlls/d2d1/hwnd_render_target.c   |   4 +
 dlls/d2d1/render_target.c        | 108 ++++++++++++++++++++++++++
 dlls/d2d1/tests/d2d1.c           | 160 +++++++++++++++++++++++++++++++++++++++
 dlls/d2d1/wic_render_target.c    |   4 +
 7 files changed, 285 insertions(+)

diff --git a/dlls/d2d1/bitmap_render_target.c b/dlls/d2d1/bitmap_render_target.c
index 67b0713376..3ac5c77d36 100644
--- a/dlls/d2d1/bitmap_render_target.c
+++ b/dlls/d2d1/bitmap_render_target.c
@@ -32,6 +32,8 @@ static inline struct d2d_bitmap_render_target *impl_from_ID2D1BitmapRenderTarget
 static HRESULT STDMETHODCALLTYPE d2d_bitmap_render_target_QueryInterface(ID2D1BitmapRenderTarget *iface,
         REFIID iid, void **out)
 {
+    struct d2d_bitmap_render_target *render_target = impl_from_ID2D1BitmapRenderTarget(iface);
+
     TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
 
     if (IsEqualGUID(iid, &IID_ID2D1BitmapRenderTarget)
@@ -43,6 +45,8 @@ static HRESULT STDMETHODCALLTYPE d2d_bitmap_render_target_QueryInterface(ID2D1Bi
         *out = iface;
         return S_OK;
     }
+    else if (IsEqualGUID(iid, &IID_ID2D1GdiInteropRenderTarget))
+        return ID2D1RenderTarget_QueryInterface(render_target->dxgi_target, iid, out);
 
     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
 
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h
index 336be96a07..e80b1b9384 100644
--- a/dlls/d2d1/d2d1_private.h
+++ b/dlls/d2d1/d2d1_private.h
@@ -69,6 +69,7 @@ struct d2d_shape_resources
 struct d2d_d3d_render_target
 {
     ID2D1RenderTarget ID2D1RenderTarget_iface;
+    ID2D1GdiInteropRenderTarget ID2D1GdiInteropRenderTarget_iface;
     IDWriteTextRenderer IDWriteTextRenderer_iface;
     LONG refcount;
 
diff --git a/dlls/d2d1/dc_render_target.c b/dlls/d2d1/dc_render_target.c
index 1cf2c8d381..04b8e71dc5 100644
--- a/dlls/d2d1/dc_render_target.c
+++ b/dlls/d2d1/dc_render_target.c
@@ -51,6 +51,8 @@ static inline struct d2d_dc_render_target *impl_from_ID2D1DCRenderTarget(ID2D1DC
 
 static HRESULT STDMETHODCALLTYPE d2d_dc_render_target_QueryInterface(ID2D1DCRenderTarget *iface, REFIID iid, void **out)
 {
+    struct d2d_dc_render_target *render_target = impl_from_ID2D1DCRenderTarget(iface);
+
     TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
 
     if (IsEqualGUID(iid, &IID_ID2D1DCRenderTarget)
@@ -62,6 +64,8 @@ static HRESULT STDMETHODCALLTYPE d2d_dc_render_target_QueryInterface(ID2D1DCRend
         *out = iface;
         return S_OK;
     }
+    else if (IsEqualGUID(iid, &IID_ID2D1GdiInteropRenderTarget))
+        return ID2D1RenderTarget_QueryInterface(render_target->dxgi_target, iid, out);
 
     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
 
diff --git a/dlls/d2d1/hwnd_render_target.c b/dlls/d2d1/hwnd_render_target.c
index 2ce7b713b5..027189693d 100644
--- a/dlls/d2d1/hwnd_render_target.c
+++ b/dlls/d2d1/hwnd_render_target.c
@@ -40,6 +40,8 @@ static inline struct d2d_hwnd_render_target *impl_from_ID2D1HwndRenderTarget(ID2
 static HRESULT STDMETHODCALLTYPE d2d_hwnd_render_target_QueryInterface(ID2D1HwndRenderTarget *iface,
         REFIID iid, void **out)
 {
+    struct d2d_hwnd_render_target *render_target = impl_from_ID2D1HwndRenderTarget(iface);
+
     TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
 
     if (IsEqualGUID(iid, &IID_ID2D1HwndRenderTarget)
@@ -51,6 +53,8 @@ static HRESULT STDMETHODCALLTYPE d2d_hwnd_render_target_QueryInterface(ID2D1Hwnd
         *out = iface;
         return S_OK;
     }
+    else if (IsEqualGUID(iid, &IID_ID2D1GdiInteropRenderTarget))
+        return ID2D1RenderTarget_QueryInterface(render_target->dxgi_target, iid, out);
 
     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
 
diff --git a/dlls/d2d1/render_target.c b/dlls/d2d1/render_target.c
index 0f372643af..e7297b3078 100644
--- a/dlls/d2d1/render_target.c
+++ b/dlls/d2d1/render_target.c
@@ -207,6 +207,8 @@ static inline struct d2d_d3d_render_target *impl_from_ID2D1RenderTarget(ID2D1Ren
 
 static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_QueryInterface(ID2D1RenderTarget *iface, REFIID iid, void **out)
 {
+    struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
+
     TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
 
     if (IsEqualGUID(iid, &IID_ID2D1RenderTarget)
@@ -217,6 +219,12 @@ static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_QueryInterface(ID2D1Rende
         *out = iface;
         return S_OK;
     }
+    else if (IsEqualGUID(iid, &IID_ID2D1GdiInteropRenderTarget))
+    {
+        ID2D1GdiInteropRenderTarget_AddRef(&render_target->ID2D1GdiInteropRenderTarget_iface);
+        *out = &render_target->ID2D1GdiInteropRenderTarget_iface;
+        return S_OK;
+    }
 
     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
 
@@ -1866,6 +1874,105 @@ static const struct IDWriteTextRendererVtbl d2d_text_renderer_vtbl =
     d2d_text_renderer_DrawInlineObject,
 };
 
+static inline struct d2d_d3d_render_target *impl_from_ID2D1GdiInteropRenderTarget(ID2D1GdiInteropRenderTarget *iface)
+{
+    return CONTAINING_RECORD(iface, struct d2d_d3d_render_target, ID2D1GdiInteropRenderTarget_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d2d_gdi_interop_render_target_QueryInterface(ID2D1GdiInteropRenderTarget *iface,
+        REFIID iid, void **out)
+{
+    struct d2d_d3d_render_target *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
+
+    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+    return d2d_d3d_render_target_QueryInterface(&render_target->ID2D1RenderTarget_iface, iid, out);
+}
+
+static ULONG STDMETHODCALLTYPE d2d_gdi_interop_render_target_AddRef(ID2D1GdiInteropRenderTarget *iface)
+{
+    struct d2d_d3d_render_target *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return d2d_d3d_render_target_AddRef(&render_target->ID2D1RenderTarget_iface);
+}
+
+static ULONG STDMETHODCALLTYPE d2d_gdi_interop_render_target_Release(ID2D1GdiInteropRenderTarget *iface)
+{
+    struct d2d_d3d_render_target *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return d2d_d3d_render_target_Release(&render_target->ID2D1RenderTarget_iface);
+}
+
+static HRESULT d2d_d3d_render_target_get_surface(struct d2d_d3d_render_target *render_target, IDXGISurface1 **surface)
+{
+    ID3D10Resource *resource;
+    HRESULT hr;
+
+    ID3D10RenderTargetView_GetResource(render_target->view, &resource);
+    hr = ID3D10Resource_QueryInterface(resource, &IID_IDXGISurface1, (void **)surface);
+    ID3D10Resource_Release(resource);
+    if (FAILED(hr))
+    {
+        *surface = NULL;
+        WARN("Failed to get DXGI surface, %#x.\n", hr);
+        return hr;
+    }
+
+    return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE d2d_gdi_interop_render_target_GetDC(ID2D1GdiInteropRenderTarget *iface,
+        D2D1_DC_INITIALIZE_MODE mode, HDC *dc)
+{
+    struct d2d_d3d_render_target *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
+    IDXGISurface1 *surface;
+    HRESULT hr;
+
+    TRACE("iface %p, mode %d, dc %p.\n", iface, mode, dc);
+
+    if (FAILED(hr = d2d_d3d_render_target_get_surface(render_target, &surface)))
+        return hr;
+
+    hr = IDXGISurface1_GetDC(surface, mode != D2D1_DC_INITIALIZE_MODE_COPY, dc);
+    IDXGISurface1_Release(surface);
+
+    return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE d2d_gdi_interop_render_target_ReleaseDC(ID2D1GdiInteropRenderTarget *iface,
+        const RECT *update)
+{
+    struct d2d_d3d_render_target *render_target = impl_from_ID2D1GdiInteropRenderTarget(iface);
+    IDXGISurface1 *surface;
+    RECT update_rect;
+    HRESULT hr;
+
+    TRACE("iface %p, update rect %s.\n", iface, wine_dbgstr_rect(update));
+
+    if (FAILED(hr = d2d_d3d_render_target_get_surface(render_target, &surface)))
+        return hr;
+
+    if (update)
+        update_rect = *update;
+    hr = IDXGISurface1_ReleaseDC(surface, update ? &update_rect : NULL);
+    IDXGISurface1_Release(surface);
+
+    return hr;
+}
+
+static const struct ID2D1GdiInteropRenderTargetVtbl d2d_gdi_interop_render_target_vtbl =
+{
+    d2d_gdi_interop_render_target_QueryInterface,
+    d2d_gdi_interop_render_target_AddRef,
+    d2d_gdi_interop_render_target_Release,
+    d2d_gdi_interop_render_target_GetDC,
+    d2d_gdi_interop_render_target_ReleaseDC,
+};
+
 HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target, ID2D1Factory *factory,
         IDXGISurface *surface, const D2D1_RENDER_TARGET_PROPERTIES *desc)
 {
@@ -2314,6 +2421,7 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
         WARN("Ignoring feature level %#x.\n", desc->minLevel);
 
     render_target->ID2D1RenderTarget_iface.lpVtbl = &d2d_d3d_render_target_vtbl;
+    render_target->ID2D1GdiInteropRenderTarget_iface.lpVtbl = &d2d_gdi_interop_render_target_vtbl;
     render_target->IDWriteTextRenderer_iface.lpVtbl = &d2d_text_renderer_vtbl;
     render_target->refcount = 1;
     render_target->factory = factory;
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index 7dccbd7d97..fa29122aa4 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -250,6 +250,33 @@ static BOOL compare_surface(IDXGISurface *surface, const char *ref_sha1)
     return ret;
 }
 
+static BOOL compare_wic_bitmap(IWICBitmap *bitmap, const char *ref_sha1)
+{
+    UINT stride, width, height, buffer_size;
+    IWICBitmapLock *lock;
+    BYTE *data;
+    HRESULT hr;
+    BOOL ret;
+
+    hr = IWICBitmap_Lock(bitmap, NULL, WICBitmapLockRead, &lock);
+    ok(SUCCEEDED(hr), "Failed to lock bitmap, hr %#x.\n", hr);
+
+    hr = IWICBitmapLock_GetDataPointer(lock, &buffer_size, &data);
+    ok(SUCCEEDED(hr), "Failed to get bitmap data, hr %#x.\n", hr);
+
+    hr = IWICBitmapLock_GetStride(lock, &stride);
+    ok(SUCCEEDED(hr), "Failed to get bitmap stride, hr %#x.\n", hr);
+
+    hr = IWICBitmapLock_GetSize(lock, &width, &height);
+    ok(SUCCEEDED(hr), "Failed to get bitmap size, hr %#x.\n", hr);
+
+    ret = compare_sha1(data, stride, 4, width, height, ref_sha1);
+
+    IWICBitmapLock_Release(lock);
+
+    return ret;
+}
+
 static void serialize_figure(struct figure *figure)
 {
     static const char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -2248,6 +2275,7 @@ static void test_shared_bitmap(void)
 {
     IDXGISwapChain *swapchain1, *swapchain2;
     IWICBitmap *wic_bitmap1, *wic_bitmap2;
+    ID2D1GdiInteropRenderTarget *interop;
     D2D1_RENDER_TARGET_PROPERTIES desc;
     D2D1_BITMAP_PROPERTIES bitmap_desc;
     IDXGISurface *surface1, *surface2;
@@ -2366,6 +2394,10 @@ static void test_shared_bitmap(void)
     hr = ID2D1RenderTarget_CreateBitmap(rt1, size, NULL, 0, &bitmap_desc, &bitmap1);
     ok(SUCCEEDED(hr), "Failed to create bitmap, hr %#x.\n", hr);
 
+    hr = ID2D1RenderTarget_QueryInterface(rt1, &IID_ID2D1GdiInteropRenderTarget, (void **)&interop);
+    ok(SUCCEEDED(hr), "Failed to get interop target, hr %#x.\n", hr);
+    ID2D1GdiInteropRenderTarget_Release(interop);
+
     hr = ID2D1Factory_CreateWicBitmapRenderTarget(factory2, wic_bitmap2, &desc, &rt2);
     ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr);
     hr = ID2D1RenderTarget_CreateSharedBitmap(rt2, &IID_ID2D1Bitmap, bitmap1, NULL, &bitmap2);
@@ -2764,6 +2796,7 @@ static void test_create_target(void)
 
     for (i = 0; i < sizeof(create_dpi_tests) / sizeof(*create_dpi_tests); ++i)
     {
+        ID2D1GdiInteropRenderTarget *interop;
         D2D1_RENDER_TARGET_PROPERTIES desc;
         float dpi_x, dpi_y;
 
@@ -2782,6 +2815,10 @@ static void test_create_target(void)
         if (FAILED(hr))
             continue;
 
+        hr = ID2D1RenderTarget_QueryInterface(rt, &IID_ID2D1GdiInteropRenderTarget, (void **)&interop);
+        ok(SUCCEEDED(hr), "Failed to get interop target, hr %#x.\n", hr);
+        ID2D1GdiInteropRenderTarget_Release(interop);
+
         ID2D1RenderTarget_GetDpi(rt, &dpi_x, &dpi_y);
         ok(dpi_x == create_dpi_tests[i].rt_dpi_x, "Wrong dpi_x %.8e, expected %.8e, test %u\n",
             dpi_x, create_dpi_tests[i].rt_dpi_x, i);
@@ -2946,6 +2983,7 @@ static void test_dc_target(void)
         { DXGI_FORMAT_R8G8B8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED },
     };
     D2D1_TEXT_ANTIALIAS_MODE text_aa_mode;
+    ID2D1GdiInteropRenderTarget *interop;
     D2D1_RENDER_TARGET_PROPERTIES desc;
     D2D1_MATRIX_3X2_F matrix, matrix2;
     D2D1_ANTIALIAS_MODE aa_mode;
@@ -2998,6 +3036,10 @@ static void test_dc_target(void)
     hr = ID2D1Factory_CreateDCRenderTarget(factory, &desc, &rt);
     ok(SUCCEEDED(hr), "Failed to create target, hr %#x.\n", hr);
 
+    hr = ID2D1DCRenderTarget_QueryInterface(rt, &IID_ID2D1GdiInteropRenderTarget, (void **)&interop);
+    ok(SUCCEEDED(hr), "Failed to get interop target, hr %#x.\n", hr);
+    ID2D1GdiInteropRenderTarget_Release(interop);
+
     size = ID2D1DCRenderTarget_GetSize(rt);
     ok(size.width == 0.0f, "got width %.08e.\n", size.width);
     ok(size.height == 0.0f, "got height %.08e.\n", size.height);
@@ -3125,6 +3167,7 @@ static void test_dc_target(void)
 static void test_hwnd_target(void)
 {
     D2D1_HWND_RENDER_TARGET_PROPERTIES hwnd_rt_desc;
+    ID2D1GdiInteropRenderTarget *interop;
     D2D1_RENDER_TARGET_PROPERTIES desc;
     ID2D1HwndRenderTarget *rt;
     ID2D1Factory *factory;
@@ -3167,6 +3210,10 @@ static void test_hwnd_target(void)
     hr = ID2D1Factory_CreateHwndRenderTarget(factory, &desc, &hwnd_rt_desc, &rt);
     ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr);
 
+    hr = ID2D1HwndRenderTarget_QueryInterface(rt, &IID_ID2D1GdiInteropRenderTarget, (void **)&interop);
+    ok(SUCCEEDED(hr), "Failed to get interop target, hr %#x.\n", hr);
+    ID2D1GdiInteropRenderTarget_Release(interop);
+
     size.width = 128;
     size.height = 64;
     hr = ID2D1HwndRenderTarget_Resize(rt, &size);
@@ -3181,6 +3228,7 @@ static void test_hwnd_target(void)
 static void test_bitmap_target(void)
 {
     D2D1_HWND_RENDER_TARGET_PROPERTIES hwnd_rt_desc;
+    ID2D1GdiInteropRenderTarget *interop;
     D2D1_SIZE_U pixel_size, pixel_size2;
     D2D1_RENDER_TARGET_PROPERTIES desc;
     ID2D1HwndRenderTarget *hwnd_rt;
@@ -3226,6 +3274,10 @@ static void test_bitmap_target(void)
             D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, &rt);
     ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr);
 
+    hr = ID2D1BitmapRenderTarget_QueryInterface(rt, &IID_ID2D1GdiInteropRenderTarget, (void **)&interop);
+    ok(SUCCEEDED(hr), "Failed to get interop target, hr %#x.\n", hr);
+    ID2D1GdiInteropRenderTarget_Release(interop);
+
     /* See if parent target is referenced. */
     ID2D1HwndRenderTarget_AddRef(hwnd_rt);
     refcount = ID2D1HwndRenderTarget_Release(hwnd_rt);
@@ -3871,6 +3923,113 @@ static void test_draw_geometry(void)
     DestroyWindow(window);
 }
 
+static void test_gdi_interop(void)
+{
+    ID2D1GdiInteropRenderTarget *interop;
+    D2D1_RENDER_TARGET_PROPERTIES desc;
+    IWICImagingFactory *wic_factory;
+    IWICBitmap *wic_bitmap;
+    ID2D1Factory *factory;
+    ID3D10Device1 *device;
+    ID2D1RenderTarget *rt;
+    D2D1_COLOR_F color;
+    HRESULT hr;
+    BOOL match;
+    RECT rect;
+    HDC dc;
+
+    if (!(device = create_device()))
+    {
+        skip("Failed to create device, skipping tests.\n");
+        return;
+    }
+
+    hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &IID_ID2D1Factory, NULL, (void **)&factory);
+    ok(SUCCEEDED(hr), "Failed to create factory, hr %#x.\n", hr);
+
+    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+    hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
+            &IID_IWICImagingFactory, (void **)&wic_factory);
+    ok(SUCCEEDED(hr), "Failed to create WIC imaging factory, hr %#x.\n", hr);
+    hr = IWICImagingFactory_CreateBitmap(wic_factory, 16, 16,
+            &GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnDemand, &wic_bitmap);
+    ok(SUCCEEDED(hr), "Failed to create bitmap, hr %#x.\n", hr);
+    IWICImagingFactory_Release(wic_factory);
+
+    /* WIC target, default usage */
+    desc.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
+    desc.pixelFormat.format = DXGI_FORMAT_UNKNOWN;
+    desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
+    desc.dpiX = 0.0f;
+    desc.dpiY = 0.0f;
+    desc.usage = D2D1_RENDER_TARGET_USAGE_NONE;
+    desc.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
+
+    hr = ID2D1Factory_CreateWicBitmapRenderTarget(factory, wic_bitmap, &desc, &rt);
+    ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr);
+
+    hr = ID2D1RenderTarget_QueryInterface(rt, &IID_ID2D1GdiInteropRenderTarget, (void **)&interop);
+    ok(SUCCEEDED(hr), "Failed to get gdi interop interface, hr %#x.\n", hr);
+
+    ID2D1RenderTarget_BeginDraw(rt);
+    dc = (void *)0xdeadbeef;
+    hr = ID2D1GdiInteropRenderTarget_GetDC(interop, D2D1_DC_INITIALIZE_MODE_COPY, &dc);
+    ok(FAILED(hr), "GetDC() was expected to fail, hr %#x.\n", hr);
+todo_wine
+    ok(dc == NULL, "Expected NULL dc, got %p.\n", dc);
+    ID2D1GdiInteropRenderTarget_Release(interop);
+    ID2D1RenderTarget_EndDraw(rt, NULL, NULL);
+
+    ID2D1RenderTarget_Release(rt);
+
+    /* WIC target, gdi compatible */
+    desc.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
+
+    hr = ID2D1Factory_CreateWicBitmapRenderTarget(factory, wic_bitmap, &desc, &rt);
+    ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr);
+
+    hr = ID2D1RenderTarget_QueryInterface(rt, &IID_ID2D1GdiInteropRenderTarget, (void **)&interop);
+    ok(SUCCEEDED(hr), "Failed to get gdi interop interface, hr %#x.\n", hr);
+
+    ID2D1RenderTarget_BeginDraw(rt);
+    dc = NULL;
+    hr = ID2D1GdiInteropRenderTarget_GetDC(interop, D2D1_DC_INITIALIZE_MODE_COPY, &dc);
+    ok(SUCCEEDED(hr), "GetDC() was expected to succeed, hr %#x.\n", hr);
+    ok(dc != NULL, "Expected NULL dc, got %p.\n", dc);
+    ID2D1GdiInteropRenderTarget_ReleaseDC(interop, NULL);
+    ID2D1RenderTarget_EndDraw(rt, NULL, NULL);
+
+    /* Test if ReleaseDC() flushes automatically */
+    ID2D1RenderTarget_BeginDraw(rt);
+    set_color(&color, 1.0f, 0.0f, 0.0f, 1.0f);
+    ID2D1RenderTarget_Clear(rt, &color);
+    ID2D1RenderTarget_EndDraw(rt, NULL, NULL);
+
+    match = compare_wic_bitmap(wic_bitmap, "54034063dbc1c1bb61cb60ec57e4498678dc2b13");
+    ok(match, "Bitmap does not match.\n");
+
+    /* Do solid fill using GDI */
+    ID2D1RenderTarget_BeginDraw(rt);
+
+    hr = ID2D1GdiInteropRenderTarget_GetDC(interop, D2D1_DC_INITIALIZE_MODE_COPY, &dc);
+    ok(SUCCEEDED(hr), "GetDC() was expected to succeed, hr %#x.\n", hr);
+
+    SetRect(&rect, 0, 0, 16, 16);
+    FillRect(dc, &rect, GetStockObject(BLACK_BRUSH));
+    ID2D1GdiInteropRenderTarget_ReleaseDC(interop, NULL);
+
+    ID2D1RenderTarget_EndDraw(rt, NULL, NULL);
+
+    match = compare_wic_bitmap(wic_bitmap, "60cacbf3d72e1e7834203da608037b1bf83b40e8");
+    ok(match, "Bitmap does not match.\n");
+
+    ID2D1GdiInteropRenderTarget_Release(interop);
+    ID2D1RenderTarget_Release(rt);
+
+    IWICBitmap_Release(wic_bitmap);
+    ID2D1Factory_Release(factory);
+}
+
 START_TEST(d2d1)
 {
     test_clip();
@@ -3894,4 +4053,5 @@ START_TEST(d2d1)
     test_stroke_style();
     test_gradient();
     test_draw_geometry();
+    test_gdi_interop();
 }
diff --git a/dlls/d2d1/wic_render_target.c b/dlls/d2d1/wic_render_target.c
index 57f5d61941..70032abdf3 100644
--- a/dlls/d2d1/wic_render_target.c
+++ b/dlls/d2d1/wic_render_target.c
@@ -100,6 +100,8 @@ static inline struct d2d_wic_render_target *impl_from_ID2D1RenderTarget(ID2D1Ren
 
 static HRESULT STDMETHODCALLTYPE d2d_wic_render_target_QueryInterface(ID2D1RenderTarget *iface, REFIID iid, void **out)
 {
+    struct d2d_wic_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
+
     TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
 
     if (IsEqualGUID(iid, &IID_ID2D1RenderTarget)
@@ -110,6 +112,8 @@ static HRESULT STDMETHODCALLTYPE d2d_wic_render_target_QueryInterface(ID2D1Rende
         *out = iface;
         return S_OK;
     }
+    else if (IsEqualGUID(iid, &IID_ID2D1GdiInteropRenderTarget))
+        return ID2D1RenderTarget_QueryInterface(render_target->dxgi_target, iid, out);
 
     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
 
-- 
2.11.0




More information about the wine-patches mailing list