2
votes

I have a dll and I even have the header files for the dll, but I don't have the implementation neither the lib file for the dll. I try to load up the dll with the QLibrary class and get class instance from it. I successfully retrieved the class after 2hours, but when I try to call a function on the object I get unresolved external symbol which tells me that the dll did not exported properly. For simplicity I re-created the issue with the following sources: DLL-Project (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-Project (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-Project (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();
}

This is very straight forward, does not contain anything fancy really. As you can see I kept the class default as the QtCreator does did not change anything, except added another function with extern "C" and the export defined in global. the purpose of this would be to get an object from the dll itself, (since I have the .h and .dll nothing else). Now for the loader application, again dirty yet simple basic stuff:

#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();
}

I added the header file to the project because i have it anyway. I used QLibrary to load up the dll and retrieved the getInstance method from it with which I could get an instance of the TestLibrary class. However if I try to call the Test() method of TestLibrary within the if(tl) { ... } i get an unresolved external symbol error message that tells me it can't find the definition of the Test method. What am I missing in here?

P.S.: I won't get lib files so let's focus on the problem with the dll loading :).

Regards, Joey

1
So there are two ways to link to a dll: implicit linking and explicit linking. With implicit linking, they do give you a .lib file along side the .dll that tells you how to you link, which I find MUCH easier. If you don't have this, you have to use explicit linking (see stackoverflow.com/questions/20294545/…) - IdeaHat
Trying to export C++ classes from a DLL is a very bad idea. Windows does not have a standard binary interface, and every C++ compiler (including different versions of the same compiler, and different compiler options passed to the same version of the same compiler) will mismatch. Use function exports with plain C-compatible signatures, and if you want to export objects, use v-tables like COM does. - Ben Voigt

1 Answers

2
votes

Well since you've written void Test() { in your .cpp file and not void TestLibrary::Test { your function isn't being defined and so it isn't exported at all.

EDIT: After this code like that works fine and prints "Hello" in qDebug (dll should be compiled in debug, I failed on that the first time)

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

Decorated function name is not very nice but I don't know what exactly can be done about it :) And also you'll get differently mangled names with different compilers so using Qt in this case will not be cross-platform anyway.