为什么我不能使用 GetProcAddress 在 DLL 中调用C++静态类工厂方法?

Why can't I call a C++ static class factory method in a DLL with GetProcAddress?

本文关键字:C++ 调用 静态类 工厂 方法 DLL 不能 GetProcAddress 为什么      更新时间:2023-10-16

我正在尝试使用以下标头加载一个假设的插件:

#ifndef _DLL_H_
#define _DLL_H_
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */

class DLLIMPORT DllClass
{ 
  public:
    virtual ~DllClass(void);
    static DllClass* getPCFilter(); 
    virtual int Process(int a, int b);
  protected:
    DllClass();
};

#endif /* _DLL_H_ */

我的主机代码确实:

HINSTANCE hinstDLL;
hinstDLL = LoadLibrary(L"PCFilter.dll");
if(hinstDLL)
{
    typedef DllClass*(*Factory)();
    Factory fun1;
  fun1 = (Factory)GetProcAddress(hinstDLL, "DllClass::getPCFilter");

dll 将打开,但 GetProcAddress 找不到静态工厂方法。我不应该这样做吗?

我尝试摆脱静态方法,而是在类声明之后执行以下操作:

extern "C" DLLIMPORT void* getPCFilterInstance()
{
    return (void*)new DllClass();
}

但是,在编译主机源时,链接器抱怨:

In function `getPCFilterInstance'::
[Linker Error] undefined reference to `_imp___ZN8DllClassC1Ev'

我可以通过链接到 .a 库来解决。但是 DLL 的想法不是在编译时不需要链接吗?

您忽略了以下事实:函数名称将被修饰("名称重整")或在 DLL 接口中根本不可见(在给定名称下)。据我所知,GetProcAddress不执行任何名称拆解,但是链接器会这样做(当静态导入带有导出类的 DLL 时)。

据我所知,最佳做法是提供一个工厂函数,该函数具有未修饰的名称和预定义的调用约定,就像 COM 规定的那样(请参阅DllGetClassObject)。

注意:我应该补充一点,根据所使用的编译器/链接器,装饰("残缺")名称会有所不同。不同的编译器,不同的规则。因此,如果没有大量的修补,它们甚至可能彼此不兼容。

编辑:关于这个问题:

但是 DLL 的想法不是在编译时不需要链接吗?

嗯,是也不是。在Windows上,整个过程与unixoid系统中的过程有些不同。加载程序将负责解析依赖项等,但关键是有两种加载 DLL 的方法。一种是通过静态导入 DLL,在这种情况下,名称解析在您的程序开始运行之前完成(或在此之前失败),另一种是通过 LoadLibrary 和朋友动态加载 DLL,然后使用 GetProcAddress 解析函数地址。后者有一个变体(由链接器支持),称为延迟加载。最终,它仍然只是第二种方法。

延迟加载可能完全提供您想要的内容,方法是让链接器关心要解析的名称,并且仍然能够在运行时处理加载 DLL 或解析名称的故障。

您可以使用

extern "C"语句导出与在代码中声明的函数相同的名称 - 否则它将被C ++编译器破坏