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
);
我正在尝试为 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
);