DLL帮助类
c++中手动调用dll是比较繁琐的,调用过程是:加载dll后还要定义一个对应的函数指针类型,接着调用GetProAddress获取函数地址,在转成函数指针,最后调用该函数如下例子:
#include "MyDLL.h"
#include <iostream>
#include <windows.h>
void TestDll()
{
typedef int(*pMax)(int a, int b);
typedef int(*pGet)(int a);
HINSTANCE hDLL = LoadLibrary("C:/Users/zsffuture/Desktop/cosmos-master/cpp11book/第三章/3-9/3-9/MyDll.dll");
if (hDLL == nullptr)
{
return;
}
pMax Max = (pMax)GetProcAddress(hDLL, "Max");
if (Max == nullptr)
{
return;
}
int ret = Max(5, 8);
pGet Get = (pGet)GetProcAddress(hDLL, "Get");
if (Get == nullptr)
{
return;
}
int ret2 = Get(5);
FreeLibrary(hDLL);
}
int main(void)
{
TestDll();
system("pause");
return 0;
}
上面的方法调用一个两个还好,如果调用上百个呢?因此通过c++11可以有效的降低复杂程度
使用c++11新特性,首先要把函数指针转换成一种函数对象或泛型函数,这里可以用std::function去做这个事情,即通过一个函数封装GetProcAddress,这样通过函数名称就能获取一个泛型函数std::function,希望这个function是通用的,不论dll中是什么函数都可以转换成这个function,最后调用这个通用的function就可以了。但是调用这个通用的function还有两个问题需要解决: 1)函数的返回值可能是不同类型,如何以一种通用的返回值来消除这种不同返回值导 致的差异呢? 2)函数的人参数目可能任意个数,且类型也不尽相同,如何来消除人参个数和类型的 差异呢?
返回值类型可以通过std::result_of<std::function<T>(Args...)>::type自动获取
参数可以使用可变参数模板进行解决,因此整体的解决方法如下:
#pragma once
#include <Windows.h>
#include <string>
#include <map>
#include <functional>
using namespace std;
class DllParser
{
public:
// 构造函数初始化dll句柄
DllParser():m_hMod(nullptr)
{
}
// 析构函数
~DllParser()
{
UnLoad();
}
//加载dll
bool Load(const string& dllPath)
{
// 获取句柄
m_hMod = LoadLibraryA(dllPath.data());
if (nullptr == m_hMod)
{
printf("LoadLibrary failed\n");
return false;
}
return true;
}
bool UnLoad()
{
//释放资源
if (m_hMod == nullptr)
return true;
auto b = FreeLibrary(m_hMod);
if (!b)
return false;
m_hMod = nullptr;
return true;
}
// 类模板参数,
template <typename T>
std::function<T> GetFunction(const string& funcName)
{
// 通过一个字典把从dll中加载进来的函数保存到字典中进行缓存,这样后面在使用时不用一直从dll加载
auto it = m_map.find(funcName);
if (it == m_map.end())// 如果搜索到最后说明没搜索到,那就需要继续加载
{
auto addr = GetProcAddress(m_hMod, funcName.c_str()); // 通过dll的句柄和需要加载额函数名称进行加载
// 获取到函数的地址后判断是否为空然后进行保存
if (!addr)
return nullptr;
m_map.insert(std::make_pair(funcName, addr)); // 把加载到的函数和地址进行保存
// 然后在进行查找
it = m_map.find(funcName);
}
// 把查找到的地址进程强制类型转换即 (T*) (it->second),然后返回function的函数对象
return std::function<T>((T*) (it->second));
}
// 总调用接口函数
template <typename T, typename... Args> //模板参,T是函数类型如int(int),后面该函数是返回类型是int,参数是int Args是可变参数
typename std::result_of<std::function<T>(Args...)>::type // 通过std::result_of推到返回的结果类型
ExcecuteFunc(const string& funcName, Args&&... args) // funcName具体的函数名称, args参数列表
{
// T是函数类型,funcName函数名称,获取到function类型的f后,把参数传入计算
auto f = GetFunction<T>(funcName);
if (f == nullptr)
{
string s = "can not find this function " + funcName;
throw std::exception(s.c_str());
}
// std::forward完美转发,即args是右转引用,通过完美转发后仍然是右转引用类型
return f(std::forward<Args>(args)...);
}
private:
HMODULE m_hMod;// dll的句柄
std::map<string, FARPROC> m_map; // FARPROC函数的句柄
};
#include "DllParser_orig.hpp"
#include <iostream>
void TestDllParser()
{
DllParser dllParser;
std::string str("MyDLL.dll");
dllParser.Load(str);
int a = 5;
int b = 8;
auto max = dllParser.ExcecuteFunc<int(const int&, const int&)>("Max", a, b);
auto add = dllParser.ExcecuteFunc<int(int&, int&)>("Add", a, b);
}
int main(void)
{
TestDllParser();
system("pause");
return 0;
}
|