代码改变世界

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

  Clingingboy  阅读(530)  评论(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;
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示