由于项目开发需要,原有的程序用C++开发,但是现有用C#开发,所以需要对用C++开发的接口利用COM进行封装,供c#语言调用,在此处用到一个字节数组,所以此处对其进行封装。
SAFEARRAY* SafeArrayCreate( VARTYPE vt, unsigned int cDims, SAFEARRRAYBOUND * rgsabound );
VARTYPE 数组数据的类型,此处为:VT_UI1表示1个字节的BYTE类型。具体类型如下:
VT_UI1 无符号1字节整数(BYTE)数组 VT_UI2 无符号2字节整数(WORD)数组 VT_UI4 无符号4字节整数(DWORD)数组 VT_UINT 无符号整数(UINT)数组 VT_INT 有符号整数(INT)数组 VT_I1 有符号1字节整数数组 VT_I2 有符号2字节整数数组 VT_I4 有符号4字节整数数组 VT_R4 IEEE 4字节浮点数(float)数组 VT_R8 IEEE 8字节浮点数(double)数组 VT_CY 8字节定点数货币值数组 VT_BSTR VB字符串数组 VT_DECIMAL 12字节定点数(大数字)数组 VT_ERROR 标准错误编号数组 VT_BOOL 布尔值数组 VT_DATE 日期型数组 VT_VARIANT VB Variant类型数组
cDims 表示数组维数,此处赋值为1,表示一维数组
SAFEARRAYBOUND* rgsabound:Pointer to a vector of bounds (one for each dimension) to allocate for the array.
存放的是一组数据,每一组代表一维中数据的个数以及下标下界。
typedef struct tagSAFEARRAYBOUND { unsigned long cElements; //该维元素个数 unsigned long lLbound; //该未下标的下界 } SAFEARRAYBOUND;
HRESULT SafeArrayAccessData( SAFEARRAY * psa, void HUGEP ** ppvData );
SAFEARRAY* psa [in] SAFEARRAY指针
ppvData [out],数组指针,若获取成功,可以用下标方式访问数组中的数据, (*ppvData)[i];
HRESULT SafeArrayUnaccessData( SAFEARRAY FAR* psa );
操作结果
S_OK 操作成功 | |
E_INVALIDARG 不合法的数针 | |
[ object, uuid(2D33B425-58DE-4D4C-BAC2-B39502E0644F), dual, nonextensible, helpstring("IComByteArray 接口"), pointer_default(unique) ] interface IComByteArray : IDispatch{ [id(1), helpstring("方法CreateArray")] HRESULT CreateArray([in] UINT nArraySize, [out,retval] VARIANT_BOOL* retVal); [id(2), helpstring("方法PutItem")] HRESULT PutItem([in]UINT itemIndex ,[in] BYTE content, [out,retval] VARIANT_BOOL* retVal); [id(3), helpstring("方法GetItem")] HRESULT GetItem([in]UINT itemIndex, [out,retval] BYTE* retVal); };
IDL文件中定义了如下接口:数组的创建、数据的put和get操作
/*********************************************************************** 文件名: ComByteArray.h 类名: CComByteArray 作者: 定义时间:2012-4-27 功能:字节数组COM封装 ************************************************************************/ #pragma once #include "resource.h" // 主符号 #include "COMM_COM_Client.h" #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) #error "Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”,原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。" #endif class ATL_NO_VTABLE CComByteArray : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CComByteArray, &CLSID_ComByteArray>, public IDispatchImpl<IComByteArray, &IID_IComByteArray, &LIBID_COMM_COM_ClientLib, { public: CComByteArray(); ~CComByteArray(); DECLARE_REGISTRY_RESOURCEID(IDR_COMBYTEARRAY) BEGIN_COM_MAP(CComByteArray) COM_INTERFACE_ENTRY(IComByteArray) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { } public: private: UINT m_nSize; //数组大小 SAFEARRAY* m_pSafeArray; //SAFEARRAY指针 VARIANT_BOOL m_bAutoDelete;//是否自动删除 BYTE HUGEP* m_pContent; //数组数据内存首指针 STDMETHOD(CreateArray)(UINT nArraySize, VARIANT_BOOL* retVal); STDMETHOD(PutItem)(UINT itemIndex, BYTE content, VARIANT_BOOL* retVal); STDMETHOD(GetItem)(UINT itemIndex, BYTE* retVal); }; OBJECT_ENTRY_AUTO(__uuidof(ComByteArray), CComByteArray)
/************************************************************************ 函数名:Create 功能:创建指定大小的数组内容 参数:[in]nArraySize 数组大小 [out]retVal 操作结果 /************************************************************************/ STDMETHODIMP CComByteArray::CreateArray(UINT nArraySize, VARIANT_BOOL* retVal) { // TODO: 在此添加实现代码 HRESULT hr; if (nArraySize < 0) { *retVal = VARIANT_FALSE; return E_INVALIDARG; } if (0 == nArraySize) { *retVal = VARIANT_TRUE; return S_OK; } SAFEARRAYBOUND rgsabound[1]; //定义数组维度信息并创建数组 rgsabound[0].lLbound = 0; rgsabound[0].cElements = nArraySize; m_nSize = nArraySize; m_pSafeArray = SafeArrayCreate(VT_UI1, 1, rgsabound); if (NULL == m_pSafeArray) { hr = ResultFromScode(E_OUTOFMEMORY); return hr; } hr = ::SafeArrayAccessData(m_pSafeArray, (void**)&m_pContent); //获取数据数据内存首指针 if (FAILED(hr)) return hr; return S_OK; }
数据的插入:
/************************************************************************ 函数名:PutItem 功能:向指定下标的数组中存放内容 参数:[in]itemIndex 数组下标 [in]content 内容 [out]retVal 操作结果 /************************************************************************/ STDMETHODIMP CComByteArray::PutItem(UINT itemIndex, BYTE content, VARIANT_BOOL* retVal) { // TODO: 在此添加实现代码 if (m_nSize <= itemIndex || itemIndex < 0) { *retVal = VARIANT_FALSE; return E_INVALIDARG; } m_pContent[itemIndex] = content; *retVal = VARIANT_TRUE; return S_OK; }
/************************************************************************ 函数名:GetItem 功能:获取指定下标的数组内容 参数:[in]itemIndex 数组下标 [out]retVal 输出数据位置指针 /************************************************************************/ STDMETHODIMP CComByteArray::GetItem(UINT itemIndex, BYTE* retVal) { // TODO: 在此添加实现代码 if (m_nSize <= itemIndex || itemIndex < 0) { *retVal = VARIANT_FALSE; return E_INVALIDARG; } *retVal = m_pContent[itemIndex]; return S_OK; }
using System; using System.Collections.Generic; using System.Text; using COMM_COM_ClientLib; namespace COMMClientTest { class Program { static void Main(string[] args) { IComByteArray comByteArray = new ComByteArray(); //COM对象创建 comByteArray.CreateArray((uint)100); for (uint i = 0; i < 5; i++) //放入数据 { bool bRet = comByteArray.PutItem(i, (Byte)i); if (bRet) Console.WriteLine("Put Item Succ"); else Console.Write("Put Item Fail"); } Console.WriteLine("-----------------------------------"); for (uint i = 0; i < 5; i++) //读取放入的数据 { Byte value; value = comByteArray.GetItem(i); Console.WriteLine(value); } Console.ReadLine(); } } }
测试结果:
//COM byteArray测试 void comTest() { CoInitialize(NULL); { IComByteArrayPtr ptr = NULL; //COM对象创建 ptr.CreateInstance(__uuidof(ComByteArray)); if (!ptr) { cout<<"Com Object Init Failed"<<endl; return ; } ptr->CreateArray(UINT(100)); //创建并放入数据 for (UINT i = 0; i < 5; i++) { ptr->PutItem(i, (BYTE)i); } for (UINT i = 0; i < 5; i++) //读取数据 { BYTE value; value = ptr->GetItem(i); cout<<(int)value<<endl; } } CoUninitialize(); }
测试结果: