当前位置: 首页 > article >正文

Windows上工程组织方式 --- dll插件式

一个工程需要分模块开发,各个模块以动态链接库或者共享库的形式存在是一种比较好的选择
使用动态库开发,软件编译后的体积比静态库较小,运行时占用内存也会相对较少。
对于软件的线上更新动态库会更加方便,特别是客户端软件,模块的更新只要下载新的动态库即可。
下面是一个简单的示例
main.cpp

#include <list>
#include <iostream>
#include <tuple>
#include <cassert>
#include <Windows.h>

#include "plugin_interface.h"

int main()
{
	std::list<std::pair<HMODULE, iplugin*>> plugins;
	GlobalEnv env;
	const char* plugin_paths[] = { "Plugin1.dll","Plugin2.dll" };
	for (const auto* path : plugin_paths)
	{
		HMODULE handle = LoadLibraryA(path);
		assert(handle != nullptr);

		plugin_reg_init_t reg_init = (plugin_reg_init_t)GetProcAddress(handle, kFNamePluginRegInit);
		auto* plugin = reg_init(&env);
		plugins.emplace_back(handle, plugin);
	}


	//...



	for (auto& [handle, plugin] : plugins)
	{
		plugin_reg_release_t reg_release = (plugin_reg_release_t)GetProcAddress(handle, kFNamePluginRegRelease);
		reg_release(plugin);
	}

	exit(EXIT_SUCCESS);
}


通过LoadLibraryA 将动态库加载进来,约定每个库都有一个注册函数,取消注册函数,注册函数进行一些初始化操作,可以把全局对象传入到模块中,各个模块之间可以能通过一个全局对象进行通信。

Plugin1的dllmain.cpp

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain(HMODULE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

#include "plugin_interface.h"
#include "MainObj.h"

extern "C" _declspec(dllexport)
iplugin* plugin_reg_init(GlobalEnv* env)
{
	return new MainObj(env);
}

extern "C" _declspec(dllexport)
void plugin_reg_release(iplugin* plugin)
{
	delete plugin;
}

在MainObj中编写各个模块的业务功能代码。

plugin_interface.h 是接口定义

#ifndef __PLUGIN_INTERFACE_H__
#define __PLUGIN_INTERFACE_H__

#include "global_env.h"

class iplugin {
public:
	explicit iplugin(GlobalEnv* env) :envPtr_(env) {}
	virtual ~iplugin() {}

protected:
	GlobalEnv* envPtr_;
};

#endif // !__PLUGIN_INTERFACE_H__

GlobalEnv 是全局类

#ifndef __GLOBAL_ENV_H__
#define __GLOBAL_ENV_H__

class iplugin;

class GlobalEnv
{
};

constexpr const char* kFNamePluginRegInit = "plugin_reg_init";
constexpr const char* kFNamePluginRegRelease = "plugin_reg_release";

typedef iplugin* (*plugin_reg_init_t)(GlobalEnv*);
typedef void (*plugin_reg_release_t)(iplugin*);

#endif // !__GLOBAL_ENV_H__

运行后输出如下

1 MainObj init
Plugin2 mainobj init
1 MainObj release
Plugin2 mainobj release

http://www.kler.cn/a/536506.html

相关文章:

  • C# 异常处理
  • QUIC 与 UDP 关系
  • 人人皆可创建自己的AI应用:DigitalOcean GenAI平台正式上线
  • DeepSeek回答禅宗三重境界重构交易认知
  • mac 安装 dotnet 环境
  • 如何在Arduino上使用NodeMCU
  • 本地缓存怎么保证数据一致性?
  • pikachu[皮卡丘] 靶场全级别通关教程答案 以及 学习方法 如何通过渗透测试靶场挑战「pikachu」来精通Web渗透技巧? 一篇文章搞完这些问题
  • 高级测试工程师,在数据安全方面,如何用AI提升?DeepSpeek的回答
  • iOS pod install一直失败,访问github超时记录
  • LabVIEW位移测量系统
  • 06vue3实战-----项目开发准备
  • windows部署本地deepseek
  • arkui-x 鼠标切换为键盘,焦点衔接问题
  • 【实战篇】DeepSeek + Cline 编程实战:从入门到“上头”
  • STM32上部署AI的两个实用软件——Nanoedge AI Studio和STM32Cube AI
  • 流媒体缓存管理策略
  • Python的那些事第十四篇:Flask与Django框架的趣味探索之旅
  • 阿里云cdn怎样设置图片压缩
  • 【Spring】_SpringBoot配置文件
  • Jetpack ViewModel
  • grafana面板配置opentsdb
  • 大模型deepseek-r1 本地快速搭建
  • 3D展示已成趋势,哪些产品适合3D交互展示?
  • 不用调试器,如何定位“Hard Fault”?
  • 用户点击商品埋点的实现方案