動態連接庫dll的兩種加載方式

在第一篇技術博客"動態連接庫簡介"中說到了兩種加載方式,當時沒有詳細說明,這裏詳細說明一下ide

能夠經過兩種方式函數

     1.隱式連接(須要.dll,.lib,.h)測試

        2.顯式連接(須要.dll,.h)spa

方法1:隱式連接----須要.lib.dll.h文件

 

隱式連接就是在程序開始執行時就將DLL文件加載到內存當中,而顯示連接,是實時加載,程序須要的時候加載,不須要的時候,卸載。指針

這種方式須要DLL文件,以及相應的Lib文件和頭文件blog

 

只要沒有在程序中顯式連接的,都是隱式連接內存

 

Windows程序bin目錄包含了可執行文件(.exe)和動態連接庫(.dlll),lib目錄包含了靜態庫get

步驟

第一步:將.dll,lib,.h文件放入對應的搜索路徑
      
●其中動態庫的搜索路徑點擊這裏查看,記住最重要的兩個
             
1、項目當前目錄(.cpp)目錄
              2
path環境變量中的目錄博客

       ●靜態庫的搜索路徑包括
              1
項目當前目錄.cpp目錄(項目和解決方案的Debug不行)(也不是解決方案目錄)
              2
VC設置中的庫目錄(Library Directories)it

wKiom1QCrPPAhtguAABUIFJfVj4365.jpg

注:若是lib庫不放到搜索路徑中,也能夠在程序中添加

              #pragmacomment(lib,"D:/DLLTest.lib")//如果相對路徑,則爲項目當前.cpp目錄

       頭文件搜索路徑包括
              1
VC設置中的包含目錄(Include Directories)

wKioL1QCrgqxNCLnAABfcSNujig200.jpg

第二步:必定要在VC設置中的依賴項中添加你用到的庫的名字

wKiom1QCrPPgJ2ncAACcllno2sw139.jpg

第一種(對應上面每種搜索路徑1):針對數量較少的庫

設置.dll,.lib搜索路徑:直接將.dll,.lib,.h放入項目當前目錄下(即含有項目源文件.cpp的目錄)

wKioL1QCrgqSH4rIAAKnYpg6FNo833.jpg

設置.h的搜索路徑:VC設置中的包含目錄(Include Directories)加入你的.h路徑

而後在連接->輸入->附加依賴項中加入你要使用的靜態庫。

這裏只添加靜態庫



wKiom1QCrPORqDOIAAM4IWin4Ao267.jpg



就可使用DLL中的函數了。

 

第二種(對應上面每種搜索路徑2):針對數量比較多的庫(Opencv)

Opencv,OSG等開源庫的配置

這種方式也是一般開源庫的配置方式,Opencv,OSG

步驟以下

步驟1. 添加DLL的目錄

       方法1dll目錄(一般爲bin目錄)放入環境變量Path(須要重啓)path是搜索動態庫的目錄

步驟2.添加靜態庫lib庫目錄和頭文件的目錄

在工程中的VC++目錄中添加靜態庫目錄和頭文件目錄

wKioL1QCrguS-J6-AAN0P0KRB7A809.jpg


步驟3.添加靜態庫

在連接->輸入->附加依賴項中加入你要使用的靜態庫(當程序中調用時,會在上述配置的庫目錄中尋找這個庫)

這裏只添加靜態庫,動態庫的目錄已放入環境變量中,系統會搜索這個路徑的,自動加載.dll

RmwRoadBoundaryStraightLineDLL.lib


而後,在程序中添加頭文件 (在上述配置的頭文件目錄中尋找),就可使用DLL中的函數了。


方法2:顯式連接---須要DLL(不須要.lib,.h文件)

就是顯式加載DLL

wKioL1QCrguB9C3yAAHL_WjDxyg976.jpg

wKiom1QCrPTB0AWmAAOXuLDq8io704.jpg

wKioL1QCrgyTN_cpAAJEsq00lLc798.jpg


注意:顯示連接,導出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

 

 

測試代碼:

       typedefint(*Add)(int a, int b);

       typedefint(*Sub)(int a, int b);

       HINSTANCE hDLL;

       Add Add_;//函數指針

       hDLL = LoadLibrary(_T("D:/DLLTest.dll"));//加載動態連接庫DLLTest.dll文件;

       Add_ = (Add)GetProcAddress(hDLL,"Add");

       intresult = 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

 

測試代碼

       typedefint(*Add)(int a, int b);

       typedefint(*Sub)(int a, int b);

       HINSTANCE hDLL;

       Add Add_;//函數指針

       //也能夠採用hDLL =LoadLibrary(_T("D:/DLLTest.dll"));

       hDLL =LoadLibraryA(("D:/DLLTest.dll"));//加載動態連接庫DLLTest.dll文件;

 

Add_ = (Add)GetProcAddress(hDLL,"?Add@@YAHHH@Z");//!!!!獲取函數地址

       intresult = Add_(5, 8);

       printf("5+8:%d\n",result);

       FreeLibrary(hDLL);//卸載.dll文件;

這裏須要注意的是:GetProcAddress(hDLL,"函數名");中的函數名要是DLL中的函數名,這個函數名能夠用PE Explorer軟件查看

因爲採用的是VC++處理函數名方式,因此

GetProcAddress(hDLL,"?Add@@YAHHH@Z");// GetProcAddress(hDLL,"函數名");


wKiom1QCrPWy97AQAACg59nalXs720.jpg

而不是簡單的「Add」,由於DLL中的函數名是結果VC++方式處理過的函數名

顯示調用,最好採用extern 「C」的方式導出DLL

wKioL1QCrgzDSEVOAAc-IvtlRq4253.jpg

因此採用隱式連接方式的時候,只加載須要的DLL在附加依賴項中,只添加須要的DLL對於的lib,不要多加,不然會形成1.加大程序啓動時間 2.內存浪費


參考文獻

1、《C++ Primer(4 特別版)

2、《VC++深刻詳解》孫鑫

相關文章
相關標籤/搜索