【发布时间】:2015-12-04 02:04:14
【问题描述】:
我正在尝试使用 WINAPI 函数 FindFirstFile 和 FindNextFile。 但是,我遇到了一些问题。
当我第一次调用函数 FindFirstFile 时,它工作正常。我有一个有效的处理程序,第一个文件夹/文件名正确填充在 WIN32_FIND_DATA 结构中。 GetLastError 未发现错误。
然后,我调用 FindNextFile,它返回 true,因为我正在扫描的目录中有更多文件夹。但我无法检索下一个文件夹/文件名,GetLastError 返回 123 (0x7B) ERROR_INVALID_NAME。 我有点困惑,正如官方文档中所说,如果发生错误,它应该返回 0。
https://msdn.microsoft.com/en-us/library/windows/desktop/aa364428(v=vs.85).aspx
返回值
如果函数成功,则返回值非零,并且 lpFindFileData 参数包含有关找到的下一个文件或目录的信息。 如果函数失败,返回值为零,lpFindFileData 的内容是不确定的。要获取扩展错误信息,请调用 GetLastError 函数。 如果函数因找不到更多匹配文件而失败,GetLastError 函数将返回 ERROR_NO_MORE_FILES。
我在 Windows 7 x64 上使用 .NET 4.5.1 和 Visual Studio 2013。 这是一个示例代码。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WIN32_FIND_DATA
{
public uint dwFileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
}
...
[DllImport("Kernel32.dll", EntryPoint = "FindFirstFile", SetLastError = true)]
public static extern IntPtr FindFirstFile(string lpFileName, ref WIN32_FIND_DATA lpFindFileData);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("Kernel32.dll", EntryPoint = "FindFirstFile", SetLastError = true)]
public static extern bool FindNextFile(IntPtr hFindFile, ref WIN32_FIND_DATA lpFindFileData);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("Kernel32.dll", EntryPoint = "FindClose", SetLastError = true)]
public static extern bool FindClose(IntPtr hFindFile);
...
public static void Test()
{
WIN32_FIND_DATA metaDataFile = new WIN32_FIND_DATA();
IntPtr nextHandle = FileScanner.FindFirstFile("C:\\*", ref metaDataFile);
Console.WriteLine(Marshal.GetLastWin32Error()); // This equals 0x0 ERROR_SUCCESS
Console.WriteLine(metaDataFile.cFileName); // This equals $Recycle.Bin
/* Check invalid handler */
if (nextHandle != new IntPtr(-1L))
{
bool moreFiles = true;
while (moreFiles)
{
moreFiles = FileScanner.FindNextFile(nextHandle, ref metaDataFile);
Console.WriteLine(Marshal.GetLastWin32Error()); // This equals 0x7B ERROR_INVALID_NAME
Console.WriteLine(metaDataFile.cFileName); // This equals $Recycle.Bin and this value never change.
}
FindClose(nextHandle);
}
}
由于某种原因,moreFiles 始终为 true,并且 GetLastError 返回 ERROR_INVALID_NAME ...
如果您需要任何详细信息,请询问我。 任何帮助将不胜感激!
【问题讨论】:
-
不要调用
GetLastError(),除非确实发生了故障(即返回记录的故障代码),否则结果毫无意义。 -
重新发明轮子时,请确保您想出的东西确实类似于轮子。如果这太乏味,请改用System.IO.Directory.EnumerateDirectories 或System.IO.Directory.EnumerateFiles。完整的功能记录在System.IO.Directory。