一、前言
- dll(dynamic)動態鏈接庫,包含多個程序執行的代碼和數據,程序運行時是需要使用dll;
- lib(static)靜態鏈接庫,包含dll中各函數的入口信息,在程序編譯時用到;
- 動態連接庫可以使設計者隱藏函數的具體實現,便噶增加代碼的複用性;
- 動態鏈接庫參與的程序中,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的引用
- 屬性—>輸入—>附加依賴項,出入需要的XXX.lib文件;
- 將lib文件放到目標工程目錄下,確保該目錄是在屬性—>c++—>常規—>附加包含目錄中,若沒有,添加即可;
- 將dll文件放到Debug/release文件下;
- 在工程文件中太你家與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;
}
具體參考: