在C++中,我們可以通過 __declspec(dllexport) 將函數導出為Dll中供其它程序使用,例如:
_declspec(dllexport) int add(int a, int b);
在這種方式下,如果調用該dll的是一個c++程序(同一個編譯器的版本)是沒有問題的。但是,如果調用該dll是一個其它語言的程序(如C#、VB),則會出錯。究其原因,是因為在C++中存在函數的重載,允許函數重名,因此在編譯器生成dll的時候,為了區別重名的程序,會將其進行一定算法進行名稱轉換。例如,對於前面的add函數,實際的函數名稱是如下形式。
因此,我們直接通過函數名add是無法找到該函數的,從而導致調用失敗。為了解決這一問題,我們往往在函數前面再加一個extern "C",使用C方式的函數命名規則。
extern "C" _declspec(dllexport) int add(int a, int b);
這樣函數的名稱就成add了。
這樣,我們就需要在每一個函數簽名加上"extern "C" _declspec(dllexport)"這一長串聲明。如果需要導出的函數較多則顯得非常繁瑣,也非常難看。為了簡化這一過程,MS引入了def文件方便我們操作。
使用Def文件比較簡單,只需要在項目中添加一個def文件,然后把我們要導出的函數放在def文件中即可。
Def文件的簡單示例如下:
LIBRARY
EXPORTS
add
最后記得在鏈接器選項中選中使用的def文件(默認情況下,添加def文件時會自動加上該選項,無需手動更改)。
這樣,我們的函數無需加那一堆前綴,仍然可以使用默認的int add(int a, int b);形式,但導出后的方式依然是C形式的函數定義。
最后指得一提的是,一般C/C++默認的調用方式是__cdecl,這種方式下需要調用方對函數清棧。如果對外提供api共其它非C++程序使用時,調用方會無法清棧而出錯(C#會直接報函數聲明不匹配的錯誤)。因此,對外提供api時還應該將接口聲明為__stdcall,讓api函數自己清棧。這也是Windows API前面都加上了一個WINAPI的宏的原因。
def文件還有許多其它的高級用法,要進一步了解的話,可以參看一下MS的官方文檔:http://msdn.microsoft.com/zh-cn/library/28d6s79h(v=vs.80).aspx