678 lines
20 KiB
C
678 lines
20 KiB
C
|
#if !defined(_FUSION_INC_FUSIONCOM_H_INCLUDED_)
|
||
|
#define _FUSION_INC_FUSIONCOM_H_INCLUDED_
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <stddef.h>
|
||
|
#include <guiddef.h>
|
||
|
#include <basetsd.h>
|
||
|
#include "smartref.h"
|
||
|
|
||
|
//
|
||
|
// The basic design for this COM support is lifted from ATL.
|
||
|
//
|
||
|
// ATL's implementation is much more complicated because it tries to
|
||
|
// support all the sorts of COM objects there may be. Perhaps over
|
||
|
// time this COM base stuff will extend as much and we may wish we
|
||
|
// just used ATL, but for now people feel that ATL is overkill, so
|
||
|
// rather than implement IUnknown::AddRef() and IUnknown::Release()
|
||
|
// a thousand times, we'll at least have enough to have a single
|
||
|
// common implementation.
|
||
|
//
|
||
|
|
||
|
|
||
|
// Turn off the warning about using a typedef name as if it were a class name.
|
||
|
// We tend to do that a lot with CFusionCOMObjectBase (which is really just
|
||
|
// a typedef for a much hairier name...)
|
||
|
|
||
|
#pragma warning(disable: 4097) // use of typedef as class name
|
||
|
#pragma warning(disable: 4505) // dead code warning
|
||
|
|
||
|
// UNUSED macro with local unique name:
|
||
|
#define FUSION_FUSIONCOM_UNUSED(x) (x)
|
||
|
|
||
|
#define FUSION_COM_PACKING 8
|
||
|
|
||
|
#pragma pack(push, FUSION_COM_PACKING)
|
||
|
|
||
|
#define offsetofclass(base, derived) (reinterpret_cast<ULONG_PTR>(static_cast<base*>(reinterpret_cast<derived*>(FUSION_COM_PACKING)))-FUSION_COM_PACKING)
|
||
|
|
||
|
struct CFusionCOMInterfaceMapEntry
|
||
|
{
|
||
|
const IID *piid;
|
||
|
DWORD_PTR dwOffset;
|
||
|
enum
|
||
|
{
|
||
|
eSimpleMapEntry,
|
||
|
eDelegate,
|
||
|
eEndOfMap,
|
||
|
} eType;
|
||
|
};
|
||
|
|
||
|
class CFusionCOMCriticalSectionSynchronization
|
||
|
{
|
||
|
public:
|
||
|
CFusionCOMCriticalSectionSynchronization() : m_fInitialized(false) { }
|
||
|
~CFusionCOMCriticalSectionSynchronization() { m_fInitialized = false; }
|
||
|
|
||
|
static ULONG Increment(ULONG &rul) { return ::InterlockedIncrement((LONG *) &rul); }
|
||
|
static ULONG Decrement(ULONG &rul) { return ::InterlockedDecrement((LONG *) &rul); }
|
||
|
|
||
|
HRESULT Initialize(DWORD dwSpinCount = (0x80000000 | 4000))
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(!m_fInitialized);
|
||
|
if (m_fInitialized)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if (!::InitializeCriticalSectionAndSpinCount(&m_cs, dwSpinCount))
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
m_fInitialized = true;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT Lock()
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(m_fInitialized);
|
||
|
if (!m_fInitialized)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
::EnterCriticalSection(&m_cs);
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT Unlock()
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(m_fInitialized);
|
||
|
if (!m_fInitialized)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
::LeaveCriticalSection(&m_cs);
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT TryLock(bool &rfLocked)
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(m_fInitialized);
|
||
|
if (!m_fInitialized)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
rfLocked = (::TryEnterCriticalSection(&m_cs) != 0);
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
CRITICAL_SECTION m_cs;
|
||
|
bool m_fInitialized;
|
||
|
};
|
||
|
|
||
|
class CFusionCOMNullSynchronization
|
||
|
{
|
||
|
public:
|
||
|
CFusionCOMNullSynchronization() : m_fInitialized(false) { }
|
||
|
~CFusionCOMNullSynchronization() { m_fInitialized = false; }
|
||
|
|
||
|
static ULONG Increment(ULONG &rul) { return ++rul; }
|
||
|
static ULONG Decrement(ULONG &rul) { return --rul; }
|
||
|
|
||
|
HRESULT Initialize()
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(!m_fInitialized);
|
||
|
if (m_fInitialized)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
m_fInitialized = true;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT Lock()
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(m_fInitialized);
|
||
|
if (!m_fInitialized)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT Unlock()
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(m_fInitialized);
|
||
|
if (!m_fInitialized)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT TryLock(bool &rfLocked)
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(m_fInitialized);
|
||
|
if (!m_fInitialized)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
rfLocked = true;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
bool m_fInitialized;
|
||
|
};
|
||
|
|
||
|
template <typename TSynch = CFusionCOMCriticalSectionSynchronization> class __declspec(novtable) CFusionCOMObjectBaseEx : public IUnknown
|
||
|
{
|
||
|
protected:
|
||
|
CFusionCOMObjectBaseEx() : m_cRef(0), m_fInFinalRelease(false), m_fFusionCOMObjectBaseExInitialized(false) { }
|
||
|
virtual ~CFusionCOMObjectBaseEx() { ASSERT(m_cRef == 0); }
|
||
|
|
||
|
ULONG _InternalAddRef()
|
||
|
{
|
||
|
// You really shouldn't be causing new references on this object after its ref
|
||
|
// count has dropped to zero...
|
||
|
ASSERT(!m_fInFinalRelease);
|
||
|
// You shouldn't be adding refs to this object prior to calling the base class's
|
||
|
// Initialize() function.
|
||
|
ASSERT(m_fFusionCOMObjectBaseExInitialized);
|
||
|
return TSynch::Increment(m_cRef);
|
||
|
}
|
||
|
|
||
|
ULONG _InternalRelease()
|
||
|
{
|
||
|
// You really shouldn't be causing new references on this object after its ref
|
||
|
// count has dropped to zero...
|
||
|
ASSERT(!m_fInFinalRelease);
|
||
|
// You shouldn't be adding (or removing) refs to this object prior to calling the base class's
|
||
|
// Initialize() function.
|
||
|
ASSERT(m_fFusionCOMObjectBaseExInitialized);
|
||
|
return TSynch::Decrement(m_cRef);
|
||
|
}
|
||
|
|
||
|
VOID OnFinalRelease() { m_srpIUnknown_FTM.Release(); }
|
||
|
|
||
|
// Derived classes must call this in order for the critical section/mutex/whatever
|
||
|
// to be initialized.
|
||
|
HRESULT Initialize(bool fCreateFTM = true)
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(!m_fFusionCOMObjectBaseExInitialized);
|
||
|
if (m_fFusionCOMObjectBaseExInitialized)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
hr = m_SynchronizationObject.Initialize();
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
if (fCreateFTM)
|
||
|
{
|
||
|
hr = ::CoCreateFreeThreadedMarshaler(this, &m_srpIUnknown_FTM);
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
m_fFusionCOMObjectBaseExInitialized = true;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
static HRESULT WINAPI InternalQueryInterface(
|
||
|
void *pThis,
|
||
|
const CFusionCOMInterfaceMapEntry* pEntries,
|
||
|
REFIID riid,
|
||
|
void **ppvObject)
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
IUnknown *pIUnknown = NULL;
|
||
|
|
||
|
ASSERT(pThis != NULL);
|
||
|
|
||
|
if (ppvObject != NULL)
|
||
|
*ppvObject = NULL;
|
||
|
|
||
|
if (ppvObject == NULL)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
while (pEntries->eType != CFusionCOMInterfaceMapEntry::eEndOfMap)
|
||
|
{
|
||
|
if ((pEntries->piid == NULL) || ((*(pEntries->piid)) == riid))
|
||
|
{
|
||
|
switch (pEntries->eType)
|
||
|
{
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
|
||
|
case CFusionCOMInterfaceMapEntry::eDelegate:
|
||
|
pIUnknown = *((IUnknown **) (((DWORD_PTR) pThis) + pEntries->dwOffset));
|
||
|
if (pIUnknown != NULL)
|
||
|
{
|
||
|
hr = pIUnknown->QueryInterface(riid, ppvObject);
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CFusionCOMInterfaceMapEntry::eSimpleMapEntry:
|
||
|
ASSERT(pEntries->eType == CFusionCOMInterfaceMapEntry::eSimpleMapEntry);
|
||
|
|
||
|
pIUnknown = (IUnknown *) (((DWORD_PTR) pThis) + pEntries->dwOffset);
|
||
|
pIUnknown->AddRef();
|
||
|
*ppvObject = pIUnknown;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
// If we did find a match, get out of here. (This may have been
|
||
|
// a delegation entry that matched, but there was no delegatee in
|
||
|
// the storage at pEntries->dwOffset, so we skipped it. This allows
|
||
|
// a derived class to not create, for example, a free threaded marshaler
|
||
|
// and have normal marshaling semantics.
|
||
|
if (pIUnknown != NULL)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pEntries++;
|
||
|
}
|
||
|
|
||
|
if (pEntries->eType == CFusionCOMInterfaceMapEntry::eEndOfMap)
|
||
|
{
|
||
|
hr = E_NOINTERFACE;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
hr = NOERROR;
|
||
|
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
ULONG m_cRef;
|
||
|
TSynch m_SynchronizationObject;
|
||
|
CSmartRef<IUnknown> m_srpIUnknown_FTM;
|
||
|
bool m_fInFinalRelease;
|
||
|
bool m_fFusionCOMObjectBaseExInitialized;
|
||
|
};
|
||
|
|
||
|
typedef CFusionCOMObjectBaseEx<CFusionCOMCriticalSectionSynchronization> CFusionCOMObjectBase;
|
||
|
|
||
|
// Putting the entry macros before the begin/end map macros so that
|
||
|
// we can use the entry macros in the begin/end map macros to
|
||
|
// automatically add entries for IUnknown and IMarshal.
|
||
|
#define FUSION_COM_INTERFACE_ENTRY(x) { &__uuidof(x), offsetofclass(x, _ComMapClass), CFusionCOMInterfaceMapEntry::eSimpleMapEntry },
|
||
|
|
||
|
#define FUSION_COM_INTERFACE_ENTRY2(x, x2) { &__uuidof(x), (DWORD_PTR)((x*)(x2*)((_ComMapClass*)8))-8, CFusionCOMInterfaceMapEntry::eSimpleMapEntry },
|
||
|
|
||
|
#define FUSION_COM_INTERFACE_ENTRY_IID(iid, x) { &(iid), offsetofclass(x, _ComMapClass), CFusionCOMInterfaceMapEntry::eSimpleMapEntry },
|
||
|
|
||
|
#define FUSION_COM_INTERFACE_ENTRY_AGGREGATE(x, punk) \
|
||
|
{&__uuidof(x),\
|
||
|
offsetof(_ComMapClass, punk),\
|
||
|
CFusionCOMInterfaceMapEntry::eDelegate },
|
||
|
|
||
|
#define FUSION_BEGIN_COM_MAP_EX(x, basetype) \
|
||
|
public: \
|
||
|
virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; \
|
||
|
virtual ULONG STDMETHODCALLTYPE Release(void) = 0; \
|
||
|
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *) = 0; \
|
||
|
typedef x _ComMapClass; \
|
||
|
HRESULT _InternalQueryInterface(REFIID riid, void** ppvObject) \
|
||
|
{ \
|
||
|
return InternalQueryInterface(this, _GetEntries(), riid, ppvObject); \
|
||
|
} \
|
||
|
const static CFusionCOMInterfaceMapEntry * WINAPI _GetEntries() \
|
||
|
{ \
|
||
|
static const CFusionCOMInterfaceMapEntry _entries[] = { \
|
||
|
FUSION_COM_INTERFACE_ENTRY2(IUnknown, basetype)
|
||
|
|
||
|
#define FUSION_BEGIN_COM_MAP(x) FUSION_BEGIN_COM_MAP_EX(x, CFusionCOMObjectBase)
|
||
|
|
||
|
#define FUSION_END_COM_MAP() \
|
||
|
FUSION_COM_INTERFACE_ENTRY_AGGREGATE(IMarshal, m_srpIUnknown_FTM.m_pt) \
|
||
|
{ NULL, 0, CFusionCOMInterfaceMapEntry::eEndOfMap} \
|
||
|
}; \
|
||
|
return _entries; \
|
||
|
}
|
||
|
|
||
|
template <typename TBase> class CFusionCOMObject : public TBase
|
||
|
{
|
||
|
public:
|
||
|
CFusionCOMObject() { }
|
||
|
virtual ~CFusionCOMObject() { }
|
||
|
|
||
|
STDMETHODIMP_(ULONG) AddRef() { return this->_InternalAddRef(); }
|
||
|
STDMETHODIMP_(ULONG) Release()
|
||
|
{
|
||
|
ULONG cRef = this->_InternalRelease();
|
||
|
// If the ref count hits zero, but we were already in final release,
|
||
|
// we know that the outer Release() will actually do the delete, so
|
||
|
// we don't have to.
|
||
|
if ((cRef == 0) && !m_fInFinalRelease)
|
||
|
{
|
||
|
m_fInFinalRelease = true;
|
||
|
this->OnFinalRelease();
|
||
|
// Make sure that the OnFinalRelease() didn't do something wacky
|
||
|
// like increment the ref count...
|
||
|
ASSERT(m_fInFinalRelease);
|
||
|
ASSERT(m_cRef == 0);
|
||
|
m_fInFinalRelease = false;
|
||
|
delete this;
|
||
|
}
|
||
|
return cRef;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv) { return this->_InternalQueryInterface(riid, ppv); }
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Use CFusionAutoCOMObject<> to instantiate a CFusionCOMObject-derived instance
|
||
|
// in automatic (e.g. stack) storage.
|
||
|
//
|
||
|
|
||
|
template <typename TBase> class CFusionAutoCOMObject : public TBase
|
||
|
{
|
||
|
public:
|
||
|
CFusionAutoCOMObject() { }
|
||
|
STDMETHODIMP_(ULONG) AddRef() { return this->_InternalAddRef(); }
|
||
|
STDMETHODIMP_(ULONG) Release() { return this->_InternalRelease(); }
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv) { return this->_InternalQueryInterface(riid, ppv); }
|
||
|
|
||
|
typedef BOOL (CALLBACK * PUMPMESSAGESPROC)(LPVOID pvContext);
|
||
|
|
||
|
BOOL WaitForZeroRefCount(DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags, PUMPMESSAGESPROC lpMsgPump, LPVOID pvContext)
|
||
|
{
|
||
|
FUSION_FUSIONCOM_UNUSED(dwMilliseconds);
|
||
|
|
||
|
// Anything other than dwMilliseconds == INFINITE is not implemented today...
|
||
|
ASSERT(dwMilliseconds == INFINITE);
|
||
|
ASSERT(dwFlags & MWMO_ALERTABLE);
|
||
|
|
||
|
dwFlags |= MWMO_ALERTABLE;
|
||
|
|
||
|
while (m_cRef != 0)
|
||
|
{
|
||
|
DWORD dwTemp = ::MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, dwWakeMask, dwFlags);
|
||
|
if (dwTemp == -1)
|
||
|
return FALSE;
|
||
|
|
||
|
if (m_cRef == 0)
|
||
|
break;
|
||
|
|
||
|
if (dwTemp == WAIT_OBJECT_0)
|
||
|
{
|
||
|
BOOL fSucceeded = (*lpMsgPump)(pvContext);
|
||
|
if (!fSucceeded)
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// Use WaitForZeroRefCount() prior to this
|
||
|
virtual ~CFusionAutoCOMObject()
|
||
|
{
|
||
|
ASSERT(!m_fInFinalRelease);
|
||
|
if (!m_fInFinalRelease)
|
||
|
{
|
||
|
m_fInFinalRelease = true;
|
||
|
this->OnFinalRelease();
|
||
|
m_fInFinalRelease = false;
|
||
|
}
|
||
|
ASSERT(m_cRef == 0);
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
template <typename TEnumInterface, typename TItemInterface> class CFusionCOMIter
|
||
|
{
|
||
|
public:
|
||
|
CFusionCOMIter() { }
|
||
|
~CFusionCOMIter() { }
|
||
|
CFusionCOMIter(TEnumInterface *pTEnumInterface) { m_srpTEnumInterface = pTEnumInterface; }
|
||
|
void operator =(TEnumInterface *pTEnumInterface) { m_srpTEnumInterface = pTEnumInterface; m_srpTItemInterface.Release(); }
|
||
|
|
||
|
TEnumInterface **operator &() { return &m_srpTEnumInterface; }
|
||
|
TItemInterface *operator ->() const { return m_srpTItemInterface; }
|
||
|
operator TItemInterface *() const { return m_srpTItemInterface; }
|
||
|
|
||
|
void Release() { m_srpTEnumInterface.Release(); m_srpTItemInterface.Release(); }
|
||
|
|
||
|
bool EnumIsNull() const { return m_srpTEnumInterface == NULL; }
|
||
|
|
||
|
HRESULT Reset()
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
if (m_srpTEnumInterface == NULL)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
hr = m_srpTEnumInterface->Reset();
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
hr = m_srpTEnumInterface->Next(1, &m_srpTItemInterface, NULL);
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
bool More() const { return (m_srpTItemInterface != NULL); }
|
||
|
|
||
|
HRESULT Next()
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
if (m_srpTEnumInterface == NULL)
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
hr = m_srpTEnumInterface->Next(1, &m_srpTItemInterface, NULL);
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
CSmartRef<TEnumInterface> m_srpTEnumInterface;
|
||
|
CSmartRef<TItemInterface> m_srpTItemInterface;
|
||
|
};
|
||
|
|
||
|
template <class TInstance, class TInterface> class CFusionCOMObjectCreator : public CSmartRef<TInterface>
|
||
|
{
|
||
|
public:
|
||
|
CFusionCOMObjectCreator() : m_ptinstance(NULL), m_fDeleteInstance(false) { }
|
||
|
~CFusionCOMObjectCreator() { if (m_fDeleteInstance) { CSxsPreserveLastError ple; delete m_ptinstance; ple.Restore(); } }
|
||
|
|
||
|
HRESULT CreateInstance()
|
||
|
{
|
||
|
if (m_ptinstance != NULL) return E_UNEXPECTED;
|
||
|
m_ptinstance = NEW(CFusionCOMObject<TInstance>);
|
||
|
if (m_ptinstance == NULL) return E_OUTOFMEMORY;
|
||
|
m_fDeleteInstance = true;
|
||
|
HRESULT hr = m_ptinstance->Initialize();
|
||
|
if (FAILED(hr)) return hr;
|
||
|
hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
m_fDeleteInstance = false;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
template <typename TArg1> HRESULT CreateInstanceWithArg(TArg1 arg1)
|
||
|
{
|
||
|
if (m_ptinstance != NULL) return E_UNEXPECTED;
|
||
|
m_ptinstance = NEW(CFusionCOMObject<TInstance>);
|
||
|
if (m_ptinstance == NULL) return E_OUTOFMEMORY;
|
||
|
m_fDeleteInstance = true;
|
||
|
HRESULT hr = m_ptinstance->Initialize(arg1);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
m_fDeleteInstance = false;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
template <typename TArg1, typename TArg2> HRESULT CreateInstanceWith2Args(TArg1 arg1, TArg2 arg2)
|
||
|
{
|
||
|
if (m_ptinstance != NULL) return E_UNEXPECTED;
|
||
|
m_ptinstance = NEW(CFusionCOMObject<TInstance>);
|
||
|
if (m_ptinstance == NULL) return E_OUTOFMEMORY;
|
||
|
m_fDeleteInstance = true;
|
||
|
HRESULT hr = m_ptinstance->Initialize(arg1, arg2);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
m_fDeleteInstance = false;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
template <typename TArg1, typename TArg2, typename TArg3> HRESULT CreateInstanceWith3Args(TArg1 arg1, TArg2 arg2, TArg3 arg3)
|
||
|
{
|
||
|
if (m_ptinstance != NULL) return E_UNEXPECTED;
|
||
|
m_ptinstance = NEW(CFusionCOMObject<TInstance>);
|
||
|
if (m_ptinstance == NULL) return E_OUTOFMEMORY;
|
||
|
m_fDeleteInstance = true;
|
||
|
HRESULT hr = m_ptinstance->Initialize(arg1, arg2, arg3);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
m_fDeleteInstance = false;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
template <typename TArg1, typename TArg2, typename TArg3, typename TArg4> HRESULT CreateInstanceWith4Args(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4)
|
||
|
{
|
||
|
if (m_ptinstance != NULL) return E_UNEXPECTED;
|
||
|
m_ptinstance = NEW(CFusionCOMObject<TInstance>);
|
||
|
if (m_ptinstance == NULL) return E_OUTOFMEMORY;
|
||
|
m_fDeleteInstance = true;
|
||
|
HRESULT hr = m_ptinstance->Initialize(arg1, arg2, arg3, arg4);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
m_fDeleteInstance = false;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
template <typename TArg1, typename TArg2, typename TArg3, typename TArg4, typename TArg5> HRESULT CreateInstanceWith5Args(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5)
|
||
|
{
|
||
|
if (m_ptinstance != NULL) return E_UNEXPECTED;
|
||
|
m_ptinstance = NEW(CFusionCOMObject<TInstance>);
|
||
|
if (m_ptinstance == NULL) return E_OUTOFMEMORY;
|
||
|
m_fDeleteInstance = true;
|
||
|
HRESULT hr = m_ptinstance->Initialize(arg1, arg2, arg3, arg4, arg5);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
hr = m_ptinstance->QueryInterface(__uuidof(TInterface), (LPVOID *) &m_pt);
|
||
|
if (FAILED(hr)) return hr;
|
||
|
m_fDeleteInstance = false;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
// Call this if you need to clear out objects explicitly e.g. before uninitializing COM.
|
||
|
inline void Release()
|
||
|
{
|
||
|
CSxsPreserveLastError ple;
|
||
|
|
||
|
if (m_fDeleteInstance)
|
||
|
delete m_ptinstance;
|
||
|
CSmartRef<TInterface>::Release();
|
||
|
m_fDeleteInstance = false;
|
||
|
m_ptinstance = NULL;
|
||
|
ple.Restore();
|
||
|
}
|
||
|
|
||
|
inline TInstance *ObjectPtr() const { return m_ptinstance; }
|
||
|
|
||
|
private:
|
||
|
CFusionCOMObject<TInstance> *m_ptinstance;
|
||
|
bool m_fDeleteInstance;
|
||
|
};
|
||
|
|
||
|
|
||
|
#pragma pack(pop)
|
||
|
|
||
|
#endif
|