天天看點

使用def檔案簡化dll導出

在c++中,我們可以通過 ​​__declspec(dllexport)​​ 将函數導出為dll中供其它程式使用,例如:

    _declspec(dllexport) int add(int a, int b);

在這種方式下,如果調用該dll的是一個c++程式(同一個編譯器的版本)是沒有問題的。但是,如果調用該dll是一個其它語言的程式(如c#、vb),則會出錯。究其原因,是因為在c++中存在函數的重載,允許函數重名,是以在編譯器生成dll的時候,為了差別重名的程式,會将其進行一定算法進行​​名稱轉換​​。例如,對于前面的add函數,實際的函數名稱是如下形式。

使用def檔案簡化dll導出

是以,我們直接通過函數名add是無法找到該函數的,進而導緻調用失敗。為了解決這一問題,我們往往在函數前面再加一個extern "c",使用c方式的函數命名規則。

    extern "c" _declspec(dllexport) int add(int a, int b);

這樣函數的名稱就成add了。

使用def檔案簡化dll導出

這樣,我們就需要在每一個函數簽名加上"extern "c" _declspec(dllexport)"這一長串聲明。如果需要導出的函數較多則顯得非常繁瑣,也非常難看。為了簡化這一過程,ms引入了​​def檔案​​友善我們操作。

使用def檔案比較簡單,隻需要在項目中添加一個def檔案,然後把我們要導出的函數放在def檔案中即可。

使用def檔案簡化dll導出

def檔案的簡單示例如下:

    library

    exports

        add

最後記得在連結器選項中選中使用的def檔案(預設情況下,添加def檔案時會自動加上該選項,無需手動更改)。

使用def檔案簡化dll導出

這樣,我們的函數無需加那一堆字首,仍然可以使用預設的int add(int a, int b);形式,但導出後的方式依然是c形式的函數定義。

使用def檔案簡化dll導出

最後指得一提的是,一般c/c++預設的調用方式是__cdecl,這種方式下需要調用方對函數清棧。如果對外提供api共其它非c++程式使用時,調用方會無法清棧而出錯(c#會直接報函數聲明不比對的錯誤)。是以,對外提供api時還應該将接口聲明為__stdcall,讓api函數自己清棧。這也是windows api前面都加上了一個winapi的宏的原因。

def檔案還有許多其它的進階用法,要進一步了解的話​