|
|
/****************************************************************************
* * SampUSD.CPP * * Copyright (C) Microsoft Corporation 1996-1999 * All rights reserved * ***************************************************************************/
#define INITGUID
#include "Sampusd.h"
#include "resource.h"
/*****************************************************************************
* * Globals * *****************************************************************************/
// Reference counter for the whole library
DWORD g_cRef;
// DLL module instance
HINSTANCE g_hInst;
// Critical section for low level syncronization
CRITICAL_SECTION g_crstDll;
// Can we use UNICODE APIs
BOOL g_NoUnicodePlatform = TRUE;
// Is COM initialized
BOOL g_COMInitialized = FALSE;
/*****************************************************************************
* * @doc INTERNAL * * @func void | DllEnterCrit | * * Take the DLL critical section. * * The DLL critical section is the lowest level critical section. * You may not attempt to acquire any other critical sections or * yield while the DLL critical section is held. * *****************************************************************************/
void DllEnterCrit(void) { EnterCriticalSection(&g_crstDll); }
/*****************************************************************************
* * @doc INTERNAL * * @func void | DllLeaveCrit | * * Leave the DLL critical section. * *****************************************************************************/
void DllLeaveCrit(void) { LeaveCriticalSection(&g_crstDll); }
/*****************************************************************************
* * @doc INTERNAL * * @func void | DllAddRef | * * Increment the reference count on the DLL. * *****************************************************************************/
void DllAddRef(void) { InterlockedIncrement((LPLONG)&g_cRef); }
/*****************************************************************************
* * @doc INTERNAL * * @func void | DllRelease | * * Decrement the reference count on the DLL. * *****************************************************************************/
void DllRelease(void) { InterlockedDecrement((LPLONG)&g_cRef); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | DllInitializeCOM | * * Initialize COM libraries * * @parm IN | | * * @returns * * Returns a boolean error code. * *****************************************************************************/
BOOL DllInitializeCOM( void ) { DllEnterCrit();
if(!g_COMInitialized) { if(SUCCEEDED(CoInitialize(NULL))) { g_COMInitialized = TRUE; } }
DllLeaveCrit();
return g_COMInitialized; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | DllUnInitializeCOM | * * UnInitialize COM libraries * * @parm IN | | * * @returns * * Returns a boolean error code. * *****************************************************************************/ BOOL DllUnInitializeCOM( void ) { DllEnterCrit();
if(g_COMInitialized) { CoUninitialize(); g_COMInitialized = FALSE; }
DllLeaveCrit();
return TRUE; }
/*****************************************************************************
* * @class UsdSampClassFactory | * *****************************************************************************/
class UsdSampClassFactory : public IClassFactory { private: ULONG m_cRef;
public: STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void);
STDMETHODIMP CreateInstance( /* [unique][in] */ IUnknown __RPC_FAR *pUnkOuter, /* [in] */ REFIID riid, /* [out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
STDMETHODIMP LockServer( /* [in] */ BOOL fLock);
UsdSampClassFactory(); };
UsdSampClassFactory::UsdSampClassFactory() { //DEBUGPRINTF((DBG_LVL_DEBUG, TEXT("UsdSampClassFactory: Constructor")));
// Constructor logic
m_cRef = 0; }
STDMETHODIMP UsdSampClassFactory::QueryInterface( /* [in] */ REFIID riid, /* [out] */ void __RPC_FAR *__RPC_FAR *ppvObject) { // DEBUGPRINTF((DBG_LVL_DEBUG, TEXT("UsdSampClassFactory: QueryInterface")));
*ppvObject = NULL;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) { *ppvObject = (LPVOID)this; AddRef(); return NOERROR; } return ResultFromScode(E_NOINTERFACE); }
STDMETHODIMP_(ULONG) UsdSampClassFactory::AddRef(void) { DllAddRef(); return ++m_cRef; }
STDMETHODIMP_(ULONG) UsdSampClassFactory::Release(void) { DllRelease(); if (--m_cRef == 0) { delete this; return 0; } return m_cRef; }
STDMETHODIMP UsdSampClassFactory::CreateInstance( /* [unique][in] */ IUnknown __RPC_FAR *punkOuter, /* [in] */ REFIID riid, /* [out] */ void __RPC_FAR *__RPC_FAR *ppvObject) {
if (!IsEqualIID(riid, IID_IStiUSD) && !IsEqualIID(riid, IID_IUnknown)) { return STIERR_NOINTERFACE; }
// When created for aggregation, only IUnknown can be requested, so fail
// call if not.
if (punkOuter && !IsEqualIID(riid, IID_IUnknown)) { return CLASS_E_NOAGGREGATION; }
UsdSampDevice *pDev = NULL; HRESULT hres;
pDev = new UsdSampDevice(punkOuter); if (!pDev) { return STIERR_OUTOFMEMORY; }
//
// Move to the requested interface
//
hres = pDev->NonDelegatingQueryInterface(riid,ppvObject); pDev->NonDelegatingRelease();
return hres; }
STDMETHODIMP UsdSampClassFactory::LockServer( /* [in] */ BOOL fLock) { if (fLock) { DllAddRef(); } else { DllRelease(); }
return NOERROR; }
/*****************************************************************************
* * @class UsdSampDevice | INonDelegatingUnknown * *****************************************************************************/ STDMETHODIMP UsdSampDevice::NonDelegatingQueryInterface( REFIID riid, LPVOID* ppvObj ) { HRESULT hres;
if( !IsValid() || !ppvObj ) { return STIERR_INVALID_PARAM; }
*ppvObj = NULL;
if( IsEqualIID( riid, IID_IUnknown )) { *ppvObj = static_cast<INonDelegatingUnknown*>(this); hres = S_OK; } else if( IsEqualIID( riid, IID_IStiUSD )) { *ppvObj = static_cast<IStiUSD*>(this); hres = S_OK; } else { hres = STIERR_NOINTERFACE; }
if (SUCCEEDED(hres)) { (reinterpret_cast<IUnknown*>(*ppvObj))->AddRef(); }
return hres; }
STDMETHODIMP_(ULONG) UsdSampDevice::NonDelegatingAddRef( VOID ) { ULONG ulRef; ulRef = InterlockedIncrement((LPLONG)&m_cRef); return ulRef; }
STDMETHODIMP_(ULONG) UsdSampDevice::NonDelegatingRelease( VOID ) { ULONG ulRef; ulRef = InterlockedDecrement((LPLONG)&m_cRef);
if(!ulRef) { delete this; }
return ulRef; }
/*****************************************************************************
* * @class UsdSampDevice | IUnknown (Delegating) * * Delegating unknown methods. * *****************************************************************************/
STDMETHODIMP UsdSampDevice::QueryInterface( REFIID riid, LPVOID* ppvObj ) { return m_punkOuter->QueryInterface(riid,ppvObj); }
STDMETHODIMP_(ULONG) UsdSampDevice::AddRef( VOID ) { return m_punkOuter->AddRef(); }
STDMETHODIMP_(ULONG) UsdSampDevice::Release( VOID ) { return m_punkOuter->Release(); }
/*****************************************************************************
* * @doc INTERNAL * * @func BOOL | DllEntryPoint | * * Called to notify the DLL about various things that can happen. * * We are not interested in thread attaches and detaches, * so we disable thread notifications for performance reasons. * * @parm HINSTANCE | hinst | * * The instance handle of this DLL. * * @parm DWORD | dwReason | * * Notification code. * * @parm LPVOID | lpReserved | * * Not used. * * @returns * * Returns <c TRUE> to allow the DLL to load. * *****************************************************************************/
extern "C" DLLEXPORT BOOL APIENTRY DllEntryPoint(HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH:
g_hInst = hinst;
// Disable thread library calls to avoid
// deadlock when we spin up the worker thread
DisableThreadLibraryCalls(hinst); InitializeCriticalSection(&g_crstDll);
// Set global flags
// g_NoUnicodePlatform = !OSUtil_IsPlatformUnicode();
break;
case DLL_PROCESS_DETACH: if (g_cRef) { // DPRINTF("Sampusd: Unloaded before all objects Release()d! Crash soon!\r\n");
}
// Free COM libraries if connected to them
// DllUnInitializeCOM();
break; }
return 1; }
extern "C" DLLEXPORT BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved) { return DllEntryPoint(hinst, dwReason, lpReserved); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | DllCanUnloadNow | * * Determine whether the DLL has any outstanding interfaces. * * @returns * * Returns <c S_OK> if the DLL can unload, <c S_FALSE> if * it is not safe to unload. * *****************************************************************************/ extern "C" STDMETHODIMP DllCanUnloadNow(void) { HRESULT hres;
hres = g_cRef ? S_FALSE : S_OK;
return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | DllGetClassObject | * * Create an <i IClassFactory> instance for this DLL. * * @parm REFCLSID | rclsid | * * The object being requested. * * @parm RIID | riid | * * The desired interface on the object. * * @parm PPV | ppvOut | * * Output pointer. * * @notes * We support only one class of objects , so this function does not need * to go through table of supported classes , looking for proper constructor * * *****************************************************************************/ extern "C" STDAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, LPVOID *ppv) {
if (!ppv) { return ResultFromScode(E_FAIL); }
if (!IsEqualCLSID(rclsid, CLSID_SampUSDObj) ) { return ResultFromScode(E_FAIL); }
if (!IsEqualIID(riid, IID_IUnknown) && !IsEqualIID(riid, IID_IClassFactory)) { return ResultFromScode(E_NOINTERFACE); }
if (IsEqualCLSID(rclsid, CLSID_SampUSDObj)) { UsdSampClassFactory *pcf = new UsdSampClassFactory; if (pcf) { *ppv = (LPVOID)pcf; } }
return NOERROR; }
|