lib文件和dll文件


一. 簡介

1.1 C++兩種庫文件

  1. lib包含了函數所在的dll文件和文件中函數位置的信息(入口),代碼由運行時加載在進程空間中的dll提供,稱為動態鏈接庫dynamic link library。(這種方式更靈活,寫的程序體積小,但是需要.exe和dll同時發布)
  2. lib包含函數代碼本身,在編譯時直接將代碼加入程序當中,稱為靜態鏈接庫static link library。(這種方式不是很靈活,因為lib被編譯到.exe中,寫出的程序體積大,但是只需要發布exe即可,不需要dll文件)

1.2 C++兩種鏈接方式

  1. 動態鏈接使用動態鏈接庫,允許可執行模塊(.dll文件或.exe文件)僅包含在運行時定位 dll 函數的可執行代碼所需的信息。
  2. 靜態鏈接使用靜態鏈接庫,鏈接器從靜態鏈接庫 lib 獲取所有被引用函數,並將庫同代碼一起放到可執行文件中。

1.3 lib與dll的區別

1. 功能區別

  • lib是編譯時用到的,dll是運行時用到的。如果要完成源代碼的編譯,只需要lib;如果要使動態鏈接的程序運行起來,只需要dll。
  • 如果有dll文件,那么lib一般是一些索引信息,記錄了dll中函數的入口和位置,dll中是函數的具體內容;如果只有lib文件,那么這個lib文件是靜態編譯出來的,索引和實現都在其中。使用靜態編譯的lib文件,在運行程序時不需要再掛動態庫,缺點是導致應用程序比較大,而且失去了動態庫的靈活性,發布新版本時要發布新的應用程序才行。
  • 動態鏈接的情況下,有兩個文件:一個是LIB文件,一個是DLL文件。LIB包含被DLL導出的函數名稱和位置,DLL包含實際的函數和數據,應用程序使用LIB文件鏈接到DLL文件。在應用程序的可執行文件中,存放的不是被調用的函數代碼,而是DLL中相應函數代碼的地址,從而節省了內存資源。DLL和LIB文件必須隨應用程序一起發行,否則應用程序會產生錯誤。如果不想用lib文件或者沒有lib文件,可以用WIN32 API函數LoadLibrary、GetProcAddress裝載。

2. 文件數量的區別

  1. (靜態連接)使用lib需注意兩個文件:
  • .h頭文件,包含lib中說明輸出的類或符號原型或數據結構。應用程序調用lib時,需要將該文件包含入應用程序的源文件中。
  • .LIB文件,略。
  1. (動態連接)使用dll需注意三個文件:
  • .h頭文件,包含dll中說明輸出的類或符號原型或數據結構的.h文件。應用程序調用dll時,需要將該文件包含入應用程序的源文件中。
  • .LIB文件,是dll在編譯、鏈接成功之后生成的文件,作用是當其他應用程序調用dll時,需要將該文件引入應用程序,否則產生錯誤。如果不想用lib文件或者沒有lib文件,可以用WIN32API函數LoadLibrary、GetProcAddress裝載。
  • .dll文件,真正的可執行文件,開發成功后的應用程序在發布時,只需要有.exe文件和.dll文件,並不需要.lib文件和.h頭文件。

二. lib文件

2.1 生成工具

操作系統: Win7

開發軟件: VS2010

2.2 生成步驟

  1. 建立win32控制台工程MyLib(或者win32項目中下的靜態庫), 添加mySub.h文件以及mySub.cpp文件。

  2. 編寫mySub.h文件代碼

    #ifndef _MYSUB_H // 這里的#ifndef可以避免頭文件重復包含 #define _MYSUB_H void mySub(int a,int b); // 這一行代碼不能夠寫在上一行,只能另起一行寫 #endif 
  3. 編寫mySub.cpp文件代碼

      #include "mySub.h" //包含頭文件 #include <iostream> void mySub(int a,int b) //自定義的函數 { std::cout<<(a-b)<<std::endl; } 
  4. 由於在工程中,沒有main()函數,所以編譯可能會出錯。這時,點擊工程,並選擇工程屬性,出現下圖,選擇靜態鏈接庫即可。

     
    012302.png
  1. 這時候再按快捷鍵 F7,build solution即可產生lib文件。在Debug中只生成.lib文件。

2.3 lib文件的使用

  1. 新建一個.cpp文件myLibTest.cpp(用於測試)

    #include <iostream> #include "mySub.h" // 引用頭文件 using namespace std; #pragma comment(lib,"MyLib.lib") // 導入上一步生成的lib文件 int main() { mySub(5,4); // 調用lib中的自定義函數mySub() return 0; } 
  2. 點擊工程,並選擇工程屬性,出現下圖,將附加庫目錄新增包含剛才生成.lib的目錄。

     
    012303.png
  1. 將工程項目屬性中的配置類型改回至原來默認的應用程序(.exe),並執行myLibTest.cpp。

三. dll文件

3.1 生成.dll文件

  1. 新建win32項目,項目名稱為SubDLL,解決方案名稱為DLLTest,下一步。

  2. 選擇應用程序類型為DLL,將附加選項的“導出符號”勾選上,完成。

  3. 修改SubDLL.h中的內容(將原來代碼中,除預處理部分的代碼外全部刪除),並在后面新增你要實現的函數聲明(見代碼第21行)。注意:項目名為SubDLL,但此時生成的名字為 SUBDLL。

    #ifdef SUBDLL_EXPORTS #define SUBDLL_API __declspec(dllexport) #else #define SUBDLL_API __declspec(dllimport) #endif /* // 此類是從 SubDLL.dll 導出的 class SUBDLL_API CSubDLL { public: CSubDLL(void); // TODO: 在此添加您的方法。 }; extern SUBDLL_API int nSubDLL; SUBDLL_API int fnSubDLL(void); */ //這邊是新增的內容 SUBDLL_API void mySub(); 
  4. 修改SubDLL.cpp中的內容(將原來代碼中,除頭文件引入部分的代碼外全部刪除),並在后面新增你要實現的函數聲明(見代碼第26行)。

    // SubDLL.cpp : 定義 DLL 應用程序的導出函數。 // #include "stdafx.h" #include "SubDLL.h" #include<stdio.h> /* // 這是導出變量的一個示例 SUBDLL_API int nSubDLL=0; // 這是導出函數的一個示例。 SUBDLL_API int fnSubDLL(void) { return 42; } // 這是已導出類的構造函數。 // 有關類定義的信息,請參閱 SubDLL.h CSubDLL::CSubDLL() { return; } */ //這邊為SUM()的內容,很簡易 SUBDLL_API void mySub(int a,int b) { printf("the result is %d",a-b); } 
  5. 點擊“項目”,選擇“屬性”,進行如下圖的配置(粗體字顯示部分)。

     
    012306.png
  1. 構建項目(build)/生成解決方案,在項目的debug目錄下面會生成很多的文件,其中包括有.dll和.lib。

3.2 dll文件的使用

3.2.1 顯示調用方式

  1. 在之前“解決方案”中新建項目(選中解決方案 -> 增加 -> 新建項目),這次選擇“win32控制台應用程序”,生成向導中選擇“空項目”即可。取名為MyTest。

  2. 在新建項目的源文件下新建一個UseDLL.cpp文件,下面是其中的代碼。

    #include <iostream> #include <Windows.h> //使用函數和某些特殊變量 using namespace std; typedef void (*FUN)(int,int); //定義一個函數指針,確定調用函數的形參 int main() { const char* dllname = "SUBDLL.dll"; // 加載.dll const char* funname = "mySub"; //SUMDLL.cpp中函數名稱 HMODULE hDLL = LoadLibrary(dllname); //不要問,跟着做 if (hDLL != NULL) { FUN fp = FUN(GetProcAddress(hDLL,funname)); //繼續做,不要問 if(fp != NULL) { fp(5,4); } else { cout << "Can not Find: " << funname << endl; } FreeLibrary(hDLL); } else cout << "Can not find: " << dllname; return 0; } 
  3. 點擊解決方案名,選擇設置啟動項目 -> 通用屬性 -> 啟動項目 -> 單啟動項目(選中UseDLL)。

  4. 運行項目,出現了錯誤:Can not find:mySub。造成這種錯誤的原因正是導出函數的修飾名稱。在dll二進制文件中,經過編譯器的“加工”,實際上有了不同的名稱。這也是函數重載機制得以實現的一個技術支持。怎么辦呢?我們可以通過vs2010附帶工具dumpbin,找到加工以后的名稱。詳見dumpbin工具的使用

    • 在C:\Program Files(x86)\Microsoft Visual Studio 10.0\VC\bin目錄下,按住shift鍵,鼠標右鍵在空白處單擊,選擇在此處打開命令窗口
    • 輸入命令: dumpbin /export 文件全名
    • 將“加工”后的真是函數名復制后,粘貼。賦值給UseDLL.cpp文件中的變量funname。
    • 經過上一步后,重新執行UseDLL.cpp,成功運行。詳見VS2010 C++ 調用 DLL (C++編寫)
  5. 為了能夠使原來的UseDLL.cpp(上面第2步所示代碼)成功運行,可以進行下列操作:

    • 生成DLL文件的SubDLL項目的源文件中新建模塊定義文件createDLL.def,其中的代碼如下:

      LIBRARY createDLL  
      EXPORTS  
      mySub = ?mySub@@YAXHH@Z //?mySub@@YAXHH@Z 即為dumpbin工具找到的真實名。 
    • 修改SubDLL.h中的代碼(去掉這些不太規范的修飾名稱),修改之后重新編譯生成CreateDLL.dll。

      #ifdef SUBDLL_EXPORTS #define SUBDLL_API //去掉了原來的 __declspec(dllexport) #else //或改為 #define SUBDLL_API extern "C" __declspec(dllexport) #define SUBDLL_API //同上 #endif 
  6. 重新運行UseDLL.cpp程序,成功執行。

3.2.2 隱式調用方式

  1. 在之前“解決方案”中新建項目(選中解決方案 -> 增加 -> 新建項目),這次選擇“win32控制台應用程序”,生成向導中選擇“空項目”即可。取名為MyTest。

  2. 在新建項目的源文件下新建一個UseDLL.cpp文件,下面是其中的代碼。

    #include <iostream> extern void mySub(int,int); int main() { mySub(5,4); return 0; } 
  3. 右鍵工程–>Linker–>General–>Additional Library Directories(附加庫目錄) –>找到那個SubDLL.lib所在的目錄

  4. 右鍵UseDLL工程–>Linker->input寫下lib的名稱。如SubDLL.lib和你DEBUG文件下的對應(這步沒有也可以,因為會在上一步的路徑下尋找)。

  5. 點擊解決方案名,選擇設置啟動項目 -> 通用屬性 -> 啟動項目 -> 單啟動項目(選中UseDLL)

  6. 運行UseDLL.cpp程序,成功執行。

參考資料

四. 小結

4.1 程序中的問題

  1. error C2664: “LoadLibraryW”: 不能將參數 1 從“const char [10]”轉換為“LPCWSTR”與指向的類型無關;轉換要求 reinterpret_cast、C 樣式轉換或函數樣式轉換
    解決方法:

    選中項目,然后點擊屬性——>配置屬性——>常規——>項目默認值——>字符集,選為“使用多字節字符集"

     
    012304.png
  1. fatal error LNK1104: 無法打開文件:×××.lib的解決辦法
    一般情況是因為沒有導入相應的.lib文件,或者是導入的路徑有誤。給項目添加庫文件路徑。

    在VS中右擊項目點屬性:

    配置屬性-->鏈接器-->常規-->附加目錄 。在里面填上庫文件所在的路徑即可。

  2. fatal error LNK1104: 無法打開文件“x x x.def”
    如果不想使用xxx.def文件,可以在項目-屬性-配置屬性-鏈接器-輸入 選項中,將右側的模塊定義文件刪掉,這樣就不會提示了。

4.2 vs的常用操作

  1. 添加頭文件:

    配置屬性-->C/C++-->常規-->附加包含目錄 加上頭文件存放的目錄。

  2. 添加lib文件:

    • 配置屬性-->鏈接器-->輸入-->附加依賴項加入庫名(×××.lib);或者是在cpp源文件中用#pragma comment(lib,"×××.lib")來代替。
    • 將xxx.lib拷入工程所在目錄,或者執行文件生成的目錄,或者系統Lib目錄中(如果lib文件是自己生成的,可以跳過這一步)。
    • 給項目添加庫文件路徑:
      在VS中右擊項目點屬性。配置屬性-->鏈接器-->常規-->附加目錄 。在里面填上庫文件所在的路徑即可。

4.3 windows小常識

  1. 在當前目錄下運行命令:shift鍵 + 鼠標右鍵

  2. 首先將命令窗體屬性中的快速編輯模式選中打勾,這樣就可以一復制粘貼了。復制dos窗體中的內容:右鍵->標記->選擇復制內容->回車鍵或者鼠標右擊,粘貼的時候:鼠標右鍵粘貼。
    dos中不能使用快捷鍵。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM