531 lines
11 KiB
C++
531 lines
11 KiB
C++
/****************************************************************************
|
|
*
|
|
* 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;
|
|
}
|
|
|
|
|
|
|