C# 这是整理输出字节数组的正确方法吗?
我已从C dll导出以下函数:C# 这是整理输出字节数组的正确方法吗?,c#,pinvoke,marshalling,C#,Pinvoke,Marshalling,我已从C dll导出以下函数: // C BOOL WINAPI GetAttributeValue( IN TAG * psTag, IN DWORD dwEltIdx, IN DWORD dwAttrIdx, OUT BYTE * p
// 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
);
这就是我试图使用它的方式,基于以下几个答案:
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;
现在,在这两种情况下,我的
length
似乎填写正确,但buffer
始终保持为空。我不太精通P/Invoke和编组,所以我不确定这些是否正确。有更好的方法吗?两个版本都很好,很难猜出哪里出了问题。江湖郎中就像一个“模拟器”,模拟不正确。标记id的IntPtr是奇数。您应该对结果做一些合理的处理,比如在得到错误代码时抛出异常
一个需要传递缓冲区的C函数通常是很麻烦的,您必须猜测正确的缓冲区大小。选择2048是一个希望,它足够大的猜测,当你猜得太低时,它确实会出错。这种函数的一个常见协议是必须调用它两次。首先,故意将
数据长度的值设置为较低的值,如0。然后该函数返回一个错误代码,并将数据长度设置为所需的缓冲区大小。然后使用大小正确的缓冲区再次调用它。这只是一个猜测,它确实适合你的问题。如果所有其他的都失败了,考虑在C++中加入一个包装器…如果你做很多这样的调用,编写和调试可能会更容易。@jdv JandeVaan:幸运的是,我只有两个带缓冲区的API函数,否则这将是一个很大的麻烦。我很高兴到目前为止没有人发现代码有任何错误..>\uu>你好!“tagid”只是一个不透明的结构,它实际上是一个IntPtr。为了清晰起见,我删除了所有错误处理的内容,因为在这两种情况下我都没有错误。我可能不得不尝试用C可执行文件测试Simulator.ASSEMBLY,以确保它正常工作。也许我只是在白白浪费时间!:\这当然是你应该核实的,是的。有意地将一些数组元素设置为非零值并检查它们是否被设置回0也将是一个有用的测试。
[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;