COM雏形
COM封装字节数组,并用于C#/c++中
西昆仑 发布于 4年前,共有 1 条评论
由于项目开发需要,原有的程序用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();
        }
    }
}
测试结果:
 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();
}
测试结果:
 
                    
                
                
            
        
浙公网安备 33010602011771号