淺談Windows中DLL導出類

通常的DLL導出類方法,一個簡單的例子:java

dllExample.h:安全

 1 #pragma once
 2 
 3 #ifdef DLL_EXPORTS
 4 #define DLL_API __declspec(dllexport)
 5 #else
 6 #define DLL_API __declspec(dllimport)
 7 #endif
 8 
 9 class DLL_API ExportClass
10 {
11 pirvate:
12     int x;
13 public:
14     void foo();
15 };

dllExample.cpp:函數

1 #define DLL_EXPORTS
2 #include "dllExample.h"
3 
4 void ExportClass::foo()
5 {
6     //do something...
7     return;
8 }

而外部代碼只須要包含頭文件,就會自動導入ExportClass的定義。
編譯時鏈接該DLL對應的lib,運行時提供DLL文件,便可正常運行。spa

 

不過這種簡單的DLL導出存在一個限制,若是咱們導出的類中含有非C++基礎類型:指針

dllExample.h:code

 1 #pragma once
 2 
 3 #ifdef DLL_EXPORTS
 4 #define DLL_API __declspec(dllexport)
 5 #else
 6 #define DLL_API __declspec(dllimport)
 7 #endif
 8 
 9 class DLL_API ExportClass
10 {
11 pirvate:
12     std::string x; //此處的string類型導出是不安全的
13 public:
14     void foo();
15 };

咱們知道, 對於STL,微軟爲每一個版本的VS都有不一樣的實現,VS2008(VC90),VS2010(VC100),VS2013(VC120)。
因爲不一樣的STL的實現,咱們不能在不一樣的版本見直接傳遞std::string, 不然運行期可能出現不可預知的錯誤。
而事實上咱們在ExportClass中的std::string x變量是不但願被外部直接使用的,也就是並無export的必要,事實上,不建議讓dll向外導出任何關於非C++基礎類型的定義。
可是因爲ExportClass須要向外導出(由於須要使用foo()函數),應該如何處理這樣的矛盾呢?blog

對於這樣的問題,咱們須要使用C++的抽象類(其實就是java中的interface概念)來解決:
咱們須要:
1. 申明一個只有純虛函數和C++基礎類型的基類,全部須要向外部導出的定義都包含在該類中。
2. 申明另外一個類,繼承該基類。
3. 實現一個返回基類函數指針的getInstance函數,即返回一個派生類實例的工廠方法。
4. 在外部代碼中,經過多態機制訪問該類。繼承

dllExample.h:get

 1 #pragma once
 2 
 3 #ifdef DLL_EXPORTS
 4 #define DLL_API __declspec(dllexport)
 5 #else
 6 #define DLL_API __declspec(dllimport)
 7 #endif
 8 
 9 class DLL_API ExportInterface
10 {
11 public:
12     virtual void foo() = 0;
13 };
14 
15 extern "C" DLL_API ExportInterface*  getInstance();
16 
17 #ifdef DLL_EXPORTS  //咱們並不須要向外導出該類的定義,在外部代碼編譯時,也不須要包含此類的定義。
18 class ExportClass: public ExportInterface
19 {
20 pirvate:
21     std::string x; //因爲外部代碼對此不可見,此處的std::string是安全的。
22 public:
23     void foo(); //函數體在dllExample.cpp中實現
24 };
25 #endif

dllExample.cpp:string

#define DLL_EXPORTS
#include "dllExample.h"

extern "C" DLL_API ExportInterface* getInstance()
{
    ExportInterface* pInstance = new ExportClass();
    return pInstance;
}

void ExportClass::foo()
{
    //do something...
    return;
}
相關文章
相關標籤/搜索