ActiveX组件的BSTR参数在各语言的使用

AcitveX提供跨语言的开发方式,支持C++、C#、Pascal等语言开发,但不同语言对BSTR生成的‘头文件’多有不同,本文意在阐明BSTR在不同开发框架下的封装与解包。

一、.Net中使用,以Winform为例(WPF通用)

c#调用windowsApi

C#调用windows API的一些方法 - 南极山 - 博客园

windows API原型

SysAllocStringByteLen function (oleauto.h) - Win32 apps | Microsoft Docs

使用案例

注意bool数组转bstr写法,需要双字节对齐

/// <summary>
/// 各类数组与binary string的数据封装
/// </summary>
public class InteropEncDotNet   //InteropMarshaling
{
	[DllImport("OleAut32", ExactSpelling = true, SetLastError = true)]
	public static extern IntPtr SysAllocStringByteLen(string psz, Int32 len);
	/// <summary>
	/// int数组转bstr
	/// </summary>
	/// <param name="intArray">数组值</param>
	/// <param name="elementCount">数组长度</param>
	/// <returns>binary string</returns>
	public static string GetStringFromIntArray(int[] intArray, int elementCount = 0)
	{
		if (elementCount == 0)
			elementCount = intArray.Length;
		int size = Marshal.SizeOf(typeof(int)) * elementCount;
		IntPtr ip = SysAllocStringByteLen(null, size);
		Marshal.Copy(intArray, 0, ip, elementCount);
		string bstr = Marshal.PtrToStringBSTR(ip);
		Marshal.FreeBSTR(ip);
		return bstr;
	}

	/// <summary>
	/// bstr转int数组
	/// </summary>
	/// <param name="str">binary string</param>
	/// <param name="elementCount">目标数组长度</param>
	/// <returns>目标数组值</returns>
	public static int[] GetIntArrayFromString(string str, int elementCount)
	{
		int[] intArray3 = new int[elementCount];
		IntPtr ip_rev = Marshal.StringToBSTR(str);
		Marshal.Copy(ip_rev, intArray3, 0, elementCount);
		Marshal.FreeBSTR(ip_rev);
		return intArray3;
	}

	/// <summary>
	/// float数组转bstr
	/// </summary>
	/// <param name="floatArray">数组值</param>
	/// <param name="elementCount">数组长度</param>
	/// <returns>binary string</returns>
	public static string GetStringFromFloatArray(float[] floatArray,int elementCount = 0)
	{
		if (elementCount == 0)
			elementCount = floatArray.Length;
		int size = Marshal.SizeOf(typeof(float)) * elementCount;
		IntPtr ip = SysAllocStringByteLen(null, size);
		Marshal.Copy(floatArray, 0, ip, elementCount);
		string bstr = Marshal.PtrToStringBSTR(ip);
		Marshal.FreeBSTR(ip);
		return bstr;
	}

	/// <summary>
	/// bstr转float数组
	/// </summary>
	/// <param name="str">binary string</param>
	/// <param name="elementCount">目标数组长度</param>
	/// <returns>目标数组值</returns>
	public static float[] GetFloatArrayFromString(string str, int elementCount)
	{
		float[] arrfloat = new float[elementCount];
		IntPtr ip = Marshal.StringToBSTR(str);
		Marshal.Copy(ip, arrfloat, 0, elementCount);
		Marshal.FreeBSTR(ip);
		return arrfloat;
	}

	/// <summary>
	/// bool数组转bstr
	/// </summary>
	/// <param name="boolArray">数组值</param>
	/// <param name="elementCount">数组长度</param>
	/// <returns>binary string</returns>
	public static string GetStringFromBoolArray(bool[] boolArray, int elementCount = 0)
	{
		//Marshal.SizeOf(typeof(bool)) = 4个字节,但C++中为1字节
		if (elementCount == 0)
			elementCount = boolArray.Length;
		int size = 1 * elementCount;
		if ((size & (int)1) == 1)
			size += 1; //必须双字节对齐
		IntPtr ip = SysAllocStringByteLen(null, size);
		for (int i = 0; i < elementCount; i++)
		{
			Marshal.WriteByte(ip, i, boolArray[i] ? (byte)1 : (byte)0);
		}
		string bstr = Marshal.PtrToStringBSTR(ip);
		Marshal.FreeBSTR(ip);
		return bstr;
	}

	/// <summary>
	/// bstr转bool数组
	/// </summary>
	/// <param name="str">binary string</param>
	/// <param name="elementCount">目标数组长度</param>
	/// <returns>目标数组值</returns>
	public static bool[] GetBoolArrayFromString(string str, int elementCount)
	{
		bool[] arrBool = new bool[elementCount];
		IntPtr ip = Marshal.StringToBSTR(str);
		byte[] tmp = new byte[1];
		for (int i = 0; i < elementCount; i++)
		{
			arrBool[i] = Marshal.ReadByte(ip, i) == (byte)1 ? true : false;
		}
		Marshal.FreeBSTR(ip);
		return arrBool;
	}
}
测试转换是否可行
void TestConvert()
{
    long allTestCount = 0;
    int errCount = 0;
    //使用marshal方法转换
    for (int i = int.MinValue; i < int.MaxValue; i++)
    {          
        IntPtr ip = SysAllocStringByteLen("", Marshal.SizeOf(typeof(int)));
        Marshal.WriteInt32(ip, i);
        string strInt = Marshal.PtrToStringBSTR(ip);
        Marshal.FreeBSTR(ip);

        //反算
        IntPtr ip_rev = Marshal.StringToBSTR(strInt);
        int i_rev = Marshal.ReadInt32(ip_rev);
        Marshal.FreeBSTR(ip_rev);

        if (i != i_rev)
        {
            Console.WriteLine("转换错误, i= " + i + " i_rev = " + i_rev);
            ++errCount;
        }       
        ++allTestCount;       
    }
    Console.WriteLine("测试结束,错误转换率:" + errCount + "/" + allTestCount);
}

二、C++中使用,以MFC为例

A:应用层 --> ActiveX (封装:自定义数组传入COM组件)
//a1: 申请bstr内存空间
BSTR strFacePoints = ::SysAllocStringLen(NULL, sizeof(M_POINT) * 4);
//a2: 赋值bstr 
M_POINT facePoints[4]; 
memcpy(strFacePoints, facePoints, sizeof(M_POINT) * 4);
//a3: 使用bstr
pEncCtrl->DrawFace(faceStyleId, &strFacePoints, 4);	
//a4: 释放bstr内存空间
::SysFreeString(strFacePoints); 
B:ActiveX --> 应用层(解包:COM组件传出的自定义数组)
//b1: 申请bstr内存空间
int poCount = pncCtrl->GetFaceCoorCount(faceId);	
BSTR strFacePoints = ::SysAllocStringLen(NULL, sizeof(M_POINT) * poCount);
//b2: 使用bstr
pEncCtrl->GetFaceCoor(faceStyleId, &strFacePoints);	
//b3: bstr解析出可用数组 
M_POINT* facePoints = new M_POINT[poCount]; 
memcpy(facePoints, strFacePoints, sizeof(M_POINT) * 4);
//b4: 释放bstr内存空间
::SysFreeString(strFacePoints);  
//b5: 使用完坐标数组并释放
delete[] facePoints;

三、Pascal-Delphi中使用

delphi中使用比较简单

procedure TFromDemo.TestBSTR();

var arrPoints: array of TPoint;          //点数组
var pPointBString: Pwidestring;

begin
    SetLength(arrPoints, 2);
    arrPoints[0].x := 1;
    arrPoints[0].y := 1;
    arrPoints[1].x := 2;
    arrPoints[1].y := 2;
    pPointBString := Pwidestring(@arrPoints); 
    TEST_BSTR_FUNCTION(pPointBString^);
end;

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值