天天看點

Windows 動态庫程式設計技術 C++ 庫檔案三種模式: lib、dll、dll+lib詳解及其建立使用

       動态連結庫為子產品化應用程式提供了一種方式,使得更新和重用程式更加友善,當幾個應用程式在同一時間使用相同的函數時,它也幫助減少記憶體消耗,這是因為雖然每個應用程式有獨立的資料拷貝,但是它們的代碼是共享的。

C++ 庫會涉及到三個東西: .h .lib .dll檔案。

庫的使用方式有三種:

1>. .h + .lib 

2>. .dll

3>. .h + .lib + .dll 

第三種方式是最常見的,第一種次之,第二種較少用。

(下面執行個體使用vs2013)

1>. .h + .lib 

     lib中存放了函數名及具體的函數實作代碼,編譯器連結時,連結lib檔案到exe可執行程式中。

      a. 建立庫lib項目exampleLibFile:  建立項目,選擇-->Win32 控制台應用程式,應用類型選擇-->靜态庫 , 附加選項: 選擇--> 空項目,取消預編譯頭和安全開發生命周期檢查,(選擇控制台應用程式在項目,在項目屬性修改下 --正常--配置類型--中選擇--靜态庫(.lib) 也可以建立lib項目)。

Windows 動态庫程式設計技術 C++ 庫檔案三種模式: lib、dll、dll+lib詳解及其建立使用

b. 建立庫lib代碼:

  添加 .hpp 和 .cpp  檔案( myLib.hpp   myLib.cpp )

//.h 頭檔案

void go();
int add(int a, int b);
           
// cpp 檔案
#include <stdio.h>
#include <windows.h>

void go() {
	MessageBox(NULL, "我的來自lib的對話框", "Hello Lib", MB_OK);
}

int add(int a, int b) {
	return a + b;
}
           

c. 編譯生成  exampleLibFile.lib 檔案。

d. 調用者項目中使用  myLib.hpp 和 exampleLibFile.lib 檔案。

#include <stdio.h>
#include "myLib.hpp"

#pragma comment(lib,"../Debug/exampleLibFile.lib")

int main(void) {
	go();

	printf("來自lib的Add函數:%d\n", add(1, 2));

	system("pause");
	return 0;
}
           

2>. dll (使用 winapi調用)

      dll中存放了函數名及具體的函數實作代碼,運作時exe可執行程式通過winapi加載dll庫檔案。

      a. 建立庫dll項目exampleDllFile:  建立項目,選擇-->Win32 控制台應用程式,應用類型選擇-->靜态庫 , 附加選項: 選擇--> 空項目,取消預編譯頭和安全開發生命周期檢查,(選擇控制台應用程式在項目,在項目屬性修改下 --正常--配置類型--中選擇--靜态庫(.lib) 也可以建立lib項目)。

Windows 動态庫程式設計技術 C++ 庫檔案三種模式: lib、dll、dll+lib詳解及其建立使用

b. 建立庫dll代碼:

  添加 .hpp 和 .cpp  檔案( classDll.hpp   classDll.cpp  測試導出類, myDll.c測試導出函數)

//myDll.c


#include <stdio.h>
#include <windows.h>

//如果需要生成可供外部程式調用的函數,必須用dllexport

_declspec(dllexport) void go() {
	MessageBox(NULL, "我是來自dll", "hello Dll", MB_OK);
}



//檔案名為c 和 cpp, 生成的函數名字不同,因為C++有函數名重載機制,C沒有 
//cpp file
//void go(int a) {
//
//}
//
//void go(int a, double b) {
//
//}
           
//classDll.hpp檔案

//導出類和導出函數一樣 需要在前面加 __declspec(dllexport) 這是windows特有的
//庫中定義的類和函數 會被兩個項目使用 即原來dll項目和調用者項目
//是以要通過宏 預處理指令來實作庫中定義的類和函數能被兩個項目使用

//這裡的.hpp 頭檔案會被分成兩個檔案 一個嵌入編譯dll庫檔案中 另一個以.h檔案方式供調用者使用
//在建立庫項目時vs 編輯器會預設為庫項目添加預處理宏: EXAMPLEDLLFILE_EXPORTS, (項目名_EXPORTS),這宏也可以手動添加。

//根據這個預處理宏來差別這個頭檔案是在dll庫中使用還是在調用者項目中使用 
#ifdef _WIN32 // WIN32知識 32位程式 _WIN64 _WIN32不區分32位和64
#ifdef EXAMPLEDLLFILE_EXPORTS  //代表是庫檔案  dllexport: 導出
#define DLL_API __declspec(dllexport)
#else  //代表調用者檔案  dllimport: 導入
#define DLL_API __declspec(dllimport)
#endif
#else   //linux 為空
#define DLL_API
#endif


class DLL_API ClassDll {
public:
	ClassDll();
	~ClassDll();
	static int count;
};
           
// classDll.cpp檔案
#include <iostream>
#include "classDll.hpp"

using namespace std;

int ClassDll::count = 0;

ClassDll::ClassDll() {
	cout << "ClassDll Create" << endl;
}


ClassDll::~ClassDll() {

}
           

c. 編譯生成  exampleDllFile.lib   exampleDllFile.dll檔案。

d. 調用者項目中使用  exampleDllFile.dll 檔案。

//main.cpp

#include <stdio.h>
#include <windows.h>

//dll  windows api調用方式

int main(void) {
	HMODULE myDll = LoadLibrary("exampleDllFile1.dll");
	if(NULL != myDll) {
		GetProcAddress(myDll, "go")();
	}
	else {
		printf("沒有找到dll");
	}

	system("pause");
}
           

3>. .h + .lib + .dll 

    調用庫的時候,要有兩個檔案 lib 和 dll, lib 中記錄函數名及函數名對應的位址,dll中記錄函數的實作代碼。

  a. 建立庫dll項目exampleDllFile: 同 2>. dll (使用 winapi調用) 建立dll項目一樣。

  b. 建立庫dll代碼: 同 2>. dll (使用 winapi調用)建立庫dll代碼一樣。

  c. 編譯生成  exampleDllFile.lib   exampleDllFile.dll檔案。(注意這裡的lib檔案雖然和第一種lib庫檔案字尾名相同,但包含的内容格式不一樣,這地方lib隻有函數名及對應位址, 檔案往往就幾k大小)

  d. 調用者項目中使用 classDll.hpp  exampleDllFile.lib exampleDllFile.dll 檔案。

#include <iostream>
#include <windows.h>
#include "classDll.hpp"

using namespace std;

int main(int argc, char *argv[]) {
	ClassDll cl;
	cl.count++;
	cout << "count = " << cl.count << endl;
	getchar();
	return 0;
}
           

 在同一個解決方案中建立庫和調用程式時,最好設定項目依賴關系 友善開發:

     如:  設定項目b依賴項目a,  那麼當編譯項目b時, 要確定項目a是最新的,如果不是将先編譯項目a。

Windows 動态庫程式設計技術 C++ 庫檔案三種模式: lib、dll、dll+lib詳解及其建立使用