【问题标题】:LoadLibraryW() failing to load DLL in System32LoadLibraryW() 无法在 System32 中加载 DLL
【发布时间】:2013-08-29 22:41:21
【问题描述】:

我正在尝试使用以下代码在 C:\Windows\System32\ 文件夹中加载与打印机驱动程序一起安装的 DLL:

LoadLibraryW(L"C:\\Windows\\System32\\MagAPI.dll");

GetLastError() 报告“找不到指定的模块”。如果我将 DLL 移到 System32 文件夹之外(例如 C:\SomeFolder\MagAPI.dll),那么它会很好地加载,所以看起来这不是 DLL 本身的问题。是否有一些奇怪的 Windows 安全功能可能会阻止我的应用程序加载它?这是我唯一能想到的,但我找不到任何确定的答案。

这是 ShowSnaps 的调试输出,它显示了失败的地方:

1a8c:1fd4 @ 19006756 - LdrLoadDll - ENTER: DLL name: C:\Windows\system32\MagAPI.dll DLL path: C:\Windows\system32;C:\Windows\system;C:\Windows;.;<otherstuff>
1a8c:1fd4 @ 19006756 - LdrpLoadDll - ENTER: DLL name: C:\Windows\system32\MagAPI.dll DLL path: C:\Windows\system32;C:\Windows\system;C:\Windows;.;<otherstuff>
1a8c:1fd4 @ 19006756 - LdrpLoadDll - INFO: Loading DLL C:\Windows\system32\MagAPI.dll from path C:\Windows\system32;C:\Windows\system;C:\Windows;.;<otherstuff>
1a8c:1fd4 @ 19006756 - LdrpFindOrMapDll - ENTER: DLL name: C:\Windows\system32\MagAPI.dll DLL path: C:\Windows\system32;C:\Windows\system;C:\Windows;.;<otherstuff>
1a8c:1fd4 @ 19006756 - LdrpSearchPath - ENTER: DLL name: C:\Windows\system32\MagAPI.dll DLL path: C:\Windows\system32;C:\Windows\system;C:\Windows;.;<otherstuff>
1a8c:1fd4 @ 19006756 - LdrpResolveFileName - ENTER: DLL name: C:\Windows\system32\MagAPI.dll
1a8c:1fd4 @ 19006756 - LdrpResolveFileName - RETURN: Status: 0xc0000135
1a8c:1fd4 @ 19006756 - LdrpSearchPath - RETURN: Status: 0xc0000135
1a8c:1fd4 @ 19006756 - LdrpFindOrMapDll - RETURN: Status: 0xc0000135
1a8c:1fd4 @ 19006756 - LdrpLoadDll - RETURN: Status: 0xc0000135
1a8c:1fd4 @ 19006756 - LdrLoadDll - RETURN: Status: 0xc0000135

【问题讨论】:

  • 您使用的是哪个版本的 Windows?您可能需要管理员权限才能查看 System32 的内容。您可以做的快速测试是右键单击并以管理员身份运行您的应用程序(我认为是 win vista 及以上),如果它有效,那就是问题所在。
  • 不,我要求您确认这是否是权限问题。有时从代码访问 System32 需要对正在运行的应用程序的管理员权限,即使只是为了读取文件。
  • 似乎不是问题。我刚刚尝试以管理员身份运行该应用程序,但它仍然以完全相同的方式失败。我在 Windows 7 64 位顺便说一句。不过它是一个 32 位应用程序。
  • 当您将文件“移出”system32 时,您将它移到哪里?库是否有可能在正确加载的文件夹中满足导入依赖项,而在驻留在 system32 中时不满足。您能否对其进行依赖遍历(例如,使用来自 MS 的 depends.exe)并查看可能缺少的内容。这是一种可能性,但从您的 ShowSnaps 输出来看,文件名本身根本无法解析。多么奇怪。

标签: c++ dll loadlibrary system32


【解决方案1】:

既然您提到您的应用程序是 32 位的,那么您正在加载的 DLL 也必须是 32 位的。

LoadLibrary() 失败的可能原因是您运行的是 64 位版本的 Windows,但您的打印机驱动程序错误地将其 32 位 DLL 安装到 System32 文件夹而不是 @987654324 文件夹中@文件夹。

一些背景知识:在 64 位版本的 Windows 上,64 位 DLL 位于 System32 文件夹中,32 位 DLL 位于 SysWOW64 文件夹中。我知道这听起来应该是相反的,但不要让名字混淆你;出于向后兼容性的原因,这些文件夹的命名方式如此。 SysWOW64 文件夹应该对应用程序是透明的:Windows 有一个称为文件系统重定向的功能,它使 32 位应用程序可以通过指定 System32 文件夹来加载 32 位 DLL(就像它们总是有) 即使 DLL 实际上在 SysWOW64 中。

另一方面,LoadLibrary() 将拒绝加载放置在错误文件夹中的 DLL。这是您可能看到的行为。

解决您的问题的真正方法是联系打印机制造商并告知他们他们的驱动程序安装程序将其 DLL 放入了 64 位 Windows 版本下的错误文件夹中。如果他们解决了这个问题,您的应用程序将开始正常工作,而无需对现有代码进行任何更改。

与此同时,您应该能够通过以下方式解决您的问题:

  1. 在尝试加载 DLL 之前,将 DLL 从 %windir%\Sysnative 复制到您可以控制的某个已知文件夹。 (我建议您在%TEMP% 中创建一个唯一命名的文件夹并将DLL 复制到该文件夹​​中)。注意:Sysnative 是映射到本机系统文件夹的特殊别名,在 64 位版本的 Windows 下为 System32
  2. 调用 LoadLibrary() 并将您在步骤 1 中创建的 DLL 副本的路径传递给它。
  3. 使用完 DLL 后,将其卸载并删除您在第 1 步中创建的副本。

如果您需要支持 64 位 Windows XP,上述解决方法可能不起作用,因为已证明 Sysnative 别名仅适用于 Windows Vista 或更高版本。另一种解决方法是手动绕过文件系统重定向:

  1. 通过调用Wow64DisableWow64FsRedirection() 暂时禁用文件系统重定向。这将允许您的应用程序查看System32 中的真正内容。
  2. 将 DLL 从 System32 复制到您可以控制的某个已知文件夹。
  3. 通过调用 Wow64RevertWow64FsRedirection() 重新启用文件系统重定向。
  4. 调用 LoadLibrary() 并将您在第 2 步中创建的 DLL 副本的路径传递给它。
  5. 使用完 DLL 后,将其卸载并删除您在第 2 步中创建的副本。

请注意,如果您想调用Wow64DisableWow64FsRedirection() 以使LoadLibrary() 工作而不必复制DLL,请不要打扰:LoadLibrary() 不会注意该设置。 (我实际测试过。)

更多信息:File System Redirector

【讨论】:

  • 不幸的是,LoadLibraryW(在 32 位进程中)在我指向复制到我的桌面文件夹(来自 SysWow64)的 shell32.dll 的副本时仍然返回 0。异常消息“找不到指定的模块”令人抓狂,因为它根本不是真的,哎呀。
猜你喜欢
  • 1970-01-01
  • 2016-10-25
  • 1970-01-01
  • 1970-01-01
  • 2015-07-05
  • 2012-03-08
  • 1970-01-01
  • 2017-06-26
相关资源
最近更新 更多