You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#调用C++ DLL中I15693_Inventorys方法时,OUT参数pData无法获取返回值的问题求助

解决C#调用C++ DLL时OUT数组参数无法获取返回值的问题

我之前也踩过类似的P/Invoke参数匹配的坑,咱们一步步拆解解决:

问题根源分析

先看C++的函数声明:

DECLSPEC int WINAPI I15693_Inventorys(HID_DEVICE device, BYTE *pData, BYTE *pLen);

这里的BYTE* pData输出参数,C++函数会往这块内存地址写入标签数据;BYTE* pLen输入输出参数——你需要先传入pData缓冲区的大小,函数执行后会返回实际写入的数据长度。

厂商给的C#声明里,pData的问题出在传递方向上:C#中byte[]作为P/Invoke参数时,默认是[In]方向——只会把C#数组的数据传给C++,但C写入的数据不会回传到C#数组里。而你直接给pDataref修饰符的话,相当于把byte[]对象的指针(也就是byte**)传给了期望byte*的C函数,类型不匹配直接导致内存访问崩溃。

解决方案

1. 修正P/Invoke声明

pData参数加上[Out]属性(如果函数需要先读取缓冲区大小,就用[In, Out]),明确告诉CLR这个参数是输出方向:

[DllImport("你的DLL文件名.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int I15693_Inventorys(IntPtr device, [Out] byte[] pData, ref byte pLen);

注意:要确保CallingConvention和C++的WINAPI(即stdcall)匹配,虽然默认通常是这个,但显式指定能避免很多隐性问题。

2. 预先分配足够的缓冲区

你当前代码里chip是空数组,C++函数根本没有内存空间写入数据!根据ISO 15693协议的Inventory命令,返回的标签数据长度不会太长,先分配一个足够大的缓冲区:

// 先分配256字节的缓冲区,足够容纳多数15693标签的Inventory数据
byte[] chip = new byte[256];
// 初始化pLen为缓冲区的长度,告诉C++函数我们提供的内存大小
byte longitud = (byte)chip.Length;

3. 调用函数并处理返回数据

调用后,longitud会被更新为实际写入的数据长度,你可以截取数组的有效部分:

_ = RFIDReader.Sys_SetAntenna(g_hDevice, 0);
_ = RFIDReader.Sys_InitType(g_hDevice, 1);
_ = RFIDReader.Sys_SetAntenna(g_hDevice, 1);

int resultado = RFIDReader.I15693_Inventorys(g_hDevice, chip, ref longitud);

if (resultado == 0)
{
    // 截取实际有效数据
    byte[] validChipData = new byte[longitud];
    Array.Copy(chip, validChipData, longitud);
    // 现在validChipData就是你要的返回值了
}

补充:为什么加ref会崩溃?

CBYTE*一级指针(指向字节数组的首地址),而C#中ref byte[]传递的是二级指针(指向byte[]对象的指针)。当C函数尝试用一级指针的方式去操作这个二级指针时,必然会访问错误的内存地址,直接触发崩溃。

内容的提问来源于stack exchange,提问作者user17779610

火山引擎 最新活动