PInvoke FbwfFindFirst - FbwfCacheDetail 问题

PInvoke FbwfFindFirst - FbwfCacheDetail problems

我正在尝试为 FbwfFindFirst and am struggling with the struct FbwfCacheDetail 创建一个 PInvoke。

简而言之,我不确定如何编组 WCHAR fileName[1];,因为它是一个可变长度数组和一个非空终止数组。

欢迎任何帮助

由于整个结构是可变大小的,一种方法是这样的(我无法测试它,因为我的系统上没有这个 dll):

string volume = "";

int size = 0;
// ask for whole structure size
FbwfFindFirst(volume, IntPtr.Zero, ref size); // this call should return ERROR_MORE_DATA which is ok

// allocate for the structure
var ptr = Marshal.AllocHGlobal(size);
try
{
    FbwfFindFirst(volume, ptr, ref size); // should not return error

    // get the easy part 
    var detail = Marshal.PtrToStructure<FbwfCacheDetail>(ptr);

    // compute filename offset and get the string
    // file name length is in bytes, per documentation
    var fileName = Marshal.PtrToStringUni(ptr + Marshal.OffsetOf<FbwfCacheDetail>("fileName").ToInt32(), detail.fileNameLength / 2);
}
finally
{
    Marshal.FreeHGlobal(ptr);
}

[DllImport("fbwflib", CharSet = CharSet.Unicode)]
static extern int FbwfFindFirst(string volume, IntPtr cacheDetail, ref int size);

[StructLayout(LayoutKind.Sequential)]
struct FbwfCacheDetail
{
    public int cacheSize;
    public int openHandleCount;
    public int fileNameLength;
    byte fileName; // don't use this member
}

Simon Mourier 的回答是 99% 正确的,并且对于正常的 APIs 它肯定有效,但看起来这个特定的 API 不遵循 "normal rules",不管那是什么;)。因此,我需要修改一些东西,这对我有用:

const int ERROR_INSUFFICIENT_BUFFER = 122;
const int ERROR_MORE_DATA = 234;

var volume = "C:";
var fileName = string.Empty;
var size = 0;

while (true)
{
    var ptr = Marshal.AllocHGlobal(size); // FbwfFindFirst fails if given IntPtr.Zero - regardless of what the value of size is.

    try
    {
        var result = FbwfFindFirst(volume, ptr, ref size);

        // Despite documentation saying otherwise, it can return either of these
        if (result == ERROR_MORE_DATA || result == ERROR_INSUFFICIENT_BUFFER)
        {
            continue;
        }

        if (result != 0)
        {
            throw new Exception($"Failed with {result}");
        }

        // get the easy part 
        var detail = (FbwfCacheDetail) Marshal.PtrToStructure(ptr, typeof(FbwfCacheDetail));

        // compute filename offset and get the string
        // file name length is in bytes, per documentation
        fileName = Marshal.PtrToStringUni(ptr + Marshal.OffsetOf(typeof(FbwfCacheDetail), "fileName").ToInt32(), detail.fileNameLength / 2);
        break;
    }
    finally
    {
        Marshal.FreeHGlobal(ptr);
    }
}

编辑

忘了说FbwfFindFirst的pinvoke需要如下,否则会return ERROR_INVALID_PARAMETER:

[DllImport("fbwflib.dll")]
public static extern uint FbwfFindFirst(
    [MarshalAs(UnmanagedType.LPWStr)]    
    string volume,
    IntPtr cacheDetail,
    ref int size
);