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

 源代码下载

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"

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏开发与安全

《linux c 编程一站式学习》课后部分习题解答

1、假设变量x和n是两个正整数,我们知道x/n这个表达式的结果要取Floor,例如x是17,n是4,则结果是4。如果希望结果取Ceiling应该怎么写表达式呢?...

49960
来自专栏Jimoer

JVM学习记录-对象已死吗

前言 先来回顾一下,在jvm运行时数据区,分为两部分,一个部分是线程共享区,主要包括堆和方法区,另一部是线程私有区分包括本地方法栈,虚拟机栈和程序计数器。在线程...

36460
来自专栏海天一树

图的广度优先搜索

广度优先搜索算法是最简便的图的搜索算法之一,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索...

16630
来自专栏AhDung

【手记】注意BinaryWriter写string的小坑——会在string前加上长度前缀length-prefixed

之前以为BinaryWriter写string会严格按构造时指定的编码(不指定则是无BOM的UTF8)写入string的二进制,如下面的代码:

33030
来自专栏小勇DW3

回过头来看对象的四种状态强软弱虚引用的理解

  在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(W...

12640
来自专栏debugeeker的专栏

《coredump问题原理探究》Linux x86版7.7节 set对象

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/detai...

11610
来自专栏mathor

TRIE(4)

 这道题的大意是我们有一个网站,然后要配置规则,决定哪些IP能访问,哪些IP不能。这些规则大概长这个样子:

11440
来自专栏Ryan Miao

java基础面试题

参考:http://blog.csdn.net/jackfrued/article/details/44921941 说未经允许不转载,我只好参考了。 1.面向...

38150
来自专栏HansBug's Lab

1012: [JSOI2008]最大数maxnumber

1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MB Submit: 443...

29350
来自专栏Jackson0714

PHP内核之旅-3.变量

16840

扫码关注云+社区

领取腾讯云代金券