NT4/private/windows/base/advapi/digsig/inc/atlcom.h
2020-09-30 17:12:29 +02:00

1060 lines
28 KiB
C++

// This is a part of the ActiveX Template Library.
// Copyright (C) 1996 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// ActiveX Template Library Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// ActiveX Template Library product.
#ifndef __ATLCOM_H__
#define __ATLCOM_H__
#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
#pragma pack(push, _ATL_PACKING)
inline BOOL InlineIsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
return (
((PLONG) &rguid1)[0] == ((PLONG) &rguid2)[0] &&
((PLONG) &rguid1)[1] == ((PLONG) &rguid2)[1] &&
((PLONG) &rguid1)[2] == ((PLONG) &rguid2)[2] &&
((PLONG) &rguid1)[3] == ((PLONG) &rguid2)[3]);
}
/////////////////////////////////////////////////////////////////////////////
// Smart OLE pointers provide automatic AddRef/Release
// CComPtr<IFoo> p;
template <class T>
class CComPtr
{
public:
CComPtr() {p=NULL;}
CComPtr(T* p_){Init(p_);}
~CComPtr() { Release(); }
void Release() {if (p) p->Release();}
void Init(LPUNKNOWN lp) {if ((p = lp) != NULL) p->AddRef();}
LPUNKNOWN Assign(LPUNKNOWN lp);
operator T*() { return (T*)p; }
operator int() { return (int)p;}
T& operator*() { _ASSERTE(p!=NULL); return *(T*)p; }
T** operator&() {Release(); p = NULL; return (T**)&p; }
T* operator->() { _ASSERTE(p!=NULL); return (T*)p; }
T* operator=(T* p_) { return (T*)Assign(p_);}
protected:
LPUNKNOWN p;
};
template <class T>
LPUNKNOWN CComPtr<T>::Assign(LPUNKNOWN lp)
{
if (lp != NULL)
lp->AddRef();
if (p)
p->Release();
p = lp;
return p;
}
/////////////////////////////////////////////////////////////////////////////
// COM Objects
typedef HRESULT (PASCAL *_ATL_CREATORFUNC)(LPUNKNOWN pUnk, REFIID riid, LPVOID* ppv);
template <class T1>
class CComSimpleCreator
{
public:
static HRESULT PASCAL CreateInstance(LPUNKNOWN pUnk, REFIID riid, LPVOID* ppv)
{
T1* p = new T1(pUnk);
HRESULT hRes = p->QueryInterface(riid, ppv);
if (hRes != S_OK)
delete p;
return hRes;
}
};
template <class T1>
class CComNoAggCreator
{
public:
static HRESULT PASCAL CreateInstance(LPUNKNOWN pUnk, REFIID riid, LPVOID* ppv)
{
if (pUnk == NULL)
{
T1* p = new T1;
HRESULT hRes = p->QueryInterface(riid, ppv);
if (hRes != S_OK)
delete p;
return hRes;
}
else
{
*ppv = NULL;
return CLASS_E_NOAGGREGATION;
}
}
};
template <class T1, class T2>
class CComAggCreator
{
public:
static HRESULT PASCAL CreateInstance(LPUNKNOWN pUnk, REFIID riid, LPVOID* ppv)
{
if (pUnk == NULL)
{
T1* p = new T1;
HRESULT hRes = p->QueryInterface(riid, ppv);
if (hRes != S_OK)
delete p;
return hRes;
}
else
{
T2* p = new T2(pUnk);
HRESULT hRes = p->QueryInterface(riid, ppv);
if (hRes != S_OK)
delete p;
return hRes;
}
}
};
#define DECLARE_NOT_AGGREGATABLE(x) public:\
typedef CComNoAggCreator< CComObject<x> > _CreatorClass;
#define DECLARE_AGGREGATABLE(x) public:\
typedef CComAggCreator< CComObject<x>, CComAggObject<x> > _CreatorClass;
struct _ATL_INTMAP_ENTRY
{
const IID* piid; // the interface id (IID) (NULL for aggregate)
DWORD dw;
enum Flags {offset, creator, aggregate} m_flag;
};
#define BEGIN_COM_MAP(x) public:\
typedef x _atl_classtype;\
HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject)\
{return InternalQueryInterface(this, _GetEntries(), iid, ppvObject);}\
const _ATL_INTMAP_ENTRY* _GetEntries() {\
static const _ATL_INTMAP_ENTRY _entries[] = {
#define COM_INTERFACE_ENTRY(x) {&IID_##x, (DWORD)((x*)((_atl_classtype*)8))-8, _ATL_INTMAP_ENTRY::offset},
#define COM_INTERFACE_ENTRY_IID(iid, x) {&iid, (DWORD)((x*)((_atl_classtype*)8))-8, _ATL_INTMAP_ENTRY::offset},
#define COM_INTERFACE_ENTRY2(x, x2) {&IID_##x, (DWORD)((x*)(x2*)((_atl_classtype*)8))-8, _ATL_INTMAP_ENTRY::offset},
#define COM_INTERFACE_ENTRY2_IID(iid, x, x2) {&iid, (DWORD)((x*)(x2*)((_atl_classtype*)8))-8, _ATL_INTMAP_ENTRY::offset},
#define COM_INTERFACE_ENTRY_TEAR_OFF(iid, x) {&iid, (DWORD)(_ATL_CREATORFUNC)CComSimpleCreator< CComTearOffObject<x, _atl_classtype> >::CreateInstance, _ATL_INTMAP_ENTRY::creator},
#define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk) {&iid, (DWORD)offsetof(_atl_classtype, punk), _ATL_INTMAP_ENTRY::aggregate},
#define END_COM_MAP() {NULL, 0, _ATL_INTMAP_ENTRY::offset}};\
return _entries;}
struct _ATL_OBJMAP_ENTRY
{
const CLSID* pclsid;
_ATL_CREATORFUNC pFunc;
LPCTSTR lpszProgID;
LPCTSTR lpszVerIndProgID;
UINT nDescID;
DWORD dwFlags;
IClassFactory* pCF;
DWORD dwRegister; // cookie returned by CoRegisterClassObject
//Methods
void UpdateRegistry(HINSTANCE hInst, HINSTANCE hInstResource);
void RemoveRegistry();
HRESULT RegisterClassObject(DWORD dwClsContext, DWORD dwFlags);
HRESULT RevokeClassObject()
{return dwRegister ? CoRevokeClassObject(dwRegister) : E_INVALIDARG;}
};
#define BEGIN_OBJECT_MAP(x) static _ATL_OBJMAP_ENTRY x[] = {
#define RAWOBJECT_ENTRY(iid, pf, p1, p2, id, dw) {&iid, pf, _T(p1), _T(p2), id, dw, NULL, (DWORD)0},
#define END_OBJECT_MAP() {NULL, 0}};
#if defined(_WINDLL) | defined(_USRDLL)
#define OBJECT_ENTRY(iid, class, p1, p2, id, dw) {&iid, (_ATL_CREATORFUNC)&(CComNoAggCreator< CComObject< CComClassFactory<class> > >::CreateInstance), _T(p1), _T(p2), id, dw, NULL, (DWORD)0},
#define FACTORYOBJECT_ENTRY(iid, factory, p1, p2, id, dw) {&iid, (_ATL_CREATORFUNC)&(CComNoAggCreator< CComObject< factory > >::CreateInstance), _T(p1), _T(p2), id, dw, NULL, (DWORD)0},
#else
// don't let class factory refcount influence lock count
#define OBJECT_ENTRY(iid, class, p1, p2, id, dw) {&iid, (_ATL_CREATORFUNC)&(CComNoAggCreator< CComObjectNoLock< CComClassFactory<class> > >::CreateInstance), _T(p1), _T(p2), id, dw, NULL, (DWORD)0},
#define FACTORYOBJECT_ENTRY(iid, factory, p1, p2, id, dw) {&iid, (_ATL_CREATORFUNC)&(CComNoAggCreator< CComObjectNoLock< factory > >::CreateInstance), _T(p1), _T(p2), id, dw, NULL, (DWORD)0},
#endif
#define THREADFLAGS_APARTMENT 0x1
#define THREADFLAGS_BOTH 0x2
#define AUTPRXFLAG 0x4
#define CONTROLFLAG 0x8
// the functions in this class don't need to be virtual because
// they are called from CComObject
class CComObjectRoot
{
public:
CComObjectRoot() {m_dwRef = 0L;}
void FinalConstruct() {}
ULONG InternalAddRef() {return CComThreadModel::Increment(&m_dwRef);}
ULONG InternalRelease()
{
if (m_dwRef == 0)
return 0;
return CComThreadModel::Decrement(&m_dwRef);
}
static HRESULT PASCAL InternalQueryInterface(void* pThis,
const _ATL_INTMAP_ENTRY* entries, REFIID iid, void** ppvObject);
//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);}
#ifndef ATL_NOEXTENDEDERROR
static HRESULT PASCAL Error(const CLSID& clsid, LPCOLESTR lpszDesc,
const IID& iid = GUID_NULL, HRESULT hRes = 0);
static HRESULT PASCAL Error(const CLSID& clsid, LPCSTR lpszDesc,
const IID& iid = GUID_NULL, HRESULT hRes = 0);
static HRESULT PASCAL Error(const CLSID& clsid, HINSTANCE hInst,
UINT nID, const IID& iid, HRESULT hRes = 0);
#endif
protected:
union
{
long m_dwRef;
IUnknown* m_pOuterUnknown;
};
};
template <const CLSID* pclsid>
class CComObjectBase : public CComObjectRoot
{
public:
static HRESULT PASCAL Error(LPCOLESTR lpszDesc,
const IID& iid = GUID_NULL, HRESULT hRes = 0)
{return CComObjectRoot::Error(*pclsid, lpszDesc, iid, hRes);}
static HRESULT PASCAL Error(LPCSTR lpszDesc,
const IID& iid = GUID_NULL, HRESULT hRes = 0)
{return CComObjectRoot::Error(*pclsid, lpszDesc, iid, hRes);}
static HRESULT PASCAL Error(UINT nDescID, const IID& iid,
HRESULT hRes = 0)
{return CComObjectRoot::Error(*pclsid, _Module.GetModuleInstance(),
nDescID, iid, hRes);}
};
template <const CLSID* pclsid, class Owner>
class CComTearOffObjectBase : public CComObjectBase<pclsid>
{
public:
CComObject<Owner>* m_pOwner;
};
//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:
CComObject(LPUNKNOWN = NULL)
{
_Module.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
FinalConstruct();
}
~CComObject(){_Module.Unlock();}
//If InternalAddRef or InteralRelease is undefined then your class
//doesn't derive from CComObjectBase
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);}
};
//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:
//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
CComObjectNoLock(LPUNKNOWN p = NULL){FinalConstruct();}
//If InternalAddRef or InteralRelease is undefined then your class
//doesn't derive from CComObjectBase
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);}
};
// It is possible for Base not to derive from CComObjectRoot in this case
// in order to avoid the 4 bytes for a refcount.
// However, you will need to provide FinalConstruct and InternalQueryInterface
template <class Base>
class CComObjectGlobal : public Base
{
public:
CComObjectGlobal(LPUNKNOWN p = NULL){FinalConstruct();}
STDMETHOD_(ULONG, AddRef)() {return _Module.Lock();}
STDMETHOD_(ULONG, Release)(){return _Module.Unlock();}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{return _InternalQueryInterface(iid, ppvObject);}
};
//Base is the user's class that derives from CComObjectRoot and whatever
//interfaces the user wants to support on the object
//Owner is the class of object that Base is a tear-off for
template <class Base, class Owner>
class CComTearOffObject : public Base
{
public:
CComTearOffObject(void* p)
{
m_pOwner = reinterpret_cast<CComObject<Owner>*>(p);
m_pOwner->AddRef();
//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
FinalConstruct();
}
~CComTearOffObject(){m_pOwner->Release();}
//If InternalAddRef or InteralRelease is undefined then your class
//doesn't derive from CComObjectBase
STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
STDMETHOD_(ULONG, Release)()
{
ULONG l = InternalRelease();
if (l == 0)
delete this;
return l;
}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{
if (InlineIsEqualGUID(iid, IID_IUnknown) ||
FAILED(_InternalQueryInterface(iid, ppvObject)))
{
return m_pOwner->QueryInterface(iid, ppvObject);
}
return S_OK;
}
};
template <class Base> //Base must be derived from CComObjectRoot
class CComContainedObject : public Base
{
public:
CComContainedObject(LPUNKNOWN lpUnk) {m_pOuterUnknown = lpUnk;}
STDMETHOD_(ULONG, AddRef)() {return OuterAddRef();}
STDMETHOD_(ULONG, Release)() {return OuterRelease();}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{return OuterQueryInterface(iid, ppvObject);}
protected:
friend class CComAggObject<Base>;
};
//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 CComObjectRoot
{
public:
CComAggObject(LPUNKNOWN lpUnk) : m_contained(lpUnk)
{_Module.Lock();m_contained.FinalConstruct();}
~CComAggObject(){_Module.Unlock();}
STDMETHOD_(ULONG, AddRef)() {return CComThreadModel::Increment(&m_dwRef);}
STDMETHOD_(ULONG, Release)()
{
if (m_dwRef == 0)
return 0;
LONG l = CComThreadModel::Decrement(&m_dwRef);
if (l==0)
delete this;
return l;
}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{
if (InlineIsEqualGUID(iid, IID_IUnknown))
{
*ppvObject = this;
AddRef();
}
else
return m_contained._InternalQueryInterface(iid, ppvObject);
return NOERROR;
}
protected:
CComContainedObject<contained> m_contained;
};
class CComClassFactoryBase : public IClassFactory, public CComObjectRoot
{
public:
BEGIN_COM_MAP(CComClassFactoryBase)
COM_INTERFACE_ENTRY(IClassFactory)
END_COM_MAP()
STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj);
STDMETHOD(LockServer)(BOOL fLock);
STDMETHOD(implCreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid,
void** ppvObj)=0;
};
template <class impl>
class CComClassFactory : public CComClassFactoryBase
{
public:
STDMETHOD(implCreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid,
void** ppvObj)
{
return impl::_CreatorClass::CreateInstance(pUnkOuter, riid, ppvObj);
}
};
// 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:
GUID* m_pguid;
GUID* m_plibid;
WORD m_wMajor;
WORD m_wMinor;
ITypeInfo* m_pInfo;
long m_dwRef;
public:
// GetTI doesn't refcount
HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo);
void AddRef();
void Release();
HRESULT GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
HRESULT GetIDsOfNames(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 <class T, IID* piid, GUID* plibid, WORD wMajor = 1, WORD wMinor = 0>
class CComDualImpl : public T
{
public:
CComDualImpl() {_tih.AddRef();}
~CComDualImpl() {_tih.Release();}
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 CComTypeInfoHolder _tih;
static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
{return _tih.GetTI(lcid, ppInfo);}
};
template <class T, IID* piid, GUID* plibid, WORD wMajor = 1, WORD wMinor = 0>
CComTypeInfoHolder CComDualImpl<T, piid, plibid, wMajor, wMinor>::_tih =
{ piid, plibid, wMajor, wMinor, NULL, 0};
/////////////////////////////////////////////////////////////////////////////
// CISupportErrorInfo
template <const IID* piid>
class CComISupportErrorInfoImpl : public ISupportErrorInfo
{
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)\
{return (InlineIsEqualGUID(riid,*piid)) ? S_OK : S_FALSE;}
};
/////////////////////////////////////////////////////////////////////////////
// CComEnumImpl
// These _CopyXXX classes are used with enumerators in order to control
// how enumerated items are initialized, copied, and deleted
// Default is shallow copy with no special init or cleanup
template <class T>
class _Copy
{
public:
static void copy(T* p1, T* p2) {memcpy(p1, p2, sizeof(T));}
static void init(T*) {}
static void destroy(T*) {}
};
class _Copy<VARIANT>
{
public:
static void copy(VARIANT* p1, VARIANT* p2) {VariantCopy(p1, p2);}
static void init(VARIANT* p) {VariantInit(p);}
static void destroy(VARIANT* p) {VariantClear(p);}
};
class _Copy<CONNECTDATA>
{
public:
static void copy(CONNECTDATA* p1, CONNECTDATA* p2)
{
*p1 = *p2;
if (p1->pUnk)
p1->pUnk->AddRef();
}
static void init(CONNECTDATA* ) {}
static void destroy(CONNECTDATA* p) {if (p->pUnk) p->pUnk->Release();}
};
template <class T>
class _CopyInterface
{
public:
static void copy(T** p1, T** p2)
{*p1 = *p2;if (*p1) (*p1)->AddRef();}
static void init(T** ) {}
static void destroy(T** p) {if (*p) (*p)->Release();}
};
template<class T>
class CComIEnum : public IUnknown
{
public:
STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched) = 0;
STDMETHOD(Skip)(ULONG celt) = 0;
STDMETHOD(Reset)(void) = 0;
STDMETHOD(Clone)(CComIEnum<T>** ppEnum) = 0;
};
template <class Base, IID* piid, class T, class Copy>
class CComEnumImpl : public Base
{
public:
CComEnumImpl() {m_begin = m_end = m_iter = NULL; m_dwFlags = 0; m_pUnk = NULL;}
~CComEnumImpl();
STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched);
STDMETHOD(Skip)(ULONG celt);
STDMETHOD(Reset)(void){m_iter = m_begin;return S_OK;}
STDMETHOD(Clone)(Base** ppEnum);
void Init(T* begin, T* end, IUnknown* pUnk, BOOL bCopy = FALSE,
BOOL bNoInitialUnkAddRef = FALSE);
IUnknown* m_pUnk;
T* m_begin;
T* m_end;
T* m_iter;
DWORD m_dwFlags;
enum Flags
{
FlagCopy = 1,
FlagNoInitialUnkAddRef = 2
};
};
template <class Base, IID* piid, class T, class Copy>
CComEnumImpl<Base, piid, T, Copy>::~CComEnumImpl()
{
if (m_dwFlags & FlagCopy)
{
for (T* p = m_begin; p != m_end; p++)
Copy::destroy(p);
delete [] m_begin;
}
if (m_pUnk && !(m_dwFlags & FlagNoInitialUnkAddRef))
m_pUnk->Release();
}
template <class Base, IID* piid, class T, class Copy>
STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Next(ULONG celt, T* rgelt,
ULONG* pceltFetched)
{
if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
return E_POINTER;
if (m_begin == NULL || m_end == NULL || m_iter == NULL)
return E_FAIL;
ULONG nRem = (ULONG)(m_end - m_iter);
HRESULT hRes = S_OK;
if (nRem < celt)
hRes = S_FALSE;
ULONG nMin = min(celt, nRem);
if (pceltFetched != NULL)
*pceltFetched = nMin;
while(nMin--)
Copy::copy(rgelt++, m_iter++);
return hRes;
}
template <class Base, IID* piid, class T, class Copy>
STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Skip(ULONG celt)
{
m_iter += celt;
if (m_iter < m_end)
return S_OK;
m_iter = m_end;
return S_FALSE;
}
template <class Base, IID* piid, class T, class Copy>
STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Clone(Base** ppEnum)
{
typedef CComObject<CComEnum<Base, piid, T, Copy> > _class;
HRESULT hRes = E_POINTER;
if (ppEnum != NULL)
{
_class* p = new _class;
if (p == NULL)
{
*ppEnum = NULL;
hRes = E_OUTOFMEMORY;
}
else
{
p->Init(m_begin, m_end, (m_dwFlags & FlagCopy) ? this : m_pUnk);
p->m_iter = m_iter;
hRes = p->_InternalQueryInterface(*piid, (void**)ppEnum);
if (FAILED(hRes))
delete p;
}
}
return hRes;
}
template <class Base, IID* piid, class T, class Copy>
void CComEnumImpl<Base, piid, T, Copy>::Init(T* begin, T* end, IUnknown* pUnk,
BOOL bCopy, BOOL bNoInitialUnkAddRef)
{
_ASSERTE(!bNoInitialUnkAddRef || (pUnk!=NULL));
if (bCopy)
{
m_begin = new T[end-begin];
m_iter = m_begin;
for (T* i=begin; i != end; i++)
{
Copy::init(m_iter);
Copy::copy(m_iter++, i);
}
m_end = m_begin + (end-begin);
}
else
{
m_begin = begin;
m_end = end;
}
m_pUnk = pUnk;
if (m_pUnk && !bNoInitialUnkAddRef)
m_pUnk->AddRef();
m_iter = m_begin;
if (bCopy)
m_dwFlags = FlagCopy;
if (bNoInitialUnkAddRef)
m_dwFlags |= FlagNoInitialUnkAddRef;
}
template <class Base, IID* piid, class T, class Copy>
class CComEnum : public CComEnumImpl<Base, piid, T, Copy>, public CComObjectRoot
{
public:
typedef CComEnum<Base, piid, T, Copy > _atl_classtype;
HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject)
{
static const _ATL_INTMAP_ENTRY _entries[] =
{
{piid, 0, _ATL_INTMAP_ENTRY::offset},
{NULL, 0, _ATL_INTMAP_ENTRY::offset}
};
return InternalQueryInterface(this, _entries, iid, ppvObject);
}
};
#ifndef ATL_NOCONNPTS
/////////////////////////////////////////////////////////////////////////////
// Connection Points
#define BEGIN_CONNECTION_POINT_MAP()\
virtual const IID** _GetConnMap() {\
static const IID* _entries[] = {
#define CONNECTION_POINT_ENTRY(x) &IID_##x,
#define END_CONNECTION_POINT_MAP() NULL}; return _entries;}
#ifndef _DEFAULT_VECTORLENGTH
#define _DEFAULT_VECTORLENGTH 4
#endif
template <unsigned int nMaxSize>
class CComStaticArrayCONNECTDATA
{
public:
CComStaticArrayCONNECTDATA()
{
memset(m_arr, 0, sizeof(CONNECTDATA)*nMaxSize);
m_pCurr = &m_arr[0];
}
BOOL Add(IUnknown* pUnk);
BOOL Remove(DWORD dwCookie);
CONNECTDATA* begin() {return &m_arr[0];}
CONNECTDATA* end() {return &m_arr[nMaxSize];}
protected:
CONNECTDATA m_arr[nMaxSize];
CONNECTDATA* m_pCurr;
};
template <unsigned int nMaxSize>
inline BOOL CComStaticArrayCONNECTDATA<nMaxSize>::Add(IUnknown* pUnk)
{
for (CONNECTDATA* p = begin();p<end();p++)
{
if (p->pUnk == NULL)
{
p->pUnk = pUnk;
p->dwCookie = (DWORD)pUnk;
return TRUE;
}
}
return FALSE;
}
template <unsigned int nMaxSize>
inline BOOL CComStaticArrayCONNECTDATA<nMaxSize>::Remove(DWORD dwCookie)
{
CONNECTDATA* p;
for (p=begin();p<end();p++)
{
if (p->dwCookie == dwCookie)
{
p->pUnk = NULL;
p->dwCookie = NULL;
return TRUE;
}
}
return FALSE;
}
class CComStaticArrayCONNECTDATA<1>
{
public:
CComStaticArrayCONNECTDATA() {m_cd.pUnk = NULL; m_cd.dwCookie = 0;}
BOOL Add(IUnknown* pUnk)
{
if (m_cd.pUnk != NULL)
return FALSE;
m_cd.pUnk = pUnk;
m_cd.dwCookie = (DWORD)pUnk;
return TRUE;
}
BOOL Remove(DWORD dwCookie)
{
if (dwCookie != m_cd.dwCookie)
return FALSE;
m_cd.pUnk = NULL;
m_cd.dwCookie = 0;
return TRUE;
}
CONNECTDATA* begin() {return &m_cd;}
CONNECTDATA* end() {return (&m_cd)+1;}
protected:
CONNECTDATA m_cd;
};
class CComDynamicArrayCONNECTDATA
{
public:
CComDynamicArrayCONNECTDATA()
{
m_nSize = 0;
m_pCD = NULL;
}
~CComDynamicArrayCONNECTDATA() {free(m_pCD);}
BOOL Add(IUnknown* pUnk);
BOOL Remove(DWORD dwCookie);
CONNECTDATA* begin()
{
CONNECTDATA* p;
switch(m_nSize)
{
case 0:
case 1:
p = &m_cd;
p = &m_cd;
break;
default:
p = m_pCD;
break;
}
return p;
}
CONNECTDATA* end()
{
CONNECTDATA* p;
switch(m_nSize)
{
case 0:
p = &m_cd;
break;
case 1:
p = (&m_cd)+1;
break;
default:
p = &m_pCD[m_nSize];
break;
}
return p;
}
protected:
CONNECTDATA* m_pCD;
CONNECTDATA m_cd;
int m_nSize;
};
class CComConnectionPointBase : public IConnectionPoint
{
typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA,
_Copy<CONNECTDATA> > CComEnumConnections;
public:
CComConnectionPointBase(IConnectionPointContainer* pContainer,
const IID* piid)
{
_ASSERTE(pContainer != NULL);
_ASSERTE(piid != NULL);
m_pContainer = pContainer;
m_piid = piid;
}
//Connection point lifetimes are determined by the container
STDMETHOD_(ULONG, AddRef)() {return m_pContainer->AddRef();}
STDMETHOD_(ULONG, Release)(){return m_pContainer->Release();}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{
static const _ATL_INTMAP_ENTRY entries[] = {{&IID_IConnectionPoint, 0, _ATL_INTMAP_ENTRY::offset}};
return CComObjectRoot::InternalQueryInterface(this, entries, iid, ppvObject);
}
STDMETHOD(GetConnectionInterface)(IID* piid);
STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer** ppCPC);
protected:
IConnectionPointContainer* m_pContainer;
const IID* m_piid;
};
template <class CDV>
class CComConnectionPoint : public CComConnectionPointBase
{
typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA,
_Copy<CONNECTDATA> > CComEnumConnections;
public:
CComConnectionPoint(IConnectionPointContainer* pContainer, const IID* piid) :
CComConnectionPointBase(pContainer, piid)
{m_sec.Init();}
~CComConnectionPoint() {m_sec.Term();}
//Connection point lifetimes are determined by the container
STDMETHOD(Advise)(IUnknown* pUnkSink, DWORD* pdwCookie);
STDMETHOD(Unadvise)(DWORD dwCookie);
STDMETHOD(EnumConnections)(IEnumConnections** ppEnum);
protected:
CComThreadModel::ObjectCriticalSection m_sec;
CDV m_vec;
friend class CComConnectionPointContainerImpl<CDV>;
};
template <class CDV>
STDMETHODIMP CComConnectionPoint<CDV>::Advise(IUnknown* pUnkSink,
DWORD* pdwCookie)
{
IUnknown* p;
HRESULT hRes = S_OK;
if (pUnkSink == NULL || pdwCookie == NULL)
return E_POINTER;
m_sec.Lock();
if (SUCCEEDED(pUnkSink->QueryInterface(*m_piid, (void**)&p)))
{
*pdwCookie = (DWORD)p;
hRes = m_vec.Add(p) ? S_OK : CONNECT_E_ADVISELIMIT;
if (hRes != S_OK)
{
*pdwCookie = 0;
p->Release();
}
}
else
hRes = CONNECT_E_CANNOTCONNECT;
m_sec.Unlock();
return hRes;
}
template <class CDV>
STDMETHODIMP CComConnectionPoint<CDV>::Unadvise(DWORD dwCookie)
{
m_sec.Lock();
HRESULT hRes = m_vec.Remove(dwCookie) ? S_OK : CONNECT_E_NOCONNECTION;
IUnknown* p = (IUnknown*) dwCookie;
m_sec.Unlock();
if (hRes == S_OK && p != NULL)
p->Release();
return hRes;
}
template <class CDV>
STDMETHODIMP CComConnectionPoint<CDV>::EnumConnections(
IEnumConnections** ppEnum)
{
CComEnumConnections* pEnum = new CComObject<CComEnumConnections>;
m_sec.Lock();
CONNECTDATA* pcd = new CONNECTDATA[m_vec.end()-m_vec.begin()];
CONNECTDATA* pend = pcd;
// Copy the valid CONNECTDATA's
for (CONNECTDATA* p = m_vec.begin();p<m_vec.end();p++)
{
if (p->pUnk != NULL)
{
p->pUnk->AddRef();
*pend++ = *p;
}
}
// don't copy the data, but transfer ownership to it
pEnum->Init(pcd, pend, NULL, FALSE);
pEnum->m_dwFlags |= CComEnumConnections::FlagCopy;
m_sec.Unlock();
*ppEnum = pEnum;
return S_OK;
}
template <class CDV>
class CComConnectionPointContainerImpl : public IConnectionPointContainer
{
typedef CComEnum<IEnumConnectionPoints,
&IID_IEnumConnectionPoints, IConnectionPoint*,
_CopyInterface<IConnectionPoint> >
CComEnumConnectionPoints;
public:
void FinalConstruct();
~CComConnectionPointContainerImpl();
STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints** ppEnum);
STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint** ppCP);
protected:
virtual const IID** _GetConnMap() = 0;
CComConnectionPoint<CDV>** m_ppCP;
int m_nCP;
};
template <class CDV>
void CComConnectionPointContainerImpl<CDV>::FinalConstruct()
{
const IID** ppiid= _GetConnMap();
m_nCP=0;
while (*ppiid++ != NULL)
m_nCP++;
_ASSERTE(m_nCP > 0);
m_ppCP = new CComConnectionPoint<CDV>*[m_nCP];
CComConnectionPoint<CDV>** ppCP = m_ppCP;
ppiid= _GetConnMap();
for (int i=0;i<m_nCP;i++, ppiid++, ppCP++)
{
//don't AddRef this pointer because it will AddRef us
*ppCP = new CComConnectionPoint<CDV>(this, *ppiid);
}
}
template <class CDV>
CComConnectionPointContainerImpl<CDV>::~CComConnectionPointContainerImpl()
{
_ASSERTE(m_nCP > 0);
CComConnectionPoint<CDV>** ppCP = m_ppCP;
for (int i=0;i<m_nCP;i++, ppCP++)
delete *ppCP;
delete [] m_ppCP;
}
template <class CDV>
STDMETHODIMP CComConnectionPointContainerImpl<CDV>::EnumConnectionPoints(
IEnumConnectionPoints** ppEnum)
{
_ASSERTE(m_nCP > 0);
CComEnumConnectionPoints* pEnum = new CComObject<CComEnumConnectionPoints>;
// don't copy the data but do AddRef this object
pEnum->Init((IConnectionPoint**)&m_ppCP[0],
(IConnectionPoint**)&m_ppCP[m_nCP], this, FALSE);
*ppEnum = pEnum;
return S_OK;
}
template <class CDV>
STDMETHODIMP CComConnectionPointContainerImpl<CDV>::FindConnectionPoint(
REFIID riid, IConnectionPoint** ppCP)
{
_ASSERTE(m_nCP > 0);
if (ppCP == NULL)
return E_POINTER;
*ppCP = NULL;
HRESULT hRes = CONNECT_E_NOCONNECTION;
const IID** ppiid= _GetConnMap();
for (int i=0;i<m_nCP;i++, ppiid++)
{
if (InlineIsEqualGUID(**ppiid, riid))
{
*ppCP = m_ppCP[i];
(*ppCP)->AddRef();
hRes = S_OK;
break;
}
}
return hRes;
}
#endif //!ATL_NOCONNPTS
#pragma pack(pop)
#endif // __ATLCOM_H__
/////////////////////////////////////////////////////////////////////////////