1、dll的起源
動態鏈結庫(dll)是從c語言函式庫和pascal庫單元的概念發展而來的。所有的c語言標準庫函式都存放在某一函式庫中。在鏈結應用程式的過程中,鏈結器從庫檔案中拷貝程式呼叫的函式**,並把這些函式**新增到可執行檔案中。這種方法同只把函式儲存在已編譯的obj檔案中相比更有利於**的重用。
但隨著windows這樣的多工環境的出現,函式庫的方法顯得過於累贅。如果為了完成螢幕輸出、訊息處理、記憶體管理、對話方塊等操作,每個程式都不得不擁有自己的函式,那麼windows程式將變得非常龐大。windows的發展要求允許同時執行的幾個程式共享一組函式的單一拷貝。動態鏈結庫就是在這種情況下出現的。動態鏈結庫不用重複編譯或鏈結,一旦裝入記憶體,dll函式可以被系統中的任何正在執行的應用程式軟體所使用,而不必再將dll函式的另一拷貝裝入記憶體。
2、dll中函式的宣告
根據微軟dll的編寫和呼叫規範,在dll中,宣告和定義匯出函式時,需要在函式前使用__declspec(dllexport)關鍵字,以表明該函式是dll的匯出函式;在dll的隱式呼叫方式中,應用程式在呼叫匯出函式時,必須使用__declspec(dllimport)關鍵字先宣告匯入的函式。這種匯入和匯出函式的宣告方法也符合c/c++的函式的先宣告再呼叫的呼叫規範。
3、dll匯出函式的鏈結類別及引用方式
匯出函式在編譯、鏈結過程中,可以採用c鏈結和c++鏈結兩種方式,當採用c鏈結時,編譯器不更改匯出函式的名稱,與之相反,當採用c++鏈結時,編譯器則更改匯出函式的名稱。
匯出函式可以使用c語言編寫,也可以使用c++語言編寫。對於採用c語言編寫的執行檔案而言,如果呼叫採用c++語言編寫的匯出函式,應當強制指定使用c鏈結而不是c++鏈結生成匯出函式庫;而對於採用c++語言編寫的執行檔案而言,如果呼叫採用c語言編寫的匯出函式,應當強制指定使用c鏈結生成匯出函式庫。根據編譯器規範,指定、宣告函式使用c鏈結,則應當在函式宣告前使用關鍵字extern "c"。
通常情況下,為了確保不同的語言編寫的可執行模組都能夠正確地訪問到匯出函式,習慣上都採用extern "c"來指定匯出函式採用c鏈結方式。
4、dll頭檔案格式
在實際的程式設計中,通常都是把匯出函式的宣告統一放在乙個標頭檔案中,而其定義則根據需要分布在不同的cpp檔案中,這樣的實現方式比較方便對檔案及其功能的管理和維護。因此,dll標頭檔案的格式如下:
#ifndef _dllmodulename_h
#define _dllmodulename_h
....../*
* if using c++ compiler to compile the file, adopting c linkage mode
*/#ifdef __cplusplus
extern "c"
#endif
#endif
根據微軟dll隱式呼叫的規範,在使用匯出函式前,應當首先宣告該匯出函式。在實際程式設計中,大多採用在乙個標頭檔案中,統一宣告程式執行中呼叫到的dll匯出函式,然後在所有呼叫dll匯出函式的檔案中,包含該標頭檔案的方式。因此匯出函式的引入頭檔案格式如下:
#ifndef _importfunc_h
#define _importfunc_h
#ifdef __cplusplus
extern "c"
#endif
#endif
從上述闡述可以看出,對於dll匯出函式而言,在dll標頭檔案中宣告了一次,而在隱式呼叫時,又宣告了一次,為消除這種重複宣告和減少檔案數量,實際應用中通常將兩個標頭檔案合併成乙個dll標頭檔案,同時定義乙個巨集,用於控制函式處於匯出宣告或呼叫匯入宣告狀態。對於dll定義檔案,在包含dll標頭檔案之前,首先定義乙個控制巨集,用於宣告所有的函式為匯出函式;而在隱式呼叫中,在包含dll標頭檔案時不需要定義控制巨集,用於宣告所有的函式為匯入函式。因此最終的dll頭檔案格式如下:
#ifndef _dllmodulename_h
#define _dllmodulename_h
#include
#include ""
/** if using c++ compiler to compile the file, adopting c linkage mode
*/#ifdef __cplusplus
extern "c"
#endif
#endif
5、dll標頭檔案的使用
dll匯出函式的鏈結、匯入、匯出指示符在函式第一次宣告時確定,在以後的函式宣告和定義時,函式都接受第一次函式的鏈結、匯入、匯出宣告,不必再次對函式作鏈結、匯入、匯出宣告,因此dll匯出函式的定義檔案中,可以使用如下的編碼格式:
/** ensure compiler to compile correctly, through including
* the precompiled headers, or else resulting in c1010 error
*/#include "stdafx.h"
#define _dllmodulename_
#include "dllmodulename.h"
returntype funcname (parameters)
// other functions definitions
而在呼叫檔案中,只需要包含標頭檔案即可,即使用#include "dllmodulename.h"語句實現對dll匯出函式的匯入宣告。
參考文獻
DLL的雙向標頭檔案
動態庫dll的巨集定義標頭檔案雙向使用方法小結 如果想在自己的dll檔案中使用函式修改定義巨集,又想同時在提供給客戶端的標頭檔案中讓客戶使用,有兩種方法比較方便,當然如果你直接自己定義也未為不可,但比較費事。當然,同時你得在def檔案中宣告匯出函式,防止函式改名。1 第一種方法 在孫鑫老師的教程的方...
呼叫dll和編寫dll的幾種格式
一共兩種 extern c declspec dllexport dword sum int narg1,char nar 2 extern c 表示使用c的編譯方式編譯,c 格式 declspec dllexport 將乙個函式申明為匯出函式 就申明了乙個匯出函式 但是這中建立的dll的匯出函式序...
標頭檔案和原始檔
一.例1 test.h void show test.cpp include using namespace std void show includeproblem.cpp include test.h int main 可以看到 includeproblem.cpp檔案彙總 include te...