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

时间:2012-04-09 12:08:38

标签: 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_ */

我的主机代码确实:

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 lib来解决。但是不是DLL的想法在编译时不需要链接吗?

2 个答案:

答案 0 :(得分:5)

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

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

注意:我应该补充说,根据使用的编译器/链接器,装饰(“受损”)名称会有所不同。不同的编译器,不同的规则。因此,如果没有相当的修补,它们甚至可能在彼此之间不相容。

关于这个问题的

编辑

  

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

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

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

答案 1 :(得分:1)

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