C# 这是整理输出字节数组的正确方法吗?

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 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
    );
这就是我试图使用它的方式,基于以下几个答案:

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;