動態庫dll的呼叫方式-顯式連結
阿新 • • 發佈:2021-08-11
這裡有個疑問,VS2017生成dll時為何會同時生成一個lib檔案?
靜態庫生成lib,動態庫也生成lib。
動態庫生成的那個lib一般管它叫"匯入庫",這樣的lib在大多數情況下要比靜態庫的lib小,
裡面不包含涉及到的函式的具體程式碼,裡面只包含"這個函式在什麼dll裡面叫什麼名字"這樣的資訊。即函式的宣告
你平時程式設計比如windows.h裡的那些api,都是通過這種方式連結的。
比如彈出訊息框的MessageBoxA,它在user32.lib中,但是user32.lib卻沒有包含MessageBoxA的具體程式碼,
它只寫明瞭這個函式在user32.dll中,名字叫做MessageBoxA。生成exe以後,windows在執行這個exe裡的程式碼之前,
會先載入user32.dll,然後在裡面查詢MessageBoxA,隨後把MessageBoxA所在的地址寫入exe指定的位置(一般是匯入表)。
dll要呼叫這個函式的時候,就從匯入表獲取函式地址,然後呼叫過去。
方法2:顯式連結---需要DLL(不需要.lib,.h檔案)
注意:顯示連結,匯出DLL的時候,採用extern “C”的方式,
而不採用_declspec(dllexport),因為_declspec(dllexport)會有一個”名字改編”的問題(採用了_cdecl呼叫規約的C++編譯方式)。
如庫檔案對應的標頭檔案如下 #ifndef DLLTEST_H #defineDLLTEST_H //該巨集完成在dll專案內部使用__declspec(dllexport)匯出 //在dll專案外部使用時,用__declspec(dllimport)匯入 //巨集DLL_EXPORTS在.cpp中定義 #ifdefDLL_EXPORTS #defineDLL_EXPORTS extern"C"_declspec(dllexport) #else #define DLL_EXPORTS extern"C"_declspec(dllimport) #endif //函式宣告 DLL_EXPORTSint Add(int a,int b); DLL_EXPORTSint Sub(int a,int b); DLL_EXPORTSint Divide(int a,int b); #endif//DLLTEST_H
測試程式碼: typedef int(*funAdd)(int a, int b); typedef int(fun *Sub)(int a, int b); HINSTANCE hDLL; funAdd Add;//函式指標 hDLL =LoadLibrary(_T("D:/DLLTest.dll"));//載入動態連結庫DLLTest.dll檔案; Add = (funAdd)GetProcAddress(hDLL,"Add"); int result = Add(5, 8); printf("5+8:%d\n",result); FreeLibrary(hDLL);//解除安裝.dll檔案;
以下是採用__declspec(dllexport)方式匯出,不推薦這種方式需要注意函式名的書寫問題! 現在DLLTest.h中有函式(採用__declspec(dllexport)方式匯出) #ifndef DLLTEST_H #defineDLLTEST_H //該巨集完成在dll專案內部使用__declspec(dllexport)匯出 //在dll專案外部使用時,用__declspec(dllimport)匯入 //巨集DLL_EXPORTS在.cpp中定義 #ifdefDLL_EXPORTS #defineDLL_EXPORTS __declspec(dllexport) #else #define DLL_EXPORTS __declspec(dllimport) #endif intDLL_EXPORTS Add(int a,int b); intDLL_EXPORTS Sub(int a,int b); intDLL_EXPORTS Divide(int a,int b); #endif//DLLTEST_H
測試程式碼 typedef int(*funAdd)(int a, int b); typedef int(*funSub)(int a, int b); HINSTANCE hDLL; funAdd Add;//函式指標 //也可以採用hDLL =LoadLibrary(_T("D:/DLLTest.dll")); hDLL =LoadLibraryA(("D:/DLLTest.dll"));//載入動態連結庫DLLTest.dll檔案; Add = (funAdd)GetProcAddress(hDLL,"?Add@@YAHHH@Z");//!!!!獲取函式地址 int result = Add_(5, 8); printf("5+8:%d\n",result); FreeLibrary(hDLL);//解除安裝.dll檔案;
這裡需要注意的是:GetProcAddress(hDLL,"函式名");中的函式名要是DLL中的函式名,這個函式名可以用PE Explorer軟體檢視
由於採用的是VC++處理函式名方式,所以
"?Add@@YAHHH@Z";// GetProcAddress(hDLL,"函式名");
而不是簡單的“Add”,因為DLL中的函式名是結果VC++方式處理過的函式名
顯式呼叫,最好採用extern “C”的方式匯出DLL
所以顯式隱式連結方式的時候,只加載需要的DLL,在附加依賴項中,只新增需要的DLL 對於的lib,不要多加
否則會造成
1.加大程式啟動時間
2.記憶體浪費