動態鏈接庫(dll)與靜態連接庫(lib)

一、前言

  1. dll(dynamic)動態鏈接庫,包含多個程序執行的代碼和數據,程序運行時是需要使用dll;
  2. lib(static)靜態鏈接庫,包含dll中各函數的入口信息,在程序編譯時用到;
  3. 動態連接庫可以使設計者隱藏函數的具體實現,便噶增加代碼的複用性;
  4. 動態鏈接庫參與的程序中,lib文件和dll文件都要用到。

二、dll的生成

頭文件中增加下面幾行代碼

#pragma once
#ifdef XXXX_EXPORTS                        //如果定義了XXXX_EXPORTS 變量
#define DLL_API __declspec(dllexport)      //那麼定義DLL_API爲__declspec(dllexport)的別名
#else                                      //若梅定義
#define DLL_API __declspec(dllimport)      //定義DLL_API字段爲導入
#endif

__declspec(dllexport)爲導出標誌;若要將某個類導出:

class DLL_API 類名

若要將某個函數導出:

extern "C" 返回值類型 DLL_API 函數名(參數1,參數2,...)

extern "C"表示在其他類中已經定義了該代碼裏內容,這裏只是聲明,“C”表明按照C語言方式進行編譯和鏈接,因爲C++編譯時會對函數名進行修飾,用於實現函數的重載,而C裏面沒有這個功能,多以需要用extern “C”在而文件頭聲明時加以區分,以便鏈接時進行正確的函數名查找;

三、dll和lib的引用

  1. 屬性—>輸入—>附加依賴項,出入需要的XXX.lib文件;
  2. 將lib文件放到目標工程目錄下,確保該目錄是在屬性—>c++—>常規—>附加包含目錄中,若沒有,添加即可;
  3. 將dll文件放到Debug/release文件下;
  4. 在工程文件中太你家與lib名稱相同的頭文件,文件最上方添加:
class __declspec(dllimport) XXX.lib

   

若導入函數:

extern "C" __declspec(dllimport) void 函數名(參數列表);

導入動態連接庫可以也可以如下寫法:

#include "../DLL/DLL.h"   //通過相對路徑或絕對路徑添加頭文件
#pragma comment (lib,"../DLL/DLL1.lib")  //添加庫文件

四、實例

dllExample.h

#pragma once
#include <iostream>
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
 
class DLL_API ExportInterface
{
public:
	virtual void foo() = 0;
	virtual ~ExportInterface()
	{
		std::cout << "call ~ExportInterface"<< std::endl;
	}
};
 
extern "C" DLL_API ExportInterface* getInstance();
extern "C" DLL_API void releaseInstance(ExportInterface* pInstance);
 
#ifdef DLL_EXPORTS  //我們並不需要向外導出該類的定義,在外部代碼編譯時,也不需要包含此類的定義。
class ExportClass : public ExportInterface
{
private:
	std::string x; //由於外部代碼對此不可見,此處的std::string是安全的。
public:
	void foo(); //函數體在dllExample.cpp中實現
	virtual ~ExportClass()
	{
		std::cout << "call ~ExportClass" << std::endl;
	}
};
#endif

dllExample.cpp:

#define DLL_EXPORTS
#include "dlltest.h"
#include <iostream>
 
extern "C" DLL_API ExportInterface* getInstance()
{
	ExportInterface* pInstance = new ExportClass();
	return pInstance;
}
 
extern "C" DLL_API void releaseInstance(ExportInterface* pInstance)
{
	pInstance->~ExportInterface();
}
 
void ExportClass::foo()
{
	std::cout << "call func foo" << std::endl;
	//do something...
	return;
}

調用

#include <iostream>
#include <windows.h>
#include "dlltest.h"
using namespace std;
// 動態加載DLL
// 函數指針,用於獲取GetProcAddress返回的函數地址,並調用DLL中的函數
typedef ExportInterface* (*DllGetInstance)(void);
typedef void (*DllReleaseInstance)(ExportInterface*);
 
int main()
{
	DllGetInstance getInstance;
	DllReleaseInstance releaseInstance;
	ExportInterface* pTest;
	// 顯式加載
	HINSTANCE hInstLibrary = LoadLibrary("./TestDll.dll");
 
	if (hInstLibrary == NULL)
	{
		FreeLibrary(hInstLibrary);
		cout << "cant load dll" << endl;
	}
	getInstance = (DllGetInstance)GetProcAddress(hInstLibrary, "getInstance");
	releaseInstance = (DllReleaseInstance)GetProcAddress(hInstLibrary, "releaseInstance");
	if (getInstance == NULL || releaseInstance == NULL)
	{
		FreeLibrary(hInstLibrary);
		cout << "cant get func" << endl;
	}
	
	pTest = getInstance();
	pTest->foo();
	releaseInstance(pTest);
 
	std::cin.get();
 
	FreeLibrary(hInstLibrary);
 
	std::cin.get();
	return 0;
}

具體參考:

https://blog.csdn.net/fantasysolo/article/details/88553742?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-2

https://blog.csdn.net/AnthonyStark/article/details/98237701

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章