2008-08-26 64 views
23

我大部分的C/C++開發包括單片模塊文件和任何絕對沒有課,所以通常當我需要做一個DLL與使用的功能我只是用標準__declspec(dllexport)指令導出它們。然後通過LoadLibrary()或在編譯時使用頭文件和lib文件動態訪問它們。從DLL導出C++類

當你想導出整個類(以及它的所有公共方法和屬性)時,你如何做到這一點?

是否有可能在運行時動態加載該類,如果有,如何?

你會怎麼做一個頭和lib編譯時鏈接?

+0

一個很好的答案寫後:http://stackoverflow.com/a/22797419/1995714 – 2016-08-25 19:21:39

回答

15

那麼遲綁定呢?如在加載 它與LoadLibrary()和 GetProcAddress()?我使用 可以在運行時加載庫,如果您可以在此處執行 ,它會很棒。

所以有兩種方法來加載DLL。首先是引用DLL中的一個或多個符號(例如,您的類名),提供相應的導入.LIB,並讓鏈接器將所有內容全部排除。

第二個是通過LoadLibrary顯式加載DLL。

這兩種方法都適用於C級功能導出。你可以讓鏈接器處理它,或者像你注意的那樣調用GetProcAddress。

但是,當涉及到輸出時,通常只使用第一種方法,即隱式鏈接到DLL。在這種情況下,DLL在應用程序啓動時加載,如果找不到DLL,應用程序將無法加載。

如果你想鏈接到一個DLL中定義的類,並且希望該DLL動態加載,程序開始後的某個時候,你有兩個選擇:

  1. 使用創建的類的對象一個特殊的工廠功能,內部將不得不使用(一點點)彙編程序將新創建的對象「連接」到適當的偏移處。這必須在加載DLL後的運行時完成,顯然。這種方法的一個很好的解釋可以找到here

  2. 使用delay-load DLL

所有事情都考慮過......可能更好的方法是使用隱式鏈接,在這種情況下,您肯定希望使用上面顯示的預處理器技術。事實上,如果您在Visual Studio中創建一個新DLL並選擇「導出符號」選項,則會爲您創建這些宏。

好運...

12

我使用了一些宏來標記導入或導出代碼

 
#ifdef ISDLL 
#define DLL __declspec(dllexport) 
#endif 

#ifdef USEDLL 
#define DLL __declspec(dllimport) 
#endif 

然後聲明類頭文件:

 
class DLL MyClassToExport { ... } 

然後在libary #define ISDLL,並USEDLL包括前頭文件在你想使用該類的地方。

我不知道,如果你可能需要用LoadLibrary

16

工作當你建立動態連接庫,將使用DLL模塊做不同的事情,有某種的#define,你可以用它來的一個與其他區分,那麼你可以做這樣的事情在你的類的頭文件:

#if defined(BUILD_DLL) 
    #define IMPORT_EXPORT __declspec(dllexport) 
#else 
    #define IMPORT_EXPORT __declspec(dllimport) 
#endif 
class IMPORT_EXPORT MyClass { 
    ... 
}; 

編輯:crashmstr打我吧!

+0

如何處理錯位類和構造函數(等)的名字,先生? – null 2013-03-20 08:06:27

+0

就是這樣 - 你不需要處理損壞的名字。 `__declspec(dllimport)`告訴編譯器/鏈接器你正在導入它,它做的是正確的。 – 2013-03-20 12:53:56

+0

這個或crashmstr的回答與原始問題沒有任何關係。 null的問題還沒有得到妥善解決。 – AudioGL 2014-02-22 06:42:12

0

如果你願意把你導出類虛函數表,你可以導出返回的接口函數,實現.dll文件的類,然後把在.def文件中。你可能不得不做一些聲明欺騙,但它不應該太難。

就像COM一樣。 :)

7

最近我問自己完全一樣的問題,並總結我的發現in a blog post。你可能會覺得它很有用。它涵蓋了從DLL導出C++類,並且使用LoadLibrary動態加載它們,並討論了其中的一些問題,如內存管理,名稱修改和調用約定。

11

添加一個簡單的工作示例從一個DLL導出一個C++類:

例如下面給出的只給你的DLL和EXE如何相互影響(言自明)一個簡短的概述,但它需要更多的東西添加以更改爲生產代碼。

全部樣品實例在分爲兩個部分

A.創建一個.dll庫(MYDLL.DLL)

B.創建其使用的.dll庫(應用程序)的應用程序。

A.的.dll項目文件(MYDLL.DLL):

1 dllHeader.h

#ifdef MYDLL_EXPORTS 
#define DLLCALL __declspec(dllexport) /* Should be enabled before compiling 
              .dll project for creating .dll*/ 
#else 
#define DLLCALL __declspec(dllimport) /* Should be enabled in Application side 
              for using already created .dll*/ 
#endif 

// Interface Class 
class ImyMath { 
public: 
    virtual ~ImyMath() {;} 
    virtual int Add(int a, int b) = 0; 
    virtual int Subtract(int a, int b) = 0; 
}; 

// Concrete Class 
class MyMath: public ImyMath { 
public: 
    MyMath() {} 
    int Add(int a, int b); 
    int Subtract(int a, int b); 
    int a,b; 
}; 

// Factory function that will return the new object instance. (Only function 
// should be declared with DLLCALL) 
extern "C" /*Important for avoiding Name decoration*/ 
{ 
    DLLCALL ImyMath* _cdecl CreateMathObject(); 
}; 

// Function Pointer Declaration of CreateMathObject() [Entry Point Function] 
typedef ImyMath* (*CREATE_MATH)(); 

2. dllSrc.cpp

#include "dllHeader.h" 

// Create Object 
DLLCALL ImyMath* _cdecl CreateMathObject() { 
    return new MyMath(); 
} 

int MyMath::Add(int a, int b) { 
    return a+b; 
} 

int MyMath::Subtract(int a, int b) { 
    return a-b; 
} 

B.應用程序Pr選擇哪個負載並鏈接已經創建的。dll文件:

#include <iostream> 
#include <windows.h> 
#include "dllHeader.h" 

int main() 
{ 
    HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll" 

    if (hDLL == NULL) { 
     std::cout << "Failed to load library.\n"; 
    } 
    else { 
     CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject"); 
     ImyMath* pMath = pEntryFunction(); 
     if (pMath) { 
      std::cout << "10+10=" << pMath->Add(10, 10) << std::endl; 
      std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl; 
     } 
     FreeLibrary(hDLL); 
    } 
    std::cin.get(); 
    return 0; 
}