从 DLL 访问类成员(不是 LIB !!!)

Posted

技术标签:

【中文标题】从 DLL 访问类成员(不是 LIB !!!)【英文标题】:Access class members from DLL (NOT LIB!!!) 【发布时间】:2014-02-07 21:14:55 【问题描述】:

我有一个 dll,我什至有 dll 的头文件,但我没有实现,也没有 dll 的 lib 文件。我尝试使用 QLibrary 类加载 dll 并从中获取类实例。我在 2 小时后成功检索了该类,但是当我尝试在对象上调用一个函数时,我得到未解析的外部符号,它告诉我 dll 没有正确导出。为简单起见,我使用以下来源重新创建了问题: DLL 项目 (testlibrary_global.hpp):

#ifndef TESTLIBRARY_GLOBAL_HPP
#define TESTLIBRARY_GLOBAL_HPP

#include <QtCore/qglobal.h>

#if defined(TESTLIBRARY_LIBRARY)
#  define TESTLIBRARYSHARED_EXPORT Q_DECL_EXPORT
#else
#  define TESTLIBRARYSHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // TESTLIBRARY_GLOBAL_HPP

DLL-项目(testlibrary.hpp):

#ifndef TESTLIBRARY_HPP
#define TESTLIBRARY_HPP

#include "testlibrary_global.hpp"

#include <QDebug>

class TESTLIBRARYSHARED_EXPORT TestLibrary 
public:
    TestLibrary();
    ~TestLibrary();
    void Test();
;

extern "C" TESTLIBRARYSHARED_EXPORT TestLibrary* getInstance();

#endif // TESTLIBRARY_HPP

DLL-项目(testlibrary.cpp):

#include "testlibrary.hpp"


TestLibrary::TestLibrary() 
    qDebug() << "Constructor called!";


TestLibrary::~TestLibrary() 
    qDebug() << "Destructor called!";


void Test() 
    qDebug() << "Hello from library!";



TestLibrary *getInstance() 
    return new TestLibrary();

这是非常直接的,真的不包含任何花哨的东西。正如你所看到的,我保留了类默认值,因为 QtCreator 并没有改变任何东西,除了添加了另一个带有 extern "C" 的函数和在 global 中定义的导出。这样做的目的是从 dll 本身获取一个对象(因为我只有 .h 和 .dll 没有别的)。现在对于加载器应用程序,又是肮脏而简单的基本内容:

#include <QCoreApplication>
#include <QLibrary>
#include <QDebug>

#include "testlibrary.hpp"

int main(int argc, char *argv[]) 
    QCoreApplication a(argc, argv);

    QString libPath = QString("C:/Users/johorvat/Documents/QTProjects/build-TestLibrary-Desktop_Qt_5_2_0_MSVC2010_32bit_OpenGL-Debug/debug/TestLibrary.dll");
    QLibrary lib(libPath);
    bool loaded = lib.load();
    QString error = lib.errorString();
    qDebug() << "Loaded: " << loaded;

    typedef TestLibrary* (*Prototype)();
    Prototype Func = (Prototype) lib.resolve("getInstance");
    if (Func) 
        TestLibrary* tl = Func();
        if (tl) 
            qDebug() << "Yey, I gotta clazz!";
        
    

    return a.exec();

我将头文件添加到项目中,因为无论如何我都有它。我使用 QLibrary 加载 dll 并从中检索 getInstance 方法,我可以使用它获取 TestLibrary 类的实例。但是,如果我尝试在 if(tl) ... 中调用 TestLibrary 的 Test() 方法,我会收到一条未解析的外部符号错误消息,告诉我它找不到 Test 方法的定义。 我在这里缺少什么?

P.S.:我不会得到 lib 文件,所以让我们专注于 dll 加载的问题:)。

问候, 乔伊

【问题讨论】:

所以链接到一个dll有两种方式:隐式链接和显式链接。通过隐式链接,它们确实在 .dll 旁边为您提供了一个 .lib 文件,该文件告诉您如何链接,我发现这要容易得多。如果你没有这个,你必须使用显式链接(见***.com/questions/20294545/…) 更好的链接***.com/questions/1027435/… 尝试从 DLL 导出 C++ 类是一个非常糟糕的主意。 Windows 没有标准的二进制接口,每个 C++ 编译器(包括同一编译器的不同版本,以及传递给同一编译器的同一版本的不同编译器选项)都会不匹配。使用带有纯 C 兼容签名的函数导出,如果您想导出对象,请像 COM 一样使用 v-tables。 【参考方案1】:

既然您在.cpp 文件中写入了void Test() 而不是void TestLibrary::Test ,那么您的函数没有被定义,所以它根本没有被导出。

编辑: 在这样的代码工作正常并在qDebug 中打印“Hello”之后(dll 应该在调试中编译,我第一次失败了)

QFunctionPointer raw = lib.resolve("?Test@TestLibrary@@QEAAXXZ");
TestPrototype testFunc;
*(QFunctionPointer*) &testFunc = raw;
(tl->*testFunc) ();

装饰的函数名不是很好,但我不知道具体可以做些什么:) 而且你会得到不同的编译器不同的名称,所以在这种情况下使用 Qt 无论如何都不会是跨平台的.

【讨论】:

以上是关于从 DLL 访问类成员(不是 LIB !!!)的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ dll 导出一个类?

在 Qt 中访问 DLL 的 C++ 类成员函数

如何从 dll 导入公共成员

从 Dll 调用具有偏移地址的成员函数

DLL导出类静态成员函数问题

从 c# 访问 C++ .lib 库