C++制作DLL文件的方法詳解
一、DLL介紹
我理解的DLL是windows下的可執(zhí)行文件,也就是PE文件,學名動態(tài)鏈接庫。一般調用DLL,也稱加載DLL的是EXE文件。它是一種可重用的代碼和數據的集合,可以由多個應用程序同時使用,與靜態(tài)鏈接庫不同,動態(tài)鏈接庫在運行時加載到內存中,以供應用程序使用。
一個exe程序可以帶若干個dll,如下圖:
正常的windows程序基本都會帶DLL,包括操作系統(tǒng)內核的DLL,所以很關鍵。
DLL具有以下優(yōu)點:
- 可重用性:由于多個應用程序可以共享一個DLL,因此它們可以共享相同的代碼和數據,從而提高了代碼的可重用性。
- 節(jié)省內存:由于DLL在運行時才加載到內存中,因此它們可以在不占用過多內存的情況下提供所需的功能。
- 易于更新:當需要更新DLL時,只需替換現有的DLL文件即可,而無需重新編譯使用該DLL的應用程序。
- 動態(tài)鏈接:DLL在運行時才鏈接到應用程序中,因此它們可以在應用程序啟動后動態(tài)加載,從而提高了應用程序的啟動速度。
- 穩(wěn)定性:由于多個應用程序共享相同的DLL,因此如果DLL中的代碼或數據發(fā)生問題,則可以在一次更新后修復所有使用該DLL的應用程序。
使用DLL的過程分為兩個步驟:首先需要創(chuàng)建一個DLL,然后在需要使用該DLL的應用程序中加載它。為了使DLL中的函數可以在應用程序中使用,必須將其導出,可以使用__declspec(dllexport)修飾符來導出DLL中的函數和數據。而在應用程序中調用DLL中的函數,需要使用LoadLibrary()函數來加載DLL,并使用GetProcAddress()函數獲取DLL中導出函數的地址,然后使用函數指針來調用這些函數。
在Linux下,與之對應的是.so文件。MacOs下為.dylib。
二、C++制作DLL文件
需要打開你的windows Visual Satdio任意版本??梢灾苯舆x擇創(chuàng)建DLL文件,也可以先創(chuàng)建平臺程序后續(xù)再改。
這里直接展示一段簡單的代碼。
2.1 DLL端
DllDLL.h:
#pragma once #ifdef MYLIBRARY_EXPORTS #define MYLIBRARY_API __declspec(dllexport) #else #define MYLIBRARY_API __declspec(dllimport) #endif MYLIBRARY_API int Add(int a, int b);
DllDLL.cpp:
#include "DllDLL.h" int Add(int a, int b) { return a + b; }
DllDLL.def模塊定義:
LIBRARY GeneratrDLL EXPORTS Add @1
模塊定義需要在這設定:
重點:
.def文件(也稱為導出文件)是一種Windows平臺上的文件格式,用于描述可執(zhí)行文件或動態(tài)鏈接庫(DLL)中導出函數的名稱和地址。當編寫一個DLL并將其與其他應用程序鏈接時,該DLL中的函數必須明確導出,以便其他應用程序能夠調用這些函數。
2.2 調用端
代碼:
#include "..\DllDLL\DllDLL.h" #include <windows.h> #include <iostream> typedef int(*AddFunc)(int, int); int main() { HINSTANCE hinstLib = LoadLibrary(TEXT("DllDLL.dll")); if (hinstLib != NULL) { AddFunc add = (AddFunc)GetProcAddress(hinstLib, "Add"); if (add != NULL) { // 調用 DLL 中的函數 int result = add(1, 2); std::cout << result << std::endl; } } }
將UseDllDLL設置為啟動項,運行結果(DLL內部返回方法的結果):
三、DLL導出類方法
我們定義一個MyInterface基類,里面實現虛方法,再生成一個它的派生類實現虛方法,最后創(chuàng)建類工廠讓客戶端代碼更容易實例化類對象。
// MyInterface.h #ifndef MY_INTERFACE_H #define MY_INTERFACE_H class MyInterface { public: virtual ~MyInterface(){} virtual void DoSomething() = 0; virtual int GetNumber() = 0; }; class MyImplementation : public MyInterface { public: virtual void DoSomething() override; virtual int GetNumber() override; }; #endif // MY_INTERFACE_H // MyImplementation.cpp #include "MyInterface.h" void MyImplementation::DoSomething() { // } int MyImplementation::GetNumber() { return 49; } // MyDLL.h #ifndef MY_DLL_H #define MY_DLL_H #ifdef MY_DLL_EXPORTS #define MY_DLL_API __declspec(dllexport) #else #define MY_DLL_API __declspec(dllimport) #endif #include "MyInterface.h" MY_DLL_API MyInterface* CreateMyObject(); #endif // MY_DLL_H // MyDLL.cpp #define MY_DLL_EXPORTS #include "MyDLL.h" #include "MyInterface.h" MyInterface* CreateMyObject() { return new MyImplementation(); }
上面代碼的最后兩端將MyInterface* 類的對象作為導出接口,它的我實現是返回它的派生類MyImplementation類的實例對象??蛻舳丝梢允褂肅reateMyObject獲得實例。
客戶端調用DLL,首先要有實現DLL的頭文件MyInerface.h,然后去調用,具體:
#include "..\GeneratrDLL\MyInterface.h" #include <Windows.h> #include <iostream> int main() { // 加載DLL HMODULE hModule = LoadLibrary(L"C:\\Users\\liubw\\source\\repos\\GeneratrDLL\\x64\\Debug\\GeneratrDLL.dll"); if (hModule != NULL) { // 獲取接口 typedef MyInterface* (*CreateMyObjectFunc)(); CreateMyObjectFunc fun = (CreateMyObjectFunc)GetProcAddress(hModule, "CreateMyObject"); if (fun != NULL) { // 使用接口 MyInterface* myObject = createMyObject(); myObject->DoSomething(); int number = myObject->GetNumber(); std::cout << number << std::endl; delete myObject; } else { // 無法獲取接口 } // 卸載DLL FreeLibrary(hModule); } else { // 無法加載DLL } return 0; }
其中typedef MyInterface* (*CreateMyObjectFunc)();聲明了MyInterface*函數指針的函數CreateMyObjectFunc,并且沒有參數,我們可以用CreateMyObjectFunc代替返回值為MyInterface*的函數的聲明。具體如下:
以上就是C++制作DLL文件的方法詳解的詳細內容,更多關于C++制作DLL文件的資料請關注腳本之家其它相關文章!
相關文章
C++ new與malloc和delete及free動態(tài)內存管理及區(qū)別介紹
這篇文章主要介紹了深入理解C++中的new/delete和malloc/free動態(tài)內存管理,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-12-12