ddraw: Split up the ddraw refcount.

This commit is contained in:
Stefan Dösinger 2006-07-10 16:06:33 +02:00 committed by Alexandre Julliard
parent d690094807
commit 0a81295782
7 changed files with 529 additions and 114 deletions

View File

@ -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 */
}
/* 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
{
for(prev = ddraw_list; prev; prev = prev->next)
if(prev->next == This) break;
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

View File

@ -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;

View File

@ -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;
}

View File

@ -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));
}
/*****************************************************************************

View File

@ -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)));
}
}
}

View File

@ -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;
}

View File

@ -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();
}