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

作者:袖梨 2026-08-20

由于项目开发需要,原有的程序用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 数组不能被解锁

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

}

}

}

测试结果:

img_6a8683ad5179930.webp

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

}

测试结果:

img_6a8683ad517a331.webp

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

相关文章

精彩推荐