2013-10-24 58 views
0

我有选自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和编组,所以我不确定这是否正确。有一个更好的方法吗?

+0

如果一切都失败了,可以考虑在C++/cli中编写一个包装器......如果你做了很多像这样的调用,它甚至会更容易编写和调试。 – 2013-10-24 21:32:18

+0

@ jdv-JandeVaan:幸运的是,我只有两个带有缓冲区的API函数,否则这将是一大痛苦。我很高兴没有人发现任何不正确的代码到目前为止。> _> –

回答

1

这两个版本都很好,很难猜测出了什么问题。 Quacks就像一个不能正确模拟的“模拟器”。标签ID的IntPtr是奇数。你应该做一些合理的事情,结果就像抛出一个异常,当你得到一个错误代码。

需要传递缓冲区的C函数通常很麻烦,您必须猜测正确的缓冲区大小。挑选2048是一个充满希望的大猜想,当你猜得太低时,确实会出错。这种功能的通用协议是你必须调用它两次。首先,data_length的值为0,然后返回错误代码并将data_length设置为所需的缓冲区大小。然后用正确大小的缓冲区再次调用它。这只是一个猜测,它确实适合你的问题。

+0

你好! “标签ID”只是一个不透明的结构,它确实是一个IntPtr。为了清楚起见,我删除了所有错误处理内容,因为在这两种情况下我都没有遇到任何错误。我可能不得不尝试使用C可执行文件测试Simulator.ASSEMBLY,只是为了确保它能正常工作。可能我只是在浪费我的时间而已! :\ –

+0

这当然是你应该验证的东西,是的。有意将某些数组元素设置为非零值并检查它们是否设置为0也是一个有用的测试。 –

相关问题