一个简洁通用的调用DLL函数的帮助类
本次介绍一种调用dll函数的通用简洁的方法,消除了原来调用方式的重复与繁琐,使得我们调用dll函数的方式更加方便简洁。用过dll的人会发现c++中调用dll中的函数有点繁琐,调用过程是这样的:在加载dll后还要定义一个对应的函数指针类型,再调用GetProcAddress获取函数地址,再转成函数指针,最后调用该函数。下面是调用dll中Max和Get函数的例子。
void TestDll()
{
typedef int(*pMax)(int a,int b);
typedef int(*pGet)(int a);
HINSTANCE hMode =LoadLibrary("MyDll.dll");if(hMode==nullptr)
return;
PMax Max = (PMax)GetProcAddress(hDLL,"Max");
if(Max==nullptr)
return;
int ret =Max(5,8); //8
PMin Get = (PMin)GetProcAddress(hDLL,"Get");
if(Get==nullptr)
return;
int ret =Get(5); //5
FreeLibrary(hDLL);
}
这段代码看起来很繁琐,因为我没每用一个函数就需要先定义一个函数指针,然后再根据名称获取函数地址,最后调用。如果一个dll中有上百个函数的话,这种重复而繁琐的定义会让人吐的。其实获取函数地址和调用函数的过程是重复逻辑,应该消除,我不想每次都定义一个函数指针和调用GetProcAddress,我觉得可以用一种简洁通用的方式去调用dll中的函数。我希望调用dll中的函数就像调用普通的函数一样,即传入一个函数名称和函数的参数就可以实现函数的调用了。就类似于:
Ret CallDllFunc(const string&funName, T arg)
如果以这种方式调用的话,我就能避免繁琐的函数指针定义以及反复的调用GetProcAddress了。
一种可行的解决方案
如果要按照
Ret CallDllFunc(const string& funName, T arg)
这种方式调用的话,首先我要把函数指针转换成一种函数对象或者泛型函数,这里我们可以用std::function去做这个事情,即通过一个函数封装GetProcAddress,这样通过函数名称我就能获取一个泛型函数std::function,我希望这个function是通用的,不论dll中是什么函数都可以转换成这个function, 最后调用这个通用
的function就可以了。但是调用这个通用的function还有两个问题需要解决:
- 不同函数的不同类型返回值怎么处理,因为函数的返回值可能是某些类型,如何以一种通用的返回值来消除这种不同返回值导致的差异呢?
- 函数的入参数目可能任意个数,且类型也不尽相同,如何来消除入参个数和类型的差异呢?
我们一个个解决问题吧,首先看看如何封装GetProcAddress,将函数指针转换成std::function。通过如下代码就可以了。
template <typename T>
std::function<T> GetFunction(const string&funcName)
{
FARPROC funAddress = GetProcAddress(m_hMod, funcName.c_str());
return std::function<T>((T*)(funAddress));
}
其中T是std::function的模板参数,即函数类型的签名。如果我们要获取上面例子中,Max和Get函数,则可以这样获取:
auto fmax = GetFunction<int(int, int)>("Max");
auto fget = GetFunction<int(int)>("Get");
这种方式比之之前先定义函数指针再调用GetProcAddress的方式更简洁通用。
再看看如何解决函数返回值和入参不统一的问题,关于这个问题,其实在前面的博文中就讲到了,不知道的童鞋看这里:
是的,还是通过result_of和可变参数模板来搞定。最终的调用函数是这样的:
template <typename T, typename... Args>
typename std::result_of<std::function<T>(Args...)>::type ExcecuteFunc(const string& funcName,Args&&... args)
{
return GetFunction<T>(funcName)(args...);
}
上面的例子中要调用Max和Get函数,这样就行了:
auto max = ExcecuteFunc<int(int, int)>("Max", 5, 8);
auto ret = ExcecuteFunc<int(int)>("Get", 5);
怎么样,比之之前的调用方式是不是简洁直观多了,没有了繁琐的函数指针的定义,没有了反复的调用GetProcAddress及其转换和调用。
最后看看完整的代码吧。
#include <Windows.h>
#include <string>
using namespace std;
class DllParser
{
public:
DllParser()
{
}
~DllParser()
{
UnLoad();
}
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 false;
auto b = FreeLibrary(m_hMod);
if (!b)
return false;
m_hMod = nullptr;
return true;
}
template <typename T>
std::function<T> GetFunction(const string&funcName)
{
FARPROC funAddress = GetProcAddress(m_hMod, funcName.c_str());
return std::function<T>((T*)(funAddress));
}
template <typename T, typename... Args>
typename std::result_of<std::function<T>(Args...)>::type ExcecuteFunc(const string& funcName,Args&&... args)
{
return GetFunction<T>(funcName)(args...);
}
private:
HMODULE m_hMod;
};
c++11 boost技术交流群:296561497,欢迎大家来交流技术。
一个简洁通用的调用DLL函数的帮助类的更多相关文章
- (原创)一个简洁通用的调用DLL函数的帮助类
本次介绍一种调用dll函数的通用简洁的方法,消除了原来调用方式的重复与繁琐,使得我们调用dll函数的方式更加方便简洁.用过dll的人会发现c++中调用dll中的函数有点繁琐,调用过程是这样的:在加载d ...
- 在 C++Builder 工程里调用 DLL 函数
调用 Visual C++ DLL 给 C++Builder 程序员提出了一些独特的挑战.在我们试图解决 Visual C++ 生成的 DLL 之前,回顾一下如何调用一个 C++Builder 创建的 ...
- 动态调用DLL函数有时正常,有时报Access violation的异常
动态调用DLL函数有时正常,有时报Access violation的异常 typedef int (add *)(int a,int b); void test() { hInst=LoadL ...
- c++ 调用DLL函数,出现错误
c++ 调用DLL函数,出现错误 Run-Time Check Failure #0 - The value of ESP was not properly saved across a funct ...
- C++利用模板在Windows上快速调用DLL函数
更新日志 --------- 2021/08/01 更新V2.2 增加 GetHmodule 函数 - 允许用户获取HMODULE以验证加载DLL是否成功. 2021/08/03 更新V2.3 增加 ...
- 一个简洁的PHP可逆加密函数(分享)
http://www.jb51.net/article/38018.htm 本篇文章是对一个简洁的PHP可逆加密函数进行了详细的分析介绍,需要的朋友参考下 很多时候我们需要对数据进行加密解密,比如 ...
- GO语言 -- 调用DLL函数,填平所有的坑,最详尽攻略
编译dll文件(源代码c++):g++ -shared main.cpp -o test.dll set GOARCH=386 第一个DLL函数,第一个参数,要求传入一个指针,直接指向[]byte类型 ...
- QT创建与调用Dll方法(包括类成员)--显式调用
看网上的好多关于QT调用Dll的方法,大部分都是调用函数的,并没有调用C++类成员的情况,即使是有,比如说: 使用Qt编写模块化插件式应用程序 Qt 一步一步实现dll调用(附源码)---(这一篇里没 ...
- C++生成dll以及调用(函数)和类
C++新手,方法可能有很多,此方法仅仅是自己实验并可行,详细步骤如下: 生成dll文件和lib文件: (1) 新建项目-windows桌面向导,选择动态链接.dll以及空项目: (2)复制代码(头文件 ...
随机推荐
- LA 3135 (优先队列) Argus
将多个有序表合并成一个有序表就是多路归并问题,可用优先队列来解决. #include <cstdio> #include <queue> using namespace std ...
- linux 下 NetBeans 字体大小设置
在linux mint 12下安装了 NetBeans7.1.2使用之后,觉得字体不好看,字体普遍特别大,分三个方面改NetBeans的字体. 1. 代码字体大小 点击NetBeans菜单,工具--& ...
- IO负载高的来源定位
前言: 在一般运维工作中经常会遇到这么一个场景,服务器的IO负载很高(iostat中的util),但是无法快速的定位到IO负载的来源进程和来源文件导致无法进行相应的策略来解决问题. 这个现象在MySQ ...
- hdu 2818 Building Block(加权并查集)2009 Multi-University Training Contest 1
题意: 一共有30000个箱子,刚开始时都是分开放置的.接下来会有两种操作: 1. M x y,表示把x箱子所在的一摞放到y箱子那一摞上. 2. C y,表示询问y下方有多少个箱子. 输入: 首行输入 ...
- 未能加载文件或程序集“Oracle.DataAccess, Version=2.112.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342"
转载自原文 未能加载文件或程序集"Oracle.DataAccess, Version=2.112.1.0,..." 若本机的Oracle版本是32位系统,则在调用Oracle数据 ...
- codeforces 691F Couple Cover 暴力
分析:开一个300w的数组,统计,然后nlogn统计每个值在在序对第一个出现有多少种情况 时间复杂度:O(nlogn) n在3e6数量级 #include<cstdio> #include ...
- HDU-4632 http://acm.hdu.edu.cn/showproblem.php?pid=4632
http://acm.hdu.edu.cn/showproblem.php?pid=4632 题意: 一个字符串,有多少个subsequence是回文串. 别人的题解: 用dp[i][j]表示这一段里 ...
- 《浅析各类DDoS攻击放大技术》
原文链接:http://www.freebuf.com/articles/network/76021.html FreeBuf曾报道过,BT种子协议家族漏洞可用作反射分布式拒绝服务攻击(DRDoS a ...
- 限制su权限
1. 修改用户的组为wheel组 2. 修改PAM配置文件 修改PAM的配置文件,使得只有属于wheel组的用户才能使用su命令 去掉此处的注释即可: 3. 测试 当不属于wheel组的时候,即 ...
- Linux中MySQL5.5解压版普通用户安装
#查看本机mysql 安装路径 [hadoop@SY-0134 toolkit]$ rpm -qa|grep -i mysql [hadoop@SY-0134 toolkit]$ whereis my ...