您现在的位置是:首页 >技术杂谈 >C++插件管理类(下)——实际项目(阉割版)网站首页技术杂谈

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

愿天堂没有C++ 2024-07-01 18:01:02
简介C++插件管理类(下)——实际项目(阉割版)

一、背景

请参考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宏去限定生成目录
在这里插入图片描述

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。