2

The MSDN documentation for LoadLibrary warns not to use normal Unix slash "/":

When specifying a path, be sure to use backslashes (\), not forward slashes (/).

I couldn't find any problems using either forward slashes or backslashes (or both) when calling this API. I tried the following pathnames:

c:/foo/bar/baz.dll
/foo/bar/baz.dll
c:/foo/bar\\baz.dll
/foo/bar\\baz.dll
./bar/baz.dll

All combinations worked as expected. Why does the MSDN recommend against using forward slashes as path separators?

Edit:

Regarding UNC Names, it works perfectly well with "//127.0.0.1/c$/foo/bar/baz.dll" as well.

And yes if you add "\?\" it does not load the library but _wfopen would also fail to open file. How LoadLibraryW is different from any other Windows API accepting/not-accepting forward slashes? Why there are explicit warning regarding LoadLibraryW and not CreateFileW.

CreateFile: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx

The name of the file or device to be created or opened. You may use either forward slashes (/) or backslashes () in this name.

LoadLibrary: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx

When specifying a path, be sure to use backslashes (), not forward slashes (/).

Is there some other pitfails that may cause LoadLibrary to fail when forward slashes (/) are used, while other Windows API would accept forward slashes without any issue?

Artyom
  • 31,019
  • 21
  • 127
  • 215
  • 2
    You are using plain Windows API pathnames. Once you start using NT-style names (by prepending a "\\?\" prefix), on purpose or by chance, there will no longer be any translation of path separators. [Naming Files, Paths, and Namespaces](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx) has all the information you need. In essence: Always use the native path separator. – IInspectable Jan 10 '16 at 17:01
  • Did you accidentally delete half the question? I don't understand what the problem is; it sounds like you don't have any issues whatsoever?? – andlabs Jan 10 '16 at 17:06
  • It gets messed with too much, any anti-malware tinkers with it for example. You are simply violating the warranty, if you call Microsoft Support and they discover that you use a forward slash then they hang up the phone. – Hans Passant Jan 10 '16 at 17:18
  • 1
    You quoted only part of the `CreateFile` documentation. Here is the relevant remainder: *"[...] prepend "\\?\" to the path. For more information, see [Naming Files, Paths, and Namespaces](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx)."* The last link takes you to the following: *"File I/O functions in the Windows API convert "/" to "\" as part of converting the name to an NT-style name, except when using the "\\?\" prefix."* No Windows API call will convert "\\?\"-prefixed pathnames. Only difference: `LoadLibrary` comes with more accurate documentation. – IInspectable Jan 11 '16 at 08:46

2 Answers2

7

File I/O in the Windows API converts forward slashes ("/") to backslashes ("\"), before passing the request to the native API. The native API expects NT-style names. No conversion is performed when the pathname is prefixed with "\\?\". Sometimes you do not have control over whether or not this prefix is present (e.g. when retrieving the base path using the Windows API).

In short: Using the native path separator is the safe solution. Violating the contract and using a forward slash may suddenly stop working.

Complete information is documented in the MSDN at Naming Files, Paths, and Namespaces.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • But this is windows API in general. Same goes for _wfopen. It wouldn't accept forward slashes with "\\?\" prefix. How LoadLibraryW is different? I have unaccepted this question meanwhile – Artyom Jan 11 '16 at 06:45
  • @Artyom: `_wfopen` eventually calls `CreateFile`, so the same rules apply to the CRT's file I/O functions. Neither one is different from `LoadLibraryW`: If you prefix the pathname with "\\?\", no translation of the argument is performed. – IInspectable Jan 11 '16 at 08:42
  • Yes I know that once "\\?\" is added _wfopen/CreateFile wouldn't handle Unix slash (/). What I try to understand if there are more than just "\\?\" paths prefix to LoadLibrary over CreateFile and other windows API. – Artyom Jan 11 '16 at 11:08
  • @Artyom: The "\\?\"-prefix is used for all Windows APIs that deal with path names. It's purpose is to pass the argument unmodified to the native API. Some Windows APIs (e.g. `CreateFile`) allow you to use forward slashes in a path, unless it's "\\?\"-prefixed. Other APIs (e.g. `LoadLibrary`) require, that you use backslashes. Asking why violating a contract sometimes appears to work is not very useful, and I cannot tell you when it stops working. After all, it is not documented to work at all. – IInspectable Jan 11 '16 at 11:46
  • Can you provide some resources that in such a case there is no difference? Can this be related to search path or maybe PATH in general. I mean it is suspicions difference that is more than simple documentation clarification. – Artyom Jan 12 '16 at 09:54
  • @Artyom: There is no need to clarify the documentation any further. `LoadLibrary` is not part of the POSIX standard, and doesn't know or care about POSIX path separators. It requires the use of a backslash as a path separator. – IInspectable Jan 12 '16 at 13:39
  • Use for forward "/" slashes is widely accepted all around including windows and simplifies cross platform code writing. So there are good reasons to use POSIX forward slash as path separator. – Artyom Jan 17 '16 at 09:07
  • 1
    @Artyom: What sort of cross-platform code would call `LoadLibrary` though? This API call is platform specific, and if you want to use it, you need to adhere to its rules. If you want to write cross-platform code, you could define a symbolic constant that designates the path separator, and assign it a value that matches the target platform. There is not ever a good reason to violate contracts. – IInspectable Jan 17 '16 at 14:39
  • See I'm not asking for best practice - it isn't the question _at all_. i.e. if I want to blow off my leg I'll do it on my will. The question is regarding WinAPI. If you ask me? Best practice - don't support windows at all. It is useless platform for anything serious. Yet I don't say it. Using "/" is allowed explicitly by Windows API in vast majority of cases (as shown) I want to understand pitfalls regarding use of "/" in LoadLibraryW that does not exist in other WinAPI. I know that use of "\" is expected as best practice but I don't care about it in this particular case. – Artyom Jan 18 '16 at 15:54
  • @Artyom: If you don't want to target Windows, then by all means, skip Windows, and enjoy using POSIX path separators. If you want to target Windows, you need to account for its rules. If you need to know, how much wrong you can get by when calling `LoadLibrary`, do file a Premier Support Incident with Microsoft, and have them spell out implementation details for you (charged at ~250€/h). Other APIs (like `CreateFile`) support forward slashes, as they are being invoked by the CRT/C++ Std. Lib (and have to deal with ignorant developers). `LoadLibrary` isn't, and doesn't cover up for poor code. – IInspectable Jan 18 '16 at 16:03
  • once again it isn't the question. I know what is best practice well and I agree that using "\" at Windows is indeed best practice. However it is totally irrelevant in to the question I asked. – Artyom Jan 19 '16 at 08:12
  • @Artyom "Best practice - don't support windows at all. It is useless platform for anything serious." Thanks for making me rofl :) – Swordfish Nov 16 '18 at 10:28
2

The reason is so the programmer does not get into strange problems later on. The Windows API is vast and lots of combinations are expected to work. By outlawing some cases they make their life easier.

But I gather you want this particular case. Here it goes. The Windows loader needs to maintain its own databases of modules and paths, some of this is in fact exposed in the API, so at some level they have to choose a canonical representation and then they can forget about the details how the system got the DLL in the first place. This is more so in the loader which in fact an NT-layer component, not a Win32 layer component. So paths going in from Win32 get the compat treatment you notice, but paths going out go from NT-native to Win32 via a canonical transformation.

Take this example

#include "stdafx.h"

const wchar_t name[] = L"c:/windows/system32/atl.dll";

int main() {
  HMODULE mod1 = ::LoadLibrary(name);

  wchar_t lo_name[512];
  GetModuleFileName(mod1, lo_name, 512);
  wprintf(L"%s - %s", name, lo_name);

  return 0;
}

As you can see it prints different strings. Now imagine developer might decide that they need to free modules based on name equality or some weird scheme. It does not work.

bool FreeLibByName(HMODULE mod, const wchar_t* name) {
  wchar_t lo_name[512];
  GetModuleFileName(mod, lo_name, 512);
  if (wcscmp(name, lo_name) != 0) {
    return false;
  }
  FreeLibrary(mod);
  return true;
}

If you have not been programming Windows for long that function does not even look that strange.

But there's more: https://msdn.microsoft.com/en-us/library/windows/desktop/ms683196(v=vs.85).aspx

To retrieve the base name of a module in the current process, use the GetModuleFileName function to retrieve the full module name and then use a function call such as strrchr(szmodulename, '\') to scan to the beginning of the base name within the module name string. This is more efficient and more reliable than calling GetModuleBaseName with a handle to the current process.

MSDN is telling programmers 'best practices' that assume backslash, imagine if the original path representation in LoadLibrary() had been stored? makes for some messy code here.

AlienRancher
  • 639
  • 4
  • 14
  • 1
    While this answer contains substantial information, it doesn't address the question. What you describe for `LoadLibrary` is equally true for `CreateFile`. Open a file (containing forward slashes) with `CreateFile` and request *FileNameInfo* using [GetFileInformationByHandleEx](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364953.aspx). You'll observe, that the returned information now contains backslashes. – IInspectable Jan 25 '16 at 14:47