gpt4 book ai didi

c# - 查找下一个文件 ERROR_INVALID_NAME

转载 作者:太空宇宙 更新时间:2023-11-03 21:18:31 25 4
gpt4 key购买 nike

我正在尝试使用 WINAPI 函数 FindFirstFileFindNextFile。但是,我遇到了一些问题。

当我第一次调用函数 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

Return value

If the function succeeds, the return value is nonzero and the lpFindFileData parameter contains information about the next file or directory found.If the function fails, the return value is zero and the contents of lpFindFileData are indeterminate. To get extended error information, call the GetLastError function.If the function fails because no more matching files can be found, the GetLastError function returns 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 始终为真且 GetLastError 返回 ERROR_INVALID_NAME ...

如果您需要任何详细信息,请询问我。任何帮助将不胜感激!

最佳答案

只有调用Marshal.GetLastWin32Error API 调用才会报错。在 FindNextFile 的情况下,它通过返回 false 来实现。您正在不加区别地检查 Marshal.GetLastWin32Error 返回的值。

文档在告诉您函数如何指示失败时清楚地说明了这一点。你甚至链接了文本。但是你说:

I'm a little confused as it says in the official documentation that if an error occurs it should return 0.

没错。因此,请根据 0 检查返回值。对于编码为 C# boolBOOL,这意味着函数在失败时返回 false。但是您只是忽略了返回值并测试了 Marshal.GetLastWin32Error() 返回的值,这是完全不同的。

代码应该更像这样:

public static void Test()
{
WIN32_FIND_DATA fd = new WIN32_FIND_DATA();

IntPtr findHandle = FileScanner.FindFirstFile("C:\\*", ref fd);
if (findHandle == INVALID_HANDLE_VALUE)
throw new Win32Exception();

do
{
Console.WriteLine(fd.cFileName);
} while (FileScanner.FindNextFile(findHandle, ref fd));

// you might check that Marshal.GetLastWin32Error() returns ERROR_NO_MORE_FILES
// at this point, otherwise the enumeration failed abnormally

if (!FindClose(findHandle))
throw new Win32Exception();
}

您的另一个问题是您的 p/invoke 声明,这是对您伤害最大的问题。仔细看这个:

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("Kernel32.dll", EntryPoint = "FindFirstFile", SetLastError = true)]
public static extern bool FindNextFile(IntPtr hFindFile,
ref WIN32_FIND_DATA lpFindFileData);

入口点 不正确。因此,您实际上是在调用 FindFirstFile 而不是 FindNextFile 并且失败也就不足为奇了。

在不需要时指定 EntryPoint 只是自找麻烦。而你已经掉进了陷阱。我会这样声明这些导入:

[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr FindFirstFile(string lpFileName,
ref WIN32_FIND_DATA lpFindFileData);

[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool FindNextFile(IntPtr hFindFile,
ref WIN32_FIND_DATA lpFindFileData);

[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool FindClose(IntPtr hFindFile);

请注意,不需要 return 属性,因为 UnmanagedType.Bool 是默认属性。

然后您需要将结构上的 CharSet 更改为 CharSet.Unicode 以匹配。在这里选择 ANSI 毫无意义。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct WIN32_FIND_DATA
{
....
}

最后,所有这些代码在我看来都毫无意义。 Directory.EnumerateFilesDirectory.EnumerateDirectories 有什么问题?

关于c# - 查找下一个文件 ERROR_INVALID_NAME,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32456911/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com