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.
1051 lines
28 KiB
1051 lines
28 KiB
// This is a part of the Active Template Library.
|
|
// Copyright (C) 1996-2001 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Active Template Library Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Active Template Library product.
|
|
|
|
#ifndef __ATLCOM_H__
|
|
#define __ATLCOM_H__
|
|
|
|
#pragma once
|
|
|
|
#ifndef _ATL_NO_PRAGMA_WARNINGS
|
|
#pragma warning (push)
|
|
#pragma warning(disable: 4702) // unreachable code
|
|
#pragma warning(disable: 4355) // 'this' used in initializer list
|
|
#pragma warning(disable: 4511) // copy constructor could not be generated
|
|
#pragma warning(disable: 4512) // assignment operator could not be generated
|
|
#endif //!_ATL_NO_PRAGMA_WARNINGS
|
|
|
|
#ifndef __cplusplus
|
|
#error ATL requires C++ compilation (use a .cpp suffix)
|
|
#endif
|
|
|
|
#ifndef __ATLBASE_H__
|
|
#error atlcom.h requires atlbase.h to be included first
|
|
#endif
|
|
|
|
//REVIEW: Just to fix VSEE
|
|
#pragma push_macro("min")
|
|
#pragma push_macro("max")
|
|
#undef min
|
|
#undef max
|
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
|
|
|
#pragma pack(push, _ATL_PACKING)
|
|
|
|
EXTERN_C const IID IID_ITargetFrame;
|
|
|
|
#include <atlbase.inl>
|
|
#include <limits.h>
|
|
|
|
namespace ATL
|
|
{
|
|
|
|
#define _ATLDUMPIID(iid, name, hr) hr
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// AtlReportError
|
|
|
|
inline HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID, const IID& iid = GUID_NULL,
|
|
HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
|
|
{
|
|
return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), 0, NULL, iid, hRes, hInst);
|
|
}
|
|
|
|
inline HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID, DWORD dwHelpID,
|
|
LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0,
|
|
HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
|
|
{
|
|
return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), dwHelpID,
|
|
lpszHelpFile, iid, hRes, hInst);
|
|
}
|
|
|
|
inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc,
|
|
const IID& iid = GUID_NULL, HRESULT hRes = 0)
|
|
{
|
|
return AtlSetErrorInfo(clsid, lpszDesc, 0, NULL, iid, hRes, NULL);
|
|
}
|
|
|
|
inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc, DWORD dwHelpID,
|
|
LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
|
|
{
|
|
return AtlSetErrorInfo(clsid, lpszDesc, dwHelpID, lpszHelpFile, iid, hRes, NULL);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COM Objects
|
|
|
|
#define DECLARE_PROTECT_FINAL_CONSTRUCT()\
|
|
void InternalFinalConstructAddRef() {InternalAddRef();}\
|
|
void InternalFinalConstructRelease() {InternalRelease();}
|
|
|
|
template <class T1>
|
|
class CComCreator
|
|
{
|
|
public:
|
|
static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
|
|
{
|
|
ATLASSERT(ppv != NULL);
|
|
if (ppv == NULL)
|
|
return E_POINTER;
|
|
*ppv = NULL;
|
|
|
|
HRESULT hRes = E_OUTOFMEMORY;
|
|
T1* p = NULL;
|
|
ATLTRY(p = new T1(pv))
|
|
if (p != NULL)
|
|
{
|
|
p->SetVoid(pv);
|
|
p->InternalFinalConstructAddRef();
|
|
hRes = p->FinalConstruct();
|
|
if (SUCCEEDED(hRes))
|
|
hRes = p->_AtlFinalConstruct();
|
|
p->InternalFinalConstructRelease();
|
|
if (hRes == S_OK)
|
|
hRes = p->QueryInterface(riid, ppv);
|
|
if (hRes != S_OK)
|
|
delete p;
|
|
}
|
|
return hRes;
|
|
}
|
|
};
|
|
|
|
|
|
template <HRESULT hr>
|
|
class CComFailCreator
|
|
{
|
|
public:
|
|
static HRESULT WINAPI CreateInstance(void*, REFIID, LPVOID* ppv)
|
|
{
|
|
if (ppv == NULL)
|
|
return E_POINTER;
|
|
*ppv = NULL;
|
|
|
|
return hr;
|
|
}
|
|
};
|
|
|
|
template <class T1, class T2>
|
|
class CComCreator2
|
|
{
|
|
public:
|
|
static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
|
|
{
|
|
ATLASSERT(ppv != NULL);
|
|
|
|
return (pv == NULL) ?
|
|
T1::CreateInstance(NULL, riid, ppv) :
|
|
T2::CreateInstance(pv, riid, ppv);
|
|
}
|
|
};
|
|
|
|
#define DECLARE_NOT_AGGREGATABLE(x) public:\
|
|
typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
|
|
#define DECLARE_AGGREGATABLE(x) public:\
|
|
typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass;
|
|
|
|
struct _ATL_CREATORDATA
|
|
{
|
|
_ATL_CREATORFUNC* pFunc;
|
|
};
|
|
|
|
template <class Creator>
|
|
class _CComCreatorData
|
|
{
|
|
public:
|
|
static _ATL_CREATORDATA data;
|
|
};
|
|
|
|
template <class Creator>
|
|
_ATL_CREATORDATA _CComCreatorData<Creator>::data = {Creator::CreateInstance};
|
|
|
|
struct _ATL_CACHEDATA
|
|
{
|
|
DWORD dwOffsetVar;
|
|
_ATL_CREATORFUNC* pFunc;
|
|
};
|
|
|
|
template <class Creator, DWORD dwVar>
|
|
class _CComCacheData
|
|
{
|
|
public:
|
|
static _ATL_CACHEDATA data;
|
|
};
|
|
|
|
template <class Creator, DWORD dwVar>
|
|
_ATL_CACHEDATA _CComCacheData<Creator, dwVar>::data = {dwVar, Creator::CreateInstance};
|
|
|
|
struct _ATL_CHAINDATA
|
|
{
|
|
DWORD_PTR dwOffset;
|
|
const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)();
|
|
};
|
|
|
|
template <class base, class derived>
|
|
class _CComChainData
|
|
{
|
|
public:
|
|
static _ATL_CHAINDATA data;
|
|
};
|
|
|
|
template <class base, class derived>
|
|
_ATL_CHAINDATA _CComChainData<base, derived>::data =
|
|
{offsetofclass(base, derived), base::_GetEntries};
|
|
|
|
|
|
#ifdef _ATL_DEBUG
|
|
#define DEBUG_QI_ENTRY(x) \
|
|
{NULL, \
|
|
(DWORD_PTR)_T(#x), \
|
|
(ATL::_ATL_CREATORARGFUNC*)0},
|
|
#else
|
|
#define DEBUG_QI_ENTRY(x)
|
|
#endif //_ATL_DEBUG
|
|
|
|
#define _ATL_DECLARE_GET_UNKNOWN(x) IUnknown* GetUnknown() throw() {return _GetRawUnknown();}
|
|
|
|
//If you get a message that FinalConstruct is ambiguous then you need to
|
|
// override it in your class and call each base class' version of this
|
|
#define BEGIN_COM_MAP(x) public: \
|
|
typedef x _ComMapClass; \
|
|
static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) throw()\
|
|
{\
|
|
_ComMapClass* p = (_ComMapClass*)pv;\
|
|
p->Lock();\
|
|
HRESULT hRes = ATL::CComObjectRootBase::_Cache(pv, iid, ppvObject, dw);\
|
|
p->Unlock();\
|
|
return hRes;\
|
|
}\
|
|
IUnknown* _GetRawUnknown() throw() \
|
|
{ ATLASSERT(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY); return (IUnknown*)((INT_PTR)this+_GetEntries()->dw); } \
|
|
_ATL_DECLARE_GET_UNKNOWN(x)\
|
|
HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) throw() \
|
|
{ return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); } \
|
|
const static ATL::_ATL_INTMAP_ENTRY* WINAPI _GetEntries() throw() { \
|
|
static const ATL::_ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x)
|
|
|
|
#define DECLARE_GET_CONTROLLING_UNKNOWN() public:\
|
|
virtual IUnknown* GetControllingUnknown() throw() {return GetUnknown();}
|
|
|
|
#define COM_INTERFACE_ENTRY(x)\
|
|
{&_ATL_IIDOF(x), \
|
|
offsetofclass(x, _ComMapClass), \
|
|
_ATL_SIMPLEMAPENTRY},
|
|
|
|
#define COM_INTERFACE_ENTRY2(x, x2)\
|
|
{&_ATL_IIDOF(x),\
|
|
reinterpret_cast<DWORD_PTR>(static_cast<x*>(static_cast<x2*>(reinterpret_cast<_ComMapClass*>(8))))-8,\
|
|
_ATL_SIMPLEMAPENTRY},
|
|
|
|
#define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)\
|
|
{&iid,\
|
|
(DWORD_PTR)offsetof(_ComMapClass, punk),\
|
|
_Delegate},
|
|
|
|
#ifdef _ATL_DEBUG
|
|
#define END_COM_MAP() \
|
|
__if_exists(_GetAttrEntries) {{NULL, (DWORD_PTR)_GetAttrEntries, _ChainAttr }, }\
|
|
{NULL, 0, 0}}; return &_entries[1];} \
|
|
virtual ULONG STDMETHODCALLTYPE AddRef( void) throw() = 0; \
|
|
virtual ULONG STDMETHODCALLTYPE Release( void) throw() = 0; \
|
|
STDMETHOD(QueryInterface)(REFIID, void**) throw() = 0;
|
|
#else
|
|
#define END_COM_MAP() \
|
|
__if_exists(_GetAttrEntries) {{NULL, (DWORD_PTR)_GetAttrEntries, _ChainAttr }, }\
|
|
{NULL, 0, 0}}; return _entries;} \
|
|
virtual ULONG STDMETHODCALLTYPE AddRef( void) throw() = 0; \
|
|
virtual ULONG STDMETHODCALLTYPE Release( void) throw() = 0; \
|
|
STDMETHOD(QueryInterface)(REFIID, void**) throw() = 0;
|
|
#endif // _ATL_DEBUG
|
|
|
|
|
|
#define BEGIN_OBJECT_MAP(x) static ATL::_ATL_OBJMAP_ENTRY x[] = {
|
|
#define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
|
|
#define OBJECT_ENTRY(clsid, class) {&clsid, class::UpdateRegistry, class::_ClassFactoryCreatorClass::CreateInstance, class::_CreatorClass::CreateInstance, NULL, 0, class::GetObjectDescription, class::GetCategoryMap, class::ObjectMain },
|
|
|
|
#ifndef OBJECT_ENTRY_PRAGMA
|
|
|
|
#if defined(_M_IX86)
|
|
#define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:___pobjMap_" #class))
|
|
#elif defined(_M_AMD64) || defined(_M_IA64)
|
|
#define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:__pobjMap_" #class))
|
|
#else
|
|
#error Unknown Platform. define OBJECT_ENTRY_PRAGMA
|
|
#endif
|
|
|
|
#endif //OBJECT_ENTRY_PRAGMA
|
|
|
|
|
|
// the functions in this class don't need to be virtual because
|
|
// they are called from CComObject
|
|
class CComObjectRootBase
|
|
{
|
|
public:
|
|
CComObjectRootBase()
|
|
{
|
|
m_dwRef = 0L;
|
|
}
|
|
HRESULT FinalConstruct()
|
|
{
|
|
return S_OK;
|
|
}
|
|
// For library initialization only
|
|
HRESULT _AtlFinalConstruct()
|
|
{
|
|
return S_OK;
|
|
}
|
|
void FinalRelease() {}
|
|
|
|
//ObjectMain is called during Module::Init and Module::Term
|
|
static void WINAPI ObjectMain(bool /* bStarting */) {}
|
|
|
|
static const struct _ATL_CATMAP_ENTRY* GetCategoryMap() {return NULL;};
|
|
static HRESULT WINAPI InternalQueryInterface(void* pThis,
|
|
const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
|
|
{
|
|
// Only Assert here. AtlInternalQueryInterface will return the correct HRESULT if ppvObject == NULL
|
|
#ifndef _ATL_OLEDB_CONFORMANCE_TESTS
|
|
ATLASSERT(ppvObject != NULL);
|
|
#endif
|
|
ATLASSERT(pThis != NULL);
|
|
// First entry in the com map should be a simple map entry
|
|
ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
|
|
|
|
HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
|
|
return _ATLDUMPIID(iid, pszClassName, hRes);
|
|
}
|
|
|
|
//Outer funcs
|
|
ULONG OuterAddRef()
|
|
{
|
|
return m_pOuterUnknown->AddRef();
|
|
}
|
|
ULONG OuterRelease()
|
|
{
|
|
return m_pOuterUnknown->Release();
|
|
}
|
|
HRESULT OuterQueryInterface(REFIID iid, void ** ppvObject)
|
|
{
|
|
return m_pOuterUnknown->QueryInterface(iid, ppvObject);
|
|
}
|
|
|
|
void SetVoid(void*) {}
|
|
void InternalFinalConstructAddRef() {}
|
|
void InternalFinalConstructRelease()
|
|
{
|
|
ATLASSERT(m_dwRef == 0);
|
|
}
|
|
// If this assert occurs, your object has probably been deleted
|
|
// Try using DECLARE_PROTECT_FINAL_CONSTRUCT()
|
|
|
|
|
|
static HRESULT WINAPI _Delegate(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
|
|
{
|
|
HRESULT hRes = E_NOINTERFACE;
|
|
IUnknown* p = *(IUnknown**)((DWORD_PTR)pv + dw);
|
|
if (p != NULL)
|
|
hRes = p->QueryInterface(iid, ppvObject);
|
|
return hRes;
|
|
}
|
|
static HRESULT WINAPI _ChainAttr(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
|
|
{
|
|
const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)() = (const _ATL_INTMAP_ENTRY* (WINAPI *)())dw;
|
|
const _ATL_INTMAP_ENTRY *pEntries = pFunc();
|
|
if (pEntries == NULL)
|
|
return S_OK;
|
|
return InternalQueryInterface(pv, pEntries, iid, ppvObject);
|
|
}
|
|
static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
|
|
{
|
|
HRESULT hRes = E_NOINTERFACE;
|
|
_ATL_CACHEDATA* pcd = (_ATL_CACHEDATA*)dw;
|
|
IUnknown** pp = (IUnknown**)((DWORD_PTR)pv + pcd->dwOffsetVar);
|
|
if (*pp == NULL)
|
|
hRes = pcd->pFunc(pv, __uuidof(IUnknown), (void**)pp);
|
|
if (*pp != NULL)
|
|
hRes = (*pp)->QueryInterface(iid, ppvObject);
|
|
return hRes;
|
|
}
|
|
|
|
union
|
|
{
|
|
long m_dwRef;
|
|
IUnknown* m_pOuterUnknown;
|
|
};
|
|
};
|
|
|
|
|
|
template <class ThreadModel>
|
|
class CComObjectRootEx : public CComObjectRootBase
|
|
{
|
|
public:
|
|
typedef ThreadModel _ThreadModel;
|
|
typedef typename _ThreadModel::AutoCriticalSection _CritSec;
|
|
|
|
ULONG InternalAddRef()
|
|
{
|
|
ATLASSERT(m_dwRef != -1L);
|
|
return _ThreadModel::Increment(&m_dwRef);
|
|
}
|
|
ULONG InternalRelease()
|
|
{
|
|
#ifdef _DEBUG
|
|
LONG nRef = _ThreadModel::Decrement(&m_dwRef);
|
|
if (nRef < -(LONG_MAX / 2))
|
|
{
|
|
ATLASSERT(0 && _T("Release called on a pointer that has already been released"));
|
|
}
|
|
return nRef;
|
|
#else
|
|
return _ThreadModel::Decrement(&m_dwRef);
|
|
#endif
|
|
}
|
|
|
|
void Lock() {m_critsec.Lock();}
|
|
void Unlock() {m_critsec.Unlock();}
|
|
private:
|
|
_CritSec m_critsec;
|
|
};
|
|
|
|
|
|
// don't let class factory refcount influence lock count
|
|
#define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator< ATL::CComObjectNoLock< cf > > _ClassFactoryCreatorClass;
|
|
|
|
#define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory)
|
|
|
|
#define DECLARE_REGISTRY_RESOURCEID(x)\
|
|
static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()\
|
|
{\
|
|
__if_exists(_GetMiscStatus) \
|
|
{ \
|
|
ATL::_ATL_REGMAP_ENTRY regMapEntries[2]; \
|
|
memset(®MapEntries[1], 0, sizeof(ATL::_ATL_REGMAP_ENTRY)); \
|
|
regMapEntries[0].szKey = L"OLEMISC"; \
|
|
TCHAR szOleMisc[10]; \
|
|
wsprintf(szOleMisc, _T("%d"), _GetMiscStatus()); \
|
|
USES_CONVERSION; \
|
|
regMapEntries[0].szData = szOleMisc; \
|
|
__if_exists(_Module) \
|
|
{ \
|
|
return _Module.UpdateRegistryFromResource(x, bRegister, regMapEntries); \
|
|
} \
|
|
__if_not_exists(_Module) \
|
|
{ \
|
|
return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister, regMapEntries); \
|
|
} \
|
|
} \
|
|
__if_not_exists(_GetMiscStatus) \
|
|
{ \
|
|
__if_exists(_Module) \
|
|
{ \
|
|
return _Module.UpdateRegistryFromResource(x, bRegister); \
|
|
} \
|
|
__if_not_exists(_Module) \
|
|
{ \
|
|
return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister); \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
|
|
//Base is the user's class that derives from CComObjectRoot and whatever
|
|
//interfaces the user wants to support on the object
|
|
template <class Base>
|
|
class CComObject : public Base
|
|
{
|
|
public:
|
|
typedef Base _BaseClass;
|
|
CComObject(void* = NULL) throw()
|
|
{
|
|
_pAtlModule->Lock();
|
|
}
|
|
// Set refcount to -(LONG_MAX/2) to protect destruction and
|
|
// also catch mismatched Release in debug builds
|
|
~CComObject() throw()
|
|
{
|
|
m_dwRef = -(LONG_MAX/2);
|
|
FinalRelease();
|
|
_pAtlModule->Unlock();
|
|
}
|
|
//If InternalAddRef or InternalRelease is undefined then your class
|
|
//doesn't derive from CComObjectRoot
|
|
STDMETHOD_(ULONG, AddRef)() throw() {return InternalAddRef();}
|
|
STDMETHOD_(ULONG, Release)() throw()
|
|
{
|
|
ULONG l = InternalRelease();
|
|
if (l == 0)
|
|
delete this;
|
|
return l;
|
|
}
|
|
//if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
|
|
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw()
|
|
{return _InternalQueryInterface(iid, ppvObject);}
|
|
template <class Q>
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) throw()
|
|
{
|
|
return QueryInterface(__uuidof(Q), (void**)pp);
|
|
}
|
|
|
|
static HRESULT WINAPI CreateInstance(CComObject<Base>** pp) throw();
|
|
};
|
|
|
|
template <class Base>
|
|
HRESULT WINAPI CComObject<Base>::CreateInstance(CComObject<Base>** pp) throw()
|
|
{
|
|
ATLASSERT(pp != NULL);
|
|
if (pp == NULL)
|
|
return E_POINTER;
|
|
*pp = NULL;
|
|
|
|
HRESULT hRes = E_OUTOFMEMORY;
|
|
CComObject<Base>* p = NULL;
|
|
ATLTRY(p = new CComObject<Base>())
|
|
if (p != NULL)
|
|
{
|
|
p->SetVoid(NULL);
|
|
p->InternalFinalConstructAddRef();
|
|
hRes = p->FinalConstruct();
|
|
if (SUCCEEDED(hRes))
|
|
hRes = p->_AtlFinalConstruct();
|
|
p->InternalFinalConstructRelease();
|
|
if (hRes != S_OK)
|
|
{
|
|
delete p;
|
|
p = NULL;
|
|
}
|
|
}
|
|
*pp = p;
|
|
return hRes;
|
|
}
|
|
|
|
|
|
//Base is the user's class that derives from CComObjectRoot and whatever
|
|
//interfaces the user wants to support on the object
|
|
template <class Base>
|
|
class CComObjectNoLock : public Base
|
|
{
|
|
public:
|
|
typedef Base _BaseClass;
|
|
CComObjectNoLock(void* = NULL){}
|
|
// Set refcount to -(LONG_MAX/2) to protect destruction and
|
|
// also catch mismatched Release in debug builds
|
|
~CComObjectNoLock()
|
|
{
|
|
m_dwRef = -(LONG_MAX/2);
|
|
FinalRelease();
|
|
}
|
|
|
|
//If InternalAddRef or InternalRelease is undefined then your class
|
|
//doesn't derive from CComObjectRoot
|
|
STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
|
|
STDMETHOD_(ULONG, Release)()
|
|
{
|
|
ULONG l = InternalRelease();
|
|
if (l == 0)
|
|
delete this;
|
|
return l;
|
|
}
|
|
//if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
|
|
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
|
|
{return _InternalQueryInterface(iid, ppvObject);}
|
|
};
|
|
|
|
|
|
template <class Base> //Base must be derived from CComObjectRoot
|
|
class CComContainedObject : public Base
|
|
{
|
|
public:
|
|
typedef Base _BaseClass;
|
|
CComContainedObject(void* pv) {m_pOuterUnknown = (IUnknown*)pv;}
|
|
|
|
STDMETHOD_(ULONG, AddRef)() {return OuterAddRef();}
|
|
STDMETHOD_(ULONG, Release)() {return OuterRelease();}
|
|
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
|
|
{
|
|
return OuterQueryInterface(iid, ppvObject);
|
|
}
|
|
template <class Q>
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
|
|
{
|
|
return QueryInterface(__uuidof(Q), (void**)pp);
|
|
}
|
|
//GetControllingUnknown may be virtual if the Base class has declared
|
|
//DECLARE_GET_CONTROLLING_UNKNOWN()
|
|
IUnknown* GetControllingUnknown()
|
|
{
|
|
return m_pOuterUnknown;
|
|
}
|
|
};
|
|
|
|
//contained is the user's class that derives from CComObjectRoot and whatever
|
|
//interfaces the user wants to support on the object
|
|
template <class contained>
|
|
class CComAggObject :
|
|
public IUnknown,
|
|
public CComObjectRootEx< typename contained::_ThreadModel::ThreadModelNoCS >
|
|
{
|
|
public:
|
|
typedef contained _BaseClass;
|
|
CComAggObject(void* pv) : m_contained(pv)
|
|
{
|
|
_pAtlModule->Lock();
|
|
}
|
|
//If you get a message that this call is ambiguous then you need to
|
|
// override it in your class and call each base class' version of this
|
|
HRESULT FinalConstruct()
|
|
{
|
|
CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
|
|
return m_contained.FinalConstruct();
|
|
}
|
|
void FinalRelease()
|
|
{
|
|
CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
|
|
m_contained.FinalRelease();
|
|
}
|
|
// Set refcount to -(LONG_MAX/2) to protect destruction and
|
|
// also catch mismatched Release in debug builds
|
|
~CComAggObject()
|
|
{
|
|
m_dwRef = -(LONG_MAX/2);
|
|
FinalRelease();
|
|
_pAtlModule->Unlock();
|
|
}
|
|
|
|
STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
|
|
STDMETHOD_(ULONG, Release)()
|
|
{
|
|
ULONG l = InternalRelease();
|
|
if (l == 0)
|
|
delete this;
|
|
return l;
|
|
}
|
|
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
|
|
{
|
|
ATLASSERT(ppvObject != NULL);
|
|
if (ppvObject == NULL)
|
|
return E_POINTER;
|
|
*ppvObject = NULL;
|
|
|
|
HRESULT hRes = S_OK;
|
|
if (InlineIsEqualUnknown(iid))
|
|
{
|
|
*ppvObject = (void*)(IUnknown*)this;
|
|
AddRef();
|
|
}
|
|
else
|
|
hRes = m_contained._InternalQueryInterface(iid, ppvObject);
|
|
return hRes;
|
|
}
|
|
template <class Q>
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
|
|
{
|
|
return QueryInterface(__uuidof(Q), (void**)pp);
|
|
}
|
|
static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject<contained>** pp)
|
|
{
|
|
ATLASSERT(pp != NULL);
|
|
HRESULT hRes = E_OUTOFMEMORY;
|
|
CComAggObject<contained>* p = NULL;
|
|
ATLTRY(p = new CComAggObject<contained>(pUnkOuter))
|
|
if (p != NULL)
|
|
{
|
|
p->SetVoid(NULL);
|
|
p->InternalFinalConstructAddRef();
|
|
hRes = p->FinalConstruct();
|
|
if (SUCCEEDED(hRes))
|
|
hRes = p->_AtlFinalConstruct();
|
|
p->InternalFinalConstructRelease();
|
|
if (hRes != S_OK)
|
|
{
|
|
delete p;
|
|
p = NULL;
|
|
}
|
|
}
|
|
*pp = p;
|
|
return hRes;
|
|
}
|
|
|
|
CComContainedObject<contained> m_contained;
|
|
};
|
|
|
|
|
|
class CComClassFactory :
|
|
public IClassFactory,
|
|
public CComObjectRootEx<CComGlobalsThreadModel>
|
|
{
|
|
public:
|
|
BEGIN_COM_MAP(CComClassFactory)
|
|
COM_INTERFACE_ENTRY(IClassFactory)
|
|
END_COM_MAP()
|
|
|
|
// IClassFactory
|
|
STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
|
|
{
|
|
ATLASSERT(m_pfnCreateInstance != NULL);
|
|
HRESULT hRes = E_POINTER;
|
|
if (ppvObj != NULL)
|
|
{
|
|
*ppvObj = NULL;
|
|
// can't ask for anything other than IUnknown when aggregating
|
|
|
|
if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
|
|
{
|
|
hRes = CLASS_E_NOAGGREGATION;
|
|
}
|
|
else
|
|
hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
STDMETHOD(LockServer)(BOOL fLock)
|
|
{
|
|
if (fLock)
|
|
_pAtlModule->Lock();
|
|
else
|
|
_pAtlModule->Unlock();
|
|
return S_OK;
|
|
}
|
|
// helper
|
|
void SetVoid(void* pv)
|
|
{
|
|
m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
|
|
}
|
|
_ATL_CREATORFUNC* m_pfnCreateInstance;
|
|
};
|
|
|
|
|
|
template <class T, const CLSID* pclsid = &CLSID_NULL>
|
|
class CComCoClass
|
|
{
|
|
public:
|
|
DECLARE_CLASSFACTORY()
|
|
DECLARE_AGGREGATABLE(T)
|
|
typedef T _CoClass;
|
|
static const CLSID& WINAPI GetObjectCLSID() {return *pclsid;}
|
|
static LPCTSTR WINAPI GetObjectDescription() {return NULL;}
|
|
static HRESULT WINAPI Error(LPCOLESTR lpszDesc,
|
|
const IID& iid = GUID_NULL, HRESULT hRes = 0)
|
|
{
|
|
return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes);
|
|
}
|
|
static HRESULT WINAPI Error(LPCOLESTR lpszDesc, DWORD dwHelpID,
|
|
LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
|
|
{
|
|
return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID, lpszHelpFile,
|
|
iid, hRes);
|
|
}
|
|
static HRESULT WINAPI Error(UINT nID, const IID& iid = GUID_NULL,
|
|
HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
|
|
{
|
|
return AtlReportError(GetObjectCLSID(), nID, iid, hRes, hInst);
|
|
}
|
|
static HRESULT WINAPI Error(UINT nID, DWORD dwHelpID,
|
|
LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
|
|
HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
|
|
{
|
|
return AtlReportError(GetObjectCLSID(), nID, dwHelpID, lpszHelpFile,
|
|
iid, hRes, hInst);
|
|
}
|
|
static HRESULT WINAPI Error(LPCSTR lpszDesc,
|
|
const IID& iid = GUID_NULL, HRESULT hRes = 0)
|
|
{
|
|
return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes);
|
|
}
|
|
static HRESULT WINAPI Error(LPCSTR lpszDesc, DWORD dwHelpID,
|
|
LPCSTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
|
|
{
|
|
return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID,
|
|
lpszHelpFile, iid, hRes);
|
|
}
|
|
template <class Q>
|
|
static HRESULT CreateInstance(IUnknown* punkOuter, Q** pp)
|
|
{
|
|
return T::_CreatorClass::CreateInstance(punkOuter, __uuidof(Q), (void**) pp);
|
|
}
|
|
template <class Q>
|
|
static HRESULT CreateInstance(Q** pp)
|
|
{
|
|
return T::_CreatorClass::CreateInstance(NULL, __uuidof(Q), (void**) pp);
|
|
}
|
|
};
|
|
|
|
// ATL doesn't support multiple LCID's at the same time
|
|
// Whatever LCID is queried for first is the one that is used.
|
|
class CComTypeInfoHolder
|
|
{
|
|
// Should be 'protected' but can cause compiler to generate fat code.
|
|
public:
|
|
const GUID* m_pguid;
|
|
const GUID* m_plibid;
|
|
WORD m_wMajor;
|
|
WORD m_wMinor;
|
|
|
|
ITypeInfo* m_pInfo;
|
|
long m_dwRef;
|
|
struct stringdispid
|
|
{
|
|
CComBSTR bstr;
|
|
int nLen;
|
|
DISPID id;
|
|
};
|
|
stringdispid* m_pMap;
|
|
int m_nCount;
|
|
|
|
public:
|
|
|
|
HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
|
|
{
|
|
ATLASSERT(ppInfo != NULL);
|
|
if (ppInfo == NULL)
|
|
return E_POINTER;
|
|
|
|
HRESULT hr = S_OK;
|
|
if (m_pInfo == NULL)
|
|
hr = GetTI(lcid);
|
|
*ppInfo = m_pInfo;
|
|
if (m_pInfo != NULL)
|
|
{
|
|
m_pInfo->AddRef();
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
HRESULT GetTI(LCID lcid);
|
|
HRESULT EnsureTI(LCID lcid)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (m_pInfo == NULL || m_pMap == NULL)
|
|
hr = GetTI(lcid);
|
|
return hr;
|
|
}
|
|
|
|
// This function is called by the module on exit
|
|
// It is registered through _pAtlModule->AddTermFunc()
|
|
static void __stdcall Cleanup(DWORD_PTR dw)
|
|
{
|
|
CComTypeInfoHolder* p = (CComTypeInfoHolder*) dw;
|
|
if (p->m_pInfo != NULL)
|
|
p->m_pInfo->Release();
|
|
p->m_pInfo = NULL;
|
|
delete [] p->m_pMap;
|
|
p->m_pMap = NULL;
|
|
}
|
|
|
|
HRESULT GetTypeInfo(UINT /* itinfo */, LCID lcid, ITypeInfo** pptinfo)
|
|
{
|
|
HRESULT hRes = E_POINTER;
|
|
if (pptinfo != NULL)
|
|
hRes = GetTI(lcid, pptinfo);
|
|
return hRes;
|
|
}
|
|
HRESULT GetIDsOfNames(REFIID /* riid */, LPOLESTR* rgszNames, UINT cNames,
|
|
LCID lcid, DISPID* rgdispid)
|
|
{
|
|
HRESULT hRes = EnsureTI(lcid);
|
|
if (m_pInfo != NULL)
|
|
{
|
|
if (m_pMap != NULL)
|
|
{
|
|
for (int i=0; i<(int)cNames; i++)
|
|
{
|
|
int n = int( lstrlenW(rgszNames[i]) );
|
|
int j;
|
|
for (j=m_nCount-1; j>=0; j--)
|
|
{
|
|
if ((n == m_pMap[j].nLen) &&
|
|
(memcmp(m_pMap[j].bstr, rgszNames[i], m_pMap[j].nLen * sizeof(OLECHAR)) == 0))
|
|
{
|
|
rgdispid[i] = m_pMap[j].id;
|
|
break;
|
|
}
|
|
}
|
|
// if name is not in cache, delegate to ITypeInfo::GetIDsOfNames
|
|
if (j < 0)
|
|
{
|
|
hRes = m_pInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
|
|
// since we've gotten all names, break out of loop
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
hRes = m_pInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID /* riid */,
|
|
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
|
|
EXCEPINFO* pexcepinfo, UINT* puArgErr)
|
|
{
|
|
HRESULT hRes = EnsureTI(lcid);
|
|
if (m_pInfo != NULL)
|
|
hRes = m_pInfo->Invoke(p, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
|
|
return hRes;
|
|
}
|
|
HRESULT LoadNameCache(ITypeInfo* pTypeInfo)
|
|
{
|
|
TYPEATTR* pta;
|
|
HRESULT hr = pTypeInfo->GetTypeAttr(&pta);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_nCount = pta->cFuncs;
|
|
m_pMap = NULL;
|
|
if (m_nCount != 0)
|
|
{
|
|
ATLTRY(m_pMap = new stringdispid[m_nCount]);
|
|
if (m_pMap == NULL)
|
|
{
|
|
pTypeInfo->ReleaseTypeAttr(pta);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
for (int i=0; i<m_nCount; i++)
|
|
{
|
|
FUNCDESC* pfd;
|
|
if (SUCCEEDED(pTypeInfo->GetFuncDesc(i, &pfd)))
|
|
{
|
|
CComBSTR bstrName;
|
|
if (SUCCEEDED(pTypeInfo->GetDocumentation(pfd->memid, &bstrName, NULL, NULL, NULL)))
|
|
{
|
|
m_pMap[i].bstr.Attach(bstrName.Detach());
|
|
m_pMap[i].nLen = SysStringLen(m_pMap[i].bstr);
|
|
m_pMap[i].id = pfd->memid;
|
|
}
|
|
pTypeInfo->ReleaseFuncDesc(pfd);
|
|
}
|
|
}
|
|
pTypeInfo->ReleaseTypeAttr(pta);
|
|
}
|
|
return S_OK;
|
|
}
|
|
};
|
|
|
|
|
|
inline HRESULT CComTypeInfoHolder::GetTI(LCID lcid)
|
|
{
|
|
//If this assert occurs then most likely didn't initialize properly
|
|
ATLASSERT(m_plibid != NULL && m_pguid != NULL);
|
|
ATLASSERT(!InlineIsEqualGUID(*m_plibid, GUID_NULL) && "Did you forget to pass the LIBID to CComModule::Init?");
|
|
|
|
if (m_pInfo != NULL && m_pMap != NULL)
|
|
return S_OK;
|
|
|
|
CComCritSecLock<CComCriticalSection> lock(_pAtlModule->m_csStaticDataInitAndTypeInfo, false);
|
|
HRESULT hRes = lock.Lock();
|
|
if (FAILED(hRes))
|
|
{
|
|
ATLASSERT(0);
|
|
return hRes;
|
|
}
|
|
hRes = E_FAIL;
|
|
if (m_pInfo == NULL)
|
|
{
|
|
ITypeLib* pTypeLib;
|
|
hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
CComPtr<ITypeInfo> spTypeInfo;
|
|
hRes = pTypeLib->GetTypeInfoOfGuid(*m_pguid, &spTypeInfo);
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
CComPtr<ITypeInfo> spInfo(spTypeInfo);
|
|
CComPtr<ITypeInfo2> spTypeInfo2;
|
|
if (SUCCEEDED(spTypeInfo->QueryInterface(&spTypeInfo2)))
|
|
spInfo = spTypeInfo2;
|
|
|
|
m_pInfo = spInfo.Detach();
|
|
}
|
|
pTypeLib->Release();
|
|
_pAtlModule->AddTermFunc(Cleanup, (DWORD_PTR)this);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Another thread has loaded the typeinfo so we're OK.
|
|
hRes = S_OK;
|
|
}
|
|
|
|
if (m_pInfo != NULL && m_pMap == NULL)
|
|
LoadNameCache(m_pInfo);
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
#ifndef _ATL_MAX_VARTYPES
|
|
#define _ATL_MAX_VARTYPES 8
|
|
#endif
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IDispatchImpl
|
|
|
|
template <class T, const IID* piid = &__uuidof(T), const GUID* plibid = &CAtlModule::m_libid, WORD wMajor = 1,
|
|
WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
|
|
class ATL_NO_VTABLE IDispatchImpl : public T
|
|
{
|
|
public:
|
|
typedef tihclass _tihclass;
|
|
// IDispatch
|
|
STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
|
|
{
|
|
*pctinfo = 1;
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
|
|
{
|
|
return _tih.GetTypeInfo(itinfo, lcid, pptinfo);
|
|
}
|
|
STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
|
|
LCID lcid, DISPID* rgdispid)
|
|
{
|
|
return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
}
|
|
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
|
|
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
|
|
EXCEPINFO* pexcepinfo, UINT* puArgErr)
|
|
{
|
|
return _tih.Invoke((IDispatch*)this, dispidMember, riid, lcid,
|
|
wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
|
|
}
|
|
|
|
|
|
protected:
|
|
static _tihclass _tih;
|
|
static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
|
|
{
|
|
return _tih.GetTI(lcid, ppInfo);
|
|
}
|
|
|
|
};
|
|
|
|
template <class T, const IID* piid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
|
|
typename IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tihclass
|
|
IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tih =
|
|
{piid, plibid, wMajor, wMinor, NULL, 0, NULL, 0};
|
|
|
|
|
|
#pragma pack(pop)
|
|
|
|
}; //namespace ATL
|
|
|
|
//REVIEW: Just to fix VSEE
|
|
#pragma pop_macro("min")
|
|
#pragma pop_macro("max")
|
|
|
|
#ifndef _ATL_NO_PRAGMA_WARNINGS
|
|
#pragma warning (pop)
|
|
#endif
|
|
|
|
#endif // __ATLCOM_H__
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|