diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c index 93862a3772d..b3bb7c60a43 100644 --- a/dlls/dplayx/dplay.c +++ b/dlls/dplayx/dplay.c @@ -355,6 +355,13 @@ static BOOL DP_DestroyDirectPlay2( LPVOID lpDP ) return TRUE; } +static void dplay_destroy(IDirectPlayImpl *obj) +{ + DP_DestroyDirectPlay2( obj ); + obj->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection( &obj->lock ); + HeapFree( GetProcessHeap(), 0, obj ); +} /* Direct Play methods */ @@ -381,36 +388,6 @@ static HRESULT WINAPI DP_QueryInterface( IDirectPlayImpl *This, REFIID riid, voi return S_OK; } -/* Shared between all dplay types */ -static ULONG WINAPI DP_AddRef( IDirectPlayImpl *This ) -{ - ULONG ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef ); - - TRACE( "ref count incremented to %u for %p\n", ulInterfaceRefCount, This ); - - return ulInterfaceRefCount; -} - -static ULONG WINAPI DP_Release( IDirectPlayImpl *This ) -{ - ULONG ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef ); - - TRACE( "ref count decremented to %u for %p\n", ulInterfaceRefCount, This ); - - /* Deallocate if this is the last reference to the object */ - if( ulInterfaceRefCount == 0 ) - { - /* If we're destroying the object, this must be the last ref - of the last interface */ - DP_DestroyDirectPlay2( This ); - This->lock.DebugInfo->Spare[0] = 0; - DeleteCriticalSection( &This->lock ); - HeapFree( GetProcessHeap(), 0, This ); - } - - return ulInterfaceRefCount; -} - static inline DPID DP_NextObjectId(void) { return (DPID)InterlockedIncrement( &kludgePlayerGroupId ); @@ -610,25 +587,53 @@ static HRESULT WINAPI IDirectPlay4Impl_QueryInterface( IDirectPlay4 *iface, REFI static ULONG WINAPI IDirectPlay4AImpl_AddRef(IDirectPlay4A *iface) { IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface ); - return DP_AddRef( This ); + ULONG ref = InterlockedIncrement( &This->ref4A ); + + TRACE( "(%p) ref4A=%d\n", This, ref ); + + if ( ref == 1 ) + InterlockedIncrement( &This->numIfaces ); + + return ref; } static ULONG WINAPI IDirectPlay4Impl_AddRef(IDirectPlay4 *iface) { IDirectPlayImpl *This = impl_from_IDirectPlay4( iface ); - return DP_AddRef( This ); + ULONG ref = InterlockedIncrement( &This->ref4 ); + + TRACE( "(%p) ref4=%d\n", This, ref ); + + if ( ref == 1 ) + InterlockedIncrement( &This->numIfaces ); + + return ref; } static ULONG WINAPI IDirectPlay4AImpl_Release(IDirectPlay4A *iface) { IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface ); - return DP_Release( This ); + ULONG ref = InterlockedDecrement( &This->ref4A ); + + TRACE( "(%p) ref4A=%d\n", This, ref ); + + if ( !ref && !InterlockedDecrement( &This->numIfaces ) ) + dplay_destroy( This ); + + return ref; } static ULONG WINAPI IDirectPlay4Impl_Release(IDirectPlay4 *iface) { IDirectPlayImpl *This = impl_from_IDirectPlay4( iface ); - return DP_Release( This ); + ULONG ref = InterlockedDecrement( &This->ref4 ); + + TRACE( "(%p) ref4=%d\n", This, ref ); + + if ( !ref && !InterlockedDecrement( &This->numIfaces ) ) + dplay_destroy( This ); + + return ref; } static HRESULT WINAPI IDirectPlay4AImpl_AddPlayerToGroup( IDirectPlay4A *iface, DPID idGroup, @@ -4700,7 +4705,9 @@ HRESULT dplay_create( REFIID riid, void **ppv ) obj->IDirectPlay4A_iface.lpVtbl = &dp4A_vt; obj->IDirectPlay4_iface.lpVtbl = &dp4_vt; - obj->ulInterfaceRef = 1; + obj->numIfaces = 1; + obj->ref4A = 1; + obj->ref4 = 0; InitializeCriticalSection( &obj->lock ); obj->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayImpl.lock"); diff --git a/dlls/dplayx/dplay_global.h b/dlls/dplayx/dplay_global.h index 4684f5386b5..18eb8077210 100644 --- a/dlls/dplayx/dplay_global.h +++ b/dlls/dplayx/dplay_global.h @@ -184,7 +184,8 @@ typedef struct IDirectPlayImpl { IDirectPlay4A IDirectPlay4A_iface; IDirectPlay4 IDirectPlay4_iface; - LONG ulInterfaceRef; + LONG numIfaces; /* "in use interfaces" refcount */ + LONG ref4A, ref4; CRITICAL_SECTION lock; DirectPlay2Data *dp2; } IDirectPlayImpl; diff --git a/dlls/dplayx/tests/dplayx.c b/dlls/dplayx/tests/dplayx.c index b7bbac3bb65..840015d5a2f 100644 --- a/dlls/dplayx/tests/dplayx.c +++ b/dlls/dplayx/tests/dplayx.c @@ -6399,7 +6399,7 @@ static void test_COM(void) hr = IDirectPlayX_QueryInterface(dp4, &IID_IDirectPlay2A, (void**)&dp2A); ok(hr == S_OK, "QueryInterface for IID_IDirectPlay2A failed: %08x\n", hr); refcount = IDirectPlay2_AddRef(dp2A); - todo_wine ok(refcount == 2, "refcount == %u, expected 2\n", refcount); + ok(refcount == 2, "refcount == %u, expected 2\n", refcount); IDirectPlay2_Release(dp2A); hr = IDirectPlayX_QueryInterface(dp4, &IID_IDirectPlay2, (void**)&dp2);