亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

鏈接庫動態鏈接庫詳細說明

2020-02-24 14:37:52
字體:
來源:轉載
供稿:網友

windows中,鏈接庫分為兩種類型:靜態鏈接庫.lib和動態鏈接庫.dll。其中動態鏈接庫在被使用的時候,通常還提供一個.lib,稱為引入庫,它主要提供被Dll導出的函數和符號名稱,使得鏈接的時候能夠找到dll中對應的函數映射。
靜態鏈接庫和動態鏈接庫的作用相似,都是提供給其他程序進行調用的資源。其中,動態鏈接庫的調用方法分隱式調用(靜態導入調用)和顯示調用(動態導入調用)。?

編譯環境
Microsoft Visual Stdio 2010
--------------------------------------------------------------------------------
DLL導出符號
例,首先生成一個dll1.dll和dll1.lib


// DLL1工程,dll1.cpp
// _declspec(dllexport)為導出符號
_declspec(dllexport) int add(int a, int b)
{
return a + b;
}


利用微軟的depends工具查看dll1.dll,導出的符號如下:
http://www.cnblogs.com/monotone/?
其中各字段意義:Ordinal(符號序號,后面使用GetProcAddress的時候,參考的數值),Hint(這個我也不是太明白,據說是不用了解),Function(這個就是函數導出后的符號名稱了),EntryPoint(這個是函數在DLL中的地址)。
這里之所以函數的名稱變成了這樣子,是因為使用的編譯器默認使用C++方式進行編譯,由于C++支持重載,那么需要給函數名增加額外的符號,來使與同名的重載函數區分開來,才能在DLL中通過符號名來進行定位。
這里可以做個簡單的測試,新建控制臺測試工程DllTest如下。

?

?


// DllTest工程,DllTest.cpp
#include
using namespace std;
int main(void)
{
// extern int add(int a, int b);
// _declspec(dllimport)是導入聲明,這種方式比上面的方式更有效,同時編譯器能邊編譯出更加高效的代碼。
_declspec(dllimport) int add(int a, int b);
cout getchar();
return 0;
}


編譯鏈接,提示鏈接錯誤 error LNK2019: unresolved external symbol "__declspec(dllimport) int cdecl add(int,int)" (__imp_?add@@YAHHH@Z) referenced in function _main,很明顯的編譯器在編譯的時候,把add函數也給重命名了,并且和上面用depends查看的一樣。意思是沒有找到這個符號的定義。

添加代碼后如下:(注意,我這里兩個工程的輸出目錄都是在和解決方案同目錄的debug下,為了避免每次修改都重新拷貝lib文件,直接使用相對路徑聲明。)

?

?


// DllTest工程,DllTest.cpp
#include
using namespace std;
#pragma comment(lib, "../debug/dll1.lib") // 顯示的聲明要鏈接dll1.lib,隱式調用
int main(void)
{
// extern int add(int a, int b);
// _declspec(dllimport)是導入聲明,這種方式比上面的方式更有效,同時編譯器能邊編譯出更加高效的代碼。
_declspec(dllimport) int add(int a, int b);
cout getchar();
return 0;
}


編譯運行后,使用depends工具對DllTest.exe查看其依賴的輸入信息如下:
image?
可以看出,DllTest.exe通過dll1.lib,引入了對dll1.dll的依賴。

--------------------------------------------------------------------------------

DLL提供的頭文件
通常情況下,當得到一個.dll的時候,我們無法得知其提供了哪些函數調用(準確來說,應該是調用方式。因為我們可以利用depends工具查看dll導出的函數及其序號,當然也許可能有其他的方式去知道具體怎么使用,但是肯定無法得知內部具體實現細節。),因此為了方便被使用,通常會提供一個對應該dll的.h文件,來聲明其提供給客戶端使用的方式和說明等信息??蛻舳耸褂迷擃^文件對所使用的接口進行導入。但是為了避免很多地方都出現這些函數的聲明,通常在客戶端直接在.h文件中對所有接口進行導入,而在Dll編譯時,則作為導出使用。方法如下:

?

?


// DLL1工程,dll1.h
#ifndef DLL1_API
#define DLL1_API _declspec(dllimport)
#endif
// 以上代碼表示,如果在包含該頭文件之前,沒有定義DLL1_API宏,那么后面所有DLL1_API宏都展開為_declspec(dllimport),即導入。
// 因為通常情況下客戶端不會去定義這個宏(當然,假設這個宏不會被客戶端中其他文件定義),所以客戶端使用該頭文件的時候,都是用于導入。
DLL1_API int add(int a, int b);

?

?


// DLL1工程,dll1.cpp
#define DLL1_API _declspec(dllexport)
// 注意上面這行,在頭文件被包含前,先定義了DLL1_API這個宏,使得頭文件中DLL1_API都被展開為_declspec(dllexport)了,從而聲明函數作為導出。
#include "dll1.h"
// 在頭文件中進行了導出聲明的函數,就不用再聲明導出了。
int add(int a, int b)
{
return a + b;
}


相應的,TestDll工程中包含.h文件后,也不用再去申明了。

?

?


// DllTest工程,DllTest.cpp
#include
using namespace std;
#include "../dll1/dll1.h" // 包含該頭文件之后,后面就不需要再申明了
#pragma comment(lib, "../debug/dll1.lib") // 顯示的聲明要鏈接dll1.lib,隱式調用
int main(void)
{
cout getchar();
return 0;
}


以上基本解釋了為什么通常引用dll的時候都有一個頭文件,并且頭文件內有很多#ifndef之類的東東了。

--------------------------------------------------------------------------------
動態鏈接庫導出類
當然,動態鏈接庫也能導出類,要注意的是聲明的方式為class DLL1_API CSample,而不是DLL1_API class CSample。
同時,要注意導出類的同時,其所有成員函數也已經導出,但是仍然遵循類成員變量訪問權限限制。
如果單獨導出類的成員函數(聲明方式和全局函數一樣),那么在客戶端可以實例化類對象,并調用導出的成員函數,不能調用沒導出的成員函數(即使是public的)。

--------------------------------------------------------------------------------
改編了的符號名
在導出符號時,講過C++會對函數名進行改編,以支持函數重載。那么就會存在一個問題,如果使用不用的C++編譯器(導致編譯出的符號名不同)或者客戶端使用C編譯器調用,就會出現LNK2019這樣的鏈接錯誤,找不到符號。這個問題很大的限制了DLL的使用范圍。
解決方法1:
使用extern “C”(注意這個C一定要大寫)前置申明,表明函數是以C的方式編譯鏈接的。C方式編譯連接導出的函數不會改編符號名,因而可以避免上述問題。

?

?


// DLL1工程,dll1.h
#ifndef DLL1_API
#define DLL1_API extern "C" _declspec(dllimport)
#endif
// 以上代碼表示,如果在包含該頭文件之前,沒有定義DLL1_API宏,那么后面所有DLL1_API宏都展開為_declspec(dllimport),即導入。
// 因為通常情況下客戶端不會去定義這個宏(當然,假設這個宏不會被客戶端中其他文件定義),所以客戶端使用該頭文件的時候,都是用于導入。
DLL1_API int add(int a, int b);
//class CSample
//{
//public:
// DLL1_API int substract(int a,int b);// 這種情況下,導出類成員函數,編譯不能通過的
//};


這里要注意.h和.cpp中都要加上extern “C”,使得導入和導出都用C編譯方式。

?

?


// DLL1工程,dll1.cpp
#define DLL1_API extern "C" _declspec(dllexport)
// 注意上面這行,在頭文件被包含前,先定義了DLL1_API這個宏,使得頭文件中DLL1_API都被展開為_declspec(dllexport)了,從而聲明函數作為導出。
#include "dll1.h"
// 在頭文件中進行了導出聲明的函數,就不用再聲明導出了。
int add(int a, int b)
{
return a + b;
}
//
//int CSample::substract(int a,int b)
//{
// return a - b;
//}


然后用depends進行查看:
image?
導出的函數符號名和函數聲明時一樣了。由于客戶端使用的時候,導入也是用的extern “C”方式,因此客戶端在編譯鏈接的時候,也使用的是函數原名稱符號。
顯示,由于使用的是C編譯鏈接方式,C++的類和成員函數的導出就不能用這種方式了。
此外,如果我們在給函數聲明加上標準調用約定:DLL1_API int _stdcall add(int a, int b);(注意,在函數的定義中也要加上_stdcall)。那么編譯出來的結果使用depends查看符號名為_add@8,也就是說符號名稱又改了。
解決方法2:
使用模塊定義文件.def,這種文件的格式規范查看MSDN,搜索.def即可。其中LIBRARY命令用于指名該def文件用于導出庫文件,EXPORTS用于指名導出函數符號名。也就是說,.def文件主要就用于控制導出符號等信息。

?

?


LIBRARY dll1
EXPORTS
add11=add


我這里給add函數別名為add11,注意同時需要在.h文件中聲明add為add11(作用就是提供給客戶端使用,當然其實也可以直接在客戶端聲明函數為add11,前提是你知道該函數的定義方式等)。一旦提供了.def之后,.cpp中提供的任何調用約定都不再生效,因為.def指定了生成的符號名了。這里只要明白,.def控制了Dll的導出符號,客戶端使用的時候,只要提供了聲明,并且鏈接上.lib文件,就能夠使用了。
補充一句:VC6.0以后的IDE都需要在鏈接選項(LINK)的input-》module define file中,指明.def文件,編譯器才會去使用這個.def文件。

備注:
這一塊關于調用約定,以及加不加extern “C”,目前我還比較混亂。等了解了之后,再來這里進行補充,歡迎看客給我提供有關這一塊比較好的介紹資料。

--------------------------------------------------------------------------------
顯示鏈接(動態導入鏈接)
前面有提到讓導出的函數沒有名字,那么客戶端如何對其進行調用呢。就是使用符號表中的ordinal了(可以通過工具進行查看),當然也可以使用函數名進行導入。動態導入不需要lib文件和.h文件(如果知道函數名的話)。

?

?


// DllTest工程,DllTest.cpp
#include
using namespace std;
#include
int main(void)
{
HMODULE hModule = ::LoadLibraryA("dll1.dll");
if(NULL != hModule)
{
typedef int (*ADDPROC)(int a, int b);
//ADDPROC add = (ADDPROC)::GetProcAddress(hModule, "add11"); // 通過函數名導入
ADDPROC add = (ADDPROC)::GetProcAddress(hModule, MAKEINTRESOURCEA(1)); // 通過ordinal導入,注意第二個參數此時數值要放在低字節位置,具體參見MSDN說明。
if(NULL != add)
cout ::FreeLibrary(hModule);
}
getchar();
return 0;
}


值得一提的是,根據函數名稱進行動態導入的時候,實際上也是根據符號名的,也就是說,dll提供的符號名要和提供給用戶的函數聲明一致。

此外,動態導入動態鏈接庫時,.exe時無法查看到需要的輸入信息的。

--------------------------------------------------------------------------------
后記
第一次寫這么詳細和這么長的博文,可以看出來寫到后面的時候已經越來越粗糙了。因為寫到后來的時候,自己都已經不知道要寫什么了,因為如果再擴展下去,需要增加的東西就太多了。同時也有一部分原因是后面的內容我理解的不是太透徹,同時使用的也很少??傊@會我腦子已經相當混亂了。在這里對那些寫博客的大俠們表示深深的敬佩。
以上就是鏈接庫動態鏈接庫詳細說明的介紹,希望小編整理的相關知識和資料都對你們有所幫助,更多內容請繼續關注武林技術頻道網站!

?

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产成人在线播放| 欧美最顶级的aⅴ艳星| 7m第一福利500精品视频| 国外成人在线播放| 色偷偷综合社区| 欧美日韩国产精品一区二区不卡中文| 欧美精品在线观看91| 国产精品美女av| 亚洲精品永久免费| 日韩中文在线视频| 国产精品久在线观看| 亚洲白虎美女被爆操| 国产91在线播放| 欧美中文字幕视频在线观看| 青草青草久热精品视频在线观看| 色婷婷综合成人| 午夜免费日韩视频| 91青草视频久久| 欧美成人小视频| 亚洲国产欧美一区| 国产精品都在这里| 日韩经典中文字幕| 欧美精品videos另类日本| 日韩精品在线观看一区二区| 亚洲国产精品va在线观看黑人| 欧美俄罗斯乱妇| 91精品久久久久久久久久| 亚洲人成电影网站色| 国产日韩精品综合网站| 日韩av网址在线| 热99精品只有里视频精品| 日韩欧美视频一区二区三区| 91精品久久久久久久久久| 国产精品久久久久久av下载红粉| 中文字幕久久久| 亚洲自拍偷拍网址| 国产欧美精品在线播放| 欧美中文在线免费| 免费不卡在线观看av| 久热精品视频在线观看一区| 日韩欧美在线国产| 亚洲欧洲午夜一线一品| 欧美日韩另类字幕中文| 日韩不卡中文字幕| 日韩精品中文字幕在线观看| 欧美黑人xxxⅹ高潮交| 日韩在线视频网站| 欧美激情精品久久久久久黑人| 亚洲欧美国产高清va在线播| 日韩美女免费观看| 国产成人精品免高潮费视频| 国产亚洲欧美另类中文| 国产欧美久久久久久| 91理论片午午论夜理片久久| 2018中文字幕一区二区三区| 91精品在线播放| 国产视频精品va久久久久久| 日韩欧美在线观看视频| 欧美猛交ⅹxxx乱大交视频| 久久久久一本一区二区青青蜜月| 奇门遁甲1982国语版免费观看高清| 亚洲国产精品一区二区三区| 欧美成人三级视频网站| 92福利视频午夜1000合集在线观看| 一区二区三区视频免费| 国产精品一区二区三区久久| 国产69精品久久久久9999| 国产亚洲成av人片在线观看桃| 欧美一级在线播放| 欧洲亚洲免费在线| 国模吧一区二区三区| 性色av一区二区三区| 久久久久久久久久国产| 亚洲精品资源在线| 久久亚洲精品一区二区| 日韩美女在线观看一区| 久久久精品国产网站| 欧美激情xxxx| 国产精品美女在线观看| 国产日韩在线观看av| 成人国产精品免费视频| 91精品国产九九九久久久亚洲| 国产精品久久久久久五月尺| 日韩中文在线视频| 成人免费在线视频网站| 国产成人一区二区在线| 色一情一乱一区二区| 国产日韩欧美中文在线播放| 全亚洲最色的网站在线观看| 精品色蜜蜜精品视频在线观看| 亚洲自拍欧美色图| 自拍偷拍亚洲精品| 日韩一区二区在线视频| 欧美在线亚洲一区| 欧美中文在线视频| 日韩av在线直播| 庆余年2免费日韩剧观看大牛| 在线播放日韩精品| 97超碰国产精品女人人人爽| 亚洲性日韩精品一区二区| 精品国产一区二区三区久久久狼| 国产精品99久久久久久久久| 日韩高清电影好看的电视剧电影| 亚洲精品美女在线观看播放| 国产日韩欧美一二三区| 久久久久久久久91| 国产精品一区二区在线| 色综合视频一区中文字幕| 91超碰中文字幕久久精品| 91国产视频在线播放| 国产69久久精品成人看| 不卡在线观看电视剧完整版| 97超碰色婷婷| 欧美激情亚洲精品| 国产精品三级美女白浆呻吟| 色先锋资源久久综合5566| 奇米成人av国产一区二区三区| 日韩毛片在线看| 久久国产色av| 亚洲国产精品久久91精品| 久久久久九九九九| 成人福利免费观看| 粗暴蹂躏中文一区二区三区| 国产亚洲视频中文字幕视频| 国产日韩中文在线| 中文字幕不卡在线视频极品| 亚洲天堂一区二区三区| 日韩av中文字幕在线| 2020国产精品视频| 日韩精品日韩在线观看| 久久影视电视剧免费网站| 欧美激情二区三区| 欧美电影免费观看高清完整| 久久免费少妇高潮久久精品99| 欧美色欧美亚洲高清在线视频| 久久久99久久精品女同性| 欧美日韩在线另类| 992tv在线成人免费观看| 欧美做受高潮1| 亚洲一区美女视频在线观看免费| 亚洲欧洲一区二区三区久久| 欧美激情一区二区三区久久久| 精品电影在线观看| 亚洲成av人片在线观看香蕉| 亚洲午夜未删减在线观看| 亚洲精品国产福利| 91精品国产免费久久久久久| 欧美一区二区大胆人体摄影专业网站| 国产视频亚洲视频| 精品久久久久久国产| 精品呦交小u女在线| 国产精品久久久久一区二区| 九九九热精品免费视频观看网站| 一本色道久久88亚洲综合88| 国产精品福利在线观看网址| 国产精品自产拍高潮在线观看| 久久99精品久久久久久琪琪| 久久精品99无色码中文字幕| 欧美国产日本在线| 国产成人一区二区| 亚洲免费视频一区二区| 91久久久久久久久久久| 欧美电影在线免费观看网站| 午夜精品久久久久久99热软件|