C++_編寫動態連結庫
動態連結庫簡介
動態連結庫(Dynamic Link Library 或者 Dynamic-link Library,縮寫為 DLL),是微軟公司在微軟Windows作業系統中,實現共享函式庫概念的一種方式。這些庫函式的副檔名是 ”.dll”、”.ocx”(包含ActiveX控制的庫)或者 “.drv”(舊式的系統驅動程式)。
動態連結提供了一種方法,使程序可以呼叫不屬於其可執行程式碼的函式。函式的可執行程式碼位於一個 DLL 檔案中,該 DLL 包含一個或多個已被編譯、連結並與使用它們的程序分開儲存的函式。DLL 還有助於共享資料和資源。多個應用程式可同時訪問記憶體中單個 DLL 副本的內容。
通過使用DLL可以實現模組化,使之由相對獨立的元件組成,可以更快的載入應用各個模組的功能,還可以更容易的將更新應用於各個模組。
例如,一個程式含有很多個功能,將他們都編寫成DLL檔案,當軟體更新時,只需更新相應的DLL檔案而不需要重新安裝整個程式
編寫一個DLL
1、新建工程,使用VS2015編寫一個實現兩數相加的DLL
檔案->新建專案->win32專案->下一步->DLL->勾選預編譯標頭檔案,匯出符號->完成
此時VS2015會自動生成3個頭檔案和3個cpp檔案
其中TestDll.h是DLL的標頭檔案
#ifdef TESTDLL_EXPORTS #define TESTDLL_API __declspec(dllexport) #else #define TESTDLL_API __declspec(dllimport) #endif // 此類是從 TestDll.dll 匯出的 class TESTDLL_API CTestDll { public: CTestDll(void); // TODO: 在此新增您的方法。 }; //匯出的變數 extern TESTDLL_API int nTestDll; //匯出函式 TESTDLL_API int fnTestDll(void);
stdafx.h包含需要的標頭檔案
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
TestDll.cpp是原始檔
DllMain是動態連結庫的入口點,在DllMain函式中,hModule引數是該DLL模組的控制代碼,代表這個檔案的映象載入到程序的地址空間使用的基地址,ul_reason_for_call引數的指標是本次呼叫的原因,包括
- DLL_PROCESS_ATTACH,表示動態連結庫剛被某一個程序載入,對映到了某一個地址空間,可以在此進行初始化
- DLL_THREAD_ATTACH,動態連結庫將被解除安裝,可以在這進行資源釋放
- DLL_THREAD_DETACH,應用程式建立了一個新的程序
- DLL_PROCESS_DETACH,某個程序正常終止
// dllmain.cpp : 定義 DLL 應用程式的入口點。 #include "stdafx.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
2、將TestDll.h中的匯出函式改為
TESTDLL_API int fnTestDll(int a,int b);
刪除匯出變數和匯出類部分
3、將TestDll.cpp檔案中匯出函式改為
TESTDLL_API int fnTestDll(int a, int b)
{
return a+b;
}
刪除匯出類和匯出變數部分
注:Dll能夠定義兩種函式,一種是內部函式,一種是匯出函式。內部函式只能被定義這個函式的模組使用,而匯出函式不僅可以在本模組呼叫,還可以被其他模組呼叫。dll的主要功能就是向外匯出函式供其他模組使用
此時一個簡單的兩數相加的DLL就寫完了,接下來便是如何載入這個Dll了,載入這個dll有兩種方法,一種是隱式動態連結,一種是顯示動態連結
隱式動態連結
新建一個win32控制檯程式,生成剛剛寫的dll,將TestDll.lib,TestDll.dll,TestDll.h複製到該控制檯程式的資料夾下,然後新增下面的程式碼
#include "stdafx.h"
#include <iostream>
#include "TestDll.h"
using namespace std;
#pragma comment(lib,"TestDll")
int main()
{
int a, b, result;
while (cin >> a >> b)
{
result = fnTestDll(a, b);
cout << "Result : " << result << endl;
}
return 0;
}
#pragma comment(lib,”TestDll”)語句表示要連線到TestDll.lib庫,使用隱式動態連結需要指明庫所在的位置(本例中在當前資料夾下),靜態變異也會使可執行檔案的體積變大
測試結果
可以看到執行成功
顯式動態連結
模組使用LoadLIbrary()或者LoadLIbraryEx()函式顯式載入DLL,載入後呼叫GetProcAddress()函式取得DLL匯出函式的地址,然後呼叫函式。
1、在原DLL工程中建立一個模組定義檔案(DEF)來指定要匯入的函式。
在TestDll中專案->新增新項->模組定義檔案(.def)
然後在其中新增
EXPORTS
fnTestDll
fnTestDll表示要向外匯出的函式名
重新生成該專案
2、新建一個win32控制檯程式,新增如下程式碼
// ExplicitTestDll.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <iostream> #include <Windows.h> using namespace std; typedef int(*PFNEXPORTFUNC)(int, int); int main() { int a, b, result; while (cin >> a >> b) { HMODULE hModule = LoadLibrary(_T("TestDll.dll")); if (hModule != NULL) { PFNEXPORTFUNC mDLLFuncAdd = (PFNEXPORTFUNC)GetProcAddress(hModule, "fnTestDll"); if (mDLLFuncAdd != NULL) { result = mDLLFuncAdd(a, b); cout << "Result: " << result << endl; } FreeLibrary(hModule); } } return 0; }
顯式呼叫DLL分為三個步驟
- 宣告要匯出的DLL函式
- 載入目標DLL,即 LoadLibrary()函式,將DLL載入到程序的虛擬地址空間,若成功則返回該DLL模組的控制代碼,否則返回NULL
- 獲得匯出函式的地址,即GetProcAddress()函式,成功時返回函式地址,否則返回NULL
測試結果
原文地址:https://blog.csdn.net/a7055117a/article/details/47733247
參考:
- 百度百科
- 《小小黑客之路-黑客工具、攻防及防火牆入門》