#ifndef __BxComExt
#define __BxComExt
//***********************************************
// Author: Kjell Tangen (kjarild@hotmail.com)
// Filename: BxComExt.h
// Part of: Outbacks of COM
// Copyright (C) Kjell Tangen, 1998-2009
// http://www.codeproject.com/kb/atl/idispatchimplex.aspx/
// Current Version: 4.02 Date: 2009-01-24
//-----------------------------------------------
// Description:
// This file contains implementation classes for COM
// CComTypeInfoHolderEx - Extends ATL::CComTypeInfoHolder for typeinfo-driven multi interface dispatch
// IDispatchImplEx - Replaces ATL::IDispatchImpl
// PureDispatchImpl - Used to implement a pure IDispatch interface that does typeinfo-driven
// multi-interface dispatch
// CComClonableBase - Base class for clonable COM objects
//
// The implementation uses ATL and STL.
// This file should be included right after the ATL-includes
// (normally in stdafx.h)
//
//-----------------------------------------------
// Created: 1998-03-06
// 1.0 1998-05-07
// 2.0 1998-11-19: Converted to ATL 3.0
// 3.0 1999-07-10: Uses IProvideClassInfo if implemented.
// If typeinfo lookup of the CLSID fails (e.g. if the
// class and interface are defined in different typelibs
// the correct type library for the class will be inquired.
// 3.1 1999-11-18: Fixed a bug in CComTypeInfoHolderEx::Invoke when invoking a method on a referenced interface
// Now also uses IProvideClassInfo2 if IProvideClassInfo is not implemented
// 3.11 1999-12-10: Fixed a bug in CComTypeInfoHolderEx::_FindTIByReg which was present
// in Unicode builds.
// 3.12 2000-01-06: CComTypeInfoHolderEx no longer uses the critical section of the module,
// instead, it uses a private critical section.
// 3.13 2000-11-27: Fixed concurrency problem
// 3.14 2002-03-20: Fixed duplicate comdat problem related to IDispatchImplEx
// 4.0 2002-11-14: Support for implementation of a pure IDispatch implementation, added the PureDispatchImpl
// template. Has been tested with ATL 7.
// 4.01 2003-02-20: Fixed a bug related to dispatching on type libraries with version no. wMajor.wMinor > 1.0
// 4.02 2009-01-24: Changed from using _stprintf to _stprintf_s in line 306
//***********************************************
#pragma warning( disable : 4786) // identifier truncated to 255 chars
#include <utility>
#include <vector>
#include <map>
// Required by STL:
bool operator < (const GUID g1, const GUID g2);
#ifndef _stdDispIdBase // Override this to have another default
#define _stdDispIdBase -0x10F0
#endif
//***************************************************************************
// Class CComTypeInfoHolderEx
// Kjell Tangen, 1998-2009 (kjarild@hotmail.com)
//
// CComTypeInfoHolderEx is used by the IDispatchImplEx and PureDispatchImpl template classes to access
// the object's type information in order to support dispatch clients.
// These classes use type info to dispatch to any ole automation compatible
// interface on the class (declared with dual or oleautomation IDL directives).
// If you have an ATL-based implementation,
// use the IDispatchImplEx class instead of the standard ATL::IDispatchImpl
// class if your COM-class has multiple dual interfaces and you want your
// class to be scriptable. CComTypeInfoHolderEx will search through the type
// info on each of the interfaces on the class and try to bind to the
// dispatch member requested by the client.
// Even if your implementation is not based on ATL, this class can be used by
// your dual interface implementation, just look in the IDispatchImplEx
// class for details on how to use it.
// If the type info for an interface is in another type library than the class
// implementing it, the class should implement the IProvideClassInfo interface.
// Using ATL, this can be done using the IProvideClassInfo2Impl template.
//
// Alternatively, if you don't want to use dual interfaces and want to have a single IDispatch
// interface on your object, you may use PureDispatchImpl to implement the single IDispatch interface
// that dispatches on multiple oleautomation-compatiple IUnknown-derived interfaces.
// This template also uses CComTypeInfoHolderEx to walk through type information when dispatching.
// Therefore PureDispatchImpl has basically the same capabilities as IDispatchImplEx. Note that it is
// not possible to mix both templates in the same class definition. This is by design. PureDispatchImpl
// has been designed for use when a class supports no dual interfaces. If one or more dual interfaces
// are implemented, then IDispatchImplEx must be used.
//
// New in version 4.0:
// -------------------
// Added the PureDispatchImpl template. This template reuses the CComTypeInfoHolderEx template
// and therefore has the same functionality as IDispatchImplEx. However, it can be used to support
// designs where no dual interfaces are used, and instead the class has a single IDispatch interface and
// one or more IUnknown-derived, oleautomation-compatible interfaces.
//
// New in version 3.0:
// -------------------
// CComTypeInfoHolderEx now supports multi interface dispatch in cases where a
// class implements interfaces defined by other another type library than the
// module the class belongs to. Requirements for multiinterface dispatch to work
// in this more general case are:
// * The class implements IProvideClassInfo
// or
// * The class has a registered type library, i.e. a "TypeLib" subkey in the
// registry with a REG_SZ value equal to the LIBID of the module which the class belongs to
//
// Intented usage:
// ---------------
// If you have an ATL-based COM implementation, you will not use
// CComTypeInfoHolderEx directly. Instead you will just implement your dual interfaces
// by deriving your class from IDispatchImplEx instead of IDispatchImpl:
// class ATL_NO_VTABLE CMyClass :
// public IProvideClassInfo2Impl<&CLSID_MyClass,&GUID_NULL, &LIBID_MyModule>,
// public IDispatchImplEx<IMyInterface, &IID_IMyInterface, &CLSID_MyClass, &LIBID_MyModule>,
//
// If the interface is defined in an imported type library, this will still work:
// class ATL_NO_VTABLE CMyClass :
// public IProvideClassInfo2Impl<&CLSID_MyClass,&GUID_NULL, &LIBID_MyModule>,
// public IDispatchImplEx<IMyInterface, &IID_IMyInterface, &CLSID_MyClass, &LIBID_ImportedLib>,
//
// If your class supports events, replace GUID_NULL with the IID of your event interface in the
// IProvideClassInfo2Impl template
//***************************************************************************
/* Example:
IDL:
----
importlib("ImportedLib.tlb"); // Interface IC is defined here
interface IA : IDispatch
{
HRESULT MethodOnIA();
}:
interface IB : IDispatch
{
HRESULT MethodOnIB();
};
interface IPure1 : IUnknown
{
HRESULT DispMe();
};
interface IPure2 : IUnknown
{
HRESULT DispMeAgain();
};
coclass MyClass
{
[default] interface IA;
interface IB;
interface IC; // Defined in ImportedLib.tlb
};
coclass MyClassWithNoDuals
{
[default] interface IPure1;
interface IPure2;
interface ID; // Defined in ImportedLib.tlb
};
C++ implementations:
---------------------
class ATL_NO_VTABLE CMyClass :
public CComObjectRootEx<CComSingleThreadModel>,
public IProvideClassInfo2Impl<&CLSID_MyClass,&GUID_NULL, &LIBID_MyLib>,
public IDispatchImplEx<IA, &IID_IA, &CLSID_MyClass, &LIBID_MyLib>,
public IDispatchImplEx<IB, &IID_IB, &CLSID_MyClass, &LIBID_MyLib>,
public IDispatchImplEx<IC, &IID_IC, &CLSID_MyClass, &LIBID_ImportedLib>,
public CComCoClass<CMyClass, &CLSID_MyClass>,
public ISupportErrorInfo
{
..standard ATL implementation
class ATL_NO_VTABLE CMyClassWithNoDuals :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyClassWithNoDuals, &CLSID_MyClassWithNoDuals>,
public PureDispatchImpl<&CLSID_MyClassWithNoDuals, &LIBID_MyLib>,
public IPure1,
public IPure2,
public ID,
public ISupportErrorInfo,
{
..standard ATL implementation
BEGIN_COM_MAP(CMyClassWithNoDuals)
COM_INTERFACE_ENTRY(IPure1)
COM_INTERFACE_ENTRY(IPure2)
COM_INTERFACE_ENTRY(ID)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
END_COM_MAP()
...
VB script client:
-----------------
Dim instanceOfMyClass
... got instanceOfMyClass from somewhere
' Regardless of which interface I got hold of,
' I can script towards all methods on the class:
instanceOfMyClass.MethodOnIA
instanceOfMyClass.MethodOnIB
instanceOfMyClass.MethodOnIC
Dim instanceOfMyClassWithNoDuals
... got instanceOfMyClassWithNoDuals from somewhere
' Regardless of which interface I got hold of,
' I can script towards all methods on the class:
instanceOfMyClassWithNoDuals.DispMe
instanceOfMyClassWithNoDuals.DispMeAgain
instanceOfMyClassWithNoDuals.MethodOnID
*/
template<const IID* piid, const CLSID* pclsid, const GUID* plibid, long DispIdBase=_stdDispIdBase,WORD wMajor = 1,WORD wMinor = 0>
class CComTypeInfoHolderEx
: public CComTypeInfoHolder
{
typedef std::pair<long, IID> _dispidEntry;
typedef std::pair<_dispidEntry, HREFTYPE> _typeinfoEntry;
typedef std::vector<_typeinfoEntry> _idispidContainer;
typedef std::map< _dispidEntry, long> _cdispidContainer;
typedef _cdispidContainer::value_type _cdispValue;
typedef _idispidContainer::value_type _idispValue;
long m_nextIdx;
_idispidContainer m_idispCont; // Contains Interface-specific dispids
_cdispidContainer m_cdispCont; // Maps pairs of IID+dispid to class-specific dispids
const GUID* m_pclsid;
//static CComAutoCriticalSection m_csec;
static CComAutoCriticalSection& _GetCSEC()
{
static CComAutoCriticalSection csec;
return csec;
}
public:
CComTypeInfoHolderEx(const IID* pIID = piid, const CLSID* pCLSID = pclsid, const GUID* pLIBID = plibid)
: m_idispCont()
{
m_nextIdx = 0;
m_pguid = pIID;
m_pclsid = pCLSID;
m_plibid = pLIBID;
m_wMajor = wMajor;// 1;
m_wMinor = wMinor;// 0;
m_pInfo = NULL;
m_dwRef = 0;
}
long GetCDIDFromIdx(long idx) {return (DispIdBase + idx);}
long GetIdxFromCDID(long cdid){return (cdid - DispIdBase);}
long AddEntry(long lDID, IID, HREFTYPE hrt = 0);
long GetDIDFromIdx(long idx){return m_idispCont[idx].first.first;}
IID& GetIIDFromIdx(long idx) {return m_idispCont[idx].first.second;}
HREFTYPE GetHREFTYPEFromIdx(long idx) {return m_idispCont[idx].second;}
HRESULT _FindName(ITypeInfo* pInfo, LPOLESTR* rgszNames, UINT cNames, DISPID* rgdispid);
HRESULT _FindNameByReg(LPOLESTR* rgszNames, UINT cNames, DISPID* rgdispid);
HRESULT _FindTIByReg(ITypeInfo** ppifTI);
HRESULT _GetIProvideClassInfo(IUnknown* pifUnk, IProvideClassInfo** ppifCI)
{
HRESULT hr;
*ppifCI = NULL;
hr = pifUnk->QueryInterface(IID_IProvideClassInfo, (void**)ppifCI);
if(FAILED(hr))
{
hr = pifUnk->QueryInterface(IID_IProvideClassInfo2, (void**)ppifCI);
}
return hr;
}
HRESULT GetIDsOfNames(IDispatch* pDisp, REFIID riid, LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgdispid);
HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr);
};
/*template<const IID* piid, const CLSID* pclsid, const GUID* plibid, long DispIdBase>
CComAutoCriticalSection CComTypeInfoHolderEx<piid,pclsid,plibid,DispIdBase>::m_csec;*/
template<const IID* piid, const CLSID* pclsid, const GUID* plibid, long DispIdBase, WORD wMajor, WORD wMinor>
inline long CComTypeInfoHolderEx<piid,pclsid,plibid,DispIdBase,wMajor,wMinor>::AddEntry(long lDID, IID riid, HREFTYPE hrt)
{
long lNewId;
_dispidEntry e(lDID,riid);
_typeinfoEntry ti(e, hrt);
lNewId = m_nextIdx;
// Check if the entry exist
_cdispidContainer::iterator iter = m_cdispCont.find(e);
if(iter != m_cdispCont.end())
{
lNewId = (*iter).second;
}
else
{
m_idispCont.insert(m_idispCont.end(), ti);
m_cdispCont.insert(_cdispValue(e,lNewId));
InterlockedIncrement(&m_nextIdx);
}
return lNewId;
}
template<const IID* piid, const CLSID* pclsid, const GUID* plibid, long DispIdBase, WORD wMajor, WORD wMinor>
inline HRESULT CComTypeInfoHolderEx<piid,pclsid,plibid,DispIdBase,wMajor,wMinor>::_FindTIByReg(ITypeInfo** ppifTI)
{
HRESULT hRes;
// Search for the type library registered for the class
LPOLESTR psClass = NULL;
*ppifTI = NULL;
hRes = StringFromCLSID(*pclsid,&psClass);
if(SUCCEEDED(hRes))
{
TCHAR sRegKey[64];
USES_CONVERSION;
_stprintf_s(sRegKey,64,_T("CLSID\\%s\\TypeLib"), OLE2T(psClass));
HKEY hKey;
hRes = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, sRegKey,0, KEY_READ, &hKey);
if(hRes == ERROR_SUCCESS)
{
TCHAR sLibId[40];
DWORD dwSize = 40 * sizeof(TCHAR); // Buffersize, not number of characters!
DWORD dwType = REG_SZ;
hRes = ::RegQueryValueEx(hKey, _T(""), NULL, &dwType, (LPBYTE)sLibId, &dwSize);
if(SUCCEEDED(hRes))
{
GUID libid;
hRes = ::CLSIDFromString(T2OLE(sLibId),&libid);
if(SUCCEEDED(hRes))
{
ITypeLib* pTypeLib;
// I know, I know - this is a hack, but it will work in most cases.
// If it doesn't, tough luck. We have gone far enough!
// If it fails here, you should try implementing IProvideClassInfo
// on your class.
hRes = LoadRegTypeLib(libid, m_wMajor, m_wMinor, LOCALE_USER_DEFAULT, &pTypeLib);
if (SUCCEEDED(hRes))
{
hRes = pTypeLib->GetTypeInfoOfGuid(*pclsid, ppifTI);
pTypeLib->Release();
}
}
}
::RegCloseKey(hKey);
}
CoTaskMemFree(psClass);
}
return hRes;
}
template<const IID* piid, const CLSID* pclsid, const GUID* plibid, long DispIdBase, WORD wMajor, WORD wMinor>
inline HRESULT CComTypeInfoHolderEx<piid,pclsid,plibid,DispIdBase,wMajor,wMinor>::_FindNameByReg(LPOLESTR* rgszNames, UINT cNames, DISPID* rgdispid)
{
HRESULT hRes;
// Search for the type library registered for the class
ITypeInfo* pTypeInfo = NULL;
hRes = _FindTIByReg(&pTypeInfo);
if (SUCCEEDED(hRes))
{
hRes = _FindName(pTypeInfo, rgszNames, cNames, rgdispid);
pTypeInfo->Release();
}
return hRes;
}
template<const IID* piid, const CLSID* pclsid, const GUID* plibid, long DispIdBase, WORD wMajor, WORD wMinor>
inline HRESULT CComTypeInfoHolderEx<piid,pclsid,plibid,DispIdBase,wMajor,wMinor>::_FindName(ITypeInfo* pClassTI, LPOLESTR* rgszNames, UINT cNames, DISPID* rgdispid)
{
HRESULT hRes;
// Search through the class type info
TYPEATTR* pTAttr = NULL;
hRes = pClassTI->GetTypeAttr(&pTAttr);
if(SUCCEEDED(hRes) && pTAttr != NULL)
{
HREFTYPE hRefType;
unsigned int i;
bool bComplete = false;
for(i = 0; !bComplete && i < pTAttr->cImplTypes; ++i)
{
hRes = pClassTI->GetRefTypeOfImplType(i,&hRefType);
if(SUCCEEDED(hRes))
{
ITypeInfo* pifTypeInfo2;
hRes = pClassTI->GetRefTypeInfo(hRefType, &pifTypeInfo2);
if(SUCCEEDED(hRes) && pifTypeInfo2 != NULL)
{
long lDispId;
hRes = pifTypeInfo2->GetIDsOfNames(rgszNames, cNames, &lDispId);
if(SUCCEEDED(hRes))
{
TYPEATTR* pTAttr2 = NULL;
hRes = pifTypeInfo2->GetTypeAttr(&pTAttr2);
if(SUCCEEDED(hRes) && pTAttr2 != NULL)
{
bComplete = true;
_GetCSEC().Lock();
try
{
long idx = AddEntry(lDispId, (IID&)pTAttr2->guid, hRefType);
*rgdispid = GetCDIDFromIdx(idx);
}
catch(...)
{
hRes = E_FAIL;
}
_GetCSEC().Unlock();
pifTypeInfo2->ReleaseTypeAttr(pTAttr2);
}
}
pifTypeInfo2->Release();
}
}
}
pClassTI->ReleaseTypeAttr(pTAttr);
}
return hRes;
}
template<const IID* piid, const CLSID* pclsid, const GUID* plibid, long DispIdBase, WORD wMajor, WORD wMinor>
inline HRESULT CComTypeInfoHolderEx<piid,pclsid,plibid,DispIdBase,wMajor,wMinor>::GetIDsOfNames(IDispatch* pDisp, REFIID riid, LPOLESTR* rgszNames,
UINT cNames, LCID lcid, DISPID* rgdispid)
{
HRESULT hRes = DISP_E_UNKNOWNNAME;
if(piid)
{
hRes = CComTypeInfoHolder::GetIDsOfNames(riid,rgszNames,cNames,
lcid,rgdispid);
}
if(SUCCEEDED(hRes))
return hRes;
else if(hRes != DISP_E_UNKNOWNNAME)
return hRes;
LPOLESTR psName = rgszNames[0];
ITypeInfo* pInfo = NULL;
// First, check for IProvideClassInfo
if(!pDisp)
return E_POINTER;
IProvideClassInfo* pClassInfo = NULL;
hRes = _GetIProvideClassInfo(pDisp, &pClassInfo);
if(SUCCEEDED(hRes))
{
hRes = pClassInfo->GetClassInfo(&pInfo);
pClassInfo->Release();
if(SUCCEEDED(hRes))
{
long lDispId;
hRes = _FindName(pInfo, rgszNames, cNames, &lDispId);
if(SUCCEEDED(hRes))
{
*rgdispid = lDispId;
return S_OK;
}
}
}
if(piid)
{
hRes = GetTI(lcid, &pInfo);
}
unsigned int idx;
ITypeLib* pifTypeLib = NULL;
if(pInfo != NULL)
{
hRes = pInfo->GetContainingTypeLib(&pifTypeLib, &idx);
}
else
{
hRes = LoadRegTypeLib(*plibid, m_wMajor, m_wMinor, lcid, &pifTypeLib);
}
if(SUCCEEDED(hRes) && pifTypeLib != NULL)
{
ITypeInfo* pClassTI = NULL;
hRes = pifTypeLib->GetTypeInfoOfGuid(*pclsid,&pClassTI);
if(SUCCEEDED(hRes) && pClassTI != NULL)
{
ITypeComp* pifTypeComp = NULL;
if(pInfo)
hRes = pInfo->GetTypeComp(&pifTypeComp);
if(pifTypeComp != NULL)
{
ITypeInfo* pifTypeInfo2 = NULL;
DESCKIND dc;
BINDPTR bp;
long lHashId = LHashValOfName(lcid,psName);
hRes = pifTypeComp->Bind(psName,lHashId, 0,
&pifTypeInfo2, &dc, &bp);
if(SUCCEEDED(hRes) && pifTypeInfo2 != NULL)
{
long lDispId;
hRes = pifTypeInfo2->GetIDsOfNames(rgszNames, cNames, &lDispId);
if(SUCCEEDED(hRes))
{
TYPEATTR* pTAttr = NULL;
hRes = pifTypeInfo2->GetTypeAttr(&pTAttr);
if(SUCCEEDED(hRes) && pTAttr != NULL)
{
long idx;
_GetCSEC().Lock();
try
{
idx = AddEntry(lDispId, (IID&)pTAttr->guid);
*rgdispid = GetCDIDFromIdx(idx);
}
catch(...)
{
hRes = E_FAIL;
}
_GetCSEC().Unlock();
pifTypeInfo2->ReleaseTypeAttr(pTAttr);
}
}
pifTypeInfo2->Release();
}
else if(SUCCEEDED(hRes))
{
// Search through the class type info
hRes = _FindName(pClassTI, rgszNames, cNames, rgdispid);
}
pifTypeComp->Release();
}
else
{
// Search through the class type info
hRes = _FindName(pClassTI, rgszNames, cNames, rgdispid);
}
pClassTI->Release();
}
pifTypeLib->Release();
}
if(pInfo)
pInfo->Release();
if(FAILED(hRes) && !pClassInfo)
{
// One last shot: Search for another, registered type library
hRes = _FindNameByReg(rgszNames, cNames, rgdispid);
}
return hRes;
}
template<const IID* piid, const CLSID* pclsid, const GUID* plibid, long DispIdBase, WORD wMajor, WORD wMinor>
inline HRESULT CComTypeInfoHolderEx<piid,pclsid,plibid,DispIdBase,wMajor,wMinor>::Invoke(IDispatch* p, DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
HRESULT hRes = DISP_E_MEMBERNOTFOUND;
if(piid)
{
hRes = CComTypeInfoHolder::Invoke(p, dispidMember, riid, lcid, wFlags,
pdispparams, pvarResult,pexcepinfo, puArgErr);
}
if(SUCCEEDED(hRes))
return hRes;
else if(hRes != DISP_E_MEMBERNOTFOUND)
return hRes;
SetErrorInfo(0, NULL);
ITypeInfo* pInfo = NULL;
if(piid)
{
hRes = GetTI(lcid, &pInfo);
}
long ldid;
unsigned int uTypeIndex;
long idx;
_typeinfoEntry ti;
_dispidEntry e;
IID riid2;
hRes = S_FALSE;
_GetCSEC().Lock();
try
{
idx = GetIdxFromCDID(dispidMember);
ti = m_idispCont.at(idx);
e = ti.first;
ldid = e.first;
riid2 = e.second;
}
catch(...)
{
hRes = DISP_E_MEMBERNOTFOUND;
}
_GetCSEC().Unlock();
if(SUCCEEDED(hRes))
{
ITypeLib* pifTypeLib = NULL;
if(pInfo)
{
hRes = pInfo->GetContainingTypeLib(&pifTypeLib, &uTypeIndex);
}
else
{
hRes = LoadRegTypeLib(*plibid, m_wMajor, m_wMinor, lcid, &pifTypeLib);
}
if(pifTypeLib != NULL)
{
ITypeInfo* pifTypeInfo2 = NULL;
hRes = pifTypeLib->GetTypeInfoOfGuid(riid2,&pifTypeInfo2);
if(SUCCEEDED(hRes) && pifTypeInfo2 != NULL)
{
IDispatch* p2 = NULL;
hRes = p->QueryInterface(riid2,(void**)&p2);
if(p2 != NULL)
{
hRes = pifTypeInfo2->Invoke(p2, ldid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
p2->Release();
}
pifTypeInfo2->Release();
}
else
{
// Try to search for a referenced type, i.e. a type not defined by this type library.
IProvideClassInfo* pClassInfo = NULL;
hRes = _GetIProvideClassInfo(p, &pClassInfo);
if(SUCCEEDED(hRes))
{
ITypeInfo* pClassTI = NULL;
hRes = pClassInfo->GetClassInfo(&pClassTI);
pClassInfo->Release();
if(SUCCEEDED(hRes) && pClassTI)
{
hRes = pClassTI->GetRefTypeInfo(ti.second, &pifTypeInfo2);
if(SUCCEEDED(hRes) && pifTypeInfo2 != NULL)
{
IDispatch* p2 = NULL;
hRes = p->QueryInterface(riid2,(void**)&p2);
if(p2 != NULL)
{
hRes = pifTypeInfo2->Invoke(p2, ldid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
p2->Release();
}
pifTypeInfo2->Release();
}
pClassTI->Release();
}
}
else
{
// Search the registry for type info
ITypeInfo* pClassTI = NULL;
hRes = _FindTIByReg(&pClassTI);
if(SUCCEEDED(hRes) && pClassTI)
{
hRes = pClassTI->GetRefTypeInfo(ti.second, &pifTypeInfo2);
if(SUCCEEDED(hRes) && pifTypeInfo2 != NULL)
{
IDispatch* p2 = NULL;
hRes = p->QueryInterface(riid2,(void**)&p2);
if(p2 != NULL)
{
hRes = pifTypeInfo2->Invoke(p2, ldid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
p2->Release();
}
pifTypeInfo2->Release();
}
pClassTI->Release();
}
}
}
pifTypeLib->Release();
}
}
if(pInfo)
pInfo->Release();
return hRes;
}
template <class T, const IID* piid, const CLSID* pclsid, const GUID* plibid, WORD wMajor = 1,
WORD wMinor = 0, class tihclass = CComTypeInfoHolderEx<piid,pclsid,plibid, _stdDispIdBase, wMajor,wMinor> >
class ATL_NO_VTABLE IDispatchImplEx : public T
{
public:
//typedef tihclass _tihclass;
IDispatchImplEx()
{
#ifdef _ATL2 // AddRef/Release is used on the typeinfo holder in ATL2.1, so we must protect it
_GetTIH().AddRef();
#endif
}
~IDispatchImplEx()
{
#ifdef _ATL2 // AddRef/Release is used on the typeinfo holder in ATL2.1, so we must protect it
_GetTIH().Release();
#endif
}
STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
{*pctinfo = 1; return S_OK;}
STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{return _GetTIH().GetTypeInfo(itinfo, lcid, pptinfo);}
STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgdispid)
{return _GetTIH().GetIDsOfNames((IDispatch*)this, riid, rgszNames, cNames, lcid, rgdispid);}
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{return _GetTIH().Invoke((IDispatch*)this, dispidMember, riid, lcid,
wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);}
protected:
static tihclass& _GetTIH()
{
static tihclass _stih;
return _stih;
}
//static _tihclass _tih;
static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
{return _GetTIH().GetTI(lcid, ppInfo);}
};
/*template <class T, const IID* piid, const CLSID* pclsid, const GUID* plibid, WORD wMajor,
WORD wMinor, class tihclass>
IDispatchImplEx<T, piid, pclsid, plibid, wMajor, wMinor, tihclass>::_tihclass
IDispatchImplEx<T, piid, pclsid, plibid, wMajor, wMinor, tihclass>::_tih;*/
template <const CLSID* pclsid, const GUID* plibid, WORD wMajor = 1,
WORD wMinor = 0, class tihclass = CComTypeInfoHolderEx<NULL,pclsid,plibid,wMajor,wMinor> >
class ATL_NO_VTABLE PureDispatchImpl : public IDispatch
{
public:
//typedef tihclass _tihclass;
//typedef IDispatch T;
PureDispatchImpl()
{
#ifdef _ATL2 // AddRef/Release is used on the typeinfo holder in ATL2.1, so we must protect it
_GetTIH().AddRef();
#endif
}
~PureDispatchImpl()
{
#ifdef _ATL2 // AddRef/Release is used on the typeinfo holder in ATL2.1, so we must protect it
_GetTIH().Release();
#endif
}
STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
{*pctinfo = 1; return S_OK;}
STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{return _GetTIH().GetTypeInfo(itinfo, lcid, pptinfo);}
STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgdispid)
{return _GetTIH().GetIDsOfNames((IDispatch*)this, riid, rgszNames, cNames, lcid, rgdispid);}
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{return _GetTIH().Invoke((IDispatch*)this, dispidMember, riid, lcid,
wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);}
protected:
static tihclass& _GetTIH()
{
static tihclass _stih;
return _stih;
}
//static _tihclass _tih;
static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
{return _GetTIH().GetTI(lcid, ppInfo);}
};
// Required by STL
inline bool operator < (const GUID g1, const GUID g2)
{
union
{
GUID g;
struct
{
ULONG l1;
ULONG l2;
ULONG l3;
ULONG l4;
} l;
} u1, u2;
u1.g = g1;
u2.g = g2;
if(g1 == g2)
return false;
if(u1.l.l1 > u2.l.l1)
return false;
else if(u1.l.l1 < u2.l.l1)
return true;
else
{
if(u1.l.l2 > u2.l.l2)
return false;
else if(u1.l.l2 < u2.l.l2)
return true;
else
{
if(u1.l.l3 > u2.l.l3)
return false;
else if(u1.l.l3 < u2.l.l3)
return true;
else
{
if(u1.l.l4 < u2.l.l4)
return true;
else
return false;
}
}
}
}
//***************************************************************************
// Class CComClonableBase
// Kjell Tangen, 1998 (kat@computas.no)
// Computas, Norway
//
// Implements the IClassFactory interface for cloning. The class in particular
// targets cloning of aggregates. Note that this class assumes that your object
// is implemented using ATL.
//
// Intented usage:
// 1. A clonable class (CMyClass) should inherit from CComClonableBase<CMyClass>
// 2. Declare and implement HRESULT Copy(CMyClass& source) in CMyClass
// 3. Add COM_INTERFACE_ENTRY(IClassFactory) to your interface map.
// Important notice: This interface entry MUST BE PRIOR TO ANY AGGREGATE
// DECLARATIONS where the aggregated object is also clonable.
//***************************************************************************
/*
Example:
class ATL_NO_VTABLE COuter :
public CComCoClass<COuter, &CLSID_Outer>,
public IMyObject,
public CComClonableBase<COuter>,
public CComObjectRootEx<CComSingleThreadModel>
{
CComBSTR m_bsExpression;
public:
IUnknown* m_pifInner; // Aggregated object
****Boiler-plate ATL-code removed for clarity****
BEGIN_COM_MAP(COuter)
COM_INTERFACE_ENTRY(IMyObject)
COM_INTERFACE_ENTRY(IClassFactory)
COM_INTERFACE_ENTRY_AGGREGATE_BLIND( m_pifInner)
END_COM_MAP()
};
// Implementation:
STDMETHODIMP COuter::Copy(COuter& source)
{
// Copy class members
m_bsExpression = source.m_bsExpression;
// Clone the aggregated object
return = _CopyAggObject(source.m_pifInner, m_pifInner);
}
*/
template <class T>
class ATL_NO_VTABLE CComClonableBase :
public IClassFactory
{
public:
// IClassFactory methods:
STDMETHOD(CreateInstance)(IUnknown* pifOuterUnk,
REFIID riid,
void** ppvObj)
{
HRESULT hr = E_UNEXPECTED;
*ppvObj = NULL;
if(pifOuterUnk)
{
IUnknown* pifInnerUnk = NULL;
// Clone should be part of an aggregate
hr = CComCreator< CComAggObject<T> >::CreateInstance(pifOuterUnk,
riid,
(void**)&pifInnerUnk);
if(pifInnerUnk)
{
CComAggObject<T>* pObject = static_cast<CComAggObject<T>*>(pifInnerUnk);
if(pObject)
{
hr = pObject->m_contained.Copy(static_cast<T&>(*this));
*ppvObj = (void*)pifInnerUnk;
}
}
}
else
{
CComObject<T>* pObject = NULL;
hr = CComObject<T>::CreateInstance(&pObject);
if(pObject)
{
pObject->AddRef();
hr = pObject->Copy(static_cast<T&>(*this));
hr = pObject->QueryInterface(riid, ppvObj);
pObject->Release();
}
}
return hr;
}
STDMETHOD(LockServer)(BOOL fLock){return E_FAIL;}
protected:
HRESULT _CopyAggObject(IUnknown* pifSourceUnk, IUnknown*& pifTargetUnk)
{
// This method is a utility to aggregate a clone of an object
CComQIPtr<IClassFactory, &IID_IClassFactory> ifElementClonable;
HRESULT hr;
ifElementClonable = pifSourceUnk;
// Release the target unknown first
if(pifTargetUnk)
pifTargetUnk->Release();
hr = ifElementClonable->CreateInstance(static_cast<T&>(*this).GetControllingUnknown(),
IID_IUnknown,
(void**)&pifTargetUnk);
return hr;
}
virtual HRESULT Copy(T& source) = 0;
};
#endif