【发布时间】:2013-03-24 23:38:30
【问题描述】:
C 定义
typedef struct {
const uint8_t* buf;
int bufLen;
} Info;
int Foo(Info* info);
C# 定义
[StructLayout(LayoutKind.Sequential)]
public struct Info
{
// [MarshalAs( ??? )]
public byte[] buf;
int bufLen
}
[DllImport(...)]
public static extern int Foo(ref Info info);
我无法确定在 C# 结构定义中为 byte[] buf 上的 MarshalAs 属性指定什么内容。缓冲区是在 .NET 端分配的,它的长度在调用时是已知的。
在一个简单的小测试中:
var info = new Info {
buf = new byte[] {0x40, 0x50, 0x60, 0x70},
bufLen = 4,
};
Foo(ref info);
似乎一切正常,但实际上我缓冲区中的数据不正确。从我看到的 DLL 中打印出来 01 00 80 00 - 不确定那是什么。
我试过了:
- 没有
MarshalAs [MarshalAs(UnmanagedType.SafeArray)]
没有任何效果。
总的来说,我也真的不知道调试这类问题的最佳方法。
【问题讨论】:
-
这样的结构很难自动编组,你必须自己做。将 buf 声明为 IntPtr 并使用 Marshal.AllocHGlobal 为其分配内存。 Marshal.Copy 来填充它。注意在非托管端发生了什么,如果它存储指针或结构的副本,你会遇到很多麻烦。
-
@HansPassant 谢谢,那行得通。为什么 CLR 无法自动处理这个问题?我的第一个猜测是它不会查看
Info来查看如何编组其任何元素 - 而只是查看Info的大小并复制那么多字节。 -
可以,但是太危险了。当数组不再固定时,本机代码可能会在以后取消引用指针。
-
@HansPassant 可以,但这与将
byte[]编组为参数的情况有何不同? -
@HansPassant 在这些情况下,我希望
MarshalAs上的struct声明支持SizeParamIndex参数的变体...