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;

现在,在这两种情况下,mylength似乎都正确填写,但buffer始终为空。我不太精通 P/Invoke 和编组,所以我不确定这是否正确。有一个更好的方法吗?

4

1 回答 1

1

两个版本都很好,很难猜出什么是错的。嘎嘎声就像一个不能正确模拟的“模拟器”。标签 id 的 IntPtr 是奇数。你应该对结果做一些合理的事情,比如当你收到错误代码时抛出异常。

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

于 2013-10-24T21:27:59.293 回答