dll的def檔案與__declspec(dllexport)匯出函式方式比較
【原文:http://www.xuebuyuan.com/1752443.html】
dll的def檔案與__declspec(dllexport)匯出函式方式比較
【__declspec(dllexport) 方式】
首先對C和C++編譯(extern "C")與呼叫約定(__cdecl、__stdcall、__fastcall)進行組合測試:
【C++編譯】
__declspec(dllexport) int add(int, int);
__declspec(dllexport) int __cdecl add(int, int);
__declspec(dllexport) int __stdcall add(int, int);
__declspec(dllexport) int __fastcall add(int, int);
對於C++編譯器的函式名修飾規則:不管__cdecl, __fastcall還是__stdcall呼叫方式,函式修飾名都是以"?"開始,後面是函式在名字,再後面是函式返回型別和引數型別按照代號拼出的參數列。對於__stdcall方式,參數列的開始標示是"@@YG”,對於__cdecl方式則是"@@YA”,對於__fastcall方式則是"@@YI”.
參數列後以"@Z”標示整個名字的結束,如果該函式無引數,則以"Z”標識結束。
更詳細的dll基礎知識請參考:
http://hi.baidu.com/luosiyong/blog/item/92bbdcfe860435375c600812.html
更深入的C++函式名修飾編碼規則請參考:
http://hi.baidu.com/wanggang2008/blog/item/cd43e60756021bc07a89470a.html
【C編譯】
extern "C" __declspec(dllexport) int add(int, int);
extern "C" __declspec(dllexport) int __cdecl add(int, int);
extern "C" __declspec(dllexport) int __stdcall add(int, int);
extern "C" __declspec(dllexport) int __fastcall add(int, int);
如果建立dll和可執行檔案都是使用的VC,那用__declspec(dllexport)足夠解決問題。但是如果建立出來的dll要和別的廠商的工具包構建的可執行檔案連結,那就有一些額外的問題來了。
在開發dll的時候,一般不讓編譯器改變函式名,所以通常是以C方式編譯,即加入了extern "C"說明。但是看上面的組合測試結果,__stdcall和__fastcall編譯出來的函式名還是和原始的函式名不同。就拿__stdcall來說,它以C編譯匯出的時候,會在函式前面加入下劃線,並在函式後面加入@和引數總大小的位元組數。
或許現在你就想,__cdecl不就是沒有改變名稱的方式嗎,並且預設也是__cdecl呼叫約定,的確,我們自己寫的dll幾乎都可以使用__cdecl方式。但是,Windows中最普遍的呼叫方式都是__stdcall(比如CALLBACK、 WINAPI),一些常用的定義如下:
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define WINAPIV __cdecl
#define APIENTRY WINAPI
#define APIPRIVATE __stdcall
#define PASCAL __stdcall
現在假如用VC的__stdcall方式開發的一個dll,裡面包含了上面那樣的add函式,如果要在VB中使用,VB的程式員需要如下宣告:
Declare Function add Lib "win.dll" Alias"_add@8"() As Integer
注意他需要寫的名稱是 "_add@8",而不是簡單的"add",否則就會出現函式未定義的連結錯誤。
【備註】
__declspec(dllexport)的位置:
To export functions, the __declspec(dllexport) keyword must appear to the left of the calling-convention keyword, if a keyword is specified.
For example:
__declspec(dllexport) void __cdecl Function1(void);
To export all of the public data members and member functions in a class, the keyword must appear to the left of the class name as follows:
class __declspec(dllexport) CExampleExport : public CObject
{ class definition };
Reference:
1.
http://msdn.microsoft.com/en-us/library/d91k01sh(VS.80).aspx
2.
http://msdn.microsoft.com/en-us/library/a90k134d(VS.80).aspx
【def檔案匯出方式】
首先了解一下 使用def檔案從dll匯出:
http://msdn.microsoft.com/zh-cn/library/d91k01sh(v=VS.80).aspx
具體到測試例項,我們的def檔案內容如下:
LIBRARY "win"
EXPORTS
add @1
其中LIBRARY指定dll的模組名稱,即dll名字,EXPORTS後的每一行指定一個匯出函式名字,這個名字和標頭檔案中的宣告一致,後面可以跟@序號指定該函式的序號(這個是可選的,後面按序號匯入函式的時候再詳細說)。
然後再測試一下__stdcall和__fastcall是否會對匯出函式改名,測試結果如下,均未改名:
extern "C" int __stdcall add();
extern "C" int __fastcall add();
另外一種方案是在程式碼中給連結器指定匯出函式名字:
extern "C" __declspec(dllexport) int __fastcall add(int a, int b);
#pragma comment(linker, "/export:add=@add@8")
這裡告訴連結器,匯出一個函式名為add的函式,函式入口點和@add@8相同
這樣,我們既可以使用add,也可以使用@add@8了。
__stdcall方式和這類似,為add=_add@8。
【按序號而不是按名稱從dll匯出函式】
http://msdn.microsoft.com/zh-cn/library/e7tsx612%28VS.80%29.aspx
def檔案定義如下:
LIBRARY "win"
EXPORTS
add @1 NONAME
函式名稱和Hint都不見了。
這樣也可以用來隱藏dll中一些重要函式。
隱藏了函式名稱,在應用程式中使用序號來匯入函式:
#include <windows.h>
#include <stdio.h>
int main()
{
typedef int (* AddFunc)(int, int);
HMODULE hModule = LoadLibrary("dll.dll");
AddFunc add = (AddFunc)GetProcAddress(hModule, MAKEINTRESOURCE(1)); //注意這裡序號的指定方式
printf("%d\n", add(1, 2));
return 0;
}
【備註】
def檔案和__declspec(dllexport)方式優缺點對比:
一、__declspec(dllexport)
若要輸出類的所有成員:資料or函式,__declspec(dllexport)要放在類名左邊宣告:
class __declspec(dllexport) Class1{}
如果類沒有資料成員,__declspec(dllexport)放在class關鍵字前宣告就會被編譯器忽略,就沒有lib生成,如下:
__declspec(dllexport) class Class1{}
使用 __declspec(dllexport) 非常方便,因為不必考慮維護 .def 檔案和獲取匯出函式的修飾名。例如,如果您設計的 DLL 供自己控制的應用程式使用,則此方法很適用。如果通過新的匯出函式重新生成 DLL,還必須重新生成應用程式,因為如果使用不同版本的編譯器進行重新編譯,則匯出的 C++ 函式的修飾名可能會發生變化。
使用 .DEF 檔案的優缺點(zz)
在 .def 檔案中匯出函式使您得以控制匯出序號。當將附加的匯出函式新增到 DLL 時,可以給它們分配更高的序號值(高於任何其他匯出函式)。當您進行此操作時,使用隱式連結的應用程式不必與包含新函式的新匯入庫重新連結。這非常重要,例如,在設計將由許多應用程式使用的第三方DLL 時。可以通過新增附加功能不斷地增強 DLL,同時確保現有應用程式繼續正常使用新的 DLL。MFC DLL 是使用 .def 檔案生成的。
DLL 的 .def 檔案中的匯出名相匹配。
相關文章
- __declspec(dllexport)和__declspec(dllimport)ExportImport
- 理解 __declspec(dllexport)和__declspec(dllimport)ExportImport
- 用DEF檔案從DLL中匯出C++類 (轉)C++
- extern "C" __declspec(dllexport)Export
- .dll,.lib,.def 和 .exp檔案
- 核心分析PE獲取DLL匯出函式地址函式
- SQL Server資料庫匯入匯出資料方式比較SQLServer資料庫
- _declspec(naked) 使用(裸函式)函式
- JavaScript 匿名函式與具名函式執行效率比較JavaScript函式
- js命名函式與匿名函式執行速度比較JS函式
- C++關於DLL匯出模板類和模板函式C++函式
- 字串比較的常用函式字串函式
- DLL庫的編寫(匯出、匯入)與使用
- excel 字元比較函式Excel字元函式
- 物件導向與函式程式設計的比較物件函式程式設計
- 幾個分析函式的比較函式
- SQL Server資料匯入匯出技術概述與比較(轉)SQLServer
- C++程式中不同函式呼叫方式的彙編碼比較C++函式
- Python的內建比較函式cmp比較原理剖析Python函式
- DB2常用函式與Oracle比較TIDB2函式Oracle
- C與C++在函式和資料的比較C++函式
- Oracle 中 replace函式和translate函式比較Oracle函式
- Mysql 一個比較好用的函式MySql函式
- C++宏和函式的比較C++函式
- MySQL匯入匯出檔案檔案MySql
- 【SQL】使用分析函式與關聯子查詢的比較SQL函式
- 檔案內容比較
- MySQL:MySQL層比較函式呼叫MySql函式
- dos下的exp匯出日期檔名樣式的檔案
- java檔案複製方式在100MB檔案條件下速度的比較Java
- 使用PowerShell比較本地文字檔案與Web上的文字檔案是否相同Web
- JavaScript - 函式 setTimeout 和 setInterval 的比較JavaScript函式
- C語言的比較庫函式--qsortC語言函式
- 拷貝建構函式(比較全的)函式
- 比較檔案是否相同,(比較MD5值)
- js匿名函式和具名函式執行效率比較JS函式
- 查詢dmp檔案(exp方式匯出) 字符集
- dll 入口函式函式