这是编组输出字节数组的正确方法吗?
本文关键字:方法 数组 字节数 输出 字节 | 更新日期: 2023-09-27 18:36:56
我从C dll导出了以下函数:
// C
BOOL WINAPI GetAttributeValue(
IN TAG * psTag,
IN DWORD dwEltIdx,
IN DWORD dwAttrIdx,
OUT BYTE * pbBuffer,
IN OUT DWORD * pdwLen )
// C#
[DllImport(Simulator.ASSEMBLY, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public extern static int GetAttributeValue(
IntPtr tag_id,
int element_index,
int attribute_index,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=4)]
byte[] data_buffer,
[In, Out]
ref int data_length
);
这就是我尝试使用它的方式,基于 SO 上的几个答案:
int result = -1;
byte[] buffer = new byte[2048];
int length = buffer.Length;
result = Simulator.GetAttributeValue(
tag.NativeId,
element_index,
attribute_index,
buffer,
ref length
);
int[] output = new int[length];
for (int i = 0; i < length; i++)
{
output[i] = buffer[i];
}
return output;
我尝试的另一件事是这样的,也是基于在SO上找到的答案:
[DllImport(Simulator.ASSEMBLY, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public extern static int GetAttributeValue(
IntPtr tag_id,
int element_index,
int attribute_index,
IntPtr data_buffer, // changed this
[In, Out]
ref int data_length
);
// snip
GCHandle pinned_array = GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr pointer = pinned_array.AddrOfPinnedObject();
result = Simulator.GetAttributeValue(
tag.NativeId,
element_index,
attribute_index,
pointer,
ref length
);
// snip, copying stuff to output
pinned_array.Free();
return output;
现在,在这两种情况下,我的length
似乎都填写正确,但buffer
始终为空。我不太精通 P/Invoke 和编组,所以我不确定这些是否正确。有没有更好的方法可以做到这一点?
两个版本都很好,很难猜出出了什么问题。 嘎嘎就像一个无法正确模拟的"模拟器"。 标签 ID 的 IntPtr 是奇数。 您应该对结果做一些合理的事情,例如在收到错误代码时抛出异常。
需要你传递缓冲区的 C 函数通常很麻烦,你必须猜测正确的缓冲区大小。 选择2048是一个希望足够大的猜测,当你猜得太低时,它确实会出错。 此类函数的常见协议是您必须调用它两次。 首先使用故意较低的data_length
值,例如 0。 然后,该函数返回错误代码,并将data_length
设置为所需的缓冲区大小。 然后,使用大小正确的缓冲区再次调用它。 这只是一个猜测,它确实适合您的问题。