IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++11新特性的使用---可变模板参数、type_traits、function综合使用 -> 正文阅读

[C++知识库]c++11新特性的使用---可变模板参数、type_traits、function综合使用

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;
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 11:50:13  更:2022-04-04 11:54:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:48:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码