C++插件管理类(下)——实际项目(阉割版)

news2024/11/26 2:52:32

文章目录

  • 一、背景
  • 二、代码结构
  • 三、两个CMakeLists.txt
    • 3.1 父目录
    • 3.2 子目录src
  • 四、代码实例
    • 4.1 main.cpp
    • 4.2 Plugin.h
    • 4.3 Plugin.cpp
    • 4.4 Comm.h
    • 4.5 calc.cpp
  • 五、 踩坑点

一、背景

请参考C++插件管理类(上)

二、代码结构

在这里插入图片描述

三、两个CMakeLists.txt

3.1 父目录

#设置cmake的最低版本
cmake_minimum_required(VERSION 3.10)
# Set CMAKE_SKIP_BUILD_RPATH to TRUE
# 设置工程的名称
project(PluginManagers)

# 设置库和可执行文件的输出目录
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

add_subdirectory(src)
# 将源代码添加到工程生成可执行文件
add_executable(PluginManagers main.cpp Plugin.h Plugin.cpp Comm.h)

3.2 子目录src

cmake_minimum_required(VERSION 3.0)
message("${CMAKE_BINARY_DIR}/${IDE_BIN_DIR}")
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${IDE_BIN_DIR})
add_library(calcu SHARED "calcu.cpp")

四、代码实例

4.1 main.cpp

#include<iostream>
#include <vector>
#include "Plugin.h"
#include "Comm.h"
using namespace std;
typedef int (*_add_function_)(int a, int b);
typedef int (*_sub_function_)(int a, int b);
int main()
{
	PluginMannager plug;
	if (FAILURE == plug.tuiLoadPlugin("calcu"))
	{
		cout << "Has No DLL" << endl;
	}
	void* func = nullptr;
	if (FAILURE == plug.getFunction(func, ADD_FUNCTION))
	{
		return false;
	}
	int Sum=((_add_function_)func)(1,2);
	cout << "Sum is:" << Sum << endl;

	if (FAILURE == plug.getFunction(func, SUB_FUNCTION))
	{
		return false;
	}
	int Sub= ((_sub_function_)func)(1, 2);
	cout << "Sub is:" << Sub << endl;
	return 0;
}

4.2 Plugin.h

#include<iostream>
#include <vector>
using namespace std;
typedef void* PluginHandle;
typedef struct PluginInterfaceInformatin
{
	string dllName = "";
	string version = "";
	string interfaceName = "";
	PluginHandle function = NULL;
	int type = -1;

}PluginInfo;

using PluginInfoVector = std::vector<PluginInfo>;

class Plugin
{
public:
	bool Init(const std::string& filename);
	bool Execute(void* &func, int type);
private:
	PluginHandle handle = nullptr;
	PluginInfoVector EntryVector;
};

class PluginMannager
{
public:
	/*加载插件*/
	bool tuiLoadPlugin(const std::string& filename);
	/*获取函数指针*/
	bool getFunction(void*& func, int type);
private:
	/*插件库*/
	std::vector<Plugin> pluginList;
};

4.3 Plugin.cpp

#include "Plugin.h"
#include "Comm.h"
#include <Windows.h>

bool Plugin::Init(const std::string& filename)
{
	PluginHandle handle = nullptr;
	handle = LoadLibrary(filename.c_str());
	if (handle == nullptr)
		return FAILURE;
	this->handle = handle;
	this->EntryVector.swap(*(PluginInfoVector*)GetProcAddress((HMODULE)handle, str(plugins)));
	return SUCCESS;
}

bool Plugin::Execute(void* &func, int type)
{
	for (auto& entry : this->EntryVector)
	{
		if(type == entry.type)
		{
			func = entry.function;
			return SUCCESS;
		}
	}
	return 0;
}

bool PluginMannager::tuiLoadPlugin(const std::string& filename)
{
	Plugin plug;
	if (FAILURE == plug.Init(filename))
	{
		return FAILURE;
	}
	this->pluginList.push_back(plug);
	return SUCCESS;
}

bool PluginMannager::getFunction(void*& func, int type)
{
	for (auto& plug : pluginList)
	{
		if (SUCCESS == plug.Execute(func, type))
		{
			return SUCCESS;
		}
		else
		{
			return FAILURE;
		}
	}
	return SUCCESS;
}

4.4 Comm.h

#if (_WIN32) || (_WIN64)
#define PLUGIN_EXPORT extern "C" _declspec(dllexport) 
#else
#define PLUGIN_EXPORT exter "C" 
#endif

typedef enum PLUGIN_FUN_TYPE
{
	ADD_FUNCTION = 0,
	SUB_FUNCTION
};

#define __data__ plugins

#define PLUGIN_DATA(...) PluginInfoVector __data__={__VA_ARGS__}

#define PLUGIN_DEFINE					 \
PLUGIN_EXPORT PluginInfoVector	__data__ ;\

#define str(e) #e

#define SUCCESS 0
#define FAILURE 1

4.5 calc.cpp

#include "../Plugin.h"
#include "../Comm.h"
PLUGIN_DEFINE

int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}

PLUGIN_DATA({ "calc", "1.0","add",(void*)add, ADD_FUNCTION }
,{ "calc", "1.0","sub",(void*)sub, SUB_FUNCTION });

五、 踩坑点

🎈:可执行文件和库文件需要再同一文件目录下:所以需要使用CMake宏去限定生成目录
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/585993.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

stackqueue的模拟实现

stack模拟&#xff1a; stack的源代码&#xff1a; stack的全部源代码就这些。 stack的代码少&#xff0c;原因在于采用了适配器模式&#xff0c;所谓适配器&#xff0c;以电器为例&#xff0c;每个电器都有电源适配器&#xff0c;中国的家用电源为220V的交流电&#xff0c;但是…

3d虚拟主播形象能提升提升企业销售额

随着科技的不断进步和发展&#xff0c;虚拟人形象正在被广泛地应用于商业宣传中。3D虚拟人形象是指采用计算机图形学、人工智能等技术&#xff0c;模拟真实人类形象的虚拟形象。相比于传统产品营销方式&#xff0c;采用3D虚拟人形象进行产品交互讲解对提升企业销售额具有很多优…

JavaWeb12(实现基础分页模糊查询的分页)

目录 一. 效果预览 ​编辑 二. 实现基本分页 2.1 分页sql --每页3条 取第二页 --由于伪列不能作用与大于符号也不能作用于between....and --因此需要将伪列----->名列 2.2 万能公式 2.3 首页&上一页&下一页实现 ②前端代码 2.4 末页实现&优化 ①底层代…

目标检测复盘 -- 6. YOLOv4

Backbone YOLOv4的骨干是CSPDarknet53 CSP结构的作用&#xff1a;1. 增强CNN的学习能力 2. 移出计算瓶颈 3. 减少内存开销 CSP首先将输入的特征层分成两个部分&#xff0c;这里以densenet为例&#xff0c;part2分支经过denseblock后&#xff0c;进过一个transition&#xff0c…

Redis之高可用方案浅析

在工程项目中&#xff0c;系统应用的高可用性越来越重要&#xff0c;业主越来越重视。其实高可用可以分为应用层高可用和数据层高可用&#xff0c;数据层高可用中常见的有关系型数据库mysql的高可用、非关系型NoSQl数据库redis的高可用等&#xff0c;下面聊聊典型的NoSQL数据库…

C# 事件和委托的区别并说明

1.区别 事件是基于委托的&#xff0c;为委托提供了一个发布/订阅机制。可以说事件是一种特殊的委托&#xff0c;他的调用和委托是一样的。 事件的声明 public event 委托类型 事件名称 通常事件的命名以事件名称Event来命名。如public event delegate NotifyEvent; 事件和委…

C++ Primer Plus 第二章习题

目录 复习题 1.C程序的模块叫什么&#xff1f; 2.#include 预处理器编译指令的用处&#xff1f; 3.using namespace std; 该语句是干什么用的&#xff1f; 4.什么语句可以打印一个语句"hello,world"&#xff0c;然后重新换行&#xff1f; 5.什么语句可以用来创…

桂院校园导航 导入 与 配置教程

将 静态项目/云开发项目 文件夹下最新版本的 文件夹下的 项目 的整个文件夹 复制到项目路径下&#xff08;比如 D:\WeChatProjects&#xff09;&#xff0c;强烈建议不要直接扔在桌面上 云开发项目 需开通 云开发 功能&#xff08;首月免费&#xff0c;次月19.9&#xff09;&am…

【论文阅读笔记】CRFL: Certifiably Robust Federated Learning against Backdoor Attacks

个人阅读笔记&#xff0c;如有错误欢迎指出! 会议&#xff1a;PMLR 2021[2106.08283] CRFL: Certifiably Robust Federated Learning against Backdoor Attacks (arxiv.org) 问题&#xff1a; 现有的防御算法缺乏健壮性 创新&#xff1a; 证明了所提出框架得稳定性 通过马尔…

Generative AI 新世界 | 走进文生图(Text-to-Image)领域

在之前的四篇 “Generative AI 新世界” 中&#xff0c;我们带领大家一起探索了生成式 AI&#xff08;Generative AI&#xff09;&#xff0c;以及大型语言模型&#xff08;LLMs&#xff09;的全新世界概览。并在文本生成&#xff08;Text Generation&#xff09;领域做了一些概…

javascript基础十:说说你对Javascript中this对象的理解

一、定义 函数的 this 关键字在 JavaScript 中的表现略有不同&#xff0c;此外&#xff0c;在严格模式和非严格模式之间也会有一些差别 在绝大多数情况下&#xff0c;函数的调用方式决定了 this 的值&#xff08;运行时绑定&#xff09; this 关键字是函数运行时自动生成的一…

进程控制与进程调度 —— 时间片轮转调度算法(C++版)

目录 实验一 进程控制与进程调度 一、实验目的 二、实验内容 三、数据结构及符号说明 四、运行环境说明 五、代码段 六、 效果展示 实验一 进程控制与进程调度 备注&#xff1a;大二&#xff08;下&#xff09;操作系统实验一 一、实验目的 掌握进程状态的转变、…

多次调用java.awt.Toolkit.getDefaultToolkit方法获得是同一个单例的Toolkit

多次调用java.awt.Toolkit.getDefaultToolkit方法获得是同一个单例的Toolkit java.awt.Toolkit.getDefaultToolkit()import java.awt.Toolkit;public class 多次调用Toolkit的getDefaultToolkit方法获得是同一个单例的Toolkit {static public void main (String...arguments)t…

WMS:系统窗口添加过程

WMS:系统窗口添加过程 1、经常使用的两大类窗口2、系统窗口StatusBar2.1 StatusBarWindowView添加流程2.2 简要时序图 android12-release 1、经常使用的两大类窗口 Android中的“窗口”类型有很多&#xff0c;经常使用的“窗口”大致分为两大类&#xff1a;一是&#xff0c;由系…

对于后端Linux的入门知识

为什么使用Linux 文章来自https://librehunt.org/&#xff0c;在这个网站里&#xff0c;你可以根据它提供的选项&#xff0c;最终选出适合你的Linux版本 It’s safe and private. No tracking. No company watching over you, no “big brother is watching you” nonsense. Ju…

article-三自由度机械臂运动学分析+仿真

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rOmeEm3I-1685366971102)(data:image/svgxml;utf8, )] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kCu0JrBB-1685366971103)(data:image/svgxml;utf8, )] 建立坐标系 1…

ROS:创建工作空间和编译功能包

目录 一、工作空间二、创建工作空间三、编译空代码的工作空间四、功能包五、创建功能包六、设置和检查环境变量七、功能包中的两个重要文件 一、工作空间 存放工程开发相关文件的文件夹。类似一个IDE&#xff08;例如Pycharm&#xff09;新建一个工程&#xff0c;就是一个工作…

权威认可!腾讯云EdgeOne入选Gartner® DDoS缓解方案市场指南

近日&#xff0c;Gartner发布《Market Guide for DDoS Mitigation Solutions》报告&#xff0c;腾讯云EdgeOne入选Gartner DDoS缓解方案市场指南。 “分布式拒绝服务&#xff08;DDoS&#xff09;缓解市场包括检测和缓解DDoS攻击并将其作为专用产品提供的供应商。它包括专业供…

有这个证书,网络安全工程师找工作不用愁

想要成为网络安全工程师&#xff0c;满足企业的用人要求。最基本的&#xff0c;你需要熟悉TCP/IP协议&#xff0c;熟悉sql注入原理和手工检测、熟悉内存缓冲区溢出原理和防范措施、熟悉信息存储和传输安全、熟悉数据包结构、熟悉Ddos攻击类型和原理。并且有一定的ddos攻防经验&…

I2C通信协议MPU6050

目录 I2C通信协议 硬件 软件 I2C时序 MPU6050 I2C通信协议 硬件 为了避免总线没协调好导致电源短路&#xff0c;配置为开漏输出&#xff0c;所有设备输出低电平不输出高电平&#xff0c;即右图。又为了避免高电平造成的引浮空&#xff0c;&#xff08;第三点&#xff09;总…