1

I want to check if a certain file exists in the specified location. I have been trying multiple solutions for that but seem like none of them work properly, since all of them return false.

There is no doubt that the file exists in the specified location.

Executable is being run as administrator, so I'm having the appropriate permissions.

Code I used:

#include <io.h>
#include <string>
#include <Shlwapi.h>

std::string str = "C:\WINDOWS\System32\iluminated.dll";
unsigned long attrib = GetFileAttributes(str.c_str());

bool exists1 = (attrib != INVALID_FILE_ATTRIBUTES && 
            !(attrib & FILE_ATTRIBUTE_DIRECTORY)) &&
            GetLastError() != ERROR_FILE_NOT_FOUND; // false
bool exists2 = ( _access( str.c_str(), 0 ) != -1 ); // false
bool exists3 = PathFileExists(str.c_str()) != 0; // false

Is there anything I'm doing wrong?

RA.
  • 969
  • 13
  • 36

2 Answers2

4

You should use double back slashes for paths, since if you use single back slashes in a string they are interpreted as command symbols (line \n, for example):

"C:\\WINDOWS\\System32\\iluminated.dll"

Alternatively, you can use forward slashes, they work on most operating systems:

"C:/WINDOWS/System32/iluminated.dll"
SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
  • Oh, nice one. Thank you. – RA. Feb 02 '17 at 06:30
  • Btw. any idea how can I replace the single slash returned by `GetWindowsDirectory` function with \\ or `/`? – RA. Feb 02 '17 at 06:59
  • @DonaldDuck, something like `path.replace("\","/");` – SingerOfTheFall Feb 02 '17 at 07:00
  • Unfortunately, still doesn't work properly. Tried both \\ and / slashes. – RA. Feb 02 '17 at 07:34
  • @DonaldDuck, you can call [GetLastError](https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms679360(v=vs.85).aspx) to see what exactly went wrong. Also try converting your string as mentioned in the answer to [this question](http://stackoverflow.com/questions/10976071/why-pathfileexists-not-working) – SingerOfTheFall Feb 02 '17 at 07:48
  • `GetLastError` always returns `2` (file not found). Converting to `wchar_t` or `TSTR` makes no changes. – RA. Feb 02 '17 at 08:19
  • 1
    \\ is interpreted by the compiler, not by you. Do not modify what `GetWindowsDirectory()` returns; that is already correct. Only use \\ when building a string or character literal in C (`"..."`, for example). When the compiler sees \\, it eats the extra \ and produces a single \ in the output. – andlabs Feb 02 '17 at 09:00
  • 1
    Or use raw string literals: `R"(C:\WINDOWS\System32\iluminated.dll)"`. BTW _illuminated_ has two L's, that might also explain why you can't find the file. – MSalters Feb 02 '17 at 09:44
  • Please, for the Love of God, do not recommend using forward slashes. On Windows, the path separator is a backslash ("\"). The fact that *some* API calls (in combination with *some* input strings) translate forward slashes to backslashes has caused more trouble than good. The rules are intricate. Simply always use a backslash on Windows. This works with *all* API calls and *all* inputs. – IInspectable Feb 02 '17 at 12:01
  • Regarding my issue: I realized that ALL of the file exist check are failing for files inside the `\Windows\System32` directory. When I move my dll file to `Windows\SySWOW64` or `Windows\system` directory, it works like a charm. Odd issue. – RA. Feb 02 '17 at 16:29
  • It is not odd at all. You code is obviously 32bit running on a 64bit machine, so your access to the `System32` folder are subject to WOW64's [File System Redirector](https://msdn.microsoft.com/en-us/library/windows/desktop/aa384187.aspx). – Remy Lebeau Feb 03 '17 at 01:42
1

I found the answer. Turns out Windows is always redirecting system32 to syswow64 while trying to access in 64-bit Windows. I had to use SysNative directory, even though it doesnt exist - Windows redirects it to the proper system32 directory.

Since Visual Studio 2012, application projects default to “Any CPU 32-bit preferred”. If you run such an executable on a 64-bit Windows operating system, then it will start as a 32-bit process and be affected by WOW64 file system redirection.

When a 32-bit process on 64-bit Windows tries to access "C:\Windows\System32", WOW64 redirects it to "C:\Windows\SysWOW64". There are several ways to access the real "C:\Windows\System32" directory:

  • Use "C:\Windows\SysNative", which WOW64 redirects to "C:\Windows\System32" even though it does not appear in directory listings. This is an easy way and unlikely to cause problems.
  • Use Wow64DisableWow64FsRedirection and Wow64RevertWow64FsRedirection.
  • Use a 64-bit process.

Source: https://social.msdn.microsoft.com/Forums/en-US/c54f8368-035e-478e-b988-b180a3c7e3da/file-not-found-for-existing-file-in-system32-directory?forum=csharpgeneral

RA.
  • 969
  • 13
  • 36
  • *"Any CPU 32-bit preferred"* is relevant for .NET applications only. The rules for 32-bit processes on 64-bit Windows are the same for native (C++) applications, though. – IInspectable Feb 02 '17 at 19:40
  • The official documentation is [File System Redirector](https://msdn.microsoft.com/en-us/library/windows/desktop/aa384187.aspx): "*32-bit applications can access the native system directory by substituting `%windir%\Sysnative` for `%windir%\System32`. WOW64 recognizes `Sysnative` as a special alias used to indicate that the file system should not redirect the access. This mechanism is flexible and easy to use, therefore, it is the recommended mechanism to bypass file system redirection. Note that 64-bit applications cannot use the `Sysnative` alias as it is a virtual directory not a real one.*" – Remy Lebeau Feb 03 '17 at 01:40