LoadLibraryW和POSIX路径分隔符

时间:2016-01-10 16:52:13

标签: winapi dll posix loadlibrary

LoadLibrary的MSDN文档警告不要使用普通的Unix斜杠“/”:

  

指定路径时,请务必使用反斜杠(\),而不是正斜杠(/)。

在调用此API时,我无法使用正斜杠或反斜杠(或两者)找到任何问题。我尝试了以下路径名:

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

所有组合均按预期工作。为什么MSDN建议不要使用正斜杠作为路径分隔符?

修改

关于UNC名称,它也适用于“//127.0.0.1/c$/foo/bar/baz.dll”。

是的,如果添加“\?\”,它不会加载库,但_wfopen也无法打开文件。 LoadLibraryW与接受/不接受正斜杠的任何其​​他Windows API有何不同?为什么有关于LoadLibraryW而不是CreateFileW的明确警告。

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

  

要创建或打开的文件或设备的名称。您可以在此名称中使用正斜杠(/)或反斜杠()。

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

  

指定路径时,请务必使用反斜杠(),而不是正斜杠(/)。

当使用正斜杠(/)时,是否存在其他可能导致LoadLibrary失败的陷阱,而其他Windows API会接受正斜杠而没有任何问题?

2 个答案:

答案 0 :(得分:6)

在将请求传递给本机API之前,Windows API中的文件I / O会将正斜杠(" /")转换为反斜杠(" \")。本机API需要NT样式的名称。当路径名以" \\?\"为前缀时,不会执行转换。有时您无法控制是否存在此前缀(例如,在使用Windows API检索基本路径时)。

简而言之:使用本机路径分隔符是安全的解决方案。违反合同并使用正斜杠可能会突然停止工作。

完整信息记录在MSDN的{{3}}。

答案 1 :(得分:1)

原因是程序员以后不会遇到奇怪的问题。 Windows API非常庞大,预计会有很多组合。通过禁止某些案件,他们可以让他们的生活更轻松。

但我知道你想要这个特例。在这里。 Windows加载器需要维护自己的模块和路径数据库,其中一些实际上是在API中公开的,所以在某种程度上他们必须选择规范表示然后他们可以忘记系统获取DLL的详细信息首先。在加载器中更是如此,实际上是NT层组件,而不是Win32层组件。所以从Win32进入的路径会得到你注意到的compat处理,但是通过规范的转换,路径从NT-native转到Win32。

以此为例

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

如您所见,它会打印不同的字符串。现在想象开发人员可能会决定他们需要基于name相等或一些奇怪的方案来释放模块。它不起作用。

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

如果你没有对Windows进行长时间编程,那么这个功能看起来甚至都不那么奇怪。

但还有更多:https://msdn.microsoft.com/en-us/library/windows/desktop/ms683196(v=vs.85).aspx

  

要在当前进程中检索模块的基本名称,请使用   GetModuleFileName函数检索完整的模块名称然后   使用strrchr(szmodulename,'\')之类的函数调用来扫描   模块名称字符串中基本名称的开头。这是更多   比使用a调用GetModuleBaseName更高效,更可靠   处理当前流程。

MSDN告诉程序员采用反斜杠的最佳实践',想象一下LoadLibrary()中的原始路径表示是否已存储?这里有一些杂乱的代码。