【问题标题】:Unable to load some functions from DLL with GetProcAddress()无法使用 GetProcAddress() 从 DLL 加载某些函数
【发布时间】:2011-10-26 18:05:59
【问题描述】:

我正在尝试构建一个 DLL,稍后我想使用 SetWindowsHookEx() 函数将其注入到某些进程中。奇怪的是,当我尝试加载 DLL 并尝试使用 GetProcAddress 获取其中包含的过程的地址时,如果我尝试获取 CBT 消息处理过程的地址,它会返回 NULL,但它适用于其他功能。

这是代码。

DLL 头文件 (.h)

#include <windows.h>

extern "C" {
    __declspec(dllexport) LRESULT CALLBACK hookProc(int code, WPARAM wParam, LPARAM lParam);
    __declspec(dllexport) int add(int a, int b);
}

DLL 文件 (.cpp)

#include "SimpleHook.h"

extern "C" {
    __declspec(dllexport) LRESULT CALLBACK hookProc(int code, WPARAM wParam, LPARAM lParam) {
        return CallNextHookEx(0, code, wParam, lParam);
    }

    __declspec(dllexport) int add(int a, int b) {
        return a + b;
    }
}

主文件

#include <iostream>
#include <windows.h>
#include <tchar.h>

int main(int argc, char* argv[]) {
    HINSTANCE dllHandle = LoadLibrary(_T("SimpleHook.dll"));

    if (dllHandle) {
        // returns the correct address
        cout << "add address: " << GetProcAddress(dllHandle, "add") << endl;

        // returns NULL
        cout << "hookProc address: " << GetProcAddress(dllHandle, "hookProc") << endl;
    }
}

如果我使用 GetLastError(),我会得到 127 错误代码:

ERROR_PROC_NOT_FOUND:找不到指定的过程。

奇怪的是同一个文件中的其他函数都被正确加载了。 非常感谢任何帮助!

【问题讨论】:

    标签: c++ dll


    【解决方案1】:

    调用约定改变了名称修饰。 __stdcall 函数的名称总是以 _ 开头,并以其他方式损坏,因此链接失败,但 __cdecl 函数没有损坏,因此它被找到了。

    要从您使用__declspec(dllexport) 构建的 DLL 导入,您应该始终在要导入的所有内容上包含带有 __declspec(dllimport) 的标头,并链接您从构建 DLL 获得的库。这将保证您的所有函数都正确链接,并且您不必深入到与 C 兼容的链接。

    您不应将GetProcAddressextern "C"__declspec(dllexport) 结合使用。

    标题:

    #include <windows.h>
    
    #ifndef MAIN
    #define DLL_API __declspec(dllexport)
    #else
    #define DLL_API __declspec(dllimport)
    #endif
    
    DLL_API LRESULT CALLBACK hookProc(int code, WPARAM wParam, LPARAM lParam);
    DLL_API int add(int a, int b);
    

    DLL .cpp 文件:

    #include "SimpleHook.h"
    
    DLL_API LRESULT CALLBACK hookProc(int code, WPARAM wParam, LPARAM lParam) {
        return CallNextHookEx(0, code, wParam, lParam);
    }
    
    DLL_API int add(int a, int b) {
        return a + b;
    }
    

    主 .cpp 文件:

    #define MAIN
    #include "SimpleHook.h"
    
    int main(int argc, char* argv[]) {
    
        if (dllHandle) {
            // returns the correct address
            cout << "add address: " << add << endl;
    
            // returns NULL
            cout << "hookProc address: " << hookProc << endl;
        }
    }
    

    不要忘记将库添加到链接器。

    【讨论】:

    • @Ben Voigt:因为__cedcl 函数根本不会被破坏。我的主要观点是他甚至不应该使用 GetProcAddress。
    • 你不能简单地避免在所有情况下使用GetProcAddress。你也不能盲目地去改变调用约定。
    • 我没有更改调用约定。 GetProcAddress 并非总是可以避免的,但如果是,那么__declspec(dllexport) 不是与之配对的合适导出工具。
    • 对不起,我误读了您的部分答案。不过,您可能想改写最后的建议,因为按照它的写法,它听起来像 (1) 永远不要使用 GetProcAddress 和 (2) 如果使用 dllexport,请不要使用 extern "C"。无论如何,使用dllexport 和 DEF 文件,而不是单独使用 DEF 文件并没有什么坏处,而且我总是更喜欢尽可能向编译器表达范围。
    • 所以当我需要使用 GetProcAddress(如 MSDN 所述)时,与之配对的合适导出工具是什么?
    【解决方案2】:

    CALLBACK 宏解析为 __stdcall。因此,您必须在函数名称前加上一个下划线字符并将参数的大小附加到函数名称中:

    cout << "hookProc address: " << GetProcAddress(dllHandle, "_hookProc@12")
         << endl;
    

    【讨论】:

    • 你怎么知道 hookProc 使用了 __stdcall 约定?
    【解决方案3】:

    您必须使用诸如 dumpbin 或 Dependency Walker 之类的工具来了解损坏的名称。

    或者您可以在链接时使用 DEF 文件,将您选择的名称放入导出表中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多