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();}//加载dllbool 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;
}

c++11新特性的使用---可变模板参数、type_traits、function综合使用相关推荐

  1. c++11新特性的使用---可变模板参数、lambda、type_traits、optional综合使用

    通过惰性求值类的实现综合采用了可变模板参数.lambda.type_traits.optional进行实现 该类功能是:当初始化某个对象时,该对象引用了一个大对象,这个对象的创建需要较长的时间,同时有 ...

  2. C++11新特性之泛型编程与模板

    模板 泛型编程 函数模板 普通函数模板 成员函数模板 函数模板重载 模板函数的特化 类模板 类模板中的成员函数模板 类模板的特化与偏特化 类模板成员特化 模板 Template所代表的泛型编程是C++ ...

  3. C++11新特性之 可变参数模板

    C++ 11的可变模版参数是其新增的最强大的特性之一.通过对参数进行了泛化,可以表示从0到任意个数.任意类型的参数.我们知道对于一个模板类来说,通常只能含固定数量的模版参数,可变模版参数无疑是一个巨大 ...

  4. C++11新特性选讲 语言部分 侯捷

    C++11新特性选讲 语言部分 侯捷 本课程分为两个部分:语言的部分和标准库的部分.只谈新特性,并且是选讲. 本文为语言部分笔记. 语言 Variadic Templates move semanti ...

  5. C++11新特性(原封不动转载待查)

    C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...

  6. C++11新特性总结

    目录 一. 统一的列表初始化 {}  适用于各种STL容器 二. 类型推导 auto 和 decltype的出现 三. 右值引用移动语义  (特别重要的新特性) 四.  万能引用  +  完美转发 五 ...

  7. 深入浅出之C++11新特性

    1. auto类型赋予新含义 1.1 auto类型定义 在之前的 C++ 版本中,auto 关键字用来指明变量的存储类型,它和 static 关键字是相对的.auto 表示变量是自动存储的,这也是编译 ...

  8. 《深入理解C++11:C++ 11新特性解析与应用》——导读

    前 言 为什么要写这本书 相比其他语言的频繁更新,C++语言标准已经有十多年没有真正更新过了.而上一次标准制定,正是面向对象概念开始盛行的时候.较之基于过程的编程语言,基于面向对象.泛型编程等概念的C ...

  9. C++11 新特性简介

    1.auto auto是旧关键字,在C++11之前,auto用来声明自动变量,表明变量存储在栈,很少使用.在C++11中被赋予了新的含义和作用,用于类型推断. auto关键字主要有两种用途:一是在变量 ...

最新文章

  1. 数据竞争(data race)问题分析的利器——valgrind的Helgrind
  2. centos php 局域网访问,CentOS8安装搭建php环境
  3. [推荐]SharePoint开发WebCast
  4. 【控制】《多智能体系统一致性协同演化控制理论与技术》纪良浩老师-第2章-周期间歇脉冲控制下多智能体系统一致性
  5. 在苏州的一个超级棒的事情
  6. P4774 [NOI2018]屠龙勇士
  7. java JFrame 设置背景颜色无效的理解
  8. mysql优化--叶金荣老师讲座笔记
  9. 【英语学习】【Daily English】U12 E-World L01 Do you have Wi-Fi here?
  10. CSS圆角兼容IE6
  11. 开发者工具——web前端助手
  12. php更换wordpress用户头像,WordPress用户头像不显示的解决方法
  13. SpringCloud之服务提供者和服务消费者
  14. 在JS中的数字存储问题
  15. 安卓使用MediaPlayer播放视频
  16. 2D物理引擎--谁碰了我的奶酪
  17. Markdown 中 LaTex 数学公式命令
  18. 抖音xg8404 X-Gorgon算法 IOS苹果协议算法
  19. 图像处理(一):傅里叶变换简单讲解
  20. android 判断安装微信,Android开发中判断手机是否安装了QQ或者微信

热门文章

  1. selenium web的自动化测试工具
  2. cout输出精确小数点
  3. CSDN在2017年度的若干“升级”
  4. 深度学习网络模型实战
  5. 为什么数据可视化很重要
  6. 大数据平台应用开发的痛点有哪些
  7. python占位符_Python(2)——Python的基础语句
  8. LADRC的学习——用simulink搭建仿真模型
  9. 如何在Windows环境下使用PyCharm开发PySpark
  10. python 获取当前目录,上级目录,上上级目录,N级目录