You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
650 lines
17 KiB
650 lines
17 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: classfac.c
|
|
* Content: direct draw class factory code
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 24-dec-95 craige initial implementation
|
|
* 05-jan-96 kylej added interface structures
|
|
* 14-mar-96 colinmc added a class factory for clippers
|
|
* 22-mar-96 colinmc Bug 13316: uninitialized interfaces
|
|
* 22-oct-97 jeffno Merge class factories, add classfac for CLSID_DirectDrawFactory2
|
|
*
|
|
***************************************************************************/
|
|
#include "ddrawpr.h"
|
|
|
|
static IClassFactoryVtbl directDrawClassFactoryVtbl;
|
|
|
|
typedef struct DDRAWCLASSFACTORY
|
|
{
|
|
IClassFactoryVtbl *lpVtbl;
|
|
DWORD dwRefCnt;
|
|
CLSID TargetCLSID;
|
|
} DDRAWCLASSFACTORY, *LPDDRAWCLASSFACTORY;
|
|
|
|
#define VALIDEX_DIRECTDRAWCF_PTR( ptr ) \
|
|
( !IsBadWritePtr( ptr, sizeof( DDRAWCLASSFACTORY )) && \
|
|
(ptr->lpVtbl == &directDrawClassFactoryVtbl) )
|
|
|
|
/************************************************************
|
|
*
|
|
* DirectDraw Driver Class Factory Member Functions.
|
|
*
|
|
************************************************************/
|
|
|
|
#define DPF_MODNAME "DirectDrawClassFactory::QueryInterface"
|
|
|
|
/*
|
|
* DirectDrawClassFactory_QueryInterface
|
|
*/
|
|
STDMETHODIMP DirectDrawClassFactory_QueryInterface(
|
|
LPCLASSFACTORY this,
|
|
REFIID riid,
|
|
LPVOID *ppvObj )
|
|
{
|
|
LPDDRAWCLASSFACTORY pcf;
|
|
|
|
DPF( 2, A, "ClassFactory::QueryInterface" );
|
|
ENTER_DDRAW();
|
|
TRY
|
|
{
|
|
pcf = (LPDDRAWCLASSFACTORY)this;
|
|
if( !VALIDEX_DIRECTDRAWCF_PTR( pcf ) )
|
|
{
|
|
DPF_ERR( "Invalid this ptr" );
|
|
LEAVE_DDRAW();
|
|
return E_FAIL;
|
|
}
|
|
|
|
if( !VALID_PTR_PTR( ppvObj ) )
|
|
{
|
|
DPF_ERR( "Invalid object ptr" );
|
|
LEAVE_DDRAW();
|
|
return E_INVALIDARG;
|
|
}
|
|
*ppvObj = NULL;
|
|
|
|
if( !VALID_IID_PTR( riid ) )
|
|
{
|
|
DPF_ERR( "Invalid iid ptr" );
|
|
LEAVE_DDRAW();
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if( IsEqualIID(riid, &IID_IClassFactory) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
pcf->dwRefCnt++;
|
|
*ppvObj = this;
|
|
LEAVE_DDRAW();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
DPF( 0, "E_NOINTERFACE" );
|
|
LEAVE_DDRAW();
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
} /* DirectDrawClassFactory_QueryInterface */
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DirectDrawClassFactory::AddRef"
|
|
|
|
/*
|
|
* DirectDrawClassFactory_AddRef
|
|
*/
|
|
STDMETHODIMP_(ULONG) DirectDrawClassFactory_AddRef( LPCLASSFACTORY this )
|
|
{
|
|
LPDDRAWCLASSFACTORY pcf;
|
|
|
|
ENTER_DDRAW();
|
|
TRY
|
|
{
|
|
pcf = (LPDDRAWCLASSFACTORY)this;
|
|
if( !VALIDEX_DIRECTDRAWCF_PTR( pcf ) )
|
|
{
|
|
DPF_ERR( "Invalid this ptr" );
|
|
LEAVE_DDRAW();
|
|
return (ULONG)E_FAIL;
|
|
}
|
|
pcf->dwRefCnt++;
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DDRAW();
|
|
return (ULONG)E_INVALIDARG;
|
|
}
|
|
|
|
DPF( 5, "ClassFactory::AddRef, dwRefCnt=%ld", pcf->dwRefCnt );
|
|
LEAVE_DDRAW();
|
|
return pcf->dwRefCnt;
|
|
|
|
} /* DirectDrawClassFactory_AddRef */
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DirectDrawClassFactory::Release"
|
|
|
|
/*
|
|
* DirectDrawClassFactory_Release
|
|
*/
|
|
STDMETHODIMP_(ULONG) DirectDrawClassFactory_Release( LPCLASSFACTORY this )
|
|
{
|
|
LPDDRAWCLASSFACTORY pcf;
|
|
|
|
ENTER_DDRAW();
|
|
TRY
|
|
{
|
|
pcf = (LPDDRAWCLASSFACTORY)this;
|
|
if( !VALIDEX_DIRECTDRAWCF_PTR( pcf ) )
|
|
{
|
|
DPF_ERR( "Invalid this ptr" );
|
|
LEAVE_DDRAW();
|
|
return (ULONG)E_FAIL;
|
|
}
|
|
pcf->dwRefCnt--;
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DDRAW();
|
|
return (ULONG)E_INVALIDARG;
|
|
}
|
|
DPF( 5, "ClassFactory::Release, dwRefCnt=%ld", pcf->dwRefCnt );
|
|
|
|
if( pcf->dwRefCnt != 0 )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return pcf->dwRefCnt;
|
|
}
|
|
MemFree( pcf );
|
|
LEAVE_DDRAW();
|
|
return 0;
|
|
|
|
} /* DirectDrawClassFactory_Release */
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DirectDrawClassFactory::CreateInstance"
|
|
|
|
/*
|
|
* DirectDrawClassFactory_CreateInstance
|
|
*
|
|
* Creates an instance of a DirectDraw object
|
|
*/
|
|
STDMETHODIMP DirectDrawClassFactory_CreateInstance(
|
|
LPCLASSFACTORY this,
|
|
LPUNKNOWN pUnkOuter,
|
|
REFIID riid,
|
|
LPVOID *ppvObj
|
|
)
|
|
{
|
|
HRESULT hr = DD_OK;
|
|
LPDDRAWI_DIRECTDRAW_INT pdrv_int = NULL;
|
|
LPDDRAWCLASSFACTORY pcf;
|
|
LPDIRECTDRAWCLIPPER pclipper;
|
|
|
|
DPF( 2, A, "ClassFactory::CreateInstance" );
|
|
|
|
pcf = (LPDDRAWCLASSFACTORY) this;
|
|
if( !VALIDEX_DIRECTDRAWCF_PTR( pcf ) )
|
|
{
|
|
DPF_ERR( "Invalid this ptr" );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if( !VALIDEX_IID_PTR( riid ) )
|
|
{
|
|
DPF_ERR( "Invalid iid ptr" );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if( !VALIDEX_PTR_PTR( ppvObj ) )
|
|
{
|
|
DPF_ERR( "Invalid object ptr" );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
#ifdef POSTPONED
|
|
if (pUnkOuter && !IsEqualIID(riid,&IID_IUnknown))
|
|
{
|
|
DPF_ERR("Can't aggregate with a punkouter != IUnknown");
|
|
return CLASS_E_NOAGGREGATION;
|
|
}
|
|
#else
|
|
if (pUnkOuter)
|
|
{
|
|
return CLASS_E_NOAGGREGATION;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* is DirectDraw supported on this system?
|
|
*/
|
|
if( !DirectDrawSupported( TRUE ) )
|
|
{
|
|
DPF_ERR( "DirectDraw not supported!" );
|
|
return E_FAIL;
|
|
}
|
|
|
|
/*
|
|
* go build an DirectDraw interface
|
|
*
|
|
* NOTE: We provide the "uninitialized callback table
|
|
* to prevent the use of this object for anything other
|
|
* than AddRef(), Release() or Initialized().
|
|
*/
|
|
ENTER_DDRAW();
|
|
if ( IsEqualIID(&pcf->TargetCLSID, &CLSID_DirectDraw ) ||
|
|
IsEqualIID(&pcf->TargetCLSID, &CLSID_DirectDraw7 ) )
|
|
{
|
|
if ( IsEqualIID(riid, &IID_IUnknown) )
|
|
{
|
|
/*
|
|
* If we're aggregated, then we don't need to worry about the IUnknown being
|
|
* the runtime identity (we are hidden inside the outer, since it's the one
|
|
* that will field the QI for IUnknown).
|
|
* This means we can point an aggregated interface at the nondelegating
|
|
* unknowns
|
|
*/
|
|
if (pUnkOuter)
|
|
{
|
|
#ifdef POSTPONED
|
|
pdrv_int = NewDriverInterface( NULL, &ddUninitNonDelegatingUnknownCallbacks );
|
|
#else
|
|
pdrv_int = NewDriverInterface( NULL, &ddUninitCallbacks );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Not aggregated, so the IUnknown has to have the same pointer value
|
|
* as the IDirectDraw interfaces, since QI always simply returns the
|
|
* this ptr when asked for IUnknown
|
|
* (Note this actually doesn't work right now because Initalize will swap
|
|
* vtbls).
|
|
*/
|
|
pdrv_int = NewDriverInterface( NULL, &ddUninitCallbacks );
|
|
}
|
|
}
|
|
else if ( IsEqualIID(riid, &IID_IDirectDraw) )
|
|
{
|
|
pdrv_int = NewDriverInterface( NULL, &ddUninitCallbacks );
|
|
}
|
|
else if ( IsEqualIID(riid, &IID_IDirectDraw2) )
|
|
{
|
|
pdrv_int = NewDriverInterface( NULL, &dd2UninitCallbacks );
|
|
}
|
|
else if ( IsEqualIID(riid, &IID_IDirectDraw4) )
|
|
{
|
|
pdrv_int = NewDriverInterface( NULL, &dd4UninitCallbacks );
|
|
}
|
|
else if ( IsEqualIID(riid, &IID_IDirectDraw7) )
|
|
{
|
|
pdrv_int = NewDriverInterface( NULL, &dd7UninitCallbacks );
|
|
}
|
|
|
|
|
|
if( NULL == pdrv_int )
|
|
{
|
|
DPF( 0, "Call to NewDriverInterface failed" );
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
#ifdef POSTPONED
|
|
/*
|
|
*
|
|
*/
|
|
if (pUnkOuter)
|
|
{
|
|
pdrv_int->lpLcl->pUnkOuter = pUnkOuter;
|
|
}
|
|
else
|
|
{
|
|
pdrv_int->lpLcl->pUnkOuter = (IUnknown*) &UninitNonDelegatingIUnknownInterface;
|
|
}
|
|
#endif
|
|
|
|
pdrv_int->dwIntRefCnt--;
|
|
pdrv_int->lpLcl->dwLocalRefCnt--;
|
|
|
|
/*
|
|
* NOTE: We call DD_QueryInterface() explicitly rather than
|
|
* going through the vtable as the "uninitialized" interface
|
|
* we are using here has QueryInterface() disabled.
|
|
*/
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = DD_QueryInterface( (LPDIRECTDRAW) pdrv_int, riid, ppvObj );
|
|
if( FAILED( hr ) )
|
|
{
|
|
DPF( 0, "Could not get interface id, hr=%08lx", hr );
|
|
RemoveLocalFromList( pdrv_int->lpLcl );
|
|
RemoveDriverFromList( pdrv_int, FALSE );
|
|
MemFree( pdrv_int->lpLcl );
|
|
MemFree( pdrv_int );
|
|
}
|
|
else
|
|
{
|
|
DPF( 5, "New Interface=%08lx", *ppvObj );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if ( IsEqualIID(&pcf->TargetCLSID, &CLSID_DirectDrawClipper ) )
|
|
{
|
|
/*
|
|
* Build a new clipper.
|
|
*
|
|
* Unlike the DirectDraw driver objects, clippers create via
|
|
* CoCreateInstance() are born pretty much initialized. The only
|
|
* thing initialization might actually do is to reparent the
|
|
* clipper to a given driver object. Otherwise all Initialize()
|
|
* does is set a flag.
|
|
*/
|
|
hr = InternalCreateClipper( NULL, 0UL, &pclipper, NULL, FALSE, NULL, NULL );
|
|
if( FAILED( hr ) )
|
|
{
|
|
DPF_ERR( "Failed to create the new clipper interface" );
|
|
}
|
|
|
|
/*
|
|
* NOTE: Bizarre code fragment below works as follows:
|
|
*
|
|
* 1) InternalCreateClipper() returns a clipper with a reference count
|
|
* of 1 for each of the interface, local and global objects.
|
|
* 2) QueryInterface() can do one of two things. It can either just return
|
|
* the same interface in which case the interface, local and global
|
|
* objects all get a reference count of 2 or it can return a different
|
|
* interface in which case both interfaces have a reference count of
|
|
* 1 and the local and global objects have a reference count of 2.
|
|
* 3) The immediate Release() following the QueryInterface() will in either
|
|
* case decrement the reference counts of the local and global objects
|
|
* to 1 (as required). If the same interface was returned by
|
|
* QueryInterface() then its reference count is decremented to 1 (as
|
|
* required). If a different interface was returned then the old
|
|
* interface is decremented to zero and it is released (as required).
|
|
* Also, if QueryInterface() fails, the Release() will decrement all
|
|
* the reference counts to 0 and the object will be freed.
|
|
*
|
|
* So it all makes perfect sense - really! (CMcC)
|
|
*
|
|
* ALSO NOTE: We call DD_Clipper_QueryInterface() explicitly rather than
|
|
* going through the vtable as the "uninitialized" interface we are using
|
|
* here has QueryInterface() disabled.
|
|
*/
|
|
hr = DD_Clipper_QueryInterface( pclipper, riid, ppvObj );
|
|
DD_Clipper_Release( pclipper );
|
|
if( FAILED( hr ) )
|
|
{
|
|
DPF( 0, "Could not get interface id, hr=%08lx", hr );
|
|
}
|
|
else
|
|
{
|
|
DPF( 5, "New Interface=%08lx", *ppvObj );
|
|
}
|
|
}
|
|
#ifdef POSTPONED
|
|
else if ( IsEqualIID(&pcf->TargetCLSID, &CLSID_DirectDrawFactory2) )
|
|
{
|
|
LPDDFACTORY2 lpDDFac = NULL;
|
|
/*
|
|
* Build a new DirectDrawFactory2
|
|
* This returns an object, with refcnt=0. The QI then bumps that to 1.
|
|
*/
|
|
hr = InternalCreateDDFactory2( &lpDDFac, pUnkOuter );
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
/*
|
|
* The QI should catch that the vtable is the ddrawfactory2 vtable,
|
|
* and simply bump the addref on the passed-in pointer. This means we
|
|
* won't orphan the pointer created by InternalCreateDDFactory2.
|
|
*/
|
|
hr = ((IUnknown*)lpDDFac)->lpVtbl->QueryInterface( (IUnknown*)lpDDFac, riid, ppvObj );
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
DPF( 5, "New DDFactory2 Interface=%08lx", *ppvObj );
|
|
}
|
|
else
|
|
{
|
|
MemFree(lpDDFac);
|
|
DPF( 0, "Could not get DDFactory2 interface id, hr=%08lx", hr );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR( "Failed to create the new dd factory2 interface" );
|
|
}
|
|
}
|
|
#endif
|
|
LEAVE_DDRAW();
|
|
return hr;
|
|
|
|
} /* DirectDrawClassFactory_CreateInstance */
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DirectDrawClassFactory::LockServer"
|
|
|
|
/*
|
|
* DirectDrawClassFactory_LockServer
|
|
*
|
|
* Called to force our DLL to stayed loaded
|
|
*/
|
|
STDMETHODIMP DirectDrawClassFactory_LockServer(
|
|
LPCLASSFACTORY this,
|
|
BOOL fLock
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
HANDLE hdll;
|
|
LPDDRAWCLASSFACTORY pcf;
|
|
|
|
pcf = (LPDDRAWCLASSFACTORY) this;
|
|
if( !VALIDEX_DIRECTDRAWCF_PTR( pcf ) )
|
|
{
|
|
DPF_ERR( "Invalid this ptr" );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
/*
|
|
* call CoLockObjectExternal
|
|
*/
|
|
DPF( 2, A, "ClassFactory::LockServer" );
|
|
hr = E_UNEXPECTED;
|
|
hdll = LoadLibrary( "OLE32.DLL" );
|
|
if( hdll != NULL )
|
|
{
|
|
HRESULT (WINAPI * lpCoLockObjectExternal)(LPUNKNOWN, BOOL, BOOL );
|
|
lpCoLockObjectExternal = (LPVOID) GetProcAddress( hdll, "CoLockObjectExternal" );
|
|
if( lpCoLockObjectExternal != NULL )
|
|
{
|
|
hr = lpCoLockObjectExternal( (LPUNKNOWN) this, fLock, TRUE );
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR( "Error! Could not get procaddr for CoLockObjectExternal" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR( "Error! Could not load OLE32.DLL" );
|
|
}
|
|
|
|
/*
|
|
* track the number of server locks total
|
|
*/
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
ENTER_DDRAW();
|
|
if( fLock )
|
|
{
|
|
dwLockCount++;
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG
|
|
if( (int) dwLockCount <= 0 )
|
|
{
|
|
DPF( 0, "Invalid LockCount in LockServer! (%d)", dwLockCount );
|
|
DEBUG_BREAK();
|
|
}
|
|
#endif
|
|
dwLockCount--;
|
|
}
|
|
DPF( 5, "LockServer:dwLockCount =%ld", dwLockCount );
|
|
LEAVE_DDRAW();
|
|
}
|
|
return hr;
|
|
|
|
} /* DirectDrawClassFactory_LockServer */
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DirectDrawClassFactory::CreateInstance"
|
|
|
|
|
|
static IClassFactoryVtbl directDrawClassFactoryVtbl =
|
|
{
|
|
DirectDrawClassFactory_QueryInterface,
|
|
DirectDrawClassFactory_AddRef,
|
|
DirectDrawClassFactory_Release,
|
|
DirectDrawClassFactory_CreateInstance,
|
|
DirectDrawClassFactory_LockServer
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DllGetClassObject"
|
|
|
|
/*
|
|
* DllGetClassObject
|
|
*
|
|
* Entry point called by COM to get a ClassFactory pointer
|
|
*/
|
|
HRESULT WINAPI DllGetClassObject(
|
|
REFCLSID rclsid,
|
|
REFIID riid,
|
|
LPVOID *ppvObj )
|
|
{
|
|
LPDDRAWCLASSFACTORY pcf;
|
|
HRESULT hr;
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
if( !VALIDEX_PTR_PTR( ppvObj ) )
|
|
{
|
|
DPF_ERR( "Invalid object ptr" );
|
|
return E_INVALIDARG;
|
|
}
|
|
*ppvObj = NULL;
|
|
if( !VALIDEX_IID_PTR( rclsid ) )
|
|
{
|
|
DPF_ERR( "Invalid clsid ptr" );
|
|
return E_INVALIDARG;
|
|
}
|
|
if( !VALIDEX_IID_PTR( riid ) )
|
|
{
|
|
DPF_ERR( "Invalid iid ptr" );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
/*
|
|
* is this one our class ids?
|
|
*/
|
|
if( IsEqualCLSID( rclsid, &CLSID_DirectDraw ) ||
|
|
IsEqualCLSID( rclsid, &CLSID_DirectDraw7 ) ||
|
|
IsEqualCLSID( rclsid, &CLSID_DirectDrawClipper ) ||
|
|
IsEqualCLSID( rclsid, &CLSID_DirectDrawFactory2 ))
|
|
{
|
|
/*
|
|
* It's the DirectDraw driver class ID.
|
|
*/
|
|
|
|
/*
|
|
* only allow IUnknown and IClassFactory
|
|
*/
|
|
if( !IsEqualIID( riid, &IID_IUnknown ) &&
|
|
!IsEqualIID( riid, &IID_IClassFactory ) )
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/*
|
|
* create a class factory object
|
|
*/
|
|
ENTER_DDRAW();
|
|
pcf = MemAlloc( sizeof( DDRAWCLASSFACTORY ) );
|
|
if( pcf == NULL )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
pcf->lpVtbl = &directDrawClassFactoryVtbl;
|
|
pcf->dwRefCnt = 0;
|
|
memcpy(&pcf->TargetCLSID,rclsid,sizeof(*rclsid));
|
|
#pragma message( REMIND( "Do we need to have a refcnt of 0 after DllGetClassObject?" ))
|
|
hr = DirectDrawClassFactory_QueryInterface( (LPCLASSFACTORY) pcf, riid, ppvObj );
|
|
if( FAILED( hr ) )
|
|
{
|
|
MemFree( pcf );
|
|
*ppvObj = NULL;
|
|
DPF( 0, "QueryInterface failed, rc=%08lx", hr );
|
|
}
|
|
else
|
|
{
|
|
DPF( 5, "DllGetClassObject succeeded, pcf=%08lx", pcf );
|
|
}
|
|
LEAVE_DDRAW();
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
} /* DllGetClassObject */
|
|
|
|
/*
|
|
* DllCanUnloadNow
|
|
*
|
|
* Entry point called by COM to see if it is OK to free our DLL
|
|
*/
|
|
HRESULT WINAPI DllCanUnloadNow( void )
|
|
{
|
|
HRESULT hr;
|
|
|
|
DPF( 2, A, "DllCanUnloadNow called" );
|
|
hr = S_FALSE;
|
|
ENTER_DDRAW();
|
|
|
|
/*
|
|
* Only unload if there are no driver objects and no global
|
|
* clipper objects (there won't be any local clipper objects
|
|
* as they are destroyed by their driver so the check on driver
|
|
* object handles them).
|
|
*/
|
|
if( ( lpDriverObjectList == NULL ) &&
|
|
( lpDriverLocalList == NULL ) &&
|
|
( lpGlobalClipperList == NULL ) )
|
|
{
|
|
if( dwLockCount == 0 )
|
|
{
|
|
DPF( 3, "It is OK to unload" );
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
LEAVE_DDRAW();
|
|
return hr;
|
|
|
|
} /* DllCanUnloadNow */
|