David Wohlferd
David Wohlferd

Reputation: 7483

FindFirstFile skipping a directory

Ok, this is making me crazy. I'm writing a simple program that walks down the directory tree looking at the sizes of all files on my drive. Pretty tame stuff.

But I noticed that I wasn't getting the answer I expected. Turns out my code is skipping some directories. To start, here's a (simplified) version of my code:

#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);
  }
}

The output I am getting is pretty much what you would expect:

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

However, from a command prompt in c:\Windows\System32\wbem, dir /ad gives me:

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

A close examination reveals that the Performance and MOF directories are not listed in my output. Huh?

Clearly something is different about these directories. But what?

I'm stumped. I've even gone so far as to run chkdsk /f to see if my directory tables are screwed up. Other than some Cleaning up 472 unused index entries from index $SII of file 0x9. Cleaning up 472 unused index entries from index $SDH of file 0x9. it didn't find anything.

I've tried using FindFileEx with various options, but I still can't get these directories to appear.

I can't think what else to try. What would cause these directories to appear for dir but not for FindFile? And (more importantly) how can I get them to appear in FindFile?

FWIW:

Upvotes: 0

Views: 873

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595329

Your code is trying to access the 64-bit System32 folder.

I'm guessing your code is compiled as 32-bit, thus you would actually be accessing the 32-bit SysWOW64 folder instead due to the File System Redirector. On my Win7 x64 machine, the missing folders (MOF and Performance) only exist in the 64-bit System32\wbem folder, but not in the 32-bit SysWOW64\wbem folder.

If 32-bit code wants to access the 64-bit System32 folder, it has to use WOW64's special Sysnative alias to avoid redirection, eg:

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

Use IsWow64Process() to know if your code is running inside of the WOW64 emulator or not.

With that said, you should not hard-code the c:\\Windows path, either. Not all users install Windows to that path. Use GetWindowsDirectory(), SHGetFolderPath(CSIDL_WINDOWS), or SHGetKnownFolderPath(FOLDERID_Windows) instead to get the actual path.

Try something more like this:

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);

Upvotes: 3

Related Questions