DLL中匯出函式的兩種方式

2021-05-24 06:10:16 字數 3036 閱讀 6490

經常使用vc6的dependency檢視dll匯出函式的名字,會發現有dll匯出函式的名字有時大不相同,導致不同的原因大多是和編譯dll時候指定dll匯出函式的界定符有關係。

vc++支援兩種語言:即c/c++,這也是造成dll匯出函式差異的根源

我們用vs2008新建個dll工程,工程名為「testdll」

把預設的原始檔字尾 .cpp改為.c(c檔案)

輸入測試**如下:

01   int _stdcall myfunction(int ivariant)

02  

為了匯出上面這個函式,我們有以下幾個方法:

1.    使用傳統的模組定義檔案 (.def)

library testdll

exports

myfunction

在 link 時指定輸入依賴檔案:/def:"testdll.def"

2.    visual c++ 提供的方便方法

在01行的int 前加入 __declspec(dllexport) 關鍵字

通過以上兩種方法,我們就可以匯出myfunction函式。

我們用dependency檢視匯出的函式:

第一種方法匯出的函式為:

myfunction

第二種方法匯出的函式為:

_myfunction@4

__stdcall會使匯出函式名字前面加乙個下劃線,後面加乙個@再加上引數的位元組數,比如_myfunction@4的引數(int ivariant)就是4個位元組 

__fastcall與 __stdcall類似,不過前面沒有下劃線,而是乙個@,比如@myfunction@4

__cdecl則是始函式名。

小結:如果要匯出c檔案中的函式,並且不讓編譯器改動函式名,用def檔案匯出函式。

下面我們來看一下c++檔案

我們用vs2008新建個dll工程,工程名為「testdll」

預設的原始檔字尾為 .cpp (即c++檔案)。

輸入測試**如下:

01   int _stdcall myfunction(int ivariant)

02  

為了匯出上面這個函式,我們有以下幾個方法:

3.    使用傳統的模組定義檔案 (.def)

library testdll

exports

myfunction

在 link 時指定輸入依賴檔案:/def:"testdll.def"

4.    visual c++ 提供的方便方法

在01行的int 前加入 __declspec(dllexport) 關鍵字

通過以上兩種方法,我們就可以匯出myfunction函式。

我們用dependency檢視匯出的函式:

第一種方法匯出的函式為:

myfunction

第二種方法匯出的函式為:

?myfunction@@yghh@z

可以看到 第二種方法得到的 匯出函式名 並不是我們想要的,如果在exe中用顯示方法(loadlibrary、getprocaddress)呼叫 myfunction 肯定會失敗。

但是用引入庫(*.lib)的方式呼叫,則編譯器自動處理轉換函式名,所以總是沒有問題。

解決這個問題的方法是:

用vc 提供的預處理指示符 「#pragma」 來指定鏈結選項。

如下:#pragma comment(linker, "/export:myfunction=?myfunction@@yghh@z ")

這時,就會發現匯出的函式名字表中已經有了我們想要的myfunction。但我們發現原來的那個 ?myfunction@@yghh@z 函式還在,這時就可以把 __declspec() 修飾去掉,只需要 pragma 指令即可。

而且還可以使如下形式:

#pragma comment(linker, "/export:myfunction=_myfunction@4,private")

private 的作用與其在 def 檔案中的作用一樣。更多的#pragram請檢視msdn。

小結:如果要匯出c++檔案中的函式,並且不讓編譯器改動函式名,用def檔案匯出函式。

同時可以用#pragma指令(c 中也可以用)。

總結:c++編譯器在生成dll時,會對匯出的函式進行名字改編,並且不同的編譯器使用的改編規則不一樣,因此改編後的名字也是不同的(一般涉及到c++ 中的過載等)。

如果利用不同編譯器分別生成dll和訪問dll的exe程式,後者在訪問該dll的匯出函式時就會出現問題。如上例中函式myfunction在c++編譯器改編後的名字是?myfunction@@yghh@z。我們希望編譯後的名字不發生改變,這裡有幾種方法。

第一種方法是通過乙個稱為模組定義檔案def來解決。

library testdll

exports

myfunction

library 用來指定動態鏈結庫內部名稱。該名稱與生成的動態鏈結庫名一定要匹配,這句**不是必須的。

exports說明了dll將要匯出的函式,以及為這些匯出函式指定的符號名。

第二種是定義匯出函式時加上限定符:extern "c"

如:#define dllexport_api extern "c" _declspec(dllexport)

但extern "c"只解決了c和c++語方之間呼叫的問題(extern 「c」 是告訴編譯器,讓它按c的方式編譯),它只能用於匯出全域性函式這種情況 而不能匯出乙個類的成員函式。

同時如果匯出函式的呼叫約定發生改變,即使使用extern "c",編譯後的函式名還是會發生改變。例如上面我們加入_stdcall關鍵字說明呼叫約定(標準呼叫約定,也就是winapi呼叫約定)。

#define dllexport_api extern "c" _declspec(dllexport)

01     dllexport_api int _stdcall myfunction(int ivariant)

02    

編譯後函式名myfunction改編成了_myfunction@4

通過第一種方法模組定義檔案的方式dll編譯後匯出函式名不會發生改變。

DLL中匯出函式的兩種方式

dll中匯出函式的兩種方式 dllexport與.def檔案 2009 03 06 11 34 58 標籤 dll匯出函式 兩種方式 declspec dllexport def 檔案it 分類 程式設計技術 dll中匯出函式的宣告有兩種方式 一種方式是 在函式宣告中加上 declspec dlle...

DLL中匯出函式的兩種方式

dll中匯出函式的兩種方式 dllexport與.def檔案 2009 03 06 11 34 58 標籤 dll匯出函式 兩種方式 declspec dllexport def 檔案it 分類 程式設計技術 dll中匯出函式的宣告有兩種方式 一種方式是 在函式宣告中加上 declspec dlle...

DLL中匯出函式的兩種方式

dll中匯出函式的兩種方式 dllexport與.def檔案 2009 03 06 11 34 58 標籤 dll匯出函式 兩種方式 declspec dllexport def 檔案it 分類 程式設計技術 dll中匯出函式的宣告有兩種方式 一種方式是 在函式宣告中加上 declspec dlle...