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

Sal*_*rtz 0 c++ windows dll

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

#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_ */
Run Code Online (Sandbox Code Playgroud)

我的主机代码:

HINSTANCE hinstDLL;
hinstDLL = LoadLibrary(L"PCFilter.dll");

if(hinstDLL)
{
    typedef DllClass*(*Factory)();
    Factory fun1;

  fun1 = (Factory)GetProcAddress(hinstDLL, "DllClass::getPCFilter");
Run Code Online (Sandbox Code Playgroud)

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

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

extern "C" DLLIMPORT void* getPCFilterInstance()
{
    return (void*)new DllClass();
}
Run Code Online (Sandbox Code Playgroud)

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

In function `getPCFilterInstance'::
[Linker Error] undefined reference to `_imp___ZN8DllClassC1Ev'
Run Code Online (Sandbox Code Playgroud)

我可以通过链接到.a lib来解决这个问题.但是不是DLL的想法不需要在编译时链接?

0xC*_*22L 5

您忽略了函数名称将被装饰("名称重整")或在DLL接口中(在给定名称下)完全不可见的事实.据我所知GetProcAddress,没有做任何名称demangling,但是链接器会这样做(当静态导入带有导出类的DLL时).

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

注意:我应该添加,根据使用的编译器/链接器,装饰("受损")名称会有所不同.不同的编译器,不同的规则.因此,如果没有相当的修补,它们甚至可能彼此不兼容.

编辑:关于这个问题:

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

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

延迟加载可能会提供您想要的内容,方法是让链接器关注要解析的名称,并且仍然能够处理加载DLL或在运行时解析名称的失败.