4

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

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

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

以下是描述情况的片段:

使用绝对路径:

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 更新)。

4

2 回答 2

7

最有可能的问题是MyDll.dll依赖于与MyDll.dll. 当您的应用程序位于与 不同的文件夹中时MyDll.dll,这些依赖项将不会从包含MyDll.dll. 相反,它们由系统DLL 搜索顺序解决。

您的使用SetCurrentDirectory会影响系统 DLL 搜索顺序。这意味着 的依赖关系MyDll.dll是从包含MyDll.dll.

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

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

当然,另一种可能性是对工作目录的调用UseDLL依赖于工作目录。您可以通过在调用LoadLibrary.

于 2012-11-06T17:23:17.417 回答
5

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

更新: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;
}
于 2012-11-06T17:34:09.073 回答