【转】extern “C“以及__declspec(dllexport) 讲解和def文件dll导出方法
轉(zhuǎn)自:https://blog.csdn.net/qing666888/article/details/41135245
一,__ declspec(dllexport):
將一個函數(shù)聲名為導(dǎo)出函數(shù),就是說這個函數(shù)要被其他程序調(diào)用,即作為DLL的一個對外函數(shù)接口。通常它和extern“C”合用,形式如下:
這是由于在制作DLL導(dǎo)出函數(shù)時由于C ++存在函數(shù)重載,因此__declspec(dllexport)FUNCTION(int,int)在DLL會被裝飾,例如被裝飾成為function_int_int,而且不同的編譯器decorate的方法不同,造成了在用GetProcAddress的的取得FUNCTION地址時的不便,使用外部的“C”時,上述的裝飾不會發(fā)生,因為?沒有函數(shù)重載,如此一來被外部的“C”修飾的函數(shù),就不具備重載能力。
二,MSDN:
“在32位編譯器版本中,可以使用__declspec(dllexport)關(guān)鍵字從DLL導(dǎo)出數(shù)據(jù),函數(shù),類或類成員函數(shù).__ declspec(dllexport)將導(dǎo)出指令添加到對象文件(即obj文件) ,若要導(dǎo)出函數(shù),__ declspec(dllexport)關(guān)鍵字必須出現(xiàn)在調(diào)用約定關(guān)鍵字的左邊(如果指定了關(guān)鍵字)。例如:__ declspec
(dllexport)void __cdecl Function1(void);
若要導(dǎo)出類中的所有公共數(shù)據(jù)成員和成員函數(shù),關(guān)鍵字必須出現(xiàn)在類名的左邊,如下所示:
class __declspec(dllexport)CExampleExport:public CObject
{... class definition ...};
生成DLL時,通常創(chuàng)建一個包含正在導(dǎo)出的函數(shù)原型和/或類的頭文件,并將__declspec(dllexport)的添加到頭文件中的聲明。
若要提高代碼的可讀性,請為__declspec(DLLEXPORT )定義一個宏并對正在導(dǎo)出的每個符號使用該宏:
#define DllExport __declspec(dllexport)“
三,__ declspec(dllexport)與.def
模塊定義(.def)文件是包含一個或多個描述各種DLL屬性的模塊語句的文本文件
.1,二者的目的都是將公共符號導(dǎo)入到應(yīng)用程序中或從DLL導(dǎo)出函數(shù)
.2,添加__declspec(dllexport)是為了提供不使用.def文件從.EXE或.DLL導(dǎo)出函數(shù)的簡單方法
.3,如果不使用__declspec(dllimport)或__declspec(dllexport)導(dǎo)出DLL函數(shù),則DLL需要.def文件
.4,并不是任何時候選擇添加__declspec(dllexport)而放棄.def的方式都是好的。如果DLL是提供給VC ++用戶使用的,只需要把編譯DLL時產(chǎn)生的。 lib提供給用戶,它可以很輕松地調(diào)用你的DLL。但是如果DLL是供VB,PB,Delphi用戶使用的,那么會產(chǎn)生一個小麻煩。因為VC ++對于__declspec(dllexport)聲明的函數(shù)會進行名稱轉(zhuǎn)換,如下面的函數(shù):__ declspec?
? ? ?(dllexport)int __stdcall IsWinNT()?
? ? ?會轉(zhuǎn)換為IsWinNT @ 0,這樣你在VB中必須這樣聲明:?
? ? ?聲明函數(shù)IsWinNT Lib“my.dll”別名“IsWinNT @ 0”()As Long?
? ? ?@的后面的數(shù)由于參數(shù)類型不同而可能不同。這顯然不太方便。所以如果要想避免這種轉(zhuǎn)換,就要使用.DEF文件方式。
?
?
在C ++中,我們可以通過??__declspec(DLLEXPORT)??將函數(shù)導(dǎo)出為DLL的中供其它程序使用,例如:
????_declspec?(dllexport?)int?add(int?a,int?b);
在這種方式下,如果調(diào)用該DLL的是一個C ++程序(同一個編譯器的版本)是沒有問題的。但是,如果調(diào)用該DLL是一個其它語言的程序(如C#,VB),則會出錯。究其原因,是因為在C ++中存在函數(shù)的重載,允許函數(shù)重名,因此在編譯器生成的DLL的時候,為了區(qū)別重名的程序,其會將進行一定算法進行名稱轉(zhuǎn)換。例如,對于前面的添加函數(shù),實際的函數(shù)名稱是如下形式。
????
因此,我們直接通過函數(shù)名add是無法找到該函數(shù)的,從而導(dǎo)致調(diào)用失敗。為了解決這一問題,我們往往在函數(shù)前面再加一個extern?“C”,?使用C方式的函數(shù)命名規(guī)則。
????extern?“C”?_declspec?(dllexport?)int?add(int?a,int?b);
這樣函數(shù)的名稱就成加了。
????
這樣,我們就需要在每一個函數(shù)簽名加上“?extern?”C“?_declspec?(dllexport?)?”?這一長串聲明。如果需要導(dǎo)出的函數(shù)較多則顯得非常繁瑣,也非常難看。為了簡化這一過程, MS引入了高清文件網(wǎng)求方便我們操作。
使用默認(rèn)值文件比較簡單,只需要在項目中添加一個DEF文件,然后把我們要導(dǎo)出的函數(shù)放在DEF文件中即可。
????
DEF文件的簡單示例如下:
????LIBRARY
????EXPORTS
????????添加
最后記得在鏈接器選項中選中使用的DEF文件(默認(rèn)情況下,添加DEF文件時會自動加上該選項,無需手動更改)。
????
這樣,我們的函數(shù)無需加那一堆前綴,仍然可以使用默認(rèn)的INT?添加(詮釋一個,INT?B);形式,導(dǎo)出但后的方式依然的英文?形式的函數(shù)定義。
????
最后指得一提的是,一般的C / C ++默認(rèn)的調(diào)用方式是__cdecl,這種方式下需要調(diào)用方對函數(shù)清棧。如果對外提供API共其它非C ++程序使用時,調(diào)用方會無法清棧而出錯(C#會直接報函數(shù)聲明不匹配的錯誤)。因此,對外提供api時還應(yīng)該將接口聲明為__stdcall,讓api函數(shù)自己清棧。這也是Windows API前面都加上了一個WINAPI的宏的原因。
def文件還有許多其它的高級用法,要進一步了解的話,可以參看一下MS的官方文檔:http://msdn.microsoft.com/zh-cn/library/28d6s79h(?v = vs.80).aspx
?
總結(jié)
以上是生活随笔為你收集整理的【转】extern “C“以及__declspec(dllexport) 讲解和def文件dll导出方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python3.8怎么打开创建_Pyth
- 下一篇: 2019年市值最大的基金公司排名!其中有