zoukankan      html  css  js  c++  java
  • COM中多个数据值返回

    在COM中,实现多个数据返回,可以使用SAFEARRAY和ICollection两种方法,其他方法,我还没有考虑到。

    使用SAFEARRAY方式返回的多个数据,并不是特别灵活,而且SAFEARRAY在其他语言中,使用也不是特别方便,尤其是JavaScript中,想要处理SAFEARRAY,还是挺麻烦的一件事。同时,SAFEARRAY需要对处理的数据结构进行特别处理,应该算得上是一个麻烦吧。

    使用ICollection返回多个数据,相对比较方便,当然,也有很多细节需要注意,但是实现了这样一个ICollection对象之后,便可以重用这个对象,相比较SAFEARRAY,重用效果更好,也更容易做更多的数据扩展与数据处理。ICollection是一个枚举容器,需要枚举器来辅助进行操作元素

    ICollection是标准的COM接口:

    interface ICollection : IDispatch
    {
    [propget, id(DISPID_LISTITEM)] HRESULT Item([in] const VARIANT varIndex, [out, retval] VARIANT *pVal);
     [propget, id(DISPID_LISTCOUNT)] HRESULT Count( [out, retval] long *pVal);
    [propget, id(DISPID_COLLCOUNT)] HRESULT length([out, retval] long *pVal);
    [propget, id(DISPID_NEWENUM), restricted, hidden]HRESULT _NewEnum([out, retval] IUnknown* *pVal);
    };
    ICollection需要枚举器辅助进行数据处理,非常符合OOP的实现,这些枚举器都用IEnum开头,类似接口为:
    interface IEnumXXX : IUnknown
    {
    HRESULT Next( unsigned long celt, VARIANT * rgvar, unsigned long * pceltFetched);
    HRESULT Skip(unsigned long celt);
    HRESULT Reset();
    HRESULT Clone(IEnumVARIANT ** ppenum);
    };
    目前微软已经定义好的IEnumXXX类型有:

    下面是一个ATL中的ICollection实现:

    // idl文件:

    // DynamicArray.idl : IDL source for DynamicArray.dll
    //
    
    // This file will be processed by the MIDL tool to
    // produce the type library (DynamicArray.tlb) and marshalling code.
    
    import "oaidl.idl";
    import "ocidl.idl";
    	[
    		object,
    		uuid(7942687C-3E0D-468B-80E7-7D0FC34B15EF),
    		dual,
    		helpstring("IVector Interface"),
    		pointer_default(unique)
    	]
    	interface IVector : IDispatch
    	{
    		    [id(DISPID_NEWENUM), propget]
    			HRESULT _NewEnum([out, retval] IUnknown** ppUnk);
    
    			[id(DISPID_VALUE), propget]
    			HRESULT Item(	[in] long Index, 
    							[out, retval] VARIANT* pVal);
    
    			[id(0x00000001), propget]
    			HRESULT Count([out, retval] long * pVal);
    	};
    
    [
    	uuid(A08196C2-46C7-4BE2-824D-A26581990B43),
    	version(1.0),
    	helpstring("DynamicArray 1.0 Type Library")
    ]
    library DYNAMICARRAYLib
    {
    	importlib("stdole32.tlb");
    	importlib("stdole2.tlb");
    
    	[
    		uuid(38080E8B-9884-49CA-932D-A298E6882598),
    		helpstring("Vector Class")
    	]
    	coclass Vector
    	{
    		[default] interface IVector;
    	};
    };
    
    

    // vector.h文件

    #ifndef __VECTOR_H_
    #define __VECTOR_H_
    
    #include "resource.h"       // main symbols
    
    #include <vector>
    #include <atlcom.h>
    
    typedef std::vector<VARIANT> CollType;
    
    typedef CComEnumOnSTL<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT>, CollType > EnumType;
    typedef ICollectionOnSTLImpl<IVector, CollType, VARIANT, _Copy<VARIANT>, EnumType > CollectionType;
    
    /////////////////////////////////////////////////////////////////////////////
    // CVector
    class ATL_NO_VTABLE CVector : 
    	public CComObjectRootEx<CComSingleThreadModel>,
    	public CComCoClass<CVector, &CLSID_Vector>,
    	//public IDispatchImpl<IVector, &IID_IVector, &LIBID_DYNAMICARRAYLib>,
    	public IDispatchImpl<CollectionType, &IID_IVector, &LIBID_DYNAMICARRAYLib>
    	//public CollectionType
    {
    public:
    	CVector()
    	{
    		m_coll.push_back( CComVariant(100) );
    		m_coll.push_back( CComVariant(200) );
    		m_coll.push_back( CComVariant(300) );
    	}
    
    DECLARE_REGISTRY_RESOURCEID(IDR_VECTOR)
    
    DECLARE_PROTECT_FINAL_CONSTRUCT()
    
    BEGIN_COM_MAP(CVector)
    	COM_INTERFACE_ENTRY(IVector)
    	COM_INTERFACE_ENTRY(IDispatch)
    	// COM_INTERFACE_ENTRY(ICollection)
    END_COM_MAP()
    
    // IVector
    public:
    
    };
    

    编译后,注册到系统后。通过OLEView.exe工具查看,可以得到下面的接口信息:

    [
      uuid(7942687C-3E0D-468B-80E7-7D0FC34B15EF),
      helpstring("IVector Interface"),
      dual
    ]
    dispinterface IVector {
        properties:
        methods:
            [id(0xfffffffc), propget]
            IUnknown* _NewEnum();
            [id(00000000), propget]
            VARIANT Item([in] long Index);
            [id(0x00000001), propget]
            long Count();
    };
    
    

    显然,我们的ICollection接口实现对象已经ok了。

    前面已经说过,ICollection实现的枚举容器的接口,在JavaScript中,枚举器使用Enumerator来表示,使用方式如下:

    var enumObj = new Enumerator([collections])
    collections 可选,为任意集合对象
    

    在JavaScript中枚举器对象具有下面的接口方法:

    atEnd()	返回一个bool值,指明是否已经到达结尾.如果当前项是集合中的最后一个,或者集合为空,或者当前项没有定义,则返回true,否则返回false	enumObj.atEnd()
    item()	返回集合中的当前项 如果没有定义,则返回undefined	enumObj.item()
    moveFirst()	指针重新指向集合首位 如果集合集合中没有项,则当前项被设置为defined	enumObj.moveFirst()
    moveNext()	将集合中的当前项向下移动一项	enumObj.moveNext()
    

    这些接口方法,回自动去调用ICollection中实现的接口函数。因此,我们只需要将ICollection实现对象作为JavaScript中Enumerator对象的参数即可遍历容器中的所有数据。

    如:

    	var value = "";
            enumObj = new Enumerator(coll);
    
    	for(; !enumObj.atEnd(); enumObj.moveNext() )
    	{
    		var x = enumObj.item();
    		value += x + "\r\n";
    	}
    
    

    在VB中,有直接对枚举类型进行操作的语句,使用FOR ... NEXT方式进行。

    大部分语言中,对于ICollection中的操作都很方便,因此很容易实现对ICollection对象的实现与处理。

    ICollection可以作为数组参数进行处理,也可以作为返回值进行返回,在跨语言进行不同的数据处理时,这将是一个很好的多个数据传递粘合剂,并且实现好的枚举器,可以重复使用。

    myblog:

    http://www.cnblogs.com/ubunoon

    http://qtrstudio.com/blog

  • 相关阅读:
    关于Log和adb知识
    关于read only file system问题解决方案
    关于Android开发手机连接不上电脑问题解决方案
    Binder的设计和框架
    vi/vim基本使用方法
    利用ssh传输文件
    由tombstone文件解析jni代码过程
    关于调用系统camera和自己动手写camera
    补之前 如何改变jupyter打开文件的路径
    python logging模块
  • 原文地址:https://www.cnblogs.com/ubunoon/p/1847754.html
Copyright © 2011-2022 走看看