unsigned char*导致访问冲突异常

unsigned char* causes Access Violation Exception

本文关键字:访问冲突 异常 char unsigned      更新时间:2023-10-16

我正在开发一个包装库,允许我的项目在任何CPU环境中使用x86 C++dll库,我对dll没有控制权,因此我在C#中使用DllImport。

提供了一个在C++中声明的函数:int __stdcall Func(int V,unsigned char*a)并在VB中提供了一个示例声明:Private Declare Function Func Lib"Lib.dll"Alias_Func@8"(ByVal V为长,A为任意)为长

此功能将请求设备通过将Convert.ToInt64(decimalValue)传递为V,以及a中的一些自定义信息,向卡添加/从卡中扣除值。

以下是对A:的描述

  • 它是一个包含7个字节的字节指针
  • 前5个字节用于存储将传递到卡日志的信息(收据编号的最后4位应包含在前2个字节中,其他3位可能是A3A4A5)
  • 最后2个字节用于存储将传递给设备的信息(收据编号的最后4位)
  • 返回时,A包含一个32字节的数据

经过数小时的研究和尝试,我无法得出"访问违规异常"以外的结果。请参阅以下代码草案:

[DllImport("lib.dll", EntryPoint="_Func@8")]
public static external Int64 Func(Int64 V, StringBuilder sb);
string ReceiptNum = "ABC1234";
decimal Amount = 10m;
byte[] A = new byte[32];
A[0] = Convert.ToByte(ReceiptNum.Substring(3, 2));
A[1] = Convert.ToByte(ReceiptNum.Substring(5));
A[2] = Convert.ToByte("A3");
A[3] = Convert.ToByte("A4");
A[4] = Convert.ToByte("A5");
A[5] = Convert.ToByte(ReceiptNum.Substring(3, 2));
A[6] = Convert.ToByte(ReceiptNum.Substring(5));
StringBuilder sb = new StringBuilder(
    new ASCIIEncoding().GetString(A), A.Length
);
Int64 Result = Func(Convert.ToInt64(Amount), sb);

在这一点上,它抛出了一个例外。我尝试过传递IntPtr、byte*、byte(由A[0])、byval、byref,但它们都不起作用。(也尝试部署为x86 CPU)

非常感谢您的帮助!谢谢你抽出时间!


PS-使用StringBuilder的原因是库中包含一个接受导致相同异常的"char*Data"参数的函数,而解决方案是使用StringBuilder作为指针传递,该函数的VB声明为:Private Declare function Func1 Lib"Lib.dll"Alias_Func1@12(ByVal c为字节,ByVal o为字节,Byte Data为字符串)为长

您的外部定义是错误的。

StringBuilder是一个包含c#char数组的复杂结构。

c#字符是utf-16(双字节,具有用于解码unicode多字符的复杂规则)。可能不是你想要的。

如果你的数据是一个原始字节bufer,你应该选择byte[]

Int64也是c#long。

好吧,您的本机方法签名采用int,而您正试图传递一个long long。这显然是行不通的。返回值也是如此。不要以为VB可以清楚地映射到VB.NET,更不用说C#-Long在VB中意味着32位整数,而在.NET中则不然。本机代码是一个非常复杂的环境,在尝试与本机接口时,你最好知道自己在做什么。

StringBuilder应仅用于字符数据。这不是您的情况,您应该使用byte[]。无论你在做什么有趣的事情,你都试图传递无效的unicode数据,而不是原始字节。混淆可能是因为C没有区分byte[]string——两者通常都表示为char*

此外,我看不出你会期望这个包装器在AnyCPU环境中如何工作。如果本机DLL是32位的,则只能从32位进程中使用它。AnyCPU并不是魔法,它只是将位的决定推迟到运行时,而不是编译时。