#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;
    }
};



