【问题标题】:LoadLibrary with Absolute Path returns Incorrect HMODULE with No Error具有绝对路径的 LoadLibrary 返回不正确的 HMODULE 且没有错误
【发布时间】:2012-10-26 16:33:37
【问题描述】:

我有一些代码试图加载一个 Dll。

我遇到了一个奇怪的“错误”。当尝试从绝对路径加载 dll 时,我得到一个 Non-Null HMODULE,它在 GetLastError 调用上没有给出 Windows 错误代码(即 GetLastError 根据msdn 返回“0”或成功)。调用此 dll 中的函数时,我得到不正确的值。

这种行为很特殊,因为如果我使用 SetCurrentDirectory 将当前目录切换为当前 dll 的目录,并使用对 LoadLibrary 的相对路径调用,我会得到正确的值。

这是描述情况的sn-p:

使用绝对路径:

std::string libLoc = get_dll_location(); // Get the directory of this dll
HMODULE myDLL = LoadLibraryA(libLoc.c_str()); // Non-null value
DWORD lastError = GetLastError(); // returns 0

MyObj * value = UseDLL(myDLL); // bad value

使用相对路径:

SetCurrentDirectory("c:\\path\\containing\\dll\\"); // hard coded path to dll's folder
HMODULE myDLL = LoadLibrary("myDll.dll");  // Non-null value
MyObj * value = UseDLL(myDLL);  // Good value

我真的很想避免使用 SetCurrentDirectory,因为使用此 Dll 的应用程序可能是多线程的,并且需要目录保持不变。

对此问题的任何见解将不胜感激。希望这只是我的一个小错误。

更新:使用LoadLibraryEx 似乎是不可能的,因为我似乎无法使用 LOAD_LIBRARY_SEARCH_* 标志(我已经尝试安装 KB2533623 update) .

【问题讨论】:

  • LoadLibraryEx 可能是您最好的选择。
  • 更有可能发生其他不明显的事情。 'UseDLL' 是否受目录更改的影响?如果您使用带有硬编码相对路径(但不更改当前目录)的“LoadLibrary”会发生什么?
  • 只是稍微相关,但您是否打算在您的 SetCurrentDirectory() 路径调用中包含 DLL 名称?
  • @WhozCraig 这看起来是一个可靠的功能,我会看看它是否有效,但 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 标志仅适用于 Windows 7 及更高版本 - 这可能会引入向后兼容性问题。
  • 如果是这种情况,依靠 LoadLibrary 的搜索路径将是您唯一的选择,我建议您在下面多次阅读 David 的答案。我讨厌依赖系统搜索路径来搜索除了操作系统库之外的任何东西,只是因为如果利用得当,它可能是一个安全漏洞。听起来您对正在发生的事情有了更好的了解,这很好。

标签: c++ winapi dll absolute-path loadlibrary


【解决方案1】:

问题很可能是MyDll.dll 依赖于与MyDll.dll 位于同一文件夹中的其他DLL。当您的应用程序位于与 MyDll.dll 不同的文件夹中时,这些依赖项将不会从包含 MyDll.dll 的文件夹中解析。相反,它们由系统 DLL search order 解决。

您使用SetCurrentDirectory 会影响系统DLL 搜索顺序。这意味着MyDll.dll的依赖是从包含MyDll.dll的目录中解析出来的。

例如,您可以在配置文件模式下使用 Dependency Walker 来检验此假设。这将告诉您MyDll.dll 的依赖关系是如何在运行时解决的。

您不喜欢使用SetCurrentDirectory 是对的。最好的解决方案是将所有 DLL 与应用程序放在同一目录中。

当然,另一种可能是对UseDLL 的调用依赖于工作目录。您可以通过在调用 LoadLibrary 后将工作目录更改回其原始值来排除这种情况。

【讨论】:

  • 我认为你是对的,应该意识到这一点。现在我需要弄清楚如何让 myDll.dll 的依赖项从新目录加载 - LoadLibraryEx 看起来很有希望。
【解决方案2】:

尝试设置 SetDllDirectory 或 AddDllDirectory 而不是 SetCurrentDirectory,并使用带有标志 LOAD_LIBRARY_SEARCH_USER_DIRS 的 LoadLibraryEx 而不是 LoadLibrary。可以在 MSDN here 上找到有用的信息。

更新:Windows 7 上的 AddDllDirectory 和相关调用示例(需要 KB2533623)

#include "stdafx.h"
#include <iostream>
#include <Windows.h>

typedef DLL_DIRECTORY_COOKIE (WINAPI *ADD_DLL_PROC)(PCWSTR);
typedef BOOL (WINAPI *REMOVE_DLL_PROC)(DLL_DIRECTORY_COOKIE);

#ifndef LOAD_LIBRARY_SEARCH_USER_DIRS
#define LOAD_LIBRARY_SEARCH_USER_DIRS       0x00000400
#endif

int main()
{

    ADD_DLL_PROC lpfnAdllDllDirectory = (ADD_DLL_PROC)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddDllDirectory");
    REMOVE_DLL_PROC lpfnRemoveDllDirectory = (REMOVE_DLL_PROC)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "RemoveDllDirectory");
    if(lpfnAdllDllDirectory && lpfnRemoveDllDirectory)
    {

        DLL_DIRECTORY_COOKIE cookie = ((ADD_DLL_PROC)lpfnAdllDllDirectory)(L"c:\\windows\\system32\\");
        std::cout << cookie << std::endl;
        HMODULE module = LoadLibraryEx(L"cabview.dll", NULL, LOAD_LIBRARY_SEARCH_USER_DIRS);
        if(module)
        {
            std::cout << "Locked and loaded" << std::endl;
            FreeLibrary(module);
        }
        if(cookie && ((REMOVE_DLL_PROC)(cookie)))
        {
            std::cout << "Added and removed cookie" << std::endl;
        }


    }
    std::cin.get();
    return 0;
}

【讨论】:

  • 嗯,我引用了 kernel32.lib,但是 AddDllDirectory 和 LoadLibraryEx 的许多标志都丢失了。使用这些是否需要其他依赖项?
  • 您的开发环境(例如 Visual Studio)和版本是什么?
  • 尝试将 #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0502 #endif 添加到您的 stdafx.h 文件中。我认为您已包含 Windows.h?
  • 嗯,这是 Windows 版本。使用 GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddlDllDirectory");该函数看起来像 DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory( In PCWSTR NewDirectory );或者,SetDllDirectory 应该没有箍(当您有多个要添加的搜索路径时,AddDllDirectory 很有用)。这行得通吗?
  • 根据msdn,我相信 AddDllDirectory 仅在 Windows 8 上可用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2012-04-15
  • 1970-01-01
  • 2016-08-03
相关资源
最近更新 更多