// 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 #include 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 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 class CComFailCreator { public: static HRESULT WINAPI CreateInstance(void*, REFIID, LPVOID* ppv) { if (ppv == NULL) return E_POINTER; *ppv = NULL; return hr; } }; template 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 > _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 _CComCreatorData { public: static _ATL_CREATORDATA data; }; template _ATL_CREATORDATA _CComCreatorData::data = {Creator::CreateInstance}; struct _ATL_CACHEDATA { DWORD dwOffsetVar; _ATL_CREATORFUNC* pFunc; }; template class _CComCacheData { public: static _ATL_CACHEDATA data; }; template _ATL_CACHEDATA _CComCacheData::data = {dwVar, Creator::CreateInstance}; struct _ATL_CHAINDATA { DWORD_PTR dwOffset; const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)(); }; template class _CComChainData { public: static _ATL_CHAINDATA data; }; template _ATL_CHAINDATA _CComChainData::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(static_cast(static_cast(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 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 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 HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) throw() { return QueryInterface(__uuidof(Q), (void**)pp); } static HRESULT WINAPI CreateInstance(CComObject** pp) throw(); }; template HRESULT WINAPI CComObject::CreateInstance(CComObject** pp) throw() { ATLASSERT(pp != NULL); if (pp == NULL) return E_POINTER; *pp = NULL; HRESULT hRes = E_OUTOFMEMORY; CComObject* p = NULL; ATLTRY(p = new CComObject()) 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 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 //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 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 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::FinalConstruct(); return m_contained.FinalConstruct(); } void FinalRelease() { CComObjectRootEx::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 HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) { return QueryInterface(__uuidof(Q), (void**)pp); } static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject** pp) { ATLASSERT(pp != NULL); HRESULT hRes = E_OUTOFMEMORY; CComAggObject* p = NULL; ATLTRY(p = new CComAggObject(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 m_contained; }; class CComClassFactory : public IClassFactory, public CComObjectRootEx { 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 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 static HRESULT CreateInstance(IUnknown* punkOuter, Q** pp) { return T::_CreatorClass::CreateInstance(punkOuter, __uuidof(Q), (void**) pp); } template 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; iGetFuncDesc(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 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 spTypeInfo; hRes = pTypeLib->GetTypeInfoOfGuid(*m_pguid, &spTypeInfo); if (SUCCEEDED(hRes)) { CComPtr spInfo(spTypeInfo); CComPtr 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 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 typename IDispatchImpl::_tihclass IDispatchImpl::_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__ /////////////////////////////////////////////////////////////////////////////