青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 319, comments - 22, trackbacks - 0, articles - 11
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

關于靜態鏈接庫(Lib)與動態鏈接庫(DLL)

Posted on 2011-04-19 22:58 RTY 閱讀(1312) 評論(0)  編輯 收藏 引用 所屬分類: C/C++

  靜態鏈接庫(Lib)和動態鏈接庫(DLL)的問題困擾了我很長時間,而當中關鍵的問題是兩者有何聯系?又有何區別呢?怎么創建?怎么使用?使用的過程中要注意什么?一直想把這個問題總結一下。

  在windows下一般可以看到后綴為dll和后綴為lib的文件,但這兩種文件可以分為三種庫,分別是動態鏈接庫(Dynamic-Link Libraries),目標庫(Object Libraries)和導入庫(Import Libraries),下面一一解釋這三種庫。

目標庫(Object Libraries)

目標庫又叫靜態鏈接庫,是擴展名為.LIB的文件,包括了用戶程序要用到的各種函數。它在用戶程序進行鏈接時,“靜態鏈接”到可執行程序文件當中。例如,在VC++中最常使用到的C運行時目標庫文件就是LIBC.LIB。在鏈接應用程序時常使用所謂“靜態鏈接”的方法,即將各個目標文件(.obj)、運行時函數庫(.lib)以及已編譯的資源文件(.res)鏈接到一起,形成一個可執行文件(.exe)。使用靜態鏈接時,可執行文件需要使用的各種函數和資源都已包含到文件中。這樣做的缺點是對于多個程序都使用的相同函數和資源要重復鏈接到exe文件中,使程序變大、占用內存增加。  

導入庫(Import Libraries)

導入庫是一種特殊形式的目標庫文件形式。和目標庫文件一樣,導入庫文件的擴展名也是.LIB,也是在用戶程序被鏈接時,被“靜態鏈接”到可執行文件當中。但是不同的是,導入庫文件中并不包含有程序代碼。相應的,它包含了相關的鏈接信息,幫助應用程序在可執行文件中建立起正確的對應于動態鏈接庫的重定向表。比如KERNEL32.LIB、USER32.LIB和GDI32.LIB就是我們常用到的導入庫,通過它們,我們就可以調用Windows提供的函數了。如果我們在程序中使用到了Rectangle這個函數,GDI32.LIB就可以告訴鏈接器,這個函數在GDI32.DLL動態鏈接庫文件中。這樣,當用戶程序運行時,它就知道“動態鏈接”到GDI32.DLL模塊中以使用這個函數。其實說白了導入庫就是一個索引,一個dll動態鏈接庫的索引表,這是我的理解。

動態鏈接庫(Dynamic-Link Libraries)

“動態鏈接”是將一些公用的函數或資源組織成動態鏈接庫文件(.dll),當某個需要使用dll中的函數或資源的程序啟動時(準確的說是初始化時),系統將該dll映射到調用進程的虛擬地址空間、增加該dll的引用計數值,然后當實際使用到該dll時操作系統就將該dll載入內存;如果使用該dll的所有程序都已結束,則系統將該庫從內存中移除。使用同一dll的各個進程在運行時共享dll的代碼,但是對于dll中的數據則各有一份拷貝(當然也有在dll中共享數據的方法)。 動態鏈接庫中可以定義兩種函數:輸出函數和內部函數。輸出函數可以被其他模塊調用,內部函數只能被動態鏈接庫本身調用。動態鏈接庫也可以輸出數據,但這些數據通常只被它自己的函數所使用。

  如我們所知,Windows程序都是一些可執行文件,它們可以創建并顯示一個或多個窗體,使用消息循環來接收用戶的輸入。但是動態鏈接庫并不能直接被執行,它們一般也不會接收消息。它們只是一些包含著函數的獨立文件,這些函數可以被Windows程序或者其它DLL調用以完成某項任務。 
  “動態鏈接”是指Windows程序在運行時才把自己需要存在于某個庫中的函數鏈接進來。“靜態鏈接”是指Windows程序在編譯階段就把各種對象模塊(.OBJ)、運行時庫(.LIB)和資源文件(.RES)鏈接到一起以創建一個可執行文件(.EXE)。 
  DERNAL32.DLL,USER32.DLL,GDI32.DLL,各種驅動程序如KEYBOARD.DRV,SYSTEM.DRV和MOUSE.DRV,顯卡和打印機驅動程序等都是動態鏈接庫。這些庫可以被所有的Windows程序共同使用。 
有某些動態鏈接庫(如字體文件)稱為“resource-only”。它們只包括數據,而不包括代碼。因此,動態鏈接庫的目的之一就是為許多不同的程序提供函數和資源。在傳統的操作系統里,用戶程序在運行時只能調用操作系統自身的某些函數。而在Windows操作系統下,模塊或程序調用另一個模塊中的函數來執行是一種非常普遍的操作。因此,從某種角度看,對DLL進行編程,其實是在對Windows操作系統作擴展,也可以看作是在對用戶程序作擴展。 
  動態鏈接庫模塊可以有其它的擴展名,但是標準的擴展名是.DLL。只有具有標準擴展句的動態鏈接庫模塊才可以被Windows自動加載。而如果是其它擴展名的動態鏈接庫模塊,程序必須使用LoadLibrary或者LoadLibraryEx函數來顯示加載。 
  我們可以發現,在大型的應用軟件中,會常常使用到動態鏈接庫技術。舉個例子,假如我們要寫一個大型的應用軟件,其中包括了多個程序。我們可以發現很多程序可能都會使用到一些同樣的通用的函數。我們可以把這些通用的函數放到某個目標庫文件中(.LIB),然后在鏈接是把它加到每個程序中進行靜態鏈接。但是這是一種非常浪費的方法,因為每個程序模塊中都會包括這些通用函數的獨立拷貝。另外,如果我們要改變庫文件中的某個函數,就必須把所有使用到這個函數的程序都重新編譯一遍。但是,如果我們使用動態鏈接庫的技術,把所有這些通用函數都放到一個動態鏈接庫文件當中,我們就可以解決以上提到的各種問題。首先,動態鏈接庫在硬盤上只保留一個拷貝,程序只是在運行時才會調用其中使用到的函數,這樣我們就可以節省大量的程序存儲和運行空間。其次,如果要修改某個通用函數時,只要調用接口沒有改變,只是改變它的實現方法,那么我們就不必對每個用到它的程序都進行重新編譯,而只要把動態鏈接庫模塊重新編譯一遍就可以了。 
  動態鏈接庫模塊也可以作為一個單獨的產品來發布。這樣程序開發人員就可以使用第三方的模塊來開發自己的應用程序,提高了程序的復用程序,也節省了大量的時間和精力。

   目標庫和導入庫都是在程序開發過程中才使用到的,而動態鏈接庫是在程序運行時才使用的。在程序運行時,相應的動態鏈接庫文件必須已經保存在硬盤上了。另外,如果要使用動態鏈接庫文件,該文件必須要保存在同.EXE文件同一個目錄下,或者保存在當前目錄、Windows系統目錄、Windows目錄或環境變量中PATH參數指定的目錄下。程序也是按照這個順序來搜尋它需要的動態鏈接庫文件的。

創建靜態鏈接庫(Lib)

  創建靜態鏈接庫比較簡單,創建win32控制臺程序,選擇靜態庫,這里我沒有選擇上預編譯頭。生成工程以后就像定義一般的函數般,定義放在頭文件,然后實現放在cpp文件里頭,直接build就出來一個靜態的lib了,發布時附上頭文件給使用者就可以。

 

創建動態鏈接庫(DLL)

 

用SDK創建一個簡單的dll文件

在VC++中選擇新建一個Win32 Dynamic-Link Library。需要建立一個c/c++ head file和一個c/c++ source file并加入工程。頭文件中內容為輸出函數的聲明,源文件中內容為DllMain函數和輸出函數的定義。下面是一個最簡單的例子。

 

 

頭文件代碼如下: 

 

代碼
#ifdef TEST_CREATE_DLL_EXPORTS
#define TEST_CREATE_DLL_API __declspec(dllexport)
#else
#define TEST_CREATE_DLL_API __declspec(dllimport)
#endif

// This class is exported from the test_create_dll.dll
class TEST_CREATE_DLL_API Ctest_create_dll {
public:
Ctest_create_dll(void);
// TODO: add your methods here.
};

extern TEST_CREATE_DLL_API int ntest_create_dll;

TEST_CREATE_DLL_API int fntest_create_dll(void);

 

在創建工程的時候????TEST_CREATE_DLL_EXPORTS就已經在預定義處定義過,生成導出dll。

頭文件預處理中的__declspec是微軟增加的“C擴展類存儲屬性”(C Extended Storage-Class Attributes),它指明一個給出的實例被存儲為一種微軟特定的類存儲屬性,可以為thread,naked,dllimport或dllexport. [MSDN原文:The extended attribute syntax for specifying storage-class information uses the __declspec keyword, which specifies that an instance of a given type is to be stored with a Microsoft-specific storage-class attribute (thread, naked, dllimport, or dllexport).] 輸出函數必須指明為CALLBACK。 DllMain是dll的入口點函數。也可以不寫它。DllMain必須返回TRUE,否則系統將終止程序并彈出一個“啟動程序時出錯”對話框。 編譯鏈接后,得到動態鏈接庫文件dlldemo.dll和輸入庫文件dlldemo.lib。

_declspec(dllexport) 

聲明一個導出函數,是說這個函數要從本DLL導出。我要給別人用。一般用于dll中 。
省掉在DEF文件中手工定義導出哪些函數的一個方法。當然,如果你的DLL里全是C++的類的話,你無法在DEF里指定導出的函數,只能用__declspec(dllexport)導出類。

 

__declspec(dllimport)

聲明一個導入函數,是說這個函數是從別的DLL導入。我要用。一般用于使用某個dll的exe中 。
不使用 __declspec(dllimport) 也能正確編譯代碼,但使用 __declspec(dllimport) 使編譯器可以生成更好的代碼。編譯器之所以能夠生成更好的代碼,是因為它可以確定函數是否存在于 DLL 中,這使得編譯器可以生成跳過間接尋址級別的代碼,而這些代碼通常會出現在跨 DLL 邊界的函數調用中。但是,必須使用 __declspec(dllimport) 才能導入 DLL 中使用的變量。

相信寫WIN32程序的人,做過DLL,都會很清楚__declspec(dllexport)的作用,它就是為了省掉在DEF文件中手工定義導出哪些函數的一個方法。當然,如果你的DLL里全是C++的類的話,你無法在DEF里指定導出的函數,只能用__declspec(dllexport)導出類。但是,MSDN文檔里面,對于__declspec(dllimport)的說明讓人感覺有點奇怪,先來看看MSDN里面是怎么說的:

不使用 __declspec(dllimport) 也能正確編譯代碼,但使用 __declspec(dllimport) 使編譯器可以生成更好的代碼。編譯器之所以能夠生成更好的代碼,是因為它可以確定函數是否存在于 DLL 中,這使得編譯器可以生成跳過間接尋址級別的代碼,而這些代碼通常會出現在跨 DLL 邊界的函數調用中。但是,必須使用 __declspec(dllimport) 才能導入 DLL 中使用的變量。

extern "C"   

指示編譯器用C語言方法給函數命名。

在制作DLL導出函數時由于C++存在函數重載,因此__declspec(dllexport)    function(int,int)    在DLL會被decorate,例如被decorate成為function_int_int,而且不同的編譯器decorate的方法不同,造成了在用GetProcAddress取得function地址時的不便,使用extern "C"時,上述的decorate不會發生,因為C沒有函數重載,但如此一來被extern"C"修飾的函數,就不具備重載能力,可以說extern 和extern "C"不是一回事。

C++編譯器在生成DLL時,會對導出的函數進行名字改編,并且不同的編譯器使用的改變規則不一樣,因此改編后的名字會不一樣。這樣,如果利用不同的編譯器分別生成DLL和訪問該DLL的客戶端代碼程序的話,后者在訪問該DLL的導出函數時會出現問題。為了實現通用性,需要加上限定符:extern “C”。

但是利用限定符extern “C”可以解決C++和C之間相互調用時函數命名的問題,但是這種方法有一個缺陷,就是不能用于導出一個類的成員函數,只能用于導出全局函數。LoadLibrary導入的函數名,對于非改編的函數,可以寫函數名;對于改編的函數,就必須吧@和號碼都寫上,一樣可以加載成功,可以試試看。

解決警告  inconsistent dll linkage

 inconsistent dll linkage警告是寫dll時常遇到的一個問題,解決此警告的方法如下:

  一般PREDLL_API工程依賴于是否定義了MYDLL_EXPORTS來決定宏展開為__declspec(dllexport)還是__declspec(dllimport)。展開為__declspec(dllexport)是DLL編譯時的需要,通知編譯器該函數是需要導出供外部調用的。展開為__declspec(dllimport)是給調用者用的,通知編譯器,該函數是個外部導入函數。

對于工程設置里面的預定義宏,是最早被編譯器看到的。所以當編譯器編譯DLL工程中的MYDLL.cpp時,因為看到前面有工程設置有定義MYDLL_EXPORTS,所以就把PREDLL_API展開為__declspec(dllexport)了。

這樣做的目的是為了讓DLL和調用者共用同一個h文件,在DLL項目中,定義MYDLL_EXPORTS,PREDLL_API就是導出;在調用該DLL的項目中,不定義MYDLL_EXPORTS,PREDLL_API就是導入。

使用靜態鏈接庫(Lib)

 

  使用靜態鏈接庫需要庫的開發者提供庫的頭文件以及lib文件,一般來說lib文件都比較大(相對導入庫來說),靜態鏈接庫是將全部指令都包含入調用程序生成的EXE文件中,并不存在“導出某個函數提供給用戶使用”的情況,就是要么全要,要么都不要。

使用動態鏈接庫(DLL)

 

方法一: load-time dynamic linking (隱式調用)
  在要調用dll的應用程序鏈接時,將dll的輸入庫文件(import library,.lib文件)包含進去。具體的做法是在源文件開頭加一句#include ,然后就可以在源文件中調用dlldemo.dll中的輸出文件了。

#pragma comment(lib, "***.lib") //通知編譯器DLL的.lib文件所在路徑及文件名,也可以不采用該語句,在屬性欄——輸入——附加依賴項處添加對應的lib就可以編譯鏈接應用程序了。

extern "C" __declspec(dllimport) foo(); //聲明導入函數

方法二: run-time dynamic linking (顯式調用)
  不必在鏈接時包含輸入庫文件,而是在源程序中使用LoadLibrary或LoadLibraryEx動態的載入dll。
  主要步驟為(以demodll.dll為例): 

1) typedef函數原型和定義函數指針。
  typedef void (CALLBACK* DllFooType)(void) ;
  DllFooType pfnDllFoo = NULL ;
2) 使用LoadLibrary載入dll,并保存dll實例句柄
  HINSTANCE dllHandle = NULL ;
  ... 
  dllHandle = LoadLibrary(TEXT("dlldemo.dll"));
3) 使用GetProcAddress得到dll中函數的指針
  pfnDllFoo = (DllFooType)GetProcAddress(dllHandle,TEXT("DllFoo")) ;
  注意從GetProcAddress返回的指針必須轉型為特定類型的函數指針。
4)檢驗函數指針,如果不為空則可調用該函數 
  if(pfnDllFoo!=NULL)
  DllFoo() ;
5)使用FreeLibrary卸載dll
  FreeLibrary(dllHandle) ;

動態鏈接庫(DLL)的優點

 

  →節約內存;
  →使應用程序“變瘦”;
  →可單獨修改動態鏈接庫而不必與應用程序重新鏈接;
  →可方便實現多語言聯合編程(比如用VC++寫個dll,然后在VB中調用);
  →可將資源打包;
  →可在應用程序間共享內存
  →......

 

杭州京都醫院http://www.fjzzled.com/京都醫院

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美激情一区二区三区不卡| 国产精品久久久久久亚洲调教| 黄色成人免费观看| 欧美专区第一页| 久久精品国产亚洲5555| 一区在线视频| 欧美成年视频| 欧美日韩国产精品自在自线| 亚洲午夜久久久久久久久电影网| 亚洲一区二区三区四区五区午夜| 国产亚洲成人一区| 欧美成ee人免费视频| 欧美精品成人91久久久久久久| 亚洲素人在线| 久久精品日产第一区二区三区 | 亚洲宅男天堂在线观看无病毒| 国产精品视频观看| 久久综合999| 欧美日本国产视频| 久久精品在线观看| 欧美大片免费观看在线观看网站推荐| 亚洲一级在线观看| 久久久99爱| 亚洲丝袜av一区| 久久久久久久成人| 亚洲图色在线| 噜噜噜久久亚洲精品国产品小说| 在线性视频日韩欧美| 久久精品视频网| 亚洲一区二区三区精品在线| 久久久av毛片精品| 午夜精品免费| 欧美日本国产在线| 欧美成人a∨高清免费观看| 国产精品久久影院| 91久久精品国产91性色tv| 国产酒店精品激情| 亚洲精品美女在线观看播放| 国产一区二区视频在线观看| 一本色道**综合亚洲精品蜜桃冫| 一区精品在线播放| 亚洲欧美日韩在线播放| 亚洲一级片在线看| 欧美国产日本高清在线| 久久中文久久字幕| 国产欧美精品| 亚洲调教视频在线观看| 日韩午夜中文字幕| 美国成人直播| 免费观看日韩av| 国产日产欧美一区| 亚洲综合视频在线| 午夜精品久久一牛影视| 欧美日韩中文在线观看| 亚洲精品日韩在线| 日韩亚洲欧美一区| 欧美大片免费久久精品三p| 欧美刺激性大交免费视频| 黄色亚洲在线| 久久免费视频在线观看| 日韩系列在线| 亚洲欧美日韩区| 一区二区三区导航| 欧美国产亚洲视频| 91久久极品少妇xxxxⅹ软件| 亚洲福利在线观看| 美脚丝袜一区二区三区在线观看 | 国产精品视频内| 亚洲精品乱码| 亚洲永久在线观看| 老牛影视一区二区三区| 欧美成ee人免费视频| 在线欧美福利| 免费成人小视频| 亚洲福利小视频| 亚洲理伦在线| 欧美视频一区| 午夜一区不卡| 久久男人av资源网站| 亚洲国产99| 欧美精品一区二区三区蜜桃| 亚洲精品综合精品自拍| 亚洲综合另类| 国产亚洲女人久久久久毛片| 久久久91精品国产| 亚洲欧洲综合另类在线| 亚洲欧美国产日韩天堂区| 国产日产亚洲精品| 美女脱光内衣内裤视频久久影院 | 亚洲欧美视频| 国产亚洲高清视频| 国产有码在线一区二区视频| 国产精品草草| 午夜精品久久久久久久久久久久久| 性亚洲最疯狂xxxx高清| 在线播放精品| 欧美视频一区在线观看| 性色av一区二区三区红粉影视| 免费黄网站欧美| 亚洲一区二区黄| 极品尤物久久久av免费看| 欧美风情在线| 欧美一区二区三区精品电影| 亚洲经典三级| 亚洲美女在线视频| 99re6这里只有精品| 欧美午夜不卡视频| 久久久久网址| 亚洲一区bb| 国产一区二区福利| 欧美成人精品激情在线观看| 欧美不卡视频| 亚洲女女女同性video| 欧美国产日韩在线观看| 欧美在线啊v一区| 欧美区国产区| 欧美偷拍另类| 国产日韩欧美在线播放| 国产主播一区二区三区| 樱桃国产成人精品视频| 亚洲国产精品成人久久综合一区| 亚洲欧洲精品天堂一级 | 欧美成人精品激情在线观看| 欧美mv日韩mv国产网站app| 欧美mv日韩mv国产网站| 欧美日本一道本| 欧美日韩综合视频网址| 嫩草影视亚洲| 久久婷婷一区| 亚洲第一区中文99精品| 亚洲精品国产精品国产自| 亚洲精品国精品久久99热一| 一本色道88久久加勒比精品| 亚洲已满18点击进入久久| 久久精品毛片| 欧美激情亚洲另类| 国产精品九九| 在线观看视频亚洲| 在线亚洲精品| 久久乐国产精品| 亚洲片在线观看| 午夜精品美女自拍福到在线| 蜜臀av性久久久久蜜臀aⅴ四虎 | 国产一区二区三区免费不卡 | 欧美aⅴ一区二区三区视频| 亚洲经典在线| 欧美在线视频网站| 欧美精品日韩| 国外视频精品毛片| 亚洲午夜国产一区99re久久| 久久综合中文| 中文精品在线| 免费永久网站黄欧美| 国产精品午夜久久| 亚洲三级免费| 久久一本综合频道| 亚洲午夜未删减在线观看| 美脚丝袜一区二区三区在线观看| 欧美午夜理伦三级在线观看| 亚洲国产一区二区精品专区| 欧美一区91| 99国产精品久久久久久久久久| 久久综合九色综合久99| 国产伦精品一区二区三区视频孕妇 | 欧美高清在线播放| 午夜日韩在线观看| 欧美日韩免费网站| 亚洲精品国产品国语在线app| 久久久久综合网| 亚洲女同同性videoxma| 欧美日韩精品综合| 亚洲区中文字幕| 久久综合色综合88| 欧美一区在线直播| 国产精品你懂得| 亚洲深夜福利| 亚洲日本成人| 欧美不卡在线| 亚洲激情一区二区| 欧美成黄导航| 麻豆精品在线视频| 在线日韩一区二区| 麻豆精品传媒视频| 久久久噜噜噜久噜久久| 精久久久久久久久久久| 久久久久久久久岛国免费| 亚洲欧美日韩在线高清直播| 欧美午夜宅男影院| 亚洲伊人观看| 亚洲影院色无极综合| 国产精品久久激情| 亚洲欧美视频在线观看| 亚洲一区三区在线观看| 国产精品日产欧美久久久久| 午夜久久美女| 先锋资源久久| 黄色成人在线网站| 男女精品视频| 欧美v日韩v国产v| 99热精品在线观看|