【问题标题】:How to marshal unmanaged buffer of packed structs in c#如何在 C# 中编组打包结构的非托管缓冲区
【发布时间】:2009-02-03 07:14:41
【问题描述】:

我正在(成功地)使用以下 pinvoke 签名在 c# 中调用 Windows FilterSendMessage 函数:

[DllImport("fltlib.dll")]
    public static extern IntPtr FilterSendMessage(
        IntPtr hPort,
        IntPtr inBuffer,
        UInt32 inBufferSize,
        IntPtr outBuffer,
        UInt32 outBufferSize,
        out UInt32 bytesReturned);

outBuffer 参数填充了任意数量的结构(一个接一个地打包),在 C 中定义为:

typedef struct _BAH_RECORD {

    int evt
    int len;
    WCHAR name[1];

} BAH_RECORD, *PBAH_RECORD;

name 字段被分配了一个可变长度、以 null 结尾的 unicode 字符串。 len 字段以字节为单位描述结构的总大小(包括名称字符串)。我相信在非托管方面如何处理结构没有任何问题。

当我尝试将 outBuffer 编组到 C# 中定义为 BAH_RECORD 结构的实例时,我的问题出现了:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct BAH_RECORD
{
    public UInt32 evt;
    public UInt32 len;
    public string name;
}

IntPtr outBuffer = Marshal.AllocHGlobal(OUT_BUFFER_SIZE);

hResult = Win32.FilterSendMessage(hPortHandle, inBuffer, IN_BUFFER_SIZE, outBuffer, OUT_BUFFER_SIZE, out bytesReturned);

BAH_RECORD bah = (BAH_RECORD)Marshal.PtrToStructure(outBuffer, typeof(BAH_RECORD));

<snip>

如果我尝试打印/查看/显示 bah.name,我会得到垃圾...

为了确认 outBuffer 确实包含有效数据,我在 c# 中做了一些粗略的指针骇客来逐步处理它,调用 Marshal.ReadInt32 两次(以覆盖前 2 个结构字段),然后调用 Marshal.ReadByte 几次填充一个字节[],然后我将其用作 Encoding.Unicode.GetString() 的参数...字符串很好,所以它肯定在那里,我似乎无法让编组器正确处理它(如果它甚至可以?)

任何帮助表示赞赏

史蒂夫

【问题讨论】:

    标签: c# arrays struct marshalling buffer


    【解决方案1】:

    问题在于 C# BAH_RECORD 结构中的“名称”字符串被编组为指向字符串 (WCHAR*) 的指针,但在 C 端它是内联 WCHAR 缓冲区。因此,当您编组结构时,运行时会将缓冲区的前四个字节作为指针读取,然后尝试读取它指向的字符串。

    不幸的是,运行时无法在结构内自动编组可变大小的缓冲区,因此您需要使用手动编组(或者如您所说的“指针黑客”)。但是,当您将指针指向缓冲区时,您不需要单独读取字节然后将它们转换为字符串 - 只需调用 Marshal.PtrToStringUni。

    【讨论】:

      猜你喜欢
      • 2015-10-26
      • 2014-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多