Stefan Dösinger : ddrawex: Implement a GetDC special behavior Internet Explorer depends on.

Alexandre Julliard julliard at winehq.org
Fri Jan 9 09:52:40 CST 2009


Module: wine
Branch: master
Commit: da6c9e4cc2a85a5b46f1c9234acf17a0f2dd8874
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=da6c9e4cc2a85a5b46f1c9234acf17a0f2dd8874

Author: Stefan Dösinger <stefan at codeweavers.com>
Date:   Thu Dec 18 16:13:06 2008 +0100

ddrawex: Implement a GetDC special behavior Internet Explorer depends on.

Tests show that in ddrawex.dll it is legal to create a surface with
both DDSCAPS_VIDEOMEMORY and DDSCAPS_SYSTEMMEMORY flag set. A surface
created that way shows different behavior in IDirectDrawSurface::GetDC.

---

 dlls/ddrawex/ddraw.c           |   19 ++++++++++++++
 dlls/ddrawex/ddrawex_private.h |    4 +++
 dlls/ddrawex/surface.c         |   55 +++++++++++++++++++++++++++++++++++++---
 dlls/ddrawex/tests/surface.c   |    2 +-
 4 files changed, 75 insertions(+), 5 deletions(-)

diff --git a/dlls/ddrawex/ddraw.c b/dlls/ddrawex/ddraw.c
index 9645a3d..9e8066a 100644
--- a/dlls/ddrawex/ddraw.c
+++ b/dlls/ddrawex/ddraw.c
@@ -387,6 +387,8 @@ IDirectDraw4Impl_CreateSurface(IDirectDraw4 *iface,
 {
     IDirectDrawImpl *This = impl_from_dd4(iface);
     HRESULT hr;
+    const DWORD perm_dc_flags = DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
+    BOOL permanent_dc;
     TRACE("(%p)(%p, %p, %p)\n", This, DDSD, Surf, UnkOuter);
 
     if(UnkOuter != NULL)
@@ -395,8 +397,25 @@ IDirectDraw4Impl_CreateSurface(IDirectDraw4 *iface,
         FIXME("Implement aggregation for ddrawex surfaces\n");
     }
 
+    /* plain ddraw.dll refuses to create a surface that has both VIDMEM and SYSMEM flags
+     * set. In ddrawex this succeeds, and the GetDC() call changes the behavior. The DC
+     * is permanently valid, and the surface can be locked between GetDC() and ReleaseDC()
+     * calls. GetDC() can be called more than once too
+     */
+    if((DDSD->ddsCaps.dwCaps & perm_dc_flags) == perm_dc_flags)
+    {
+        permanent_dc = TRUE;
+        DDSD->ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
+        DDSD->ddsCaps.dwCaps |= DDSCAPS_OWNDC;
+    }
+    else
+    {
+        permanent_dc = FALSE;
+    }
+
     hr = IDirectDraw4_CreateSurface(This->parent, DDSD, Surf, UnkOuter);
     *Surf = dds_get_outer(*Surf);
+    if(permanent_dc) prepare_permanent_dc(*Surf);
     return hr;
 }
 
diff --git a/dlls/ddrawex/ddrawex_private.h b/dlls/ddrawex/ddrawex_private.h
index 12d76d5..3e7a0e2 100644
--- a/dlls/ddrawex/ddrawex_private.h
+++ b/dlls/ddrawex/ddrawex_private.h
@@ -100,6 +100,9 @@ typedef struct
     /* The interface we're forwarding to */
     IDirectDrawSurface4 *parent;
 
+    BOOL permanent_dc;
+    HDC hdc;
+
     /* An UUID we use to store the outer surface as private data in the inner surface */
 #define IID_DDrawexPriv IID_IDirectDrawSurface4
 
@@ -107,5 +110,6 @@ typedef struct
 
 IDirectDrawSurface4 *dds_get_outer(IDirectDrawSurface4 *inner);
 IDirectDrawSurface4 *dds_get_inner(IDirectDrawSurface4 *outer);
+HRESULT prepare_permanent_dc(IDirectDrawSurface4 *iface);
 
 #endif /* __WINE_DLLS_DDRAWEX_DDRAWEX_PRIVATE_H */
diff --git a/dlls/ddrawex/surface.c b/dlls/ddrawex/surface.c
index 9b16ce5..106b027 100644
--- a/dlls/ddrawex/surface.c
+++ b/dlls/ddrawex/surface.c
@@ -563,7 +563,16 @@ IDirectDrawSurface4Impl_GetDC(IDirectDrawSurface4 *iface,
 {
     IDirectDrawSurfaceImpl *This = impl_from_dds4(iface);
     TRACE("(%p)->(%p)\n", This, hdc);
-    return IDirectDrawSurface4_GetDC(This->parent, hdc);
+    if(This->permanent_dc)
+    {
+        TRACE("Returning stored dc %p\n", This->hdc);
+        *hdc = This->hdc;
+        return DD_OK;
+    }
+    else
+    {
+        return IDirectDrawSurface4_GetDC(This->parent, hdc);
+    }
 }
 
 static HRESULT WINAPI
@@ -654,8 +663,17 @@ IDirectDrawSurface4Impl_GetSurfaceDesc(IDirectDrawSurface4 *iface,
                                        DDSURFACEDESC2 *DDSD)
 {
     IDirectDrawSurfaceImpl *This = impl_from_dds4(iface);
+    HRESULT hr;
     TRACE("(%p)->(%p)\n", This, DDSD);
-    return IDirectDrawSurface4_GetSurfaceDesc(This->parent, DDSD);
+    hr = IDirectDrawSurface4_GetSurfaceDesc(This->parent, DDSD);
+
+    if(SUCCEEDED(hr) && This->permanent_dc)
+    {
+        DDSD->ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+        DDSD->ddsCaps.dwCaps &= ~DDSCAPS_OWNDC;
+    }
+
+    return hr;
 }
 
 static HRESULT WINAPI
@@ -731,8 +749,17 @@ IDirectDrawSurface4Impl_Lock(IDirectDrawSurface4 *iface,
                              HANDLE h)
 {
     IDirectDrawSurfaceImpl *This = impl_from_dds4(iface);
+    HRESULT hr;
     TRACE("(%p)->(%p,%p,0x%08x,%p)\n", This, Rect, DDSD, Flags, h);
-    return IDirectDrawSurface4_Lock(This->parent, Rect, DDSD, Flags, h);
+    hr = IDirectDrawSurface4_Lock(This->parent, Rect, DDSD, Flags, h);
+
+    if(SUCCEEDED(hr) && This->permanent_dc)
+    {
+        DDSD->ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+        DDSD->ddsCaps.dwCaps &= ~DDSCAPS_OWNDC;
+    }
+
+    return hr;
 }
 
 static HRESULT WINAPI
@@ -759,7 +786,15 @@ IDirectDrawSurface4Impl_ReleaseDC(IDirectDrawSurface4 *iface,
 {
     IDirectDrawSurfaceImpl *This = impl_from_dds4(iface);
     TRACE("(%p)->(%p)\n", This, hdc);
-    return IDirectDrawSurface4_ReleaseDC(This->parent, hdc);
+    if(This->permanent_dc)
+    {
+        TRACE("Surface has a permanent DC, not doing anything\n");
+        return DD_OK;
+    }
+    else
+    {
+        return IDirectDrawSurface4_ReleaseDC(This->parent, hdc);
+    }
 }
 
 static HRESULT WINAPI
@@ -1259,3 +1294,15 @@ IDirectDrawSurface4 *dds_get_inner(IDirectDrawSurface4 *outer)
     if(This == NULL) return NULL;
     return This->parent;
 }
+
+HRESULT prepare_permanent_dc(IDirectDrawSurface4 *iface)
+{
+    IDirectDrawSurfaceImpl *This = impl_from_dds4(iface);
+    HRESULT hr;
+    This->permanent_dc = TRUE;
+
+    hr = IDirectDrawSurface4_GetDC(This->parent, &This->hdc);
+    if(FAILED(hr)) return hr;
+    hr = IDirectDrawSurface4_ReleaseDC(This->parent, This->hdc);
+    return hr;
+}
diff --git a/dlls/ddrawex/tests/surface.c b/dlls/ddrawex/tests/surface.c
index b2065bc..c8d519b 100644
--- a/dlls/ddrawex/tests/surface.c
+++ b/dlls/ddrawex/tests/surface.c
@@ -161,7 +161,7 @@ static void CapsTest(void)
     ddsd.dwWidth = 64;
     ddsd.dwHeight = 64;
     hr = IDirectDraw_CreateSurface(dd1, &ddsd, &surf, NULL);
-    todo_wine ok(hr == DD_OK, "Creating a SYSMEM | VIDMEM surface returned 0x%08x, expected DD_OK\n", hr);
+    ok(hr == DD_OK, "Creating a SYSMEM | VIDMEM surface returned 0x%08x, expected DD_OK\n", hr);
     if(surf) IDirectDrawSurface_Release(surf);
 
     IDirectDraw_Release(dd1);




More information about the wine-cvs mailing list