Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1038 lines
32 KiB

#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> &current) : 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;
}
};