COM封装字节数组,并用于C#/c++中

由于项目开发需要,原有的程序用C++开发,但是现有用C#开发,所以需要对用C++开发的接口利用COM进行封装,供c#语言调用,在此处用到一个字节数组,所以此处对其进行封装。

 

(一)用到的COM接口:

1.1 SAFEARRAY的创建

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;


1.2. 数组数据的访问:

HRESULT SafeArrayAccessData(
 SAFEARRAY * psa,
 void HUGEP ** ppvData
);

SAFEARRAY* psa [in] SAFEARRAY指针

ppvData [out],数组指针,若获取成功,可以用下标方式访问数组中的数据, (*ppvData)[i];


1.3. 对数组访问的释放:对访问上锁数量减一,并使指针无效

HRESULT SafeArrayUnaccessData(
  SAFEARRAY FAR* psa 
);

Parameters

psa
[in, out] psa是由  SafeArrayCreate产生的。

Return Values

操作结果

E_UNEXPECTED         数组不能被解锁
 S_OK                           操作成功
E_INVALIDARG          不合法的数针



(二).BYTE类型的数组类接口定义以及实现

[
	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操作

.h文件定义如下:
/***********************************************************************
文件名: 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)


c.pp文件主要说明定义的三个接口:
1. 数组的创建:
/************************************************************************
 函数名: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;
}


(三)测试实例

先用C++语言调用COM进行测试,然后再用C#调用测试
原因:用C++测试时可以跟到COM内部,但是C#是不可以的。

3.1 c#测试代码:

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封装字节数组,并用于C#/c++中


3.2  C++测试:

//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();
}

测试结果:
COM封装字节数组,并用于C#/c++中

(四)附:最后感谢流逝的风给予的技术支持,Thank you.

你可能感兴趣的:(com,byte数组)