2014-02-07 154 views
2

我有一個DLL,我甚至有DLL的頭文件,但我沒有執行DLL文件的lib文件。我嘗試使用QLibrary類加載dll並從中獲取類實例。我在2小時後成功地檢索了這個類,但是當我嘗試調用該對象的函數時,我得到了未解析的外部符號,它告訴我該dll沒有正確導出。爲了簡單起見,我重新創建具有下列來源問題: DLL項目(testlibrary_global.hpp):訪問類成員從DLL(不LIB !!!)

#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」的函數和在全局中定義的導出。這樣做的目的是從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加載問題:)。

問候, 喬伊

+0

所以有兩種方法可以鏈接到一個dll:隱式鏈接和顯式鏈接。通過隱式鏈接,它們會爲.dll文件提供一個.lib文件,告訴您如何鏈接,這讓我覺得更容易。如果你沒有這個,你必須使用顯式鏈接(請參閱http://stackoverflow.com/questions/20294545/how-to-use-ac-class-dll-loaded-explicitly-in-visual-studio) – IdeaHat

+0

更好的鏈接http://stackoverflow.com/questions/1027435/explicitly-linking-to-classes-in-dlls – IdeaHat

+1

試圖從DLL中導出C++類是一個非常糟糕的主意。 Windows沒有標準的二進制接口,並且每個C++編譯器(包括相同編譯器的不同版本,以及傳遞給相同編譯器的相同版本的不同編譯器選項)都不匹配。使用具有普通C兼容簽名的函數導出,並且如果要導出對象,請使用像COM一樣的V表。 –

回答

2

嘛,因爲你已經在你的.cpp文件書面void Test() {並沒有被定義爲不void TestLibrary::Test {你的函數,所以它不出口的。

編輯: 此代碼後一樣,工作正常,並在qDebug打印「Hello」(DLL應在調試編譯,我的第一次失敗的)

QFunctionPointer raw = lib.resolve("[email protected]@@QEAAXXZ"); 
TestPrototype testFunc; 
*(QFunctionPointer*) &testFunc = raw; 
(tl->*testFunc)(); 

裝飾功能名稱不是很不錯,但我不知道到底能做什麼:)而且你會得到不同編譯器的不同名稱,所以在這種情況下使用Qt將不會是跨平臺的。