2013-10-02 81 views
0

我已經使用「CPPLoadLibrary」示例(來自Microsoft All-in-One框架) 好吧,有兩種從示例DLL中導出符號的方法。從DLL使用.DEF文件 的模塊定義(.DEF)文件確定DLL的符號名稱

  1. 導出符號是包含一個或描述一個DLL的各種屬性更模塊 語句的文本文件。創建.DEF文件和 構建DLL時使用.def文件。使用這種方法,我們可以按順序從名稱中導出 函數。從DLL使用__declspec(dllexport)的 __declspec(dllexport)的
  2. 出口符號增加了出口指令到目標文件,這樣我們就 不需要使用.def文件。當試圖導出裝飾的C++函數名稱時,這種便利性最爲明顯。

所以我們有下面的代碼。

typedef int  (_cdecl* LPFNGETSTRINGLENGTH1)  (PCWSTR); 
typedef int  (CALLBACK* LPFNGETSTRINGLENGTH2) (PCWSTR); 

LPFNGETSTRINGLENGTH1 lpfnGetStringLength1 = (LPFNGETSTRINGLENGTH1) 
    GetProcAddress(hModule, "GetStringLength1"); 

LPFNGETSTRINGLENGTH2 lpfnGetStringLength2 = (LPFNGETSTRINGLENGTH2) 
    GetProcAddress(hModule, "[email protected]"); 

所以我的問題是如何確定符號的名稱,以便調用GetProcAddress?在第一種情況下,它是非常簡單的,我們從.DEF文件中獲取該符號名稱。 但是「_GetStringLength2 @ 4」怎麼樣 什麼是下劃線?什麼是「@ 4」代表什麼? 謝謝。

+1

這是__stdcall調用約定的標準裝飾。函數指針聲明中的CALLBACK宏還指定__stdcall。使用LoadLibrary + GetProcAddress當然是你想要避免的一般情況,它非常容易出錯。只需讓鏈接器處理它,鏈接導入庫。 –

回答

2

如果您不使用.DEF文件,導出名稱將根據其調用約定進行修飾,以支持導出重載函數。請參閱Why can't I GetProcAddress a function I dllexport'ed?

[T]他的裝修方案因建築和建築以及從調用慣例到調用慣例而異。因此,例如,如果函數是從PPC DLL導出的,則必須執行,但如果從80386 DLL導出爲extern "C" __stdcall,則需要GetProcAddress(hinst, "[email protected]"),但如果是__fastcall,則需要GetProcAddress(hinst, "@[email protected]")

更重要的是,C++裝飾因編譯器廠商和編譯器廠商而異。如果使用Microsoft C++編譯器進行編譯,C++導出的函數可能需要GetProcAddress(hinst, "[email protected]@[email protected]"),但如果使用Borland C++編譯器進行編譯,則可能需要其他裝飾字符串。所以如果你打算人們能夠爲GetProcAddress函數,你打算你的代碼可移植到多個平臺,或者如果你打算他們能夠從C/C++以外的語言使用您的DLL或使用一個與Microsoft Visual Studio不同的C++編譯器,那麼您必須通過未裝飾的名稱導出函數。

有關各種名稱裝飾方案的說明,請參見The history of calling conventions, part3。在這種情況下,該函數使用__stdcall調用約定,所以它通過預先加下劃線並附加一個@符號和它需要的參數的字節數進行修飾。它需要一個字長大小的參數,總共4個字節,所以它的裝飾爲[email protected]

0

要回答您的實際問題,請使用您的編譯器的TDUMP或類似的工具或任何其他可顯示可執行文件導出表的工具,以便您可以看到實際導出的名稱。