前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ATL源码学习5---集合与枚举接口支持

ATL源码学习5---集合与枚举接口支持

作者头像
雪影
发布2018-08-02 14:32:00
5840
发布2018-08-02 14:32:00
举报
文章被收录于专栏:流媒体人生流媒体人生

 源代码下载

http://download.csdn.net/source/1690987

  C++程序员学过STL的都知道,STL分为三大模块,算法、容器、迭代器。容器的作用就是存储管理维护数据,迭代器的工作就是是客户能够访问(读写)容器中的数据。尽管迭代器的实现依赖于容器存储数据的方式,但是迭代器的实现细节对于客户隐藏的,客户可以使用同样的方式来读写容器中的数据。     许多的COM库暴露的都是一组对象,这些对象又称为对象模型。COM对象模型包含一组子对象和父对象。COM集合(collection)和枚举器(enumerator)将父对象和子对象粘合在一起。对象模型中父对象或者说是根对象,是允许被创建的,这个根对象有子对象或子对象的集合,这 些子对象不能自主创建而必须由他的根对象创建或者由他的父对象创建。

ATL 提供了下列帮助您实现集合和枚举数的类。 类                                               说明 ICollectionOnSTLImpl          集合接口实现 IEnumOnSTLImpl                枚举数接口实现(假定数据存储在 STL 兼容容器中) CComEnumImpl                  枚举数接口实现(假定数据存储在数组中) CComEnumOnSTL               枚举数对象实现(使用 IEnumOnSTLImpl) CComEnum                         枚举数对象实现(使用 CComEnumImpl) _Copy                                 复制策略类 _CopyInterface                   复制策略类 CAdapt                               适配器类(隐藏operator &,以便 CComPtr、CComQIPtr 和 CComBSTR 可以存储在 STL 容器中)

1.枚举器

枚举器是提供循环访问集合项的接口的COM对象。枚举数接口通过四个必需的方法 Next、Skip、Reset 和 Clone,提供对集合元素的顺序访问。

IEnumXXXX Methods      Description  Next                                Retrieves a specified number of items in the enumeration sequence. Skip                                Skips over a specified number of items in the enumeration sequence. Reset                              Resets the enumeration sequence to the beginning. Clone                              Creates another enumerator that contains the same enumeration state as the current one.

1.1 枚举器接口的支持   枚举器的接口一般通过IEnumOnSTLImpl或CComEnumImpl来实现,即就是Next、Skip、Reset 和 Clone四个方法的实现。  template <class Base, const IID* piid, class T, class Copy> class ATL_NO_VTABLE CComEnumImpl : public Base{} 和 template <class Base, const IID* piid, class T, class Copy, class CollType> class ATL_NO_VTABLE IEnumOnSTLImpl : public Base{} Base        是要实现的枚举接口,        例如IEnumVARIANT piid          是指向枚举口接口类型的IID        例如 &IID_IEnumVARIANT T              是被枚举的数据类型    Copy       是负责复制数据到客户缓冲区的类. CollType 是容器中存储的数据类型    在IEnumOnSTLImpl中定义了一个CollType类型的指针,在初始化(调用Init方法)时指向容器中的数据。 1.2枚举器组件的实现步骤 即实现枚举器组件的IUnknown接口的方法,IUnknown接口的实现需要两个步骤。     * CComObject、CComAggObject 或 CComPolyObject 实现 IUnknown 方法。     * CComObjectRoot 或 CComObjectRootEx 维护管理IUnknown的引用计数和外部指针。 因此要枚举器组件的实现同样需要从CComObjectRootEx派生实现IUnknown接口的引用计数,然后将派生类作为CComObject或CComAggObject等得模版参数,实现IUnknown 方法方法。从而得到一个完整的枚举器组件。 a.从CComObjectRootEx派生可以通过模版类CComEnum和CComEnumOnSTL来实现   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 >{} template <class Base, const IID* piid, class T, class Copy, class CollType, class ThreadModel = CComObjectThreadModel> class ATL_NO_VTABLE CComEnumOnSTL :     public IEnumOnSTLImpl<Base, piid, T, Copy, CollType>,     public CComObjectRootEx< ThreadModel > b.将前面实现的类作为CComObject、CComAggObject等类的模版参数 例: 枚举器组件接口的实现 typedef CComEnumOnSTL< EnumeratorInterface, &__uuidof(EnumeratorInterface), EnumeratorExposedType,                             EnumeratorCopyType, ContainerType > EnumeratorType; 枚举器组件的IUnknown接口的实现 typedef CComObject<EnumeratorType>  EnumeratorObjectType

CComEnumOnSTL类的继承关系与CComEnum类似

2.集合的实现 集合接口必须至少提供返回集合中项数的Count属性、基于索引返回集合项的Item 属性、以及返回集合的枚举数的_NewEnum 属性。 (可选)集合接口可以提供可在集合中插入项或从集合中删除项的Add和Remove方法,以及移除所有项的Clear方法。 ATL 提供了ICollectionOnSTLImpl接口,使您能够在对象上快速实现基于标准模板库 (STL) 的集合接口。 ICollectionOnSTLImpl模版类实现了get_Count、get_Item、get__NewEnum方法,已经一个存储数据的变量m_coll。 集合的实现步骤: a.定义一个ICollectionOnSTLImpl模版类 typedef ICollectionOnSTLImpl<CollectionInterface, ContainerType, CollectionExposedType,CollectionCopyType, EnumeratorType >  CollectionType; b.创建一个组件(即创建一个从CComObjectRootEx和CComCoClass派生的类)从ICollectionOnSTLImpl的模版类派生 class ATL_NO_VTABLE CCollect :     public CComObjectRootEx<CComSingleThreadModel>,     public CComCoClass<CCollect, &CLSID_Collect>,     public IDispatchImpl<tttydColl::CollectionType, &IID_ICollect, &LIBID_ATLCOLLECTIONLib>{} 此致,我们已经可以实现一个完整的COM聚合与枚举器。

3.实例代码以及说明

3.1 聚合接口和枚举器接口定义     interface IEnumNums;     [         object,         uuid(C08D352C-9203-41D8-8E1C-469D06844928),         dual,         helpstring("ICollect Interface"),         pointer_default(unique)     ]     interface ICollect : IDispatch     {             [id(DISPID_NEWENUM), propget]             HRESULT _NewEnum([out, retval] IUnknown** ppUnk);             [id(DISPID_VALUE), propget]             HRESULT Item(    [in] long Index,                             [out, retval] long* pVal);             [id(0x00000001), propget]             HRESULT Count([out, retval] long * pVal);     };     [     object,     uuid(E75EDDDF-3B3C-11D2-983C-00600823CFFB),     helpstring("IEnumNums Interface"),     pointer_default(unique)     ]     interface IEnumNums : IUnknown     {         [local]         HRESULT Next([in] ULONG celt,                      [out] long* rgelt,                      [out] ULONG *pceltFetched);         [call_as(Next)]         HRESULT RemoteNext([in] ULONG celt,                            [out, size_is(celt), length_is(*pceltFetched)] long* rgelt,                            [out] ULONG *pceltFetched);         HRESULT Skip([in] ULONG celt);         HRESULT Reset();         HRESULT Clone([out] IEnumNums **ppenum);     }; 3.2 枚举器组件类的定义,即定义实现IEnumNums接口的类     // 定义容器数据的存储结构     typedef std::vector<long>                    ContainerType;     //定义枚举器接口类型以及Item方法暴露的数据类型     typedef IEnumNums                                EnumeratorInterface;     typedef long                                    EnumeratorExposedType;        // 定义枚举器复制策略方法     typedef ATL::_Copy<long>        EnumeratorCopyType;     //需要将相关的类型参数填充到模版类CComEnumOnSTL中,实现枚举器类     typedef CComEnumOnSTL< EnumeratorInterface, &__uuidof(EnumeratorInterface), EnumeratorExposedType,                             EnumeratorCopyType, ContainerType > EnumeratorType; 3.3 集合组件ICollect接口的实现类定义,即定义实现ICollect接口的类     // 我们的容器接口ICollect的方法Item暴露的数据类型是long     typedef long                                    CollectionExposedType;     typedef ICollect                                CollectionInterface;     //定义集合类的实现,需要将相关的类型参数填充到模版类ICollectionOnSTLImpl中,实现集合类     typedef ICollectionOnSTLImpl<CollectionInterface, ContainerType, CollectionExposedType,                             CollectionCopyType, EnumeratorType > CollectionType; 3.4 集合组件的实现 class ATL_NO_VTABLE CCollect :     public CComObjectRootEx<CComSingleThreadModel>,     public CComCoClass<CCollect, &CLSID_Collect>,     public IDispatchImpl<tttydColl::CollectionType, &IID_ICollect, &LIBID_ATLCOLLECTIONLib> { public:     CCollect()     {         m_coll.push_back(100);         m_coll.push_back(200);         m_coll.push_back(300);         m_coll.push_back(400);     } DECLARE_REGISTRY_RESOURCEID(IDR_COLLECT) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CCollect)     COM_INTERFACE_ENTRY(ICollect)     COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() // ICollect public: }; 到这里,集合组件已经实现了,现在可以编译测试了。

3.5 客户端测试代码 我们仅仅测试集合接口IColloct::get_Item和IEnumNums::Next方法,将得到的数据打印出来。 我们的集合组件中存储的数据是100,200,300,400 #include "stdafx.h"

代码语言:javascript
复制
#include <iostream> 
#include <atlbase.h> 
#include "..//ATLCollection.h" 
#include "..//ATLCollection_i.c" 
int main(int argc, char* argv[])  
{  
    CoInitialize(NULL);  
    CComPtr<ICollect>  spPrimes;  
 if( SUCCEEDED(spPrimes.CoCreateInstance(CLSID_Collect)) )  
    {  
 long  count;  
 HRESULT hr = spPrimes->get_Count(&count);  
 for(int i=1; i<=count; i++)  
        {  
 long val;  
            spPrimes->get_Item(i,&val);  
                std::cout<<val<<" ";  
        }  
        std::cout << std::endl;  
        CComPtr<IEnumNums>  spEnum;  
        CComPtr<IUnknown>    spEnum1;  
        hr = spPrimes->get__NewEnum(&spEnum1);  
        spEnum1->QueryInterface(IID_IEnumNums,(void**)&spEnum);  
 const size_t MAX_PRIMES = 1;  
 long rgnPrimes[MAX_PRIMES];  
 do 
        {  
 ULONG cFetched;  
            hr = spEnum->Next(MAX_PRIMES, rgnPrimes, &cFetched);  
 if( SUCCEEDED(hr) )  
            {  
 if( hr == S_OK ) cFetched = MAX_PRIMES;  
 for( long* pn = &rgnPrimes[0]; pn != &rgnPrimes[cFetched]; ++pn )  
                {  
                    std::cout << *pn << " ";  
                }  
            }  
        }  
 while (hr == S_OK);  
            std::cout << std::endl;  
        spPrimes.Release();  
    }  
    CoUninitialize();  
 return 0;  
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2009年09月24日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档