将固定大小的缓冲区从 C# 编组到外部

Marshalling a fixed-size buffer from C# to extern

我在使用结构调用某些 Windows kernel32 函数时遇到了一些困难。我正在尝试调用函数 FindFirstStreamW, which return, among others, a WIN32_FIND_STREAM_DATA struct.

我在 C# 中使用这个结构来表示它:

[StructLayout(LayoutKind.Sequential)]
public unsafe struct WIN32_FIND_STREAM_DATA
{
    public long StreamSize;
    public fixed char StreamName [MAX_PATH + 32];
}

但之后我在使用 StreamName 时遇到了问题。调用该函数后,StreamName 缓冲区似乎包含一个分号(这是预期的),然后只有随机数据。

我尝试用连续的字符替换固定缓冲区,例如 s1、s2、s3 等...并且成功了(s1 包含“:”,然后 s2 包含“$”等...全部正确!)。

[StructLayout(LayoutKind.Sequential)]
public unsafe struct WIN32_FIND_STREAM_DATA
{
    public long StreamSize;
    public char s1;
    public char s2;
    public char s3;
}

因此我必须错过一些东西但找不到什么,在 8 个 firefox windows 充满 google 研究之后,我非常绝望。

这是我的 DLLImport:

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindFirstStreamW(
    [MarshalAs(UnmanagedType.LPTStr)] string filename,
    StreamInfoLevels infoLevel,
    out WIN32_FIND_STREAM_DATA data,
    int reserved = 0
    );

还有我的测试代码:

WIN32_FIND_STREAM_DATA data = default(WIN32_FIND_STREAM_DATA);
IntPtr search = FindFirstStreamW(D_TMP_TESTHANDLE_TXT, StreamInfoLevels.FindStreamInfoStandard, out data);
Debug.WriteLine(data.StreamSize);
Debug.WriteLine(new string(data.StreamName));
FindClose(search); 

在此先感谢您的帮助。

你的结构的问题 - 与你实际上有不同字符的变体相比 - 可能是它没有按预期进行编组,因为在使用 .NET 时数组是按引用而不是按值默认的。

阅读 this MSDN article 关于字符串编组的更多信息。

所以我会用这样的东西来尝试:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct WIN32_FIND_STREAM_DATA
{
    public long StreamSize;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_PATH+36)]
    public string StreamName;
}