|
|
#pragma once
// Extensions to ATL to enable things it doesn't natively support
template <const CLSID* pcoclsid, const IID* psrcid, class tihclass = CMarsTypeInfoHolder> class MarsIProvideClassInfo2Impl : public IProvideClassInfo2Impl<pcoclsid, psrcid, NULL, 0, 0, tihclass> { };
template <class T, const IID* piid, class tihclass = CMarsTypeInfoHolder> class MarsIDispatchImpl : public IDispatchImpl<T, piid, NULL, 0, 0, tihclass> { public: STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, EXCEPINFO *pexcepinfo, UINT *puArgErr) { HRESULT hr = IDispatchImpl<T, piid, NULL, 0, 0, tihclass>::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); hr = SanitizeResult(hr);
if (DISP_E_EXCEPTION == hr) { // We're getting DISP_E_EXCEPTION returns which are not generated by Mars
// whenever invalid parameter types are passed. They're probably coming
// from oleaut itself.
// ASSERT(NULL != m_pwszException);
if ((NULL != m_pwszException) && (NULL != pexcepinfo)) { memset(pexcepinfo, 0, sizeof(EXCEPINFO)); pexcepinfo->wCode = (WORD)dispidMember; pexcepinfo->bstrSource = SysAllocString(L"OM Exception"); pexcepinfo->bstrDescription = SysAllocString(m_pwszException); } } return hr; }
protected: LPWSTR m_pwszException; };
// each module implements this themselves
HRESULT GetMarsTypeLib(ITypeLib **ppTypeLib);
//==================================================================
// Begin CComTypeInfoHolder override
//
// By providing our own CComTypeInfoHolder, we can load the type
// library ourselves, rather than requiring it to be loaded from
// the registry as ATL does. Only "GetTI" is changed from
// ATL source. Since GetTI isn't virtual we need to duplicate
// the entire class.
// CMarsTypeInfoHolder accepts an ITypeLib * (with reference)
// instead of a LIBID in m_plibid
//
//==================================================================
// ATL doesn't support multiple LCID's at the same time
// Whatever LCID is queried for first is the one that is used.
class CMarsTypeInfoHolder { // 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) { 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) hr = GetTI(lcid); return hr; }
// This function is called by the module on exit
// It is registered through _Module.AddTermFunc()
static void __stdcall Cleanup2(DWORD_PTR dw) { CMarsTypeInfoHolder* p = (CMarsTypeInfoHolder*) 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) { for (int i=0; i<(int)cNames; i++) { int n = ocslen(rgszNames[i]); for (int 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; }
// Give debug warning if we differ only in case
//DEBUG_ONLY(StrEql(m_pMap[j].bstr, rgszNames[i]));
} if (j < 0) { // Not a warning. Common for behaviors as Trident passes all calls to
// our IDispatch for the first shot. We should possibly just return
// failure in this case instead of delegating to oleaut.
hRes = m_pInfo->GetIDsOfNames(rgszNames + i, 1, &rgdispid[i]); if (FAILED(hRes)) break; } } } 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 = m_nCount == 0 ? 0 : new stringdispid[m_nCount]; 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 CMarsTypeInfoHolder::GetTI(LCID lcid) { UNREFERENCED_PARAMETER(lcid);
// Change: removed asserts
if (m_pInfo != NULL) return S_OK; HRESULT hRes = E_FAIL; EnterCriticalSection(&_Module.m_csTypeInfoHolder); if (m_pInfo == NULL) { ITypeLib* pTypeLib; // Here's a change
// hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);
hRes = GetMarsTypeLib(&pTypeLib); // End change
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;
LoadNameCache(spInfo); m_pInfo = spInfo.Detach(); } pTypeLib->Release(); } } LeaveCriticalSection(&_Module.m_csTypeInfoHolder); _Module.AddTermFunc(Cleanup2, (DWORD_PTR)this); return hRes; }
//==================================================================
// End CComTypeInfoHolder override
//==================================================================
// CComClassPtr is like CComPtr but it works with C++ classes, by not
// assuming that we can cast to IUnknown unambiguously.
// Use caution when initializing within your constructor. You can't
// AddRef an object which hasn't finished constructing yet, so you can
// only initialize smart pointers to object which don't contain you.
template <class T> class _NoAddRefReleaseOnCComClassPtr : public T { public: // If you get a compile error here, make sure that the destructors
// for any CComClassPtr<> classes are protected instead of private
~_NoAddRefReleaseOnCComClassPtr() {} private: STDMETHOD_(ULONG, AddRef)()=0; STDMETHOD_(ULONG, Release)()=0; };
template <class T> class CComClassPtr { public: typedef T _PtrClass; CComClassPtr() { p=NULL; } CComClassPtr(T* lp) { if ((p = lp) != NULL) p->AddRef(); } CComClassPtr(const CComClassPtr<T>& lp) { if ((p = lp.p) != NULL) p->AddRef(); } ~CComClassPtr() { if (p) p->Release(); } void Release() { T* pTemp = p; if (pTemp) { p = NULL; pTemp->Release(); } } operator T*() const { return p; } T& operator*() const { ATLASSERT(p!=NULL); return *p; } //The assert on operator& usually indicates a bug. If this is really
//what is needed, however, take the address of the p member explicitly.
T** operator&() { ATLASSERT(p==NULL); return &p; }
HRESULT PassivateAndRelease() { if (p) { HRESULT hr = p->Passivate(); Release(); return hr; } return S_FALSE; }
_NoAddRefReleaseOnCComClassPtr<T>* operator->() const { ATLASSERT(p!=NULL); return (_NoAddRefReleaseOnCComClassPtr<T>*)p; }
T* AtlComClassPtrAssign(T** pp, T* lp) { if (lp != NULL) lp->AddRef(); if (*pp) (*pp)->Release(); *pp = lp; return lp; }
T* operator=(T* lp) { return AtlComClassPtrAssign(&p, lp); } T* operator=(const CComClassPtr<T>& lp) { return AtlComClassPtrAssign(&p, lp.p); } bool operator!() const { return (p == NULL); } bool operator<(T* pT) const { return p < pT; } bool operator==(T* pT) const { return p == pT; } // Compare two objects for equivalence
bool IsEqualObject(T* pOther) { return (p == pOther); } void Attach(T* p2) { if (p) p->Release(); p = p2; } T* Detach() { T* pt = p; p = NULL; return pt; } HRESULT CopyTo(T** ppT) { ATLASSERT(ppT != NULL); if (ppT == NULL) return E_POINTER; *ppT = p; if (p) p->AddRef(); return S_OK; } template <class Q> HRESULT QueryInterface(Q** pp) const { ATLASSERT(pp != NULL && *pp == NULL); return p->QueryInterface(__uuidof(Q), (void**)pp); } T* p; };
//////////////////////////////////////////////////////////////////////////////
// CMarsComDispatchDriver / Specialization of CComQIPtr<IDispatch, IID_IDispatch>
//
// This is better than CComDispatchDriver for these reasons:
// - CComDispatchDriver in atl30 doesn't define an assignment/copy constructor
// - CcomDispatchDriver doesn't use _NoAddRefReleaseOnCComPtr
// - Added "const" to methods which are const
//
class CMarsComDispatchDriver { public: CMarsComDispatchDriver() { p = NULL; } CMarsComDispatchDriver(IDispatch* lp) { if ((p = lp) != NULL) p->AddRef(); } CMarsComDispatchDriver(IUnknown* lp) { p=NULL; if (lp != NULL) lp->QueryInterface(IID_IDispatch, (void **)&p); } CMarsComDispatchDriver(const CMarsComDispatchDriver& lp) { if ((p = lp.p) != NULL) p->AddRef(); } ~CMarsComDispatchDriver() { if (p) p->Release(); } void Release() {if (p) p->Release(); p=NULL;} operator IDispatch*() const {return p;} IDispatch& operator*() const {ATLASSERT(p!=NULL); return *p; } IDispatch** operator&() {ATLASSERT(p==NULL); return &p; }
_NoAddRefReleaseOnCComPtr<IDispatch>* operator->() const { ATLASSERT(p!=NULL); return (_NoAddRefReleaseOnCComPtr<IDispatch>*)p; } //IDispatch* operator->() {ATLASSERT(p!=NULL); return p; }
IDispatch* operator=(IDispatch* lp){return (IDispatch*)AtlComPtrAssign((IUnknown**)&p, lp);} IDispatch* operator=(IUnknown* lp) { return (IDispatch*)AtlComQIPtrAssign((IUnknown**)&p, lp, IID_IDispatch); } IDispatch* operator=(const CMarsComDispatchDriver& lp) { return (IDispatch*)AtlComPtrAssign((IUnknown**)&p, lp.p); } BOOL operator!() const {return (p == NULL) ? TRUE : FALSE;}
HRESULT GetPropertyByName(LPCOLESTR lpsz, VARIANT* pVar) { ATLASSERT(p); ATLASSERT(pVar); DISPID dwDispID; HRESULT hr = GetIDOfName(lpsz, &dwDispID); if (SUCCEEDED(hr)) hr = GetProperty(p, dwDispID, pVar); return hr; } HRESULT GetProperty(DISPID dwDispID, VARIANT* pVar) { ATLASSERT(p); return GetProperty(p, dwDispID, pVar); } HRESULT PutPropertyByName(LPCOLESTR lpsz, VARIANT* pVar) { ATLASSERT(p); ATLASSERT(pVar); DISPID dwDispID; HRESULT hr = GetIDOfName(lpsz, &dwDispID); if (SUCCEEDED(hr)) hr = PutProperty(p, dwDispID, pVar); return hr; } HRESULT PutProperty(DISPID dwDispID, VARIANT* pVar) { ATLASSERT(p); return PutProperty(p, dwDispID, pVar); } HRESULT GetIDOfName(LPCOLESTR lpsz, DISPID* pdispid) { return p->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpsz, 1, LOCALE_USER_DEFAULT, pdispid); } // Invoke a method by DISPID with no parameters
HRESULT Invoke0(DISPID dispid, VARIANT* pvarRet = NULL) { DISPPARAMS dispparams = { NULL, NULL, 0, 0}; return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); } // Invoke a method by name with no parameters
HRESULT Invoke0(LPCOLESTR lpszName, VARIANT* pvarRet = NULL) { HRESULT hr; DISPID dispid; hr = GetIDOfName(lpszName, &dispid); if (SUCCEEDED(hr)) hr = Invoke0(dispid, pvarRet); return hr; } // Invoke a method by DISPID with a single parameter
HRESULT Invoke1(DISPID dispid, VARIANT* pvarParam1, VARIANT* pvarRet = NULL) { DISPPARAMS dispparams = { pvarParam1, NULL, 1, 0}; return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); } // Invoke a method by name with a single parameter
HRESULT Invoke1(LPCOLESTR lpszName, VARIANT* pvarParam1, VARIANT* pvarRet = NULL) { HRESULT hr; DISPID dispid; hr = GetIDOfName(lpszName, &dispid); if (SUCCEEDED(hr)) hr = Invoke1(dispid, pvarParam1, pvarRet); return hr; } // Invoke a method by DISPID with two parameters
HRESULT Invoke2(DISPID dispid, VARIANT* pvarParam1, VARIANT* pvarParam2, VARIANT* pvarRet = NULL) { CComVariant varArgs[2] = { *pvarParam2, *pvarParam1 }; DISPPARAMS dispparams = { &varArgs[0], NULL, 2, 0}; return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); } // Invoke a method by name with two parameters
HRESULT Invoke2(LPCOLESTR lpszName, VARIANT* pvarParam1, VARIANT* pvarParam2, VARIANT* pvarRet = NULL) { HRESULT hr; DISPID dispid; hr = GetIDOfName(lpszName, &dispid); if (SUCCEEDED(hr)) hr = Invoke2(dispid, pvarParam1, pvarParam2, pvarRet); return hr; } // Invoke a method by DISPID with N parameters
HRESULT InvokeN(DISPID dispid, VARIANT* pvarParams, int nParams, VARIANT* pvarRet = NULL) { DISPPARAMS dispparams = { pvarParams, NULL, nParams, 0}; return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); } // Invoke a method by name with Nparameters
HRESULT InvokeN(LPCOLESTR lpszName, VARIANT* pvarParams, int nParams, VARIANT* pvarRet = NULL) { HRESULT hr; DISPID dispid; hr = GetIDOfName(lpszName, &dispid); if (SUCCEEDED(hr)) hr = InvokeN(dispid, pvarParams, nParams, pvarRet); return hr; } static HRESULT GetProperty(IDispatch* pDisp, DISPID dwDispID, VARIANT* pVar) { ATLTRACE2(atlTraceCOM, 0, _T("CPropertyHelper::GetProperty\n")); DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; return pDisp->Invoke(dwDispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispparamsNoArgs, pVar, NULL, NULL); }
static HRESULT PutProperty(IDispatch* pDisp, DISPID dwDispID, VARIANT* pVar) { ATLTRACE2(atlTraceCOM, 0, _T("CPropertyHelper::PutProperty\n")); DISPPARAMS dispparams = {NULL, NULL, 1, 1}; dispparams.rgvarg = pVar; DISPID dispidPut = DISPID_PROPERTYPUT; dispparams.rgdispidNamedArgs = &dispidPut;
if (pVar->vt == VT_UNKNOWN || pVar->vt == VT_DISPATCH || (pVar->vt & VT_ARRAY) || (pVar->vt & VT_BYREF)) { HRESULT hr = pDisp->Invoke(dwDispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF, &dispparams, NULL, NULL, NULL); if (SUCCEEDED(hr)) return hr; }
return pDisp->Invoke(dwDispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL); }
IDispatch* p; };
#define CComDispatchDriver _DONT_USE_CComDispatchDriver_USE_CMarsComDispatchDriver
//////////////////////////////////////////////////////////////////////////////
// CMarsSimpleArray / Specialization of CSimpleArray
//
// This is better than CSimpleArray for these reasons:
// overloaded the operator=() and defined a copy constructor.
// Fixed various pointer math to use + instead of & because the operator&()
// on contained smart types (like CComPtr) gets called accidentally if you
// do this: &m_aT[i] instead of (m_aT + i).
//
/////////////////////////////////////////////////////////////////////////////
// Collection helpers - CMarsSimpleArray
#ifdef new
#pragma push_macro("new")
#define _ATL_REDEF_NEW
#undef new
#endif
template <class T> class CMarsSimpleArray { public: T* m_aT; int m_nSize; int m_nAllocSize;
// Construction/destruction
CMarsSimpleArray() : m_aT(NULL), m_nSize(0), m_nAllocSize(0) { }
~CMarsSimpleArray() { RemoveAll(); }
CMarsSimpleArray(const CMarsSimpleArray<T> ¤t) : m_aT(NULL), m_nSize(0), m_nAllocSize(0) { *this = current; }
CMarsSimpleArray &operator=(const CMarsSimpleArray<T> &right) { if (&right != this) { // BUGBUG (tnoonan) -- this code is going to potentially leak
// if the new size is smaller than the old.
T *aT = NULL; aT = (T *)realloc(m_aT, right.m_nAllocSize * sizeof(T));
// Did the realloc succeed?
if (aT) { m_aT = aT; m_nSize = right.m_nSize; m_nAllocSize = right.m_nAllocSize;
// WARNING: This is not a simple mempcy() for a very specific reason!
// Each element must be copied with = in case the T class has an
// overloaded operator=(). (i.e. in the case of smart ptrs).
//
for (int idx = 0; idx < m_nSize; ++idx) { m_aT[idx] = right.m_aT[idx]; } }
}
return *this; }
// Operations
int GetSize() const { return m_nSize; } BOOL Add(T& t) { if(m_nSize == m_nAllocSize) { T* aT; int nNewAllocSize = (m_nAllocSize == 0) ? 1 : (m_nSize * 2); aT = (T*)realloc(m_aT, nNewAllocSize * sizeof(T)); if(aT == NULL) return FALSE; m_nAllocSize = nNewAllocSize; m_aT = aT; } m_nSize++; SetAtIndex(m_nSize - 1, t); return TRUE; } BOOL Remove(T& t) { int nIndex = Find(t); if(nIndex == -1) return FALSE; return RemoveAt(nIndex); } BOOL RemoveAt(int nIndex) { ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
m_aT[nIndex].~T();
if(nIndex != (m_nSize - 1)) { //
// BUGFIX: Use m_aT + nIndex instead of &m_aT[nIndex] to avoid calling type's operator &()
//
memmove((void*)(m_aT + nIndex), (void*)(m_aT + nIndex + 1), (m_nSize - (nIndex + 1)) * sizeof(T));
ZeroMemory((void*)(m_aT + (m_nSize-1)), sizeof(m_aT[0])); } m_nSize--; return TRUE; } BOOL InsertAt(int nIndex, T& t) { // Index equal to size means to insert at the end
ATLASSERT(nIndex >= 0 && nIndex <= m_nSize);
// First check if we have room...
if(m_nSize == m_nAllocSize) { T* aT; int nNewAllocSize = (m_nAllocSize == 0) ? 1 : (m_nSize * 2); aT = (T*)realloc(m_aT, nNewAllocSize * sizeof(T)); if(aT == NULL) return FALSE; m_nAllocSize = nNewAllocSize; m_aT = aT; }
// If we're not adding to the end, then we need to shift elements past the insertion point
// down one.
if (nIndex < m_nSize) { memmove( (void*)(m_aT + (nIndex + 1)), (void*)(m_aT + (nIndex)), sizeof(T) * (m_nSize - nIndex));
// TRICKY: This memmove is a HACK -- it doesn't call the ctors and dtors of the elements.
// However below, we're going to make an assignment, and that assignment is going to
// cause the operator=() to fire on user types, which might mess up any
// internal pointers. Ouch. We need to avoid that by wiping out the memory
// destructively first.
//
// The reason this is bad is because the memmove has caused the nIndex and nIndex + 1
// entries to both share the same data, including pointers, so we have danglers. :-(
//
ZeroMemory((void*)(m_aT + nIndex), sizeof(T)); }
m_nSize++; SetAtIndex(nIndex, t); return TRUE; } void RemoveAll() { if(m_aT != NULL) { for(int i = 0; i < m_nSize; i++) m_aT[i].~T(); free(m_aT); m_aT = NULL; } m_nSize = 0; m_nAllocSize = 0; } T& operator[] (int nIndex) const { ATLASSERT(nIndex >= 0 && nIndex < m_nSize); return m_aT[nIndex]; } T* GetData() const { return m_aT; }
// Implementation
class Wrapper { public: Wrapper(T& _t) : t(_t) { } template <class _Ty> void *operator new(size_t, _Ty* p) { return p; } T t; }; void SetAtIndex(int nIndex, T& t) { ATLASSERT(nIndex >= 0 && nIndex < m_nSize); //
// BUGFIX: Use m_aT + nIndex instead of &m_aT[nIndex] to avoid calling type's operator &()
//
new(m_aT + nIndex) Wrapper(t); } int Find(T& t) const { for(int i = 0; i < m_nSize; i++) { if(m_aT[i] == t) return i; } return -1; // not found
} }; // CMarsSimpleArray
// for arrays of simple types
template <class T> class CMarsSimpleValArray : public CMarsSimpleArray< T > { public: BOOL Add(T t) { return CMarsSimpleArray< T >::Add(t); } BOOL Remove(T t) { return CMarsSimpleArray< T >::Remove(t); } T operator[] (int nIndex) const { return CMarsSimpleArray< T >::operator[](nIndex); }
CMarsSimpleValArray &operator=(const CMarsSimpleValArray<T> &right) { if (&right != this) { T *aT = NULL; aT = (T *)realloc(m_aT, right.m_nAllocSize * sizeof(T));
// Did the realloc succeed?
if (aT) { m_aT = aT; m_nSize = right.m_nSize; m_nAllocSize = right.m_nAllocSize;
CopyMemory(m_aT, right.m_aT, sizeof(T) * m_nSize); }
}
return *this; } };
#ifdef _ATL_REDEF_NEW
#pragma pop_macro("new")
#undef _ATL_REDEF_NEW
#endif
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// class CComTableMarshalPtr
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=
template <class I> class CComTableMarshalPtr : public CComPtr<I> { public: CComTableMarshalPtr(DWORD dwGITKey); virtual ~CComTableMarshalPtr();
static HRESULT RegisterInterface(IUnknown *pUnk, DWORD *pdwKey); static HRESULT RevokeInterface(DWORD dwKey);
private: CComTableMarshalPtr(); // Protect access to default ctor
}; // CComTableMarshalPtr
//============================================================================
// class CComTableMarshalPtr
//============================================================================
template <class I> CComTableMarshalPtr<I>::CComTableMarshalPtr(DWORD dwKey) { CComPtr<IGlobalInterfaceTable> spGIT(CMarsGlobalsManager::GIT());
if (spGIT) { I *pInt = NULL;
HRESULT hr = spGIT->GetInterfaceFromGlobal(dwKey, __uuidof(I), (void **)&pInt);
if (SUCCEEDED(hr)) Attach(pInt); } } // CComTableMarshalPtr
template <class I> CComTableMarshalPtr<I>::~CComTableMarshalPtr() { } // ~CComTableMarshalPtr
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
//
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
template <class I> HRESULT CComTableMarshalPtr<I>::RegisterInterface(IUnknown *pInt, DWORD *pdwKey) { HRESULT hr = E_INVALIDARG;
if (IsValidInterfacePtr(pInt) && IsValidWritePtr(pdwKey)) { CComPtr<IGlobalInterfaceTable> spGIT(CMarsGlobalsManager::GIT());
ATLASSERT(spGIT);
if (spGIT) { hr = spGIT->RegisterInterfaceInGlobal(pInt, __uuidof(I), pdwKey); } }
return hr; } // RegisterInterface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// CComTableMarshalPtr::RevokeInterface()
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
template <class I> HRESULT CComTableMarshalPtr<I>::RevokeInterface(DWORD dwKey) { HRESULT hr = E_FAIL;
CComPtr<IGlobalInterfaceTable> spGIT(CMarsGlobalsManager::GIT());
ATLASSERT(spGIT);
if (spGIT) { hr = spGIT->RevokeInterfaceFromGlobal(dwKey); }
return hr; } // RevokeInterface
typedef CComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > CComVariantEnum;
//////////////////////////////////////////////////////////////////////////////
// CMarsComEnumVariant - Simple derivation for convenience. This is the standard
// type of a CComEnum for use in a collection that returns IEnumVARIANT.
//
// Our helper class has some luxury features that completely handle the common
// case of take a CMarsSimpleArray full of "stuff," stuffing those things into
// an array of CComVariant's (so we can be type-agnostic about what the
// "things" are), and then creates a CComEnum and puts it in an out-param.
//
template <class I> class CMarsComEnumVariant : public CComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > { public: static HRESULT CreateFromMarsSimpleArray(CMarsSimpleArray<CComClassPtr< I > > &arr, IUnknown **ppUnk) { // Internal API, so rip if the out param is bad
ATLASSERT(NULL != ppUnk);
HRESULT hr = E_FAIL;
// Create one of ourselves...
CComObject<CMarsComEnumVariant<CMarsSimpleArray< CComClassPtr< I > > > > *pEnum = NULL;
hr = CComObject<CMarsComEnumVariant<CMarsSimpleArray< CComClassPtr< I > > > >::CreateInstance(&pEnum);
if (SUCCEEDED(hr)) { // Allocation must have succeeded if no error HRESULT
ATLASSERT(pEnum); pEnum->AddRef();
VARIANT *rgVar = new VARIANT[arr.GetSize()]; LONG idxEntry;
if (rgVar) { HRESULT hrTestForDispatch = E_FAIL;
for (idxEntry = 0; idxEntry < arr.GetSize(); idxEntry++) { CComClassPtr<I> spElt;
spElt = arr.operator[](idxEntry);
hrTestForDispatch = spElt->QueryInterface(IID_IDispatch, (void **)&V_DISPATCH(&rgVar[idxEntry]));
//
// This had better succeed: the type I must be a dispatch interface, because otherwise,
// you can't pass this object to script anyway, so what's the point of the collection???
// If you really want an IEnumXXXX for your non-automation interfaces, use ATL's CComEnum
// directly with appropriate template parameters.
//
ATLASSERT(SUCCEEDED(hrTestForDispatch));
V_VT(&rgVar[idxEntry]) = VT_DISPATCH; }
// If this succeeds, then ATL will have taken care of freeing our array for
// us. How nice of it.
//
hr = pEnum->Init(&rgVar[0], &rgVar[arr.GetSize()], NULL, AtlFlagTakeOwnership);
if (SUCCEEDED(hr)) { hr = pEnum->QueryInterface(IID_IUnknown, (void **)ppUnk); } else { for(idxEntry = 0; idxEntry < arr.GetSize(); idxEntry++) { VariantClear(&rgVar[idxEntry]); } delete[] rgVar; } } else { hr = E_OUTOFMEMORY; }
pEnum->Release(); } // If CreateInstance SUCCEEDED
return hr; } };
|