|
DLL中導(dǎo)出函數(shù)的聲明有兩種方式:一種為在函數(shù)聲明中加上__declspec(dllexport),這里不再舉例說(shuō)明;另外一種方式是采用模塊定義(.def) 文件聲明,.def文件為鏈接器提供了有關(guān)被鏈接程序的導(dǎo)出、屬性及其他方面的信息。
首先創(chuàng)建 一個(gè)DLL程序,.cpp中
- int __stdcall Add(int numa, int numb)
- {
- return (numa + numb);
- }
-
- int __stdcall Sub(int numa, int numb)
- {
- return (numa - numb);
- }
- int __stdcall Add(int numa, int numb)
- {
- return (numa + numb);
- }
-
- int __stdcall Sub(int numa, int numb)
- {
- return (numa - numb);
- }
然后創(chuàng)建一個(gè).def的文件,在里面加上
;DllTestDef.lib : 導(dǎo)出DLL函數(shù)
;作者:----
LIBRARY DllTestDef
EXPORTS
Add @ 1
Sub @ 2
最后創(chuàng)建一個(gè)測(cè)試程序:.cpp文件如下:
- #include <iostream>
- #include <windows.h>
-
- using namespace std;
-
- typedef int (__stdcall *FUN)(int, int);
- HINSTANCE hInstance;
- FUN fun;
-
- int main()
- {
- hInstance = LoadLibrary("DLLTestDef.dll");
- if(!hInstance)
- cout << "Not Find this Dll" << endl;
- fun = (FUN)GetProcAddress(hInstance, MAKEINTRESOURCE(1));
- if (!fun)
- {
- cout << "not find this fun" << endl;
- }
- cout << fun(1, 2) << endl;
- FreeLibrary(hInstance);
- return 0;
- }
- #include <iostream>
- #include <windows.h>
-
- using namespace std;
-
- typedef int (__stdcall *FUN)(int, int);
- HINSTANCE hInstance;
- FUN fun;
-
- int main()
- {
- hInstance = LoadLibrary("DLLTestDef.dll");
- if(!hInstance)
- cout << "Not Find this Dll" << endl;
- fun = (FUN)GetProcAddress(hInstance, MAKEINTRESOURCE(1));
- if (!fun)
- {
- cout << "not find this fun" << endl;
- }
- cout << fun(1, 2) << endl;
- FreeLibrary(hInstance);
- return 0;
- }
說(shuō)明:
.def文件的規(guī)則為:
(1)LIBRARY語(yǔ)句說(shuō)明.def文件相應(yīng)的DLL;
(2)EXPORTS語(yǔ)句后列出要導(dǎo)出函數(shù)的名稱(chēng)。可以在.def文件中的導(dǎo)出函數(shù)名后加@n,表示要導(dǎo)出函數(shù)的序號(hào)為n(在進(jìn)行函數(shù)調(diào)用時(shí),這個(gè)序號(hào)將發(fā)揮其作用);
(3).def 文件中的注釋由每個(gè)注釋行開(kāi)始處的分號(hào) (;) 指定,且注釋不能與語(yǔ)句共享一行。
如果導(dǎo)出 C++ 文件中的函數(shù),必須將修飾名放到 .def 文件中,或者通過(guò)使用外部“C”定義具有標(biāo)準(zhǔn) C 鏈接的導(dǎo)出函數(shù)。如果需要將修飾名放到 .def 文件中,則可以通過(guò)使用 DUMPBIN 工具或 /MAP 鏈接器選項(xiàng)來(lái)獲取修飾名。請(qǐng)注意,編譯器產(chǎn)生的修飾名是編譯器特定的。如果將 Visual C++ 編譯器產(chǎn)生的修飾名放到 .def 文件中,則鏈接到 DLL 的應(yīng)用程序必須也是用相同版本的 Visual C++ 生成的,這樣調(diào)用應(yīng)用程序中的修飾名才能與 DLL 的 .def
文件中的導(dǎo)出名相匹配。
如果生成擴(kuò)展 DLL 并使用 .def 文件導(dǎo)出,則將下列代碼放在包含導(dǎo)出類(lèi)的頭文件的開(kāi)頭和結(jié)尾:
#undef AFX_DATA#define AFX_DATA AFX_EXT_DATA// <body of your header file>#undef AFX_DATA#define AFX_DATA這些代碼行確保內(nèi)部使用的 MFC 變量或添加到類(lèi)的變量是從擴(kuò)展 DLL 導(dǎo)出(或?qū)耄┑?。例如,?dāng)使用 DECLARE_DYNAMIC 派生類(lèi)時(shí),該宏擴(kuò)展以將 CRuntimeClass 成員變量添加到類(lèi)。省去這四行代碼可能會(huì)導(dǎo)致不能正確編譯或鏈接 DLL,或在客戶(hù)端應(yīng)用程序鏈接到 DLL 時(shí)導(dǎo)致錯(cuò)誤。
當(dāng)生成 DLL 時(shí),鏈接器使用 .def 文件創(chuàng)建導(dǎo)出 (.exp) 文件和導(dǎo)入庫(kù) (.lib) 文件。然后,鏈接器使用導(dǎo)出文件生成 DLL 文件。隱式鏈接到 DLL 的可執(zhí)行文件在生成時(shí)鏈接到導(dǎo)入庫(kù)。
請(qǐng)注意,MFC 本身使用 .def 文件從 MFCx0.dll 導(dǎo)出函數(shù)和類(lèi)。
在VC++中,如果生成DLL可以不使用.def文件。你只需要在VC++的函數(shù)定義前要加 __declspec(dllexport)修飾就可以了。但是使用__declspec(dllexport)和使用.def文件是有區(qū)別的。如果你的 DLL是提供給VC++用戶(hù)使用的,你只需要把編譯DLL時(shí)產(chǎn)生的.lib提供給用戶(hù),它可以很輕松地調(diào)用你的DLL。但是如果你的DLL是供VB、 PB、Delphi用戶(hù)使用的,那么會(huì)產(chǎn)生一個(gè)小麻煩。因?yàn)閂C++對(duì)于__declspec(dllexport)聲明的函數(shù)會(huì)進(jìn)行名稱(chēng)轉(zhuǎn)換,如下面的函數(shù):
__declspec(dllexport) int __stdcall IsWinNT()
會(huì)轉(zhuǎn)換為IsWinNT@0,這樣你在VB中必須這樣聲明:
Declare Function IsWinNT Lib "my.dll" Alias "IsWinNT@0" () As Long
@的后面的數(shù)由于參數(shù)類(lèi)型不同而可能不同。這顯然不太方便。所以如果要想避免這種轉(zhuǎn)換,就要使用.def文件方式。
EXPORTS后面的數(shù)可以不給,系統(tǒng)會(huì)自動(dòng)分配一個(gè)數(shù)。對(duì)于VB、PB、Delphi用戶(hù),通常使用按名稱(chēng)進(jìn)行調(diào)用的方式,這個(gè)數(shù)關(guān)系不大,但是對(duì)于使用.lib鏈接的VC程序來(lái)說(shuō),不是按名稱(chēng)進(jìn)行調(diào)用,而是按照這個(gè)數(shù)進(jìn)行調(diào)用的,所以最好給出。
看來(lái)是def文件沒(méi)起到作用。最終發(fā)現(xiàn)需要將def文件配置到VC工程中的“鏈接器”的“模塊定義文件”中。
問(wèn)題2:
在def中增加幾個(gè)輸出函數(shù)定義后(這些函數(shù)本來(lái)已經(jīng)輸出,但沒(méi)有加到def文件中),發(fā)現(xiàn)某些以前編譯的程序執(zhí)行報(bào)錯(cuò)找不著函數(shù),但其他一些程序沒(méi)有報(bào)錯(cuò)??磥?lái)報(bào)錯(cuò)的程序連接時(shí)沒(méi)有使用lib文件,而沒(méi)報(bào)錯(cuò)的使用了;沒(méi)使用lib文件的通過(guò)hint定位函數(shù),所以總能找到但可能找錯(cuò)了——難怪聽(tīng)說(shuō)這個(gè)庫(kù)以前發(fā)生過(guò)函數(shù)調(diào)錯(cuò)的現(xiàn)象。
增加了輸出函數(shù)卻忘了在def中增加定義,新手寫(xiě)的代碼又無(wú)人檢查,最嚴(yán)重的是后期的版本問(wèn)題。
|