0

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

#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的想法不是不需要在编译时链接吗?

4

2 回答 2

5

您忽略了函数名称将被修饰(“名称修饰”)或在 DLL 接口中根本不可见(在给定名称下)的事实。据我所知GetProcAddress,链接器不会进行任何名称解构(当静态导入带有导出类的 DLL 时)。

据我所知,最佳实践是提供一个工厂函数,该函数具有未修饰的名称和预定义的调用约定,与 COM 所规定的非常相似(请参阅 参考资料DllGetClassObject)。

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

编辑:关于问题:

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

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

通过让链接器关心要解析的名称并且仍然能够处理加载 DLL 的失败或在运行时解析名称,延迟加载可能会提供您想要的东西。

于 2012-04-09T12:11:24.290 回答
1

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

于 2012-04-09T12:12:52.713 回答