【问题标题】:C++ GetProcAddress() can't find the method of a static classC++ GetProcAddress() 找不到静态类的方法
【发布时间】:2014-10-14 16:28:25
【问题描述】:

我需要在 C++ 中动态加载一个 dll。

我已按照本教程http://msdn.microsoft.com/en-us/library/ms235636.aspx 创建了 dll,一切正常。

然后我关注了这个http://msdn.microsoft.com/en-us/library/64tkc9y5.aspx,并调整了控制台应用程序如下:

typedef DOUBLE(CALLBACK* DllFunc)(DOUBLE, DOUBLE);

int _tmain(int argc, _TCHAR* argv[])
{
    HINSTANCE hDLL;               // Handle to DLL
    DllFunc dllFunc1;
    DOUBLE p1 = 1.0, p2 = 2.0, r;
    hDLL = LoadLibrary(L"MathFuncsDLL");
    if (hDLL != NULL)
    {
        cout <<  "DLL loaded: " << hDLL << endl;
        dllFunc1 = (DllFunc)GetProcAddress(hDLL, "MyMathFuncs@MathFuncs@Multiply");
        if (!dllFunc1)
        {
            // handle the error
            FreeLibrary(hDLL);
            cout << "Function not found!" << endl;
            return -1;
        }
        else
        {
            // call the function
            r = dllFunc1(p1, p2);
            cout << "The result is: " << r << endl;
        }               
    }
    else {
        cout << "Dll not found" << endl;
        return -1;
    }
    cout << "Press any key to exit." << endl;
    int i;
    cin >> i;
    return 0;
}

DLL 已正确加载且不为空。问题是 GetProcAddress() 函数总是返回 0。

我已经尝试过命名空间、类名、方法名的所有组合。我尝试在函数名中使用范围运算符 (::) 而不是 @。

我尝试将整个命名空间定义为 外部“C” 但没有任何改变。每次我运行或调试控制台应用程序时,它都找不到“乘法”功能。

我想我错过了什么... 我哪里错了?


编辑

Dependency Walker 向我展示了以下导出表:

现在我想知道函数名的最后一部分是什么意思... 为什么 __declspec(dllexports) 添加这些符号?

【问题讨论】:

  • 请转储你的 dll 的符号,然后添加。
  • 很难猜出你从哪里得到这个名字,看起来你只是猜到了。对于 MSVC++ 编译器,它应该是 "?Multiply@MyMathFuncs@MathFuncs@@SANNN@Z"。使用 DLL 上的 Dumpbin.exe /exports 查看名称。通过链接 DLL 项目生成的 .lib 文件,您可以避免做这种可怕的事情。
  • 您使用显示导出名称的屏幕截图更新了问题。因此,我们当然完成了。你还期待什么?
  • 仅此而已,实际上...出于好奇,我在问为什么编译器会添加这些符号.. Khouri Giordano 的回答如下,解释一下! ;)

标签: c++ dll dllexport dynamic-loading getprocaddress


【解决方案1】:

欢迎使用 C++ 名称修改。编译器添加到函数名称中的所有内容都是为了确保每个具有唯一签名的函数都有唯一的名称。 Microsoft 确实以一种方式命名重整,而 GCC/Clang 则以另一种方式命名。它不是标准化的,但特定操作系统上的编译器都会以相同的方式进行名称修改,因此它们都可以相处。

确保您的名字仍然可以被人类预测的唯一方法是将导出的 DLL 函数声明为 extern "C"。但是,这会限制您导出 C 函数。

在我处理过的库中,有一个导出的 C 函数用于初始化库并取回接口指针。在这种情况下,“接口”是指没有数据而只有虚函数的抽象虚基类。

这是声明接口类的正确方法:

struct my_interface
{
    virtual int my_function1( int param1, int param2 ) = 0;
    virtual int my_function2( const char *param ) = 0;

#if CHOOSE_DESTRUCTION_TYPE

protected:
    // Protected non-virtual destructor prevents the use of delete on the interface pointer.
    // Must be defined because it will be used as objects of derived types are destructed.
    ~my_interface() {};

#else

    // Public virtual destructor allows the use of delete on the interface pointer.
    virtual ~my_interface() = 0;

#endif

private:
    // Private copy assignment prevents "*ptr1 = *ptr2".
    // This odd syntax CAN be supported, but you probably shouldn't.
    // Only needs to be declared because nobody can call it.
    my_interface & operator=( const my_interface & );

    // Ditto for move assignment.
    my_interface & operator=( my_interface && );
};

【讨论】:

    【解决方案2】:

    使用像 dumpbin 或 Dependency Viewer 这样的工具来检查导出的函数名称。这将允许您诊断哪种可能的故障模式适用于您的案例:

    1. 函数未导出,或
    2. 函数已导出,但名称已修饰,或
    3. 函数以您期望的名称导出,但您输入的名称不正确。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      • 2018-11-07
      • 2021-10-20
      • 2020-02-27
      • 2013-04-04
      • 2013-07-29
      • 1970-01-01
      相关资源
      最近更新 更多