Windows 動態連接庫DLL使用

轉載:http://www.javashuo.com/article/p-bvmbaahp-hn.htmlhtml

轉載:https://www.cnblogs.com/jin521/p/5598529.htmlios

1、概念

DLL:Dynamic Link Library,即動態連接庫,這種庫包含了可由多個程序同時使用的代碼和數據。windows

它是microsoft在windows操做系統中實現共享函數庫概念的一種實現方式。其中windows中 一些做爲DLL實現的文件有:ide

  • ActiveX控件(.ocx)文件:如windows上的日曆控件。
  • 控制面板(.cpl)文件:控制面板中的每一項都是一個專用的DLL。
  • 設備驅動程序(.drv)文件:如控制打印到打印機的打印機驅動程序。

2、由來

DLL最初用於節約應用程序所須要的磁盤和內存空間。早前,在傳統的非共享庫中,一部分代碼簡單地附加到調用的程序中。若是兩個程序同時調用同一個子程序,就會出現兩份那段代碼。相反,許多應用共享的代碼可以切分到一個DLL中,在硬盤上存爲一個文檔,在內存中只需使用一個實例。模塊化

3、DLL的優缺點

優勢:函數

(1)節省內存和代碼重用:當多個程序使用同一個函數庫時,DLL能夠減小在磁盤和物理內存中加載代碼的重複量,且有助於代碼的重用。ui

(2)模塊化:DLL有助於促進模塊式程序開發。模塊化容許僅僅更改幾個應用程序共享使用的一個DLL中的代碼和數據而不須要更改應用程序自身。這種模塊話的基本形式容許如Microsoft Office、Microsoft Visual Studio、甚至windows自身這樣大的應用程序 使用較爲緊湊的補丁和服務包。spa

缺點:操作系統

DLL Hell:即DLL地獄,指幾個應用程序在使用同一個共享的DLL庫時發生版本衝突。.net

究其緣由,八個字:成也共用,敗也共用。由於DLL Hell正是因爲動態連接庫可與其餘程序共用函數、資源所致使。

主要有兩種狀況:

設想這樣一個場景:程序A會使用1.0版本的動態連接庫X,則在程序A安裝到系統時,會同時安裝該1.0版本的動態連接庫X。假設另外一個程序B也會使用到動態連接庫X,那麼程序B直接複製到硬盤中便可正常運行,由於動態連接庫已經存在於系統中。然而有一天,另外一程序C也要使用動態連接庫X,可是因爲程序C開發的時間較晚,其須要較新版本---2.0版本的動態連接庫X。則在程序C被安裝到系統時,2.0版本的動態連接庫X 也必須隨之安裝到系統中,此時系統中1.0版本的動態連接庫將被2.0版本所取代(替換)。

狀況1:新版本的動態連接庫不兼容舊版本。如,A何B須要X所提供的功能,在升級到2.0後,新版本的X居然把此功能取消了(很難想象吧,呵呵但有時候就是如此....)。則此時雖然C能正常運行,但A和B均沒法工做了。

狀況2:新版本的動態連接庫兼容舊版本,可是存在一個bug。

可看下面的例子(僅僅爲了說明問題):

// X1.0 version  
void func(int count)  
{  
    if(count < 0)  
        count = 0;  
    ....  
}  
  
// X2.0 version  
void func(int count)  
{  
    //負數處理被移除!  
    ...  
}  

一旦出現count爲負數的狀況,則程序A在新版本的處理下就會有問題。

解決辦法:Side-by-side Assembly,是windows Xp以及以上系統解決動態連接庫版本衝突所使用的技術,重點在於編譯程序時,由VS生成一個manifest文件,指明當前應用程序所使用的動態連接庫版本號;發佈程序時需同時發佈該manifest文件,供客戶計算機上的DLL Loader根據manifest加載適當版本的DLL,若不發佈該項manifest,客戶機則按默認版本加載DLL。下圖爲其典型的場景:

4、DLL與lib的關係

咋一看:lib是靜態連接庫;DLL是動態連接庫,一個編譯時提供;一個運行時提供,完了。

其實沒那麼簡單! lib也有靜態lib和動態lib之分

靜態lib:它將導出聲明(後面會講)和實現均放到lib中,編譯後全部代碼都嵌入到宿主程序中去。

動態lib:至關於一個h文件,它是對實現部分(.DLL)的導出部分的聲明。編譯後只是將導出聲明部分編譯到宿主程序中,運行時須要相應的DLL文件的支持,不然沒法工做。當生成一個新的DLL時,也會有配套的lib產生(即兩者需一塊兒分發),此時的lib即爲動態lib(後面會有還有實驗)。

5、如何生成一個DLL

在VS2012開發環境下,打開File\New\Project選項,能夠選擇Win32 Dynamic-Link Library或MFC AppWizard【dll】來以不一樣的方式建立Non-MFC DLL、Regular DLL、Extension DLL等不一樣種類的動態連接庫。下面以選擇Win32 Dynamic-Link Library方式來建立一個DLL(實現加法運算)

二、分別添加頭文件(.h)和源文件(.cpp)

// mydll.h file  
extern "C" _declspec(dllexport) int add(int a, int b);  
  
//mydll.cpp file  
#include "mydll.h"  
int add(int a, int b) //該DLL須要導出的函數功能:加法  
{  
    return a + b;  
}  

說明:

(1)前面的 extern 「C」 告訴編譯器函數能夠在本模塊或其餘模塊中使用,其中「C」代表需按照C語言方式編譯和鏈接它,由於C++編譯時,會對函數名進行修飾,用於實現函數重載,而C裏面沒有這個功能,因此須要用extern "C"在頭文件進行聲明的時候加以區分,以便連接時能進行正確地函數名查找。

(2)_declspec(dllexport)爲導出函數關鍵字,意爲需從DLL中導出該函數,以便使用

三、編譯鏈接

在進行編譯鏈接後會在Debug目錄下找到DLL文件和對應的lib文件

6、如何調用一個DLL

下面實現兩種調用方式:單獨.dll 和.h + .lib + .dll結合

注:需把對應的 .dll 文件以及.lib 文件和.h文件(結合方式時)拷貝至調用的程序目錄下

(1)單純使用.dll

#include<wtypes.h>   
#include <winbase.h>   
#include <iostream>  
_declspec(dllimport) int Add(int a, int b); //導入聲明,亦能夠不加,若是加上可加快程序運行  
  
typedef int(*pAdd)(int a,int b);  
  
int main()  
{  
  
    HINSTANCE hDLL;  
    pAdd Add;  
    hDLL=LoadLibrary(L"mydll.dll");  //加載 DLL文件  
    if(hDLL == NULL)std::cout<<"Error!!!\n";  
    Add=(pAdd)GetProcAddress(hDLL,"add");  //取DLL中的函數地址,以備調用  
  
    int a =Add(5,8);  
    std::cout<<"a: "<<a<<std::endl;  
      
    FreeLibrary(hDLL);  
    return 0;  
}   

輸出結果:

(2).h + .lib + .dll 結合方式

#include<wtypes.h>   
#include <winbase.h>   
#include <iostream>#include "../MyDll/mydll.h"  
#pragma comment(lib,"mydll.lib")  //將mydll.lib庫文件鏈接到目標文件中(即本工程)  
extern "C"_declspec(dllimport) int add(int a,int b);  
int main()  
{  
  
    int a =add(5,8);  
    std::cout<<"a: "<<a<<std::endl;  
  
    return 0;  
}   

 

此時若是去掉 .dll 文件(即只有.lib 和 .h文件),則會出錯:

相關文章
相關標籤/搜索