1. 程式人生 > 其它 >動態庫dll的呼叫方式-顯式連結

動態庫dll的呼叫方式-顯式連結

這裡有個疑問,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.記憶體浪費