c++動態庫封裝及調用(2、windows下動態庫創建)


DLL即動態鏈接庫(Dynamic-Link Libaray)的縮寫,相當於Linux下的共享對象。Windows系統中大量采用了DLL機制,甚至內核的結構很大程度依賴與DLL機制。Windows下的DLL文件和EXE文件實際上是一個概念,都是PE格式的二進制文件。一般的動態庫程序有lib文件和dll文件,lib文件是編譯時期連接到應用程序中的,而dll文件是運行時才會被調用的。

 

為了更好的理解DLL,首先介紹一下導出和導入的概念。

(1)導出與導入

在ELF(Linux下動態庫的格式),共享庫中所有的全局函數和變量在默認情況下都可以被其他模塊使用,即ELF默認導出所有的全局符號。DLL不同,需要顯式地“告訴”編譯器需要導出某個符號,否則編譯器默認所有的符號都不導出。

程序使用DLL的過程其實是引用DLL中導出函數和符號的過程,即導入過程。對於從其他DLL導入的符號,需要使用“__declspec(dllimport)”顯式聲明某個符號為導入符號。在ELF中,使用外部符號時,不需要額外聲明該符號是從其他共享對象導入的。

指定符號的導入導出一般有如下兩種方法:

1)MSVC編譯器提供了一系列C/C++的擴展來指定符號的導入導出,即__declspec屬性關鍵字

__declspec(dllexport) 表示該符號是從本DLL導出的符號

__declspec(dllimport) 表示該符號是從別的DLL中導入的

2)使用“.def”文件來聲明導入到導出符號,詳細參考《程序員的自我修養--鏈接、裝載與庫》。

應用程序使用DLL可以采用兩種方式:一種是隱式鏈接(調用),另一種是顯式鏈接。在使用DLL之前首先要知道DLL中函數的結構信息

4、DLL創建

下面是頭文件內容:創建工程時有默認的導出函數,這里將其刪除掉重新寫的。

4、DLL創建

以下是vs生成的代碼和我添加的測試導出函數  

  1 // 下列 ifdef 塊是創建使從 DLL 導出更簡單的  
  2 // 宏的標准方法。此 DLL 中的所有文件都是用命令行上定義的 MYDLL_EXPORTS  
  3 // 符號編譯的。在使用此 DLL 的  
  4 // 任何其他項目上不應定義此符號。這樣,源文件中包含此文件的任何其他項目都會將  
  5 // MYDLL_API 函數視為是從 DLL 導入的,而此 DLL 則將用此宏定義的  
  6 // 符號視為是被導出的。  
  7 #ifdef MYDLL_EXPORTS  
  8 #define MYDLL_API __declspec(dllexport)  
  9 #else  
 10 #define MYDLL_API __declspec(dllimport)  
 11 #endif  
 12   
 13 
 14 class MYDLL_API CmyDll{
 15 public:
 16        CmyDll(void);     
 17        //TODO:    在此添加您的方法
 18   
 19 }
 20 
 21 extern MYDLL_API int nmyDll;
 22 
 23 MYDLL_API int fnmyDll(void);
 24 
 25 
 26 //--------myDll.cpp文件代碼如下-----------------
 27 //    myDll.cpp   : 定義DLL應用程序的導出函數。
 28 
 29 #include "stdafx.h"
 30 #include "myDll.h"
 31   
 32 //這是導出變量的一個示例
 33 MYDLL_API int nmyDll = 0;
 34 
 35 //這是導出函數的一個示例
 36 MYDLL_API int fnmyDll(void)
 37 {
 38        return 42;
 39 }
 40 
 41 //這是已導出類的構造函數
 42 //有關類定義的信息,請參閱myDll.h
 43 CmyDll::CmyDll()
 44 {
 45        return;
 46 }
 47 
 48 
 49 //------------------------------------------------
 50 //-----------以上是通過vs2015生成的原始代碼
 51 
 52 
 53 //----------------以下是直接在生成的源碼上修改的版本
 54 
 55 //---------------------方式一
 56 
 57 class MYDLL_API CmyDll{
 58 public:
 59        CmyDll(void);     
 60        //TODO:    在此添加您的方法
 61 
 62       //第一種方式在類里面導出函數
 63       int Add(int x, int y);  
 64 }
 65 
 66 extern MYDLL_API int nmyDll;
 67 
 68 MYDLL_API int fnmyDll(void);
 69 
 70 //----------------方式二 通過extern 導出函數
 71 
 72 class MYDLL_API CmyDll{
 73 public:
 74        CmyDll(void);     
 75        //TODO:    在此添加您的方法
 76 }
 77 
 78 extern MYDLL_API int nmyDll;
 79 
 80 MYDLL_API int fnmyDll(void);
 81 
 82 
 83 //第一種添加extern "C"
 84 extern "C" int Add(int x, int y);
 85 
 86 //第二種情況為當有很多函數導出時,為省略extern “C”,可以將導出函數包括在{}內
 87 extern "C"
 88 {
 89         int MYDLL_API Add(int x, int y);
 90 }
 91 
 92 
 93 //--------此時相對應的myDll.cpp文件代碼如下-----------------
 94 //    myDll.cpp   : 定義DLL應用程序的導出函數。
 95 
 96 #include "stdafx.h"
 97 #include "myDll.h"
 98   
 99 //這是導出變量的一個示例
100 MYDLL_API int nmyDll = 0;
101 
102 //這是導出函數的一個示例
103 MYDLL_API int fnmyDll(void)
104 {
105        return 42;
106 }
107 
108 //這是已導出類的構造函數
109 //有關類定義的信息,請參閱myDll.h
110 CmyDll::CmyDll()
111 {
112        return;
113 }
114 
115 //通過類導出,
116 int CmyDll::Add(int x, int y)
117 {
118        return x+y;
119 }
120 
121 //通過extern導出,此時方式一和方式二都是如此,
122 int Add(int x, int y)
123 {
124        return x+y;
125 }
126 
127 //函數實現上,前面都不需要添加MYDLL_API

 

這里將Add函數聲明為導出函數;

當定義了符號MYDLL_EXPORTS,MYDLL_API被設置為 __declspec(dllexport)修飾符,This modifier enables the function to be exported by the DLL so that it can be used by other applications。若未定義則TMYDLL_API被設置為__declspec(dllimport),This modifier enables the compiler to optimize the importing of the function from the DLL for use in other applications。當DLL項目生成時,MYDLL_EXPORTS默認是定義的,所以默認設置的是__declspec(dllexport) 修飾符。 

然后編譯就會生成對應的dll文件,同時也會生成對應的lib文件。 

注意:a.DLL中導出函數的聲明有兩種方式:在函數聲明中加上__declspec(dllexport);采用模塊定義(.def)文件聲明。詳見:http://www.cnblogs.com/enterBeijingThreetimes/archive/2010/08/04/1792099.html 
  b.對於C文件創建dll時或者想使用C編譯器創建dll時,建議使用 extern “C” 標志,參見extern "C"的簡單解析。 

 

下一次講如何調用dll導出的函數

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM