From 0a81295782bc6e48bfccb2b8ae23ae66982d87f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefandoesinger@gmx.at>
Date: Mon, 10 Jul 2006 16:06:33 +0200
Subject: [PATCH] ddraw: Split up the ddraw refcount.

---
 dlls/ddraw/ddraw.c          | 115 ++++++++++-------
 dlls/ddraw/ddraw_private.h  |   5 +-
 dlls/ddraw/ddraw_thunks.c   | 160 ++++++++++++++++++-----
 dlls/ddraw/direct3d.c       |  60 ++++++---
 dlls/ddraw/main.c           |  27 ++--
 dlls/ddraw/surface.c        |  28 +++-
 dlls/ddraw/tests/refcount.c | 248 +++++++++++++++++++++++++++++++++++-
 7 files changed, 529 insertions(+), 114 deletions(-)

diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index f6be8bce744..cec78214a37 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -131,7 +131,13 @@ IDirectDrawImpl_QueryInterface(IDirectDraw7 *iface,
         TRACE("(%p) Returning IDirectDraw interface at %p\n", This, *obj);
     }
 
-    /* Direct3D */
+    /* Direct3D
+     * The refcount unit test revealed that an IDirect3D7 interface can only be queried
+     * from a DirectDraw object that was created as an IDirectDraw7 interface. No idea
+     * who had this idea and why. The older interfaces can query and IDirect3D version
+     * because they are all created as IDirectDraw(1). This isn't really crucial behavior,
+     * and messy to implement with the common creation function, so it has been left out here.
+     */
     else if ( IsEqualGUID( &IID_IDirect3D  , refiid ) ||
               IsEqualGUID( &IID_IDirect3D2 , refiid ) ||
               IsEqualGUID( &IID_IDirect3D3 , refiid ) ||
@@ -197,17 +203,30 @@ IDirectDrawImpl_QueryInterface(IDirectDraw7 *iface,
 /*****************************************************************************
  * IDirectDraw7::AddRef
  *
- * Increases the interfaces refcount. Used for version 1, 2, 4 and 7
+ * Increases the interfaces refcount, basically
+ *
+ * DDraw refcounting is a bit tricky. The different DirectDraw interface
+ * versions have individual refcounts, but the IDirect3D interfaces do not.
+ * All interfaces are from one object, that means calling QueryInterface on an
+ * IDirectDraw7 interface for an IDirectDraw4 interface does not create a new
+ * IDirectDrawImpl object.
+ *
+ * That means all AddRef and Release implementations of IDirectDrawX work
+ * with their own counter, and IDirect3DX::AddRef thunk to IDirectDraw (1),
+ * except of IDirect3D7 which thunks to IDirectDraw7
  *
  * Returns: The new refcount
+ *
  *****************************************************************************/
 static ULONG WINAPI
 IDirectDrawImpl_AddRef(IDirectDraw7 *iface)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
+    ULONG ref = InterlockedIncrement(&This->ref7);
 
-    TRACE("(%p) : incrementing from %lu.\n", This, ref -1);
+    TRACE("(%p) : incrementing IDirectDraw7 refcount from %lu.\n", This, ref -1);
+
+    if(ref == 1) InterlockedIncrement(&This->numIfaces);
 
     return ref;
 }
@@ -215,8 +234,8 @@ IDirectDrawImpl_AddRef(IDirectDraw7 *iface)
 /*****************************************************************************
  * IDirectDrawImpl_Destroy
  *
- * Destroys a ddraw object. This is to share code between normal Release
- * and the dll unload cleanup code
+ * Destroys a ddraw object if all refcounts are 0. This is to share code
+ * between the IDirectDrawX::Release functions
  *
  * Params:
  *  This: DirectDraw object to destroy
@@ -225,45 +244,49 @@ IDirectDrawImpl_AddRef(IDirectDraw7 *iface)
 void
 IDirectDrawImpl_Destroy(IDirectDrawImpl *This)
 {
-        IDirectDrawImpl *prev;
+    IDirectDrawImpl *prev;
 
-        TRACE("(%p)\n", This);
+    /* Clear the cooplevel to restore window and display mode */
+    IDirectDraw7_SetCooperativeLevel(ICOM_INTERFACE(This, IDirectDraw7),
+                                        NULL,
+                                        DDSCL_NORMAL);
 
-        /* Destroy the device window if we created one */
-        if(This->devicewindow != 0)
-        {
-            TRACE(" (%p) Destroying the device window %p\n", This, This->devicewindow);
-            DestroyWindow(This->devicewindow);
-            This->devicewindow = 0;
-        }
+    /* Destroy the device window if we created one */
+    if(This->devicewindow != 0)
+    {
+        TRACE(" (%p) Destroying the device window %p\n", This, This->devicewindow);
+        DestroyWindow(This->devicewindow);
+        This->devicewindow = 0;
+    }
 
-        /* Unregister the window class */
-        UnregisterClassA(This->classname, 0);
+    /* Unregister the window class */
+    UnregisterClassA(This->classname, 0);
 
-        /* Unchain it from the ddraw list */
-        if(ddraw_list == This)
-        {
-            ddraw_list = This->next;
-            /* No need to search for a predecessor here */
-        }
-        else
-        {
-            for(prev = ddraw_list; prev; prev = prev->next)
-                if(prev->next == This) break;
+    /* Unchain it from the ddraw list */
+    if(ddraw_list == This)
+    {
+        ddraw_list = This->next;
+        /* No need to search for a predecessor here */
+    }
+    else
+    {
+        for(prev = ddraw_list; prev; prev = prev->next)
+            if(prev->next == This) break;
 
-            if(prev)
-                prev->next = This->next;
-            else
-                ERR("Didn't find the previous ddraw element in the list\n");
-        }
+        if(prev)
+            prev->next = This->next;
+        else
+            ERR("Didn't find the previous ddraw element in the list\n");
+    }
 
-        /* Release the attached WineD3D stuff */
-        IWineD3DDevice_Release(This->wineD3DDevice);
-        IWineD3D_Release(This->wineD3D);
+    /* Release the attached WineD3D stuff */
+    IWineD3DDevice_Release(This->wineD3DDevice);
+    IWineD3D_Release(This->wineD3D);
 
-        /* Now free the object */
-        HeapFree(GetProcessHeap(), 0, This);
+    /* Now free the object */
+    HeapFree(GetProcessHeap(), 0, This);
 }
+
 /*****************************************************************************
  * IDirectDraw7::Release
  *
@@ -275,21 +298,14 @@ static ULONG WINAPI
 IDirectDrawImpl_Release(IDirectDraw7 *iface)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    ULONG ref = InterlockedDecrement(&This->ref7);
 
-    TRACE("(%p)->() decrementing from %lu.\n", This, ref +1);
+    TRACE("(%p)->() decrementing IDirectDraw7 refcount from %lu.\n", This, ref +1);
 
-    if (ref == 0)
+    if(ref == 0)
     {
-        /* No need to restore the display mode - it's done by SetCooperativeLevel */
-
-        IDirectDraw7_SetCooperativeLevel(ICOM_INTERFACE(This, IDirectDraw7),
-                                         NULL,
-                                         DDSCL_NORMAL);
-
-        /* This is for the dll cleanup code in DllMain() */
-        if(!This->DoNotDestroy)
-            IDirectDrawImpl_Destroy(This);
+        ULONG ifacecount = InterlockedDecrement(&This->numIfaces);
+        if(ifacecount == 0) IDirectDrawImpl_Destroy(This);
     }
 
     return ref;
@@ -2337,6 +2353,7 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
 
     /* Addref the ddraw interface to keep an reference for each surface */
     IDirectDraw7_AddRef(iface);
+    object->ifaceToRelease = (IUnknown *) iface;
 
     /* If the implementation is OpenGL and there's no d3ddevice, attach a d3ddevice
      * But attach the d3ddevice only if the currently created surface was
diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h
index fc571ed8afa..74bed0e4b75 100644
--- a/dlls/ddraw/ddraw_private.h
+++ b/dlls/ddraw/ddraw_private.h
@@ -90,7 +90,8 @@ struct IDirectDrawImpl
     ICOM_VFIELD_MULTI(IDirect3D2);
     ICOM_VFIELD_MULTI(IDirect3D);
 
-    LONG              ref;
+    /* See comment in IDirectDraw::AddRef */
+    LONG                    ref7, ref4, ref2, ref1, numIfaces;
 
     /* WineD3D linkage */
     IWineD3D                *wineD3D;
@@ -143,7 +144,6 @@ struct IDirectDrawImpl
 
     /* For the dll unload cleanup code */
     IDirectDrawImpl *next;
-    BOOL DoNotDestroy;
     LONG surfaces;
 };
 
@@ -202,6 +202,7 @@ struct IDirectDrawSurfaceImpl
     ICOM_VFIELD_MULTI(IDirect3DTexture);
 
     LONG                     ref;
+    IUnknown                *ifaceToRelease;
 
     int                     version;
 
diff --git a/dlls/ddraw/ddraw_thunks.c b/dlls/ddraw/ddraw_thunks.c
index 883411310dd..7ccc65d79f7 100644
--- a/dlls/ddraw/ddraw_thunks.c
+++ b/dlls/ddraw/ddraw_thunks.c
@@ -17,15 +17,32 @@
  */
 
 #include "config.h"
+#include "wine/port.h"
 
+#include <assert.h>
 #include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
 
 #include "windef.h"
 #include "winbase.h"
+#include "winnls.h"
+#include "winerror.h"
 #include "wingdi.h"
+#include "wine/exception.h"
+#include "excpt.h"
+
 #include "ddraw.h"
+#include "d3d.h"
+
 #include "ddraw_private.h"
-#include "ddcomimpl.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ddraw_thunk);
+WINE_DECLARE_DEBUG_CHANNEL(ddraw);
 
 static HRESULT WINAPI
 IDirectDrawImpl_QueryInterface(LPDIRECTDRAW This, REFIID iid, LPVOID *ppObj)
@@ -56,51 +73,93 @@ IDirectDraw4Impl_QueryInterface(LPDIRECTDRAW4 This, REFIID iid, LPVOID *ppObj)
 }
 
 static ULONG WINAPI
-IDirectDrawImpl_AddRef(LPDIRECTDRAW This)
+IDirectDrawImpl_AddRef(LPDIRECTDRAW iface)
 {
-    return IDirectDraw7_AddRef(COM_INTERFACE_CAST(IDirectDrawImpl,
-						  IDirectDraw, IDirectDraw7,
-						  This));
+    ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw, iface);
+    ULONG ref = InterlockedIncrement(&This->ref1);
+
+    TRACE("(%p) : incrementing IDirectDraw refcount from %lu.\n", This, ref -1);
+
+    if(ref == 1) InterlockedIncrement(&This->numIfaces);
+
+    return ref;
 }
 
 static ULONG WINAPI
-IDirectDraw2Impl_AddRef(LPDIRECTDRAW2 This)
+IDirectDraw2Impl_AddRef(LPDIRECTDRAW2 iface)
 {
-    return IDirectDraw7_AddRef(COM_INTERFACE_CAST(IDirectDrawImpl,
-						  IDirectDraw2, IDirectDraw7,
-						  This));
+    ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw2, iface);
+    ULONG ref = InterlockedIncrement(&This->ref2);
+
+    TRACE("(%p) : incrementing IDirectDraw2 refcount from %lu.\n", This, ref -1);
+
+    if(ref == 1) InterlockedIncrement(&This->numIfaces);
+
+    return ref;
 }
 
 static ULONG WINAPI
-IDirectDraw4Impl_AddRef(LPDIRECTDRAW4 This)
+IDirectDraw4Impl_AddRef(LPDIRECTDRAW4 iface)
 {
-    return IDirectDraw7_AddRef(COM_INTERFACE_CAST(IDirectDrawImpl,
-						  IDirectDraw4, IDirectDraw7,
-						  This));
+    ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw4, iface);
+    ULONG ref = InterlockedIncrement(&This->ref4);
+
+    TRACE("(%p) : incrementing IDirectDraw4 refcount from %lu.\n", This, ref -1);
+
+    if(ref == 1) InterlockedIncrement(&This->numIfaces);
+
+    return ref;
 }
 
 static ULONG WINAPI
-IDirectDrawImpl_Release(LPDIRECTDRAW This)
+IDirectDrawImpl_Release(LPDIRECTDRAW iface)
 {
-    return IDirectDraw7_Release(COM_INTERFACE_CAST(IDirectDrawImpl,
-						   IDirectDraw, IDirectDraw7,
-						   This));
+    ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw, iface);
+    ULONG ref = InterlockedDecrement(&This->ref1);
+
+    TRACE_(ddraw)("(%p)->() decrementing IDirectDraw refcount from %lu.\n", This, ref +1);
+
+    if(ref == 0)
+    {
+        ULONG ifacecount = InterlockedDecrement(&This->numIfaces);
+        if(ifacecount == 0) IDirectDrawImpl_Destroy(This);
+    }
+
+    return ref;
 }
 
 static ULONG WINAPI
-IDirectDraw2Impl_Release(LPDIRECTDRAW2 This)
+IDirectDraw2Impl_Release(LPDIRECTDRAW2 iface)
 {
-    return IDirectDraw7_Release(COM_INTERFACE_CAST(IDirectDrawImpl,
-						   IDirectDraw2, IDirectDraw7,
-						   This));
+    ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw2, iface);
+    ULONG ref = InterlockedDecrement(&This->ref2);
+
+    TRACE_(ddraw)("(%p)->() decrementing IDirectDraw2 refcount from %lu.\n", This, ref +1);
+
+    if(ref == 0)
+    {
+        ULONG ifacecount = InterlockedDecrement(&This->numIfaces);
+        if(ifacecount == 0) IDirectDrawImpl_Destroy(This);
+    }
+
+    return ref;
 }
 
 static ULONG WINAPI
-IDirectDraw4Impl_Release(LPDIRECTDRAW4 This)
+IDirectDraw4Impl_Release(LPDIRECTDRAW4 iface)
 {
-    return IDirectDraw7_Release(COM_INTERFACE_CAST(IDirectDrawImpl,
-						   IDirectDraw4, IDirectDraw7,
-						   This));
+    ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw4, iface);
+    ULONG ref = InterlockedDecrement(&This->ref4);
+
+    TRACE_(ddraw)("(%p)->() decrementing IDirectDraw4 refcount from %lu.\n", This, ref +1);
+
+    if(ref == 0)
+    {
+        ULONG ifacecount = InterlockedDecrement(&This->numIfaces);
+        if(ifacecount == 0) IDirectDrawImpl_Destroy(This);
+    }
+
+    return ref;
 }
 
 static HRESULT WINAPI
@@ -169,11 +228,20 @@ IDirectDrawImpl_CreatePalette(LPDIRECTDRAW This, DWORD dwFlags,
 			      LPDIRECTDRAWPALETTE *ppPalette,
 			      IUnknown *pUnkOuter)
 {
-    return IDirectDraw7_CreatePalette(COM_INTERFACE_CAST(IDirectDrawImpl,
+    HRESULT hr;
+    hr = IDirectDraw7_CreatePalette(COM_INTERFACE_CAST(IDirectDrawImpl,
 							 IDirectDraw,
 							 IDirectDraw7,
 							 This),
 				      dwFlags, pEntries, ppPalette, pUnkOuter);
+    if(SUCCEEDED(hr) && *ppPalette)
+    {
+        IDirectDraw7_Release(COM_INTERFACE_CAST(IDirectDrawImpl,
+                             IDirectDraw,
+                             IDirectDraw7,
+                             This));
+    }
+    return hr;
 }
 
 static HRESULT WINAPI
@@ -182,11 +250,19 @@ IDirectDraw2Impl_CreatePalette(LPDIRECTDRAW2 This, DWORD dwFlags,
 			       LPDIRECTDRAWPALETTE *ppPalette,
 			       IUnknown *pUnkOuter)
 {
+    HRESULT hr;
     return IDirectDraw7_CreatePalette(COM_INTERFACE_CAST(IDirectDrawImpl,
 							 IDirectDraw2,
 							 IDirectDraw7,
 							 This),
 				      dwFlags, pEntries, ppPalette, pUnkOuter);
+    if(SUCCEEDED(hr) && *ppPalette)
+    {
+        IDirectDraw7_Release(COM_INTERFACE_CAST(IDirectDrawImpl,
+                             IDirectDraw,
+                             IDirectDraw7,
+                             This));
+    }
 }
 
 static HRESULT WINAPI
@@ -195,11 +271,19 @@ IDirectDraw4Impl_CreatePalette(LPDIRECTDRAW4 This, DWORD dwFlags,
 			       LPDIRECTDRAWPALETTE *ppPalette,
 			       IUnknown *pUnkOuter)
 {
+    HRESULT hr;
     return IDirectDraw7_CreatePalette(COM_INTERFACE_CAST(IDirectDrawImpl,
 							 IDirectDraw4,
 							 IDirectDraw7,
 							 This),
 				      dwFlags, pEntries, ppPalette, pUnkOuter);
+    if(SUCCEEDED(hr) && *ppPalette)
+    {
+        IDirectDraw7_Release(COM_INTERFACE_CAST(IDirectDrawImpl,
+                             IDirectDraw,
+                             IDirectDraw7,
+                             This));
+    }
 }
 
 static HRESULT WINAPI
@@ -226,9 +310,15 @@ IDirectDrawImpl_CreateSurface(LPDIRECTDRAW This, LPDDSURFACEDESC pSDesc,
 				    pSurface7);
 
     impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, pSurface7);
-    if(impl)
+    if(SUCCEEDED(hr) && impl)
     {
         impl->version = 1;
+        IDirectDraw7_Release(COM_INTERFACE_CAST(IDirectDrawImpl,
+                             IDirectDraw,
+                             IDirectDraw7,
+                             This));
+        IDirectDraw_AddRef(This);
+        impl->ifaceToRelease = (IUnknown *) This;
     }
 
     return hr;
@@ -256,9 +346,15 @@ IDirectDraw2Impl_CreateSurface(LPDIRECTDRAW2 This, LPDDSURFACEDESC pSDesc,
 				    pSurface7);
 
     impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, pSurface7);
-    if(impl)
+    if(SUCCEEDED(hr) && impl)
     {
         impl->version = 2;
+        IDirectDraw7_Release(COM_INTERFACE_CAST(IDirectDrawImpl,
+                             IDirectDraw2,
+                             IDirectDraw7,
+                             This));
+        IDirectDraw2_AddRef(This);
+        impl->ifaceToRelease = (IUnknown *) This;
     }
 
     return hr;
@@ -280,9 +376,15 @@ IDirectDraw4Impl_CreateSurface(LPDIRECTDRAW4 This, LPDDSURFACEDESC2 pSDesc,
 				    (LPDIRECTDRAWSURFACE7 *)ppSurface,
 				    pUnkOuter);
     impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurface);
-    if(impl)
+    if(SUCCEEDED(hr) && impl)
     {
         impl->version = 4;
+        IDirectDraw7_Release(COM_INTERFACE_CAST(IDirectDrawImpl,
+                             IDirectDraw4,
+                             IDirectDraw7,
+                             This));
+        IDirectDraw4_AddRef(This);
+        impl->ifaceToRelease = (IUnknown *) This;
     }
     return hr;
 }
diff --git a/dlls/ddraw/direct3d.c b/dlls/ddraw/direct3d.c
index 679dd2fb8db..6e8c61036d5 100644
--- a/dlls/ddraw/direct3d.c
+++ b/dlls/ddraw/direct3d.c
@@ -43,10 +43,9 @@
 WINE_DEFAULT_DEBUG_CHANNEL(d3d7);
 
 /*****************************************************************************
- * IUnknown Methods. Common for Version 1, 2, 3 and 7
+ * IDirect3D7::QueryInterface
  *
- * These are thunks which relay to IDirectDraw. See ddraw.c for
- * details
+ * QueryInterface implementation with thunks to IDirectDraw7
  *
  *****************************************************************************/
 static HRESULT WINAPI
@@ -101,11 +100,30 @@ Thunk_IDirect3DImpl_1_QueryInterface(IDirect3D *iface,
                                        obj);
 }
 
+/*****************************************************************************
+ * IDirect3D7::AddRef
+ *
+ * DirectDraw refcounting is a bit odd. Every version of the ddraw interface
+ * has its own refcount, but IDirect3D 1/2/3 refcounts are linked to
+ * IDirectDraw, and IDirect3D7 is linked to IDirectDraw7
+ *
+ * IDirect3D7 -> IDirectDraw7
+ * IDirect3D3 -> IDirectDraw
+ * IDirect3D2 -> IDirectDraw
+ * IDirect3D  -> IDirectDraw
+ *
+ * So every AddRef implementation thunks to a different interface, and the
+ * IDirectDrawX::AddRef implementations have different counters...
+ *
+ * Returns
+ *  The new refcount
+ *
+ *****************************************************************************/
 static ULONG WINAPI
 Thunk_IDirect3DImpl_7_AddRef(IDirect3D7 *iface)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
-    TRACE("(%p) : Thunking to IDirectDraw7\n", This);
+    TRACE("(%p) : Thunking to IDirectDraw7.\n", This);
 
     return IDirectDraw7_AddRef(ICOM_INTERFACE(This, IDirectDraw7));
 }
@@ -114,34 +132,42 @@ static ULONG WINAPI
 Thunk_IDirect3DImpl_3_AddRef(IDirect3D3 *iface)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
-    TRACE("(%p) : Thunking to IDirectDraw7\n", This);
+    TRACE("(%p) : Thunking to IDirectDraw.\n", This);
 
-    return IDirectDraw7_AddRef(ICOM_INTERFACE(This, IDirectDraw7));
+    return IDirectDraw_AddRef(ICOM_INTERFACE(This, IDirectDraw));
 }
 
 static ULONG WINAPI
 Thunk_IDirect3DImpl_2_AddRef(IDirect3D2 *iface)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
-    TRACE("(%p) : Thunking to IDirectDraw7\n", This);
+    TRACE("(%p) : Thunking to IDirectDraw.\n", This);
 
-    return IDirectDraw7_AddRef(ICOM_INTERFACE(This, IDirectDraw7));
+    return IDirectDraw_AddRef(ICOM_INTERFACE(This, IDirectDraw));
 }
 
 static ULONG WINAPI
 Thunk_IDirect3DImpl_1_AddRef(IDirect3D *iface)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
-    TRACE("(%p) : Thunking to IDirectDraw7\n", This);
+    TRACE("(%p) : Thunking to IDirectDraw.\n", This);
 
-    return IDirectDraw7_AddRef(ICOM_INTERFACE(This, IDirectDraw7));
+    return IDirectDraw_AddRef(ICOM_INTERFACE(This, IDirectDraw));
 }
 
+/*****************************************************************************
+ * IDirect3D7::Release
+ *
+ * Same story as IDirect3D7::AddRef
+ *
+ * Returns: The new refcount
+ *
+ *****************************************************************************/
 static ULONG WINAPI
 Thunk_IDirect3DImpl_7_Release(IDirect3D7 *iface)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
-    TRACE("(%p) : Thunking to IDirectDraw7", This);
+    TRACE("(%p) : Thunking to IDirectDraw7.\n", This);
 
     return IDirectDraw7_Release(ICOM_INTERFACE(This, IDirectDraw7));
 }
@@ -150,27 +176,27 @@ static ULONG WINAPI
 Thunk_IDirect3DImpl_3_Release(IDirect3D3 *iface)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
-    TRACE("(%p) : Thunking to IDirectDraw7", This);
+    TRACE("(%p) : Thunking to IDirectDraw.\n", This);
 
-    return IDirectDraw7_Release(ICOM_INTERFACE(This, IDirectDraw7));
+    return IDirectDraw_Release(ICOM_INTERFACE(This, IDirectDraw));
 }
 
 static ULONG WINAPI
 Thunk_IDirect3DImpl_2_Release(IDirect3D2 *iface)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
-    TRACE("(%p) : Thunking to IDirectDraw7", This);
+    TRACE("(%p) : Thunking to IDirectDraw.\n", This);
 
-    return IDirectDraw7_Release(ICOM_INTERFACE(This, IDirectDraw7));
+    return IDirectDraw_Release(ICOM_INTERFACE(This, IDirectDraw));
 }
 
 static ULONG WINAPI
 Thunk_IDirect3DImpl_1_Release(IDirect3D *iface)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
-    TRACE("(%p) : Thunking to IDirectDraw7", This);
+    TRACE("(%p) : Thunking to IDirectDraw.\n", This);
 
-    return IDirectDraw7_Release(ICOM_INTERFACE(This, IDirectDraw7));
+    return IDirectDraw_Release(ICOM_INTERFACE(This, IDirectDraw));
 }
 
 /*****************************************************************************
diff --git a/dlls/ddraw/main.c b/dlls/ddraw/main.c
index ca1ff82ac35..a9bec78841e 100644
--- a/dlls/ddraw/main.c
+++ b/dlls/ddraw/main.c
@@ -135,7 +135,6 @@ DDRAW_Create(GUID *guid,
     ICOM_INIT_INTERFACE(This, IDirect3D2, IDirect3D2_Vtbl);
     ICOM_INIT_INTERFACE(This, IDirect3D3, IDirect3D3_Vtbl);
     ICOM_INIT_INTERFACE(This, IDirect3D7, IDirect3D7_Vtbl);
-    This->ref = 1;
 
     /* See comments in IDirectDrawImpl_CreateNewSurface for a description
      * of this member.
@@ -285,9 +284,10 @@ DDRAW_Create(GUID *guid,
     This->next = ddraw_list;
     ddraw_list = This;
 
-    /* Call QueryInterface to get the pointer to the requested interface */
+    /* Call QueryInterface to get the pointer to the requested interface. This also initializes
+     * The required refcount
+     */
     hr = IDirectDraw7_QueryInterface( ICOM_INTERFACE(This, IDirectDraw7), iid, DD);
-    IDirectDraw7_Release( ICOM_INTERFACE(This, IDirectDraw7) );
     if(SUCCEEDED(hr)) return DD_OK;
 
 err_out:
@@ -843,9 +843,13 @@ DllMain(HINSTANCE hInstDLL,
                     DDSURFACEDESC2 desc;
                     int i;
 
-                    WARN("DDraw %p has a refcount of %ld\n", ddraw, ddraw->ref);
+                    WARN("DDraw %p has a refcount of %ld\n", ddraw, ddraw->ref7 + ddraw->ref4 + ddraw->ref2 + ddraw->ref1);
 
-                    ddraw->DoNotDestroy = TRUE; /* Avoid to destroy the object too early */
+                    /* Add references to each interface to avoid freeing them unexpectadely */
+                    IDirectDraw_AddRef(ICOM_INTERFACE(ddraw, IDirectDraw));
+                    IDirectDraw2_AddRef(ICOM_INTERFACE(ddraw, IDirectDraw2));
+                    IDirectDraw4_AddRef(ICOM_INTERFACE(ddraw, IDirectDraw4));
+                    IDirectDraw7_AddRef(ICOM_INTERFACE(ddraw, IDirectDraw7));
 
                     /* Does a D3D device exist? Destroy it
                      * TODO: Destroy all Vertex buffers, Lights, Materials
@@ -877,12 +881,13 @@ DllMain(HINSTANCE hInstDLL,
                     if(ddraw->surfaces > 0)
                         ERR("DDraw %p still has %ld surfaces attached\n", ddraw, ddraw->surfaces);
 
-                    /* Restore the cooperative level */
-                    IDirectDraw7_SetCooperativeLevel(ICOM_INTERFACE(ddraw, IDirectDraw7),
-                                                      NULL,
-                                                      DDSCL_NORMAL);
-                    ddraw->DoNotDestroy = FALSE;
-                    IDirectDrawImpl_Destroy(ddraw);
+                    /* Release all hanging references to destroy the objects. This
+                     * restores the screen mode too
+                     */
+                    while(IDirectDraw_Release(ICOM_INTERFACE(ddraw, IDirectDraw)));
+                    while(IDirectDraw2_Release(ICOM_INTERFACE(ddraw, IDirectDraw2)));
+                    while(IDirectDraw4_Release(ICOM_INTERFACE(ddraw, IDirectDraw4)));
+                    while(IDirectDraw7_Release(ICOM_INTERFACE(ddraw, IDirectDraw7)));
                 }
             }
         }
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index 72e0eddf082..a9086d2f4fc 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -291,6 +291,7 @@ IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
 
         IDirectDrawSurfaceImpl *surf;
         IDirectDrawImpl *ddraw;
+        IUnknown *ifaceToRelease = This->ifaceToRelease;
 
         /* Destroy all complex attached surfaces
          * Therefore, start with the first surface,
@@ -385,7 +386,7 @@ IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
         IDirectDrawSurfaceImpl_Destroy(This);
 
         /* Reduce the ddraw refcount */
-        IDirectDraw7_Release(ICOM_INTERFACE(ddraw, IDirectDraw7));
+        IUnknown_Release(ifaceToRelease);
     }
 
     return ref;
@@ -1627,13 +1628,32 @@ IDirectDrawSurfaceImpl_GetDDInterface(IDirectDrawSurface7 *iface,
 {
     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
 
-    TRACE("(%p)->(%p)\n",This,DD);
+    /* It is not quite correct to use the same lpVtable for the different
+     * IDirectDrawSurface versions because the GetDDInterface return different interfaces
+     */
+    FIXME("(%p)->(%p)\n",This,DD);
 
     if(!DD)
         return DDERR_INVALIDPARAMS;
 
-    *((IDirectDraw7 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw7);
-    IDirectDraw7_AddRef( (IDirectDraw7 *) *DD);
+    switch(This->version)
+    {
+        case 7:
+            *((IDirectDraw7 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw7);
+            IDirectDraw7_AddRef(*(IDirectDraw7 **) DD);
+            break;
+
+        case 4:
+            *((IDirectDraw4 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw4);
+            IDirectDraw4_AddRef(*(IDirectDraw4 **) DD);
+
+        case 2:
+        case 1:
+            *((IDirectDraw **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw);
+            IDirectDraw_AddRef( *(IDirectDraw **) DD);
+            break;
+
+    }
 
     return DD_OK;
 }
diff --git a/dlls/ddraw/tests/refcount.c b/dlls/ddraw/tests/refcount.c
index bcdc535e9ab..6e27665b974 100644
--- a/dlls/ddraw/tests/refcount.c
+++ b/dlls/ddraw/tests/refcount.c
@@ -43,7 +43,7 @@ unsigned long getRefcount(IUnknown *iface)
     return IUnknown_Release(iface);
 }
 
-static void test_ddraw(void)
+static void test_ddraw_objects(void)
 {
     HRESULT hr;
     unsigned long ref;
@@ -135,6 +135,248 @@ static void test_ddraw(void)
     IDirectDraw7_Release(DDraw);
 }
 
+static void test_iface_refcnt(void)
+{
+    HRESULT hr;
+    IDirectDraw  *DDraw1;
+    IDirectDraw2 *DDraw2;
+    IDirectDraw4 *DDraw4;
+    IDirectDraw7 *DDraw7;
+    IDirect3D7   *D3D7;
+    IDirect3D3   *D3D3;
+    IDirect3D2   *D3D2;
+    IDirect3D    *D3D1;
+    long ref;
+
+    hr = pDirectDrawCreateEx(NULL, (void **) &DDraw7, &IID_IDirectDraw7, NULL);
+    ok(hr == DD_OK || hr==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreateEx returned: %lx\n", hr);
+    if(!DDraw7)
+    {
+        trace("Couldn't create DDraw interface, skipping tests\n");
+        return;
+    }
+
+    ref = getRefcount( (IUnknown *) DDraw7);
+    ok(ref == 1, "Initial IDirectDraw7 reference count is %ld\n", ref);
+
+    hr = IDirectDraw7_QueryInterface(DDraw7, &IID_IDirectDraw4, (void **) &DDraw4);
+    ok(hr == DD_OK, "IDirectDraw7_QueryInterface returned %08lx\n", hr);
+    hr = IDirectDraw7_QueryInterface(DDraw7, &IID_IDirectDraw2, (void **) &DDraw2);
+    ok(hr == DD_OK, "IDirectDraw7_QueryInterf&ace returned %08lx\n", hr);
+    hr = IDirectDraw7_QueryInterface(DDraw7, &IID_IDirectDraw, (void **) &DDraw1);
+    ok(hr == DD_OK, "IDirectDraw7_QueryInterface returned %08lx\n", hr);
+
+    /* All interfaces now have refcount 1! */
+    ref = getRefcount( (IUnknown *) DDraw7);
+    ok(ref == 1, "IDirectDraw7 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw7);
+    ok(ref == 1, "IDirectDraw7 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw4);
+    ok(ref == 1, "IDirectDraw4 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw2);
+    ok(ref == 1, "IDirectDraw2 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw1);
+    ok(ref == 1, "IDirectDraw reference count is %ld\n", ref);
+
+    hr = IDirectDraw7_QueryInterface(DDraw7, &IID_IDirect3D7, (void **) &D3D7);
+    ok(hr == DD_OK, "IDirectDraw7_QueryInterface returned %08lx\n", hr);
+
+    /* Apparently IDirectDrawX and IDirect3DX are linked together */
+    ref = getRefcount( (IUnknown *) D3D7);
+    ok(ref == 2, "IDirect3D7 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw7);
+    ok(ref == 2, "IDirectDraw7 reference count is %ld\n", ref);
+
+    IDirectDraw7_AddRef(DDraw7);
+    ref = getRefcount( (IUnknown *) D3D7);
+    ok(ref == 3, "IDirect3D7 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw7);
+    ok(ref == 3, "IDirectDraw7 reference count is %ld\n", ref);
+
+    IDirect3D7_Release(D3D7);
+    ref = getRefcount( (IUnknown *) D3D7);
+    ok(ref == 2, "IDirect3D7 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw7);
+    ok(ref == 2, "IDirectDraw7 reference count is %ld\n", ref);
+
+    /* Can't get older d3d interfaces. WHY????? */
+    hr = IDirectDraw7_QueryInterface(DDraw4, &IID_IDirect3D3, (void **) &D3D3);
+    todo_wine ok(hr == E_NOINTERFACE, "IDirectDraw7_QueryInterface returned %08lx\n", hr);
+    if(hr == DD_OK && D3D3) IDirect3D3_Release(D3D3);
+
+    hr = IDirectDraw4_QueryInterface(DDraw4, &IID_IDirect3D3, (void **) &D3D3);
+    todo_wine ok(hr == E_NOINTERFACE, "IDirectDraw4_QueryInterface returned %08lx\n", hr);
+    if(hr == DD_OK && D3D3) IDirect3D3_Release(D3D3);
+
+    hr = IDirectDraw7_QueryInterface(DDraw7, &IID_IDirect3D2, (void **) &D3D2);
+    todo_wine ok(hr == E_NOINTERFACE, "IDirectDraw7_QueryInterface returned %08lx\n", hr);
+    if(hr == DD_OK && D3D2) IDirect3D2_Release(D3D2);
+
+    hr = IDirectDraw2_QueryInterface(DDraw2, &IID_IDirect3D2, (void **) &D3D2);
+    todo_wine ok(hr == E_NOINTERFACE, "IDirectDraw2_QueryInterface returned %08lx\n", hr);
+    if(hr == DD_OK && D3D2) IDirect3D2_Release(D3D2);
+
+    hr = IDirectDraw7_QueryInterface(DDraw7, &IID_IDirect3D, (void **) &D3D1);
+    todo_wine ok(hr == E_NOINTERFACE, "IDirectDraw7_QueryInterface returned %08lx\n", hr);
+    if(hr == DD_OK && D3D1) IDirect3D_Release(D3D1);
+
+    hr = IDirectDraw_QueryInterface(DDraw1, &IID_IDirect3D, (void **) &D3D1);
+    todo_wine ok(hr == E_NOINTERFACE, "IDirectDraw_QueryInterface returned %08lx\n", hr);
+    if(hr == DD_OK && D3D1) IDirect3D_Release(D3D1);
+
+    hr = IDirect3D7_QueryInterface(D3D7, &IID_IDirect3D, (void **) &D3D1);
+    todo_wine ok(hr == E_NOINTERFACE, "IDirect3D7_QueryInterface returned %08lx\n", hr);
+    if(hr == DD_OK && D3D1) IDirect3D_Release(D3D1);
+
+    /* Try an AddRef, it only affects the AddRefed interface */
+    IDirectDraw4_AddRef(DDraw4);
+    ref = getRefcount( (IUnknown *) DDraw7);
+    ok(ref == 2, "IDirectDraw7 reference count is %ld\n", ref); /* <-- From the d3d query */
+    ref = getRefcount( (IUnknown *) DDraw4);
+    ok(ref == 2, "IDirectDraw4 reference count is %ld\n", ref); /* <-- The AddRef call */
+    ref = getRefcount( (IUnknown *) DDraw2);
+    ok(ref == 1, "IDirectDraw2 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw1);
+    ok(ref == 1, "IDirectDraw reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) D3D7);
+    ok(ref == 2, "IDirect3D7 reference count is %ld\n", ref); /* <-- From the d3d query */
+    IDirectDraw4_Release(DDraw4);
+
+    /* Make sure that they are one object, not different ones */
+    hr = IDirectDraw4_SetCooperativeLevel(DDraw4, GetDesktopWindow(), DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+    ok(hr == DD_OK, "IDirectDraw4::SetCooperativeLevel returned %08lx\n", hr);
+    /* After an window has been set, DDSCL_SETFOCUSWINDOW should return DDERR_HWNDALREADYSET, see the mode test */
+    hr = IDirectDraw7_SetCooperativeLevel(DDraw7, NULL, DDSCL_SETFOCUSWINDOW);
+    ok(hr == DDERR_HWNDALREADYSET, "IDirectDraw7::SetCooperativeLevel returned %08lx\n", hr);
+
+    /* All done, release all interfaces */
+    IDirectDraw7_Release(DDraw7);
+    IDirectDraw4_Release(DDraw4);
+    IDirectDraw2_Release(DDraw2);
+    IDirectDraw_Release(DDraw1);
+    IDirect3D7_Release(D3D7);
+}
+
+static void test_d3d_ifaces(void)
+{
+    IDirectDraw *DDraw1;
+    IDirectDraw2 *DDraw2;
+    IDirectDraw4 *DDraw4;
+    IDirect3D *D3D1;
+    IDirect3D2 *D3D2;
+    IDirect3D3 *D3D3;
+    IDirect3D7 *D3D7;
+    HRESULT hr;
+    long ref;
+
+    hr = DirectDrawCreate(NULL, &DDraw1, NULL);
+    ok(hr == DD_OK, "DirectDrawCreate returned %08lx\n", hr);
+    if(!DDraw1)
+    {
+        trace("DirectDrawCreate failed with %08lx\n", hr);
+        return;
+    }
+
+    hr = IDirectDraw_QueryInterface(DDraw1, &IID_IDirectDraw2, (void **) &DDraw2);
+    ok(hr == DD_OK, "IDirectDraw_QueryInterface returned %08lx\n", hr);
+    hr = IDirectDraw_QueryInterface(DDraw1, &IID_IDirectDraw4, (void **) &DDraw4);
+    ok(hr == DD_OK, "IDirectDraw_QueryInterface returned %08lx\n", hr);
+
+    ref = getRefcount( (IUnknown *) DDraw4);
+    ok(ref == 1, "IDirectDraw4 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw2);
+    ok(ref == 1, "IDirectDraw2 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw1);
+    ok(ref == 1, "IDirectDraw reference count is %ld\n", ref);
+
+    hr = IDirectDraw_QueryInterface(DDraw1, &IID_IDirect3D, (void **) &D3D1);
+    ok(hr == DD_OK, "IDirectDraw_QueryInterface returned %08lx\n", hr);
+    ref = getRefcount( (IUnknown *) DDraw4);
+    ok(ref == 1, "IDirectDraw4 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw2);
+    ok(ref == 1, "IDirectDraw2 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw1);
+    ok(ref == 2, "IDirectDraw reference count is %ld\n", ref);
+    IDirect3D_Release(D3D1);
+
+    hr = IDirectDraw2_QueryInterface(DDraw2, &IID_IDirect3D2, (void **) &D3D2);
+    ok(hr == DD_OK, "IDirectDraw_QueryInterface returned %08lx\n", hr);
+    ref = getRefcount( (IUnknown *) DDraw4);
+    ok(ref == 1, "IDirectDraw4 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw2);
+    ok(ref == 1, "IDirectDraw2 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw1);
+    ok(ref == 2, "IDirectDraw reference count is %ld\n", ref);
+    IDirect3D2_Release(D3D2);
+
+    hr = IDirectDraw4_QueryInterface(DDraw4, &IID_IDirect3D3, (void **) &D3D3);
+    ok(hr == DD_OK, "IDirectDraw_QueryInterface returned %08lx\n", hr);
+    ref = getRefcount( (IUnknown *) DDraw4);
+    ok(ref == 1, "IDirectDraw4 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw2);
+    ok(ref == 1, "IDirectDraw2 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw1);
+    ok(ref == 2, "IDirectDraw reference count is %ld\n", ref);
+    IDirect3D3_Release(D3D3);
+
+    /* Try to AddRef the D3D3 interface that has been released already */
+    IDirect3D3_AddRef(D3D3);
+    ref = getRefcount( (IUnknown *) DDraw1);
+    ok(ref == 2, "IDirectDraw reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) D3D3);
+    ok(ref == 2, "IDirect3D3 reference count is %ld\n", ref);
+    /* The newer interfaces remain untouched */
+    ref = getRefcount( (IUnknown *) DDraw4);
+    ok(ref == 1, "IDirectDraw4 reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw2);
+    ok(ref == 1, "IDirectDraw2 reference count is %ld\n", ref);
+    IDirect3D3_Release(D3D3);
+    ref = getRefcount( (IUnknown *) DDraw1);
+    ok(ref == 1, "IDirectDraw reference count is %ld\n", ref);
+    ref = getRefcount( (IUnknown *) DDraw1);
+    ok(ref == 1, "IDirectDraw reference count is %ld\n", ref);
+
+    /* It is possible to query any IDirect3D interfaces from any IDirectDraw interface,
+     * Except IDirect3D7, it can only be returned by IDirectDraw7(which can't return older ifaces)
+     */
+    hr = IDirectDraw_QueryInterface(DDraw2, &IID_IDirect3D, (void **) &D3D1);
+    ok(hr == DD_OK, "IDirectDraw2_QueryInterface returned %08lx\n", hr);
+    IDirect3D_Release(D3D1);
+    hr = IDirectDraw4_QueryInterface(DDraw4, &IID_IDirect3D, (void **) &D3D1);
+    ok(hr == DD_OK, "IDirectDraw4_QueryInterface returned %08lx\n", hr);
+    IDirect3D_Release(D3D1);
+
+    hr = IDirectDraw_QueryInterface(DDraw1, &IID_IDirect3D2, (void **) &D3D2);
+    ok(hr == DD_OK, "IDirectDraw_QueryInterface returned %08lx\n", hr);
+    IDirect3D_Release(D3D2);
+    hr = IDirectDraw4_QueryInterface(DDraw4, &IID_IDirect3D2, (void **) &D3D2);
+    ok(hr == DD_OK, "IDirectDraw4_QueryInterface returned %08lx\n", hr);
+    IDirect3D_Release(D3D2);
+
+    hr = IDirectDraw_QueryInterface(DDraw1, &IID_IDirect3D3, (void **) &D3D3);
+    ok(hr == DD_OK, "IDirectDraw_QueryInterface returned %08lx\n", hr);
+    IDirect3D_Release(D3D3);
+    hr = IDirectDraw2_QueryInterface(DDraw2, &IID_IDirect3D3, (void **) &D3D3);
+    ok(hr == DD_OK, "IDirectDraw2_QueryInterface returned %08lx\n", hr);
+    IDirect3D_Release(D3D3);
+
+    /* This does NOT work */
+    hr = IDirectDraw_QueryInterface(DDraw1, &IID_IDirect3D7, (void **) &D3D7);
+    todo_wine ok(hr == E_NOINTERFACE, "IDirectDraw_QueryInterface returned %08lx\n", hr);
+    if(D3D7) IDirect3D_Release(D3D7);
+    hr = IDirectDraw2_QueryInterface(DDraw2, &IID_IDirect3D7, (void **) &D3D7);
+    todo_wine ok(hr == E_NOINTERFACE, "IDirectDraw2_QueryInterface returned %08lx\n", hr);
+    if(D3D7) IDirect3D_Release(D3D7);
+    hr = IDirectDraw4_QueryInterface(DDraw4, &IID_IDirect3D7, (void **) &D3D7);
+    todo_wine ok(hr == E_NOINTERFACE, "IDirectDraw4_QueryInterface returned %08lx\n", hr);
+    if(D3D7) IDirect3D_Release(D3D7);
+
+    /* Release the interfaces */
+    IDirectDraw4_Release(DDraw4);
+    IDirectDraw2_Release(DDraw2);
+    IDirectDraw_Release(DDraw1);
+}
+
 START_TEST(refcount)
 {
     init_function_pointers();
@@ -143,5 +385,7 @@ START_TEST(refcount)
         trace("function DirectDrawCreateEx not available, skipping tests\n");
         return;
     }
-    test_ddraw();
+    test_ddraw_objects();
+    test_iface_refcnt();
+    test_d3d_ifaces();
 }
-- 
GitLab