PInvoke FbwfFindFirst - FbwfCacheDetail问题

问题描述 投票:0回答:2

我正在尝试为FbwfFindFirst创建一个PInvoke,并且正在与struct FbwfCacheDetail进行斗争。

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

任何帮助都会受到欢迎

c# .net pinvoke marshalling
2个回答
2
投票

由于整个结构的大小可变,一种方法就是这样(我无法测试它,因为我的系统上没有这个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
}

-1
投票

Simon Mourier的答案是正确的99%,并且使用普通的API它肯定会有效,但似乎这个特定的API不遵循“正常规则”,无论可能是什么;)。因此,我需要修改几件事情,这对我有用:

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需要如下,否则它将返回ERROR_INVALID_PARAMETER

[DllImport("fbwflib.dll")]
public static extern uint FbwfFindFirst(
    [MarshalAs(UnmanagedType.LPWStr)]    
    string volume,
    IntPtr cacheDetail,
    ref int size
);
© www.soinside.com 2019 - 2024. All rights reserved.