C++11实用技术(五)泛型编程加载dll接口函数
C++11泛型编程简化加载dll代码
常见的加载dll方式:
HMODULE m_hDataModule;
m_hDataModule = LoadLibrary("myDll.dll");typedef int (*PfunA)(int a, int b);//定义函数指针
PfunA fun = (PfunA)(GetProcAddress(m_hDataModule , "funA"));//加载接口
int ret = fun(1, 2);//执行函数
加载dll中的函数需要分为3步:
- 1.定义函数指针
- 2.从dll中加载接口
- 3.执行函数
3步看起来不多,但是如果加载上百个这样的函数,那就非常繁琐,可能会遇到重复命名、参数定义不一致等各种问题。
C++11提供了方法可以通过泛型编程的方式,提供一个加载执行dll接口函数的通用函数。
示例代码如下:
std::map<string, FARPROC> _funcMap;
HMODULE _dataModule;template <typename T>
std::function<T> LoadFunction(const string& functionName)
{auto it = _funcMap.find(functionName);if (it == _funcMap.end()){auto addr = GetProcAddress(_dataModule, functionName.c_str());if (!addr) return nullptr;_funcMap.insert(std::make_pair(functionName, addr));it = _funcMap.find(functionName);}return std::function<T>((T*)(it->second));
}
template <typename T, typename... Args>
typename std::result_of<std::function<T>(Args...)>::type ExcuteFunc(const string& funcName, Args&&... args)
{auto func = LoadFunction<T>(funcName);if (func == nullptr){std::cout << "Load " << funcName << " error!" << std::endl;}return func(std::forward<Args>(args)...);
}int main()
{_dataModule = LoadLibrary("myDll.dll");//一行代码即可加载并执行接口,并且支持各种类型的接口函数int funA = ExcuteFunc<int(int, int)>("funA", 1, 2);//有两个入参,返回int类型bool funB = ExcuteFunc<bool(int)>("funB", 1);//有一个入参,返回bool类型ExcuteFunc<void()>("funC");//没有入参,也没有返回值return 0;
上述加载dll过程分为两个函数:
- 一个是LoadFunction函数,通过泛型编程提供加载dll中的函数指针。
- 一个ExcuteFunc函数,用于执行加载后的函数。
LoadFunction
LoadFunction 函数用于加载函数指针。
它接受一个 functionName 参数,表示要加载的函数名。
首先,它在 _funcMap 中查找是否已经加载了该函数指针,如果找到了就直接返回。如果没有找到,则使用 GetProcAddress 函数从 _dataModule 中获取函数指针的地址,并将其插入到 _funcMap 中缓存起来。
最后,返回一个 std::function<T> 对象,其中 T 是函数指针的类型。
template <typename T>
std::function<T> LoadFunction(const string& functionName)
{auto it = _funcMap.find(functionName);if (it == _funcMap.end()){auto addr = GetProcAddress(_dataModule, functionName.c_str());if (!addr) return nullptr;_funcMap.insert(std::make_pair(functionName, addr));it = _funcMap.find(functionName);}return std::function<T>((T*)(it->second));
}
注意使用
auto addr = GetProcAddress(_dataModule, functionName.c_str());
得到的addr类型只是一个输入参数为空,void*返回值类型的函数类型,所以说它是不能直接使用的。我们会在后面的代码中将加载的函数指针转换为对应的函数指针类型。如何去转换就是本文最核心的点。
在函数最后返回值的时候
return std::function<T>((T*)(it->second));
作用是将 it->second(函数指针的地址)强制转换为类型为 T 的函数指针(T就是我们具体的函数指针类型),并使用 std::function 对象进行封装。
ExcuteFunc
ExcuteFunc 函数用于执行加载的函数。它接受一个 funcName 参数,表示要执行的函数名,以及可变参数 args,表示函数的实际参数。首先,它调用 LoadFunction 函数来加载函数指针。如果加载失败(即函数指针为空),则输出错误信息。然后,使用加载的函数指针 func 调用 std::function 对象,传递给定的参数,并返回执行结果。
template <typename T, typename... Args>
typename std::result_of<std::function<T>(Args...)>::type ExcuteFunc(const string& funcName, Args&&... args)
{auto func = LoadFunction<T>(funcName);if (func == nullptr){std::cout << "Load " << funcName << " error!" << std::endl;}return func(std::forward<Args>(args)...);
}
函数中
typename std::result_of<std::function<T>(Args...)>::type ExcuteFunc(const string& funcName, Args&&... args)
用到一个traits技巧result_of,用来获取函数的返回值类型。
相关文章:
C++11实用技术(五)泛型编程加载dll接口函数
C11泛型编程简化加载dll代码 常见的加载dll方式: HMODULE m_hDataModule; m_hDataModule LoadLibrary("myDll.dll");typedef int (*PfunA)(int a, int b);//定义函数指针 PfunA fun (PfunA)(GetProcAddress(m_hDataModule , "funA"));//加载…...
使用wxPython和PyMuPDF提取PDF页面指定页数的内容的应用程序
在本篇博客中,我们将探讨如何使用wxPython和PyMuPDF库创建一个简单的Bokeh应用程序,用于选择PDF文件并提取指定页面的内容,并将提取的内容显示在文本框中。 C:\pythoncode\new\pdfgetcontent.py 准备工作 首先,确保你已经安装了…...
k8s的pv和pvc创建
//NFS使用PV和PVC 1、配置nfs存储 2、定义PV 实现 下图的pv和pvc测试 pv的定义 这里定义5个PV,并且定义挂载的路径以及访问模式,还有PV划分的大小 vim /pv.yamlapiVersion: v1 kind: PersistentVolume metadata:name: pv001 spec:capacity:storage: …...
记K8S集群工作节点,AnolisOS 8.6部署显卡驱动集成Containerd运行时
1、安装gcc #安装编译环境 yum -y install make gcc gcc-c2、下载显卡驱动 点击 直达连接 nvidia高级搜索下载历史版本驱动程序(下载历史版本驱动) https://www.nvidia.cn/Download/Find.aspx?langcn3、安装驱动 安装显卡驱动 ./NVIDIA-Linux-x86…...
JavaScript 性能优化
优化JavaScript代码的性能是开发过程中的一个关键任务,它可以显著提升网站或应用的用户体验。以下是一些优化技巧,涵盖了减少重绘、减少内存占用和合并网络请求等方面: 1. **减少重绘和重排:** - **使用 CSS3 动画:…...
架构演进及常用架构
1架构演进及常用架构 1.1单体分层架构 1.2 多应用微服务架构 1.3 分布式集群部署 部署 CDN 节点: 用户访问量的增加意味着用户地域的分散请求,如果所有请求都直接发送中心服务器的话,距离越远,响应速度越差,这时就需…...
WinCC V7.5 中的C脚本对话框不可见,将编辑窗口移动到可见区域的具体方法
WinCC V7.5 中的C脚本对话框不可见,将编辑窗口移动到可见区域的具体方法 由于 Windows 系统更新或使用不同的显示器,在配置C动作时,有可能会出现C脚本编辑窗口被移动到不可见区域的现象。 由于该窗口无法被关闭,故无法进行进一步…...
【实战】十一、看板页面及任务组页面开发(二) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十四)
文章目录 一、项目起航:项目初始化与配置二、React 与 Hook 应用:实现项目列表三、TS 应用:JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…...
Vue2.7.14、vuecli@5.0.8 升级 vite@4.4.8
项目背景 Vue2.7.14、vuecli5.0.8、element-ui2.15.13、node14.18.3 vite安装 pnpm add vite4.4.8 -D 入口文件index.html 文件位置修改 将pulic里的index.html移到根目录下 根目录/public/index.html 到 根目录/index.html 文件内容修改 <link rel"icon"…...
LeetCode[面试题04.12]求和路径
难度:Medium 题目: 给定一棵二叉树,其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径的数量。注意,路径不一定非得从二叉树的根节点或叶节点开始或结束&#x…...
骑行运动耳机哪款好?五年骑行爱好者给你分享分享
作为一名骑行达人,我尝试过多种骑行耳机,有入耳式、耳罩式、骨传导等等,但总有一款让我特别满意。直到我遇到了这几款耳机,它不仅音质出色,而且非常适合骑行,让我爱不释手。下面,我将分享一下这…...
SpringBoot3集成ElasticSearch
标签:ElasticSearch8.Kibana8; 一、简介 Elasticsearch是一个分布式、RESTful风格的搜索和数据分析引擎,适用于各种数据类型,数字、文本、地理位置、结构化数据、非结构化数据; 在实际的工作中,历经过Ela…...
详解23种设计模式优缺点以及解决方案
1. 单例模式(Singleton Pattern): 优点:确保一个类只有一个实例,提供全局访问点,节省资源。缺点:可能引入全局状态,难以扩展和测试。解决方法:使用依赖注入来替代直接访…...
Oracle 数据库中删除表空间的详细步骤与示例
系列文章目录 文章目录 系列文章目录前言一、查看表空间二、数据迁移和备份三、下线表空间中的对象四、删除表空间五、删除完成后的操作总结前言 在 Oracle 数据库中,表空间是存储数据的逻辑容器。有时候,我们可能需要删除不再使用的表空间以释放空间或进行数据库重组。本文…...
<kernel>kernel 6.4 笔记
<kernel>kernel 6.4 笔记 1、kernel 与用户层通信过程 (1) kernel 通过uevent事件 通知 用户层; 第一步:准备同事事件的参数键值对存到环境变量中; 第二步 :准备环境变量数据 ACTION、DEVPATH、SUBSYSTEM…...
介绍一些编程语言— Perl 语言
介绍一些编程语言— Perl 语言 Perl 语言 简介 Perl 是一种动态解释型的脚本语言。 最初的设计者为拉里・沃尔,它于 1987 1987 1987 年 12 12 12 月 18 18 18 日发表。Perl 借取了 C、sed、awk、shell scripting 以及很多其他编程语言的特性。其中最重要的特性…...
原型与继承
原型与继承 在 JavaScript 中,对象有一个特殊的隐藏属性 [[Prototype]](如规范中所命名的),它要么为 null,要么就是对另一个对象的引用。该对象被称为“原型。 当我们从 object 中读取一个缺失的属性时,Jav…...
Flink流批一体计算(14):PyFlink Tabel API之SQL查询
举个例子 查询 source 表,同时执行计算 # 通过 Table API 创建一张表: source_table table_env.from_path("datagen") # 或者通过 SQL 查询语句创建一张表: source_table table_env.sql_query("SELECT * FROM datagen&quo…...
JRebel插件扩展-mac版
前言 上一篇分享了mac开发环境的搭建,但是欠了博友几个优化的债,今天先还一个,那就是idea里jRebel插件的扩展。 一、场景回眸 这个如果在win环境那扩展是分分钟,一个exe文件点点就行。现在在mac环境就没有这样的dmg可以执行的&…...
C语言中常见的一些语法概念和功能
常用代码: 程序入口:int main() 函数用于定义程序的入口点。 输出:使用 printf() 函数可以在控制台打印输出。 输入:使用 scanf() 函数可以接收用户的输入。 条件判断:使用 if-else 语句可以根据条件执行不同的代码…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...
sshd代码修改banner
sshd服务连接之后会收到字符串: SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢? 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头,…...
