Back

#pragma once

template <typename T>
struct _CopyVariantFromAdaptItf
{
   static HRESULT copy(VARIANT * p1, const CAdapt< CComPtr<T> > * p2)
   {
      HRESULT hr = p2->m_T->QueryInterface(IID_IDispatch, (void**)&p1->pdispVal);
      if(SUCCEEDED(hr))
         p1->vt = VT_DISPATCH;
      return hr;
   }

   static void init(VARIANT * p)
   {
      ::VariantInit(p);
   }

   static void destroy(VARIANT * p)
   {
      ::VariantClear(p);
   }
};

template <typename T>
struct _CopyItfFromAdaptItf
{
   static HRESULT copy(T ** p1, const CAdapt< CComPtr<T> > * p2)
   {
      if(*p1 = p2->m_T)
      {
         (*p1)->AddRef();
         return S_OK;
      }
      return E_POINTER;
   }

   static void init(T ** p){};

   static void destroy(T ** p)
   {
      if(*p)
         (*p)->Release();
   }
};

template <class T, class CollType, class ItemType, class CopyItem, class EnumType>
class ISafeCollectionOnSTLImpl : public T
{
public:

   ISafeCollectionOnSTLImpl()
   {
      ::InitializeCriticalSection(&m_csCollection);
   }

   ~ISafeCollectionOnSTLImpl()
   {
      ::DeleteCriticalSection(&m_csCollection);
   }

   STDMETHOD(get_Count)(long* pcount)
   {
      HRESULT hr = OnInterfaceAccess();
      if(hr != S_OK)
         return hr;

      CCritSecLock cs(m_csCollection);

      if (pcount == NULL)
         return E_POINTER;
      ATLASSUME(m_coll.size() <= LONG_MAX);

      *pcount = (long)m_coll.size();

      return S_OK;
   }

   STDMETHOD(get_Item)(long Index, ItemType* pvar)
   {
      HRESULT hr = OnInterfaceAccess();
      if(hr != S_OK)
         return hr;

      CCritSecLock cs(m_csCollection);

      if(Index < 1 || Index > (long)m_coll.size())
         return OnIndexOutOfRange();

      //Index is 1-based;
      if (pvar == NULL)
         return E_POINTER;

      hr = E_FAIL;
      Index--;
      CollType::const_iterator iter = m_coll.begin();
      while (iter != m_coll.end() && Index > 0)
      {
         iter++;
         Index--;
      }
      if (iter != m_coll.end())
         hr = CopyItem::copy(pvar, &*iter);
      return hr;
   }

   STDMETHOD(get__NewEnum)(IUnknown** ppUnk)
   {
      HRESULT hr = OnInterfaceAccess();
      if(hr != S_OK)
         return hr;

      CCritSecLock cs(m_csCollection);

      if (ppUnk == NULL)
         return E_POINTER;
      *ppUnk = NULL;
      CComObject<EnumType>* p;
      hr = CComObject<EnumType>::CreateInstance(&p);
      if (SUCCEEDED(hr))
      {
         hr = p->Init(this, m_coll);
         if(hr == S_OK)
            hr = p->QueryInterface(__uuidof(IUnknown), (void**)ppUnk);
      }
      if (hr != S_OK)
         delete p;
      return hr;
   }

   CollType m_coll;
   CRITICAL_SECTION m_csCollection;

protected:

   virtual HRESULT OnIndexOutOfRange(){return E_INVALIDARG;};
   virtual HRESULT OnInterfaceAccess(){return S_OK;}; // Notifies about access to the interface properties or methods;
};

#define DECLARE_PSL_COLLECTION(Col, T)\
   typedef vector<CAdapt<CComPtr<IPSL##T> > > Col##Type;\
   typedef CComEnumOnSTL<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _CopyVariantFromAdaptItf<IPSL##T>, Col##Type, CComGlobalsThreadModel > C##T##EnumImpl;\
   typedef ISafeCollectionOnSTLImpl<IDispatchImpl<IPSL##Col, &IID_IPSL##Col, &LIBID_ProSysLib, PSL_HiVersion, PSL_LoVersion>, Col##Type, IPSL##T*, _CopyItfFromAdaptItf<IPSL##T>, C##T##EnumImpl> C##Col##Collection;

Top