本文只是記載下學習C++動態鏈接庫的過程以及記錄學習過程中的一些程序,好開始。
先用VS2010創建一個dll的工程,好,只看圖不說話,點擊finish就完成創建了。。。
創建頭文件developer_dll.h和源代碼developer_dll.cpp兩個文件,裏面可以寫你喜歡的函數以及類。
以下是我的.h和.cpp文件代碼:
developer_dll.h:
#pragma once
#ifdef dev_dll_api
#else
#define dev_dll_api _declspec(dllimport)
#endif
namespace developer_dll_namespace
{
dev_dll_api void add(int a, int b);
dev_dll_api void subtract(int a, int b);
class dev_dll_api developer_dll_class
{
public:
void class_add(int a, int b);
void class_subtract(int a, int b);
protected:
private:
int x;
int y;
};
}
developer_dll.cpp:
#include <iostream>
#define dev_dll_api _declspec(dllexport)
#include "developer_dll.h"
namespace developer_dll_namespace
{
void add(int a, int b)
{
std::cout<<"兩者之和(調用普通函數):"<<a+b<<std::endl;
}
void subtract(int a, int b)
{
std::cout<<"兩者之差(調用普通函數):"<<((a>b)?(a-b):(b-a))<<std::endl;
}
void developer_dll_class::class_add(int a, int b)
{
std::cout<<"兩者之和(調用類的成員函數):"<<a+b<<std::endl;
}
void developer_dll_class::class_subtract(int a, int b)
{
x = a;
y = b;
std::cout<<"兩者之差(調用類的成員函數):"<<((x>y)?(x-y):(x-y))<<std::endl;
}
}
好,搞定這兩個就可以build生成.lib以及.dll文件了,看圖:
然後就可以創建使用者的.h文件和.cpp文件來加載dll,在程序中加載DLL有兩種方法,分別爲隱式鏈接和動態加載dll,隱式鏈接需要(.lib、.dll、.h)文件,動態加載dll只需(.dll)文件就可以了。
1、然後下面先以隱式鏈接測試:
創建源代碼user_dll.cpp來測試dll。
將(.lib、.dll、.h)文件複製進來並且創建相應的文件夾。
在這裏將lib的路徑加進去,不然編譯鏈接會出錯。
下面是我的user_dll.cpp:
#include <iostream>
#include <Windows.h>
#include "developer_dllh/developer_dll.h"
#pragma comment(lib, "developer_dll.lib")
using namespace std;
using namespace developer_dll_namespace;
int main()
{
add(2,3);
subtract(2,3);
developer_dll_class users;
users.class_add(2,3);
users.class_subtract(2,3);
system("pause");
return 0;
}
運行測試一把:我的結果是這樣的:
那如果我們只想導出類的部分函數要怎麼導出:
這裏我們可以利用depends這個軟件來查看dll導出了哪些函數:
這裏爲什麼函數名會是這樣子呢,主要是C++爲了實現重載實現了函數傾軋,函數名就按照一定的規則發生的變化,只要都是C++是可以正常調用的。如果要用C語言調用dll,就要添加extern “C”,但是它不能用於導出類的成員函數。如果是給其他語言調用則使用extern “C”也沒有卵用。要避免這個問題就得使用模塊定義文件.def,待會就測試這個怎麼使用。
add(2,3);
subtract(2,3);
developer_dll_class users;
users.class_add(2,3);
//users.class_subtract(2,3); 這個成員函數沒有導出,所以不能用了。
system("pause");
return 0;
好我們測試一把:
2、好下面來實現動態鏈接dll:
這裏需要用到幾個函數:
LoadLibrary:
[格式]:
- function LoadLibrary(LibFileName : PChar): Thandle;
[功能]:加載由參數 LibFileName 指定的 DLL 文件。
如果函數操作成功,將返回裝載 DLL 庫模塊的實例句柄,否則,將返回一個錯誤代碼。假如在應用程序中用 LoadLibrary 函數裝入某一個 DLL 前, 其他應用程序已把該 DLL 裝入內存中了,則系統將不再裝入該 DLL 的另一個實例,而是使該 DLL 的“引用計數”加 1 。
GetProAccess:
[格式]:
- function GetProcAddress(Module:Thandle; ProcName:PChar): TfarProc;
int main()
{
HMODULE load_ex = LoadLibrary(_T("developer_dll.dll"));//返回一個句柄
if (load_ex)
{
addprt add = (addprt)GetProcAddress(load_ex,"?add@developer_dll_namespace@@YAXHH@Z");
if (add)
{
add(2,3);
}
subtractprt subtract = (subtractprt)GetProcAddress(load_ex,"?subtract@developer_dll_namespace@@YAXHH@Z");
if (subtract)
{
subtract(2,3);
}
}
如果該函數執行成功,則返回 DLL 中由參數 ProcName 指定的過程或函數的入口地址,否則返回 nil 。
FreeLibrary:
[功能]:返回參數 Module 指定的模塊中,由參數 ProcName 指定的過程或函數的入口地址。
[格式]:
- procedure FreeLibrary(Module: Thandle);
[說明]:將由參數 Module 指定的 DLL 文件從內存中卸載 1 次。
[說明]:Module 爲 DLL 庫的句柄。這個值由 LoadLibrary 返回。由於 DLL 在內存中只裝載一次,因此調用 FreeLibrary 首先使 DLL 的引用計數減 1,如果計數減爲 0 則卸載該 DLL。
上面函數說明是從這裏摘下來的,感興趣可以去閱讀https://www.cnblogs.com/westsoft/p/5936092.html
現在測試以導出文件(.def)的方式導出dll,在工程裏面添加.def文件。
下面是我的源文件:
//.cpp文件
#include <iostream>
#include "developer_dllmd.h"
namespace developer_dll_namespace
{
void add(int a, int b)
{
std::cout<<"兩者之和(調用普通函數):"<<a+b<<std::endl;
}
void subtract(int a, int b)
{
std::cout<<"兩者之差(調用普通函數):"<<((a>b)?(a-b):(b-a))<<std::endl;
}
#if 0
void developer_dll_class::class_add(int a, int b)
{
std::cout<<"兩者之和(調用類的成員函數):"<<a+b<<std::endl;
}
void developer_dll_class::class_subtract(int a, int b)
{
x = a;
y = b;
std::cout<<"兩者之差(調用類的成員函數):"<<((x>y)?(x-y):(y-x))<<std::endl;
}
#endif
}
//.h文件
#pragma once
namespace developer_dll_namespace
{
void add(int a, int b);
void subtract(int a, int b);
#if 0
class developer_dll_class
{
public:
void class_add(int a, int b);
void class_subtract(int a, int b);
protected:
private:
int x;
int y;
};
#endif
}
//.def文件
LIBRARY "developer_dllmd"
EXPORTS
add @1
export_subtract=subtract @2
下面編寫user函數實現動態調用:
#include <iostream>
#include <Windows.h>
#include <tchar.h>
#include <winuser.h>
using namespace std;
typedef void (*addprt)(int a, int b);
typedef void (*subtractprt)(int a, int b);
int main()
{
HMODULE load_ex = LoadLibraryA("developer_dllmd.dll");//返回一個句柄
if (load_ex)
{
addprt add = (addprt)GetProcAddress(load_ex,"add");
if (add)
{
add(2,3);
}
addprt add1 = (addprt)GetProcAddress(load_ex,MAKEINTRESOURCEA(1));
if (add1)
{
cout<<"通過序號調用:"<<"\t";
add1(2,3);
}
else
{
cout<<"獲取地址失敗"<<endl;
}
subtractprt subtract = (subtractprt)GetProcAddress(load_ex,"export_subtract");
if (subtract)
{
subtract(2,3);
}
subtractprt subtract1 = (subtractprt)GetProcAddress(load_ex,MAKEINTRESOURCEA(2));
if (subtract1)
{
cout<<"通過序號調用:"<<"\t";
subtract1(2,3);
}
}
FreeLibrary(load_ex);
system("pause");
return 0;
}
好測試一把,我們看下結果如何:
對於類的動態導出其實文中方法不太好,還有更好的方法下會解說。
好,文章到此結束,謝謝觀看,歡迎提問,共同討論和提高。