【问题标题】:How to avoid copying during PInvoke marshalling when struct contains array of integers?当结构包含整数数组时,如何避免在 PInvoke 编组期间复制?
【发布时间】:2016-02-22 19:30:39
【问题描述】:

我有一个“C”结构,定义为:

typedef unsigned char tUI8;

typedef struct
{
    tUI8 Mode;
    tUI8 Data[16];
} TestStruct;

还有一个函数,它接受一个指向这个结构的指针并填充数据:

void FillTest(tUI8 Mode, TestStruct *s);

为了 PInvoke 到这个函数,我将 C# 代码编写为:

[StructLayout(LayoutKind.Sequential)]
struct TestStruct
{
    public byte Mode;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    public byte[] Data;
}

static class NativeTest
{
    [DllImport("Native.dll")]
    public static extern void FillTest(byte mode, ref TestStruct s);
}

这可行,但我怀疑在 PInvoke 编组器在调用期间复制结构并返回而不是固定它。我可以这么说,因为即使我不初始化结构,它也可以正常工作。

TestStruct s;
//here s.Data == null!
NativeTest.FillTest(10, ref s); //<<< I expected an error here
//here s.Data points to a valid byte[] of length 16
Console.WriteLine(BitConverter.ToString(s.Data));

我的问题是如何使用结构或类定义 PInvoke 签名,从而避免在编组期间复制数据?

【问题讨论】:

    标签: c# .net pinvoke marshalling


    【解决方案1】:

    我怀疑你想要一个fixed size buffer,它将内联数据到你的结构中:

    [StructLayout(LayoutKind.Sequential)]
    unsafe struct TestStruct
    {
        public byte Mode;
        public fixed byte Data[16];
    }
    

    您现在应该能够通过引用直接将其传递给您的非托管代码。 (您还需要明确允许不安全的代码。)

    我不知道您需要使用哪些属性进行编组(如果有的话),但值得一试...

    【讨论】:

    • 注意它是不安全的,将结构标记为不安全,并在项目属性中,勾选允许不安全代码。
    • 是的。我试过了,它有效,但我不得不多次声明我是一个坏人(通过标记不安全)。我也不确定 marshaller 是否会在调用期间自动固定结构,或者我必须明确地这样做。
    • @Hemant 如果你想避免复制,那么你将不得不使用 unsafe。如果你想避免不安全,那么你必须让 marshaler 复制。复制数据有什么不好?
    • 不需要固定,该结构位于不可移动的堆栈中。弄错 C 代码会炸毁堆栈。这是臭名昭著的缓冲区溢出攻击向量。因此 unsafe 关键字。
    • 每秒数百个数据包。这听起来要求不高。建议您在确定瓶颈所在之前进行概要分析。
    【解决方案2】:

    这可以在不使用不安全代码的情况下完成。

    通过编组为 ByValArray

    [StructLayout(LayoutKind.Sequential)]
    struct TestStruct
    {
        public byte Mode;
    
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] Data;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-05
      • 2012-06-10
      相关资源
      最近更新 更多