1. 程式人生 > >C++ 打包並呼叫動態連結庫 (VS2010)

C++ 打包並呼叫動態連結庫 (VS2010)

相比於原始碼,動態連結庫使用起來更加方便簡潔,而且可以對原始碼起到保護作用。

生成動態連結庫
我們以vs2010為例,生成一個動態連結庫,首先在VS2010中新建一個專案,選擇“Win32控制檯應用程式“或“Win32專案”都是可以,只要在“應用程式設定”中選擇“DLL”和“空專案”就好:
這裡寫圖片描述
然後我們分別在標頭檔案和原始檔中新增檔案:
這裡寫圖片描述
在testdll.h中新增下列內容:

#ifndef TestDll_H_
#define TestDll_H_
#ifdef MYLIBDLL
#define MYLIBDLL extern "C" _declspec(dllimport) 
#else
#define MYLIBDLL extern "C" _declspec(dllexport) #endif MYLIBDLL int Add(int plus1, int plus2); #endif

在testdll.cpp中新增下列內容:

#include "testDll.h"
#include <iostream>
using namespace std;
int Add(int x, int y)
{
    int add_result = x + y;
    return add_result;
}

生成解決方案,在工程目錄下檢視生成結果:
這裡寫圖片描述

這樣的話,並沒有生成我們需要的lib!!!
這是因為:有了匯出類和函式才會有lib,如果只有匯出函式,不會生出lib


我們有兩種辦法解決這個問題:
(1)加上.def檔案,也就是模組定義檔案:
這裡寫圖片描述

在testdll.def中新增程式碼:

LIBRARY  testdll  // 庫名為testdll,省略庫名即為動態連結庫檔名 
EXPORTS           // 輸出 
Add @1            // 帶序號的輸出函式名 

再次生成解決方案:
這裡寫圖片描述

(2)新建Win32 DLL專案的時候勾選“匯出符號”選項
我們重新生成工程:
這裡寫圖片描述
完成後我們發現,編譯器給我們新增好了一些東西:
這裡寫圖片描述
這和我們上面說的情況是一樣的,新增好的.h與.cpp檔案中已經寫好了類,所以不在需要定義.def檔案。
在這裡我們就不再重複這種情況下的匯出過程,和第一種差不多的。
至此,動態連結庫就生成好了。

呼叫動態連結庫

既然要呼叫動態連結庫,就用瞭解我們生成的東西在呼叫的過程中的作用。

大家可以參考這個部落格,我也把其中重要的東西摘錄到這裡:

(1)lib是編譯時用到的,dll是執行時用到的。如果要完成原始碼的編譯,只需要lib;如果要使動態連結的程式執行起來,只需要dll。
(2)如果有dll檔案,那麼lib一般是一些索引資訊,記錄了dll中函式的入口和位置,dll中是函式的具體內容;如果只有lib檔案,那麼這個lib檔案是靜態編譯出來的,索引和實現都在其中。使用靜態編譯的lib檔案,在執行程式時不需要再掛動態庫,缺點是導致應用程式比較大,而且失去了動態庫的靈活性,釋出新版本時要釋出新的應用程式才行。
(3)動態連結的情況下,有兩個檔案:一個是LIB檔案,一個是DLL檔案。LIB包含被DLL匯出的函式名稱和位置,DLL包含實際的函式和資料,應用程式使用LIB檔案連結到DLL檔案。在應用程式的可執行檔案中,存放的不是被呼叫的函式程式碼,而是DLL中相應函式程式碼的地址,從而節省了記憶體資源。DLL和LIB檔案必須隨應用程式一起發行,否則應用程式會產生錯誤。
(4)h標頭檔案,包含lib中說明輸出的類或符號原型或資料結構。應用程式呼叫lib時,需要將該檔案包含入應用程式的原始檔中。

所以在使用動態連結庫時,其實需要三個檔案:
(1).h標頭檔案,包含dll中說明輸出的類或符號原型或資料結構的.h檔案。應用程式呼叫dll時,需要將該檔案包含入應用程式的原始檔中。
(2).LIB檔案,是dll在編譯、連結成功之後生成的檔案,作用是當其他應用程式呼叫dll時,需要將該檔案引入應用程式,否則產生錯誤。
(3).dll檔案,真正的可執行檔案,開發成功後的應用程式在釋出時,只需要有.exe檔案和.dll檔案,並不需要.lib檔案和.h標頭檔案。

新建一個Win32控制檯程式,將用於生成動態連結庫的testdll.h加入到工程,並新建一個.cpp檔案:
這裡寫圖片描述

testdll.h中已經有程式碼了,在main.cpp中新增:

#include "testdll.h"
#include <iostream>

using namespace std;

int main()
{
  cout<<Add(5,2)<<endl;
  getchar();
  return 0;
}

為了再具體的說明下這三個檔案的作用,我們按步驟測試下他們的作用,現在我們只用到了.h檔案,直接編譯。
程式報錯:
這裡寫圖片描述
在Add函式中轉到定義,可以檢視到該函式的定義:
這裡寫圖片描述

這裡寫圖片描述

這就是.h檔案的作用,定義了函式的結構,但是由於沒有庫檔案,編譯無法通過。

加入庫檔案
附加庫目錄新增庫的路徑:
這裡寫圖片描述
附加依賴項新增庫的名稱:
這裡寫圖片描述

再次編譯,可以通過,編譯成功就不截圖了,太佔地方了,通過後執行程式:

這裡寫圖片描述

這就是缺少dll檔案的錯誤提醒,因為dll檔案才是真正的可執行檔案。

加入dll
其實我們可以直接把dll檔案放進工程檔案的程式所在的目錄內,這樣不再需要配置任何東西就可以直接執行。
這裡寫圖片描述