FindFirstFile跳过目录

时间:2017-02-24 00:26:55

标签: windows winapi directory

好的,这让我发疯了。我正在编写一个简单的程序,沿着目录树查看我的驱动器上所有文件的大小。很温顺的东西。

但我注意到我没有得到我预期的答案。结果我的代码是跳过一些目录。首先,这是我的代码的(简化)版本:

#include <stdio.h>
#include <Windows.h>

int main()
{
  WIN32_FIND_DATA fd;
  HANDLE h = FindFirstFile(L"c:\\Windows\\System32\\wbem\\*.*", &fd);

  if (h !=  INVALID_HANDLE_VALUE)
  {
    BOOL b;
    do {
      if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
          printf("d: %S\n", fd.cFileName);
      //else
      //    printf("f: %S\n", fd.cFileName);

      b = FindNextFile(h, &fd);
    } while (b != FALSE);
    FindClose(h);
  }
}

我得到的输出几乎是你所期望的:

d: .
d: ..
d: AutoRecover
d: en-US
d: Logs
d: Repository
d: tmf
d: xml

但是,从c:\ Windows \ System32 \ wbem中的命令提示符,dir /ad给了我:

06/15/2016  07:20 PM    <DIR>          .
06/15/2016  07:20 PM    <DIR>          ..
04/14/2016  05:40 PM    <DIR>          AutoRecover
03/24/2011  03:52 PM    <DIR>          en-US
07/13/2009  06:34 PM    <DIR>          Logs
07/13/2009  09:08 PM    <DIR>          MOF
02/20/2017  10:32 PM    <DIR>          Performance
02/23/2017  03:59 AM    <DIR>          Repository
07/13/2009  06:36 PM    <DIR>          tmf
07/13/2009  07:20 PM    <DIR>          xml
               0 File(s)              0 bytes
              10 Dir(s)  171,203,104,768 bytes free

仔细检查发现我的输出中未列出PerformanceMOF目录。咦?

显然这些目录有些不同。但是什么?

  • 查看dir输出,我们可以看到它们不是联结。
  • 使用attrib,没有设置任何特殊标志(如系统或隐藏)。
  • fsutil不显示任何硬链接。
  • 查看目录权限,管理员(我是)可以完全控制。

我很难过。我甚至跑到chkdsk /f以查看我的目录表是否搞砸了。除了一些Cleaning up 472 unused index entries from index $SII of file 0x9. Cleaning up 472 unused index entries from index $SDH of file 0x9.之外,它没有找到任何东西。

我尝试过使用各种选项的FindFileEx,但我仍然无法显示这些目录。

我想不出还有什么可尝试的。什么会导致这些目录显示dir但不显示FindFile? (更重要的是)如何让它们出现在FindFile中?

FWIW:

  • Windows 7 Professional x64
  • 驱动器C是NTFS
  • 使用MSVC 2010构建

1 个答案:

答案 0 :(得分:3)

您的代码正在尝试访问64位System32文件夹。

我猜你的代码被编译为32位,因此你实际上会因为File System Redirector而访问32位SysWOW64文件夹。在我的Win7 x64计算机上,缺少的文件夹(MOFPerformance)仅存在于64位System32\wbem文件夹中,但不存在于32位SysWOW64\wbem文件夹中。

如果32位代码想要访问64位System32文件夹,则必须使用WOW64的特殊Sysnative别名来避免重定向,例如:

HANDLE h = FindFirstFile(L"c:\\Windows\\Sysnative\\wbem\\*.*", &fd);

使用IsWow64Process()了解您的代码是否在WOW64模拟器中运行。

话虽如此,您也不应该对c:\\Windows路径进行硬编码。并非所有用户都将Windows安装到该路径。请改用GetWindowsDirectory()SHGetFolderPath(CSIDL_WINDOWS)SHGetKnownFolderPath(FOLDERID_Windows)来获取实际路径。

尝试更像这样的事情:

bool IsRunningInWow64()
{
    #ifndef _WIN64
    BOOL bIsWow64 = FALSE;
    if (IsWow64Process(GetCurrentProcess(), &bIsWow64) && bIsWow64)
        return true;
    #endif

    return false;
}

...

WCHAR szMask[MAX_PATH];

if (IsRunningInWow64())
{
    // Must be a 32-bit process running on a 64-bit system.
    // Use the 'Sysnative' alias...

    GetWindowsDirectory(szMask, MAX_PATH);
    // or: SHGetFolderPath(..., CSIDL_WINDOWS, ...);
    // or: SHGetKnownFolderPath(FOLDERID_Windows, ...);
    PathAppend(szMask, L"Sysnative");
}
else
{
    // Must be either:
    // - A 32-bit process running on a 32-bit system.
    // - A 64-bit process running on a 64-bit system.
    // Use the standard 'System32' path...

    GetSystemDirectory(szMask, MAX_PATH);
    // or: SHGetFolderPath(..., CSIDL_SYSTEM, ...);
    // or: SHGetKnownFolderPath(FOLDERID_System, ...);
}

PathAppend(szMask, L"wbem");
PathAppend(szMask, L"*.*");

HANDLE h = FindFirstFile(szMask, &fd);