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