代码改变世界

COM中集合和枚举器笔记(2)枚举器内部实现

2012-11-08 13:20  Clingingboy  阅读(523)  评论(0编辑  收藏  举报

 

一.ATL枚举器接口

CComIEnum通用枚举器接口

template<class T>
class ATL_NO_VTABLE CComIEnum : 
    public IUnknown
{
public:
    STDMETHOD(Next)(
        _In_ ULONG celt, 
        _Out_ T* rgelt, 
        _Out_opt_ ULONG* pceltFetched) = 0;
    STDMETHOD(Skip)(_In_ ULONG celt) = 0;
    STDMETHOD(Reset)(void) = 0;
    STDMETHOD(Clone)(_Deref_out_ CComIEnum<T>** ppEnum) = 0;
};

二.CComEnumImpl定义

template <class Base, const IID* piid, class T, class Copy>
class ATL_NO_VTABLE CComEnumImpl : 
    public Base
{
public:
    CComEnumImpl() 
    {
        m_begin = m_end = m_iter = NULL;
        m_dwFlags = 0;
    }
    virtual ~CComEnumImpl();
    
    STDMETHOD(Next)(
        _In_ ULONG celt, 
        _Out_ T* rgelt, 
        _Out_opt_ ULONG* pceltFetched);
    STDMETHOD(Skip)(_In_ ULONG celt);
    STDMETHOD(Reset)(void)
    {
        m_iter = m_begin;
        return S_OK;
    }
    STDMETHOD(Clone)(_Deref_out_ Base** ppEnum);
    HRESULT Init(
        _In_ T* begin, 
        _In_ T* end, 
        _In_opt_ IUnknown* pUnk,
        _In_ CComEnumFlags flags = AtlFlagNoCopy);
    
    CComPtr<IUnknown> m_spUnk;
    T* m_begin;
    T* m_end;
    T* m_iter;
    DWORD m_dwFlags;
protected:
    enum FlagBits
    {
        BitCopy=1,
        BitOwn=2
    };
};

m_begin,m_end,m_iter表示元素位置

三.Next实现

template <class Base, const IID* piid, class T, class Copy>
STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Next(
    _In_ ULONG celt, 
    _Out_ T* rgelt,
    _Out_opt_ ULONG* pceltFetched)
{
    if (pceltFetched != NULL)
        *pceltFetched = 0;
    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 = celt < nRem ? celt : nRem ;
    if (pceltFetched != NULL)
        *pceltFetched = nMin;
    T* pelt = rgelt;
    while(nMin--)
    {
        HRESULT hr = Copy::copy(pelt, m_iter);
        if (FAILED(hr))
        {
            while (rgelt < pelt)
                Copy::destroy(rgelt++);
            if (pceltFetched != NULL)
                *pceltFetched = 0;
            return hr;
        }
        pelt++;
        m_iter++;
    }
    return hRes;
}

 

关键部分在于Copy::copy和Copy::destroy方法,所以拷贝策略在于外部的Copy类的的静态方法copy

四.拷贝策略类

template <class T>
class _Copy
{
public:
    static HRESULT copy(_Out_ T* p1, _In_ const T* p2) 
    { 
        Checked::memcpy_s(p1, sizeof(T), p2, sizeof(T)); 
        return S_OK;
    }
    static void init(_Inout_opt_ T*) 
    {
    }
    static void destroy(_Inout_opt_ T*) 
    {
    }
};

除此之外,还提供了一些常用的特化类

image

五.CComEnum类

 

template <class Base, const IID* piid, class T, class Copy, class ThreadModel = CComObjectThreadModel>
class ATL_NO_VTABLE CComEnum :
    public CComEnumImpl<Base, piid, T, Copy>,
    public CComObjectRootEx< ThreadModel >
{
public:
    typedef CComEnum<Base, piid, T, Copy > _CComEnum;
    typedef CComEnumImpl<Base, piid, T, Copy > _CComEnumBase;
    BEGIN_COM_MAP(_CComEnum)
        COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
    END_COM_MAP()
};

如上,所以要所以CComEnum 的话,需如下定义

typedef CComEnum< IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,
    _Copy<VARIANT> > CComEnumVariant;