创建插件 DLL 项目

Step 1: 创建插件 DLL 项目

在 Visual Studio 中创建一个新的 DLL 项目,并添加以下文件和代码。

头文件:CShapeBase.h

 

cpp

复制代码

#pragma once #include <afxwin.h> // MFC 必需头文件 #include <string> #include <vector> #include "tinyxml.h" // 使用 TiXml 库的 XML 支持 #include "CxImage.h" // 使用 CxImage 库的图像处理支持 enum EDrawShape { RECTANGLE, CIRCLE, LINE }; // 示例绘制形状类型枚举 class CShapeBase { public: CShapeBase(EDrawShape nDrawShape); virtual ~CShapeBase(); virtual void Draw(CDC* pDC) = 0; virtual void InertRootItem(TiXmlElement* ItemElement, CString sItem, CString str); virtual void InertRootItem(TiXmlElement* ItemElement, CString sItem, int value); virtual void InertRootItem(TiXmlElement* ItemElement, CString sItem, float value); virtual void LoadDetPara(TiXmlElement* pDetElement); virtual void OnDrawResult(CDC* pDC); EDrawShape GetShapeType(); protected: EDrawShape m_nDrawShape; std::vector<CPoint> m_points; };

源文件:CShapeBase.cpp

 

cpp

复制代码

#include "CShapeBase.h" CShapeBase::CShapeBase(EDrawShape nDrawShape) : m_nDrawShape(nDrawShape) {} CShapeBase::~CShapeBase() {} void CShapeBase::InertRootItem(TiXmlElement* ItemElement, CString sItem, CString str) { ItemElement->SetAttribute(std::string(CT2A(sItem)).c_str(), std::string(CT2A(str)).c_str()); } void CShapeBase::InertRootItem(TiXmlElement* ItemElement, CString sItem, int value) { ItemElement->SetAttribute(std::string(CT2A(sItem)).c_str(), value); } void CShapeBase::InertRootItem(TiXmlElement* ItemElement, CString sItem, float value) { ItemElement->SetDoubleAttribute(std::string(CT2A(sItem)).c_str(), value); } void CShapeBase::LoadDetPara(TiXmlElement* pDetElement) { // 加载检测参数的示例实现 } void CShapeBase::OnDrawResult(CDC* pDC) { // 示例绘制结果 } EDrawShape CShapeBase::GetShapeType() { return m_nDrawShape; }

派生类:CSetDetDamage.h

 

cpp

复制代码

#pragma once #include "CShapeBase.h" class CSetDetDamage : public CShapeBase { public: CSetDetDamage(); void Draw(CDC* pDC) override; void OnDrawResult(CDC* pDC) override; };

派生类实现:CSetDetDamage.cpp

 

cpp

复制代码

#include "CSetDetDamage.h" CSetDetDamage::CSetDetDamage() : CShapeBase(RECTANGLE) {} void CSetDetDamage::Draw(CDC* pDC) { CRect rect(10, 10, 100, 100); pDC->Rectangle(rect); } void CSetDetDamage::OnDrawResult(CDC* pDC) { // 定义特定的绘图逻辑,例如检测结果 }

导出函数的实现:Plugin.cpp

 

cpp

复制代码

#include "pch.h" #include "CSetDetDamage.h" extern "C" __declspec(dllexport) CShapeBase* CreateShapeInstance() { return new CSetDetDamage(); } extern "C" __declspec(dllexport) void DestroyShapeInstance(CShapeBase* pInstance) { delete pInstance; } extern "C" __declspec(dllexport) EDrawShape GetShapeType(CShapeBase* pInstance) { return pInstance->GetShapeType(); }

主程序示例代码

在主程序中,可以通过动态加载 DLL,调用导出的创建和销毁函数。

 

cpp

复制代码

#include <afxwin.h> #include <Windows.h> #include <iostream> #include "CShapeBase.h" typedef CShapeBase* (*CreateShapeFunc)(); typedef void (*DestroyShapeFunc)(CShapeBase*); typedef EDrawShape (*GetShapeTypeFunc)(CShapeBase*); class CMainApp : public CWinApp { public: BOOL InitInstance() override { CWnd wnd; wnd.Create(NULL, _T("Main Window")); HMODULE hModule = LoadLibrary(L"YourPlugin.dll"); if (!hModule) { std::cerr << "Failed to load DLL" << std::endl; return FALSE; } CreateShapeFunc createShape = (CreateShapeFunc)GetProcAddress(hModule, "CreateShapeInstance"); DestroyShapeFunc destroyShape = (DestroyShapeFunc)GetProcAddress(hModule, "DestroyShapeInstance"); GetShapeTypeFunc getShapeType = (GetShapeTypeFunc)GetProcAddress(hModule, "GetShapeType"); if (createShape && destroyShape && getShapeType) { CShapeBase* pShape = createShape(); CDC* pDC = wnd.GetDC(); pShape->Draw(pDC); EDrawShape shapeType = getShapeType(pShape); std::cout << "Shape type: " << shapeType << std::endl; destroyShape(pShape); wnd.ReleaseDC(pDC); } FreeLibrary(hModule); return TRUE; } }; CMainApp theApp;

编译和运行步骤

  1. 插件 DLL:编译并生成 YourPlugin.dll 文件。
  2. 主程序:通过 LoadLibrary 动态加载 DLL,并调用导出函数创建 CSetDetDamage 实例,绘制形状并获取形状类型。

注意事项

  • DLL 和主程序的字符集(如 Unicode 或 ANSI)应保持一致。
  • 使用 tinyxmlCxImage 库时,请确保库文件正确配置。
  • 为提高健壮性,可以在 DLL 导出函数中加入错误检查和异常处理逻辑。

4o

您说:

如果有N个插件如何实现和管理

ChatGPT 说:

ChatGPT

记忆已更新

要管理和实现多个插件,可以采用插件管理器(Plugin Manager)模式。该模式能够动态加载、卸载、并调用不同的插件,以下是一个实现方法:

1. 插件接口定义

定义一个通用接口,所有插件需要实现这个接口。可以创建一个基类 IPlugin,包含每个插件应实现的虚函数:

 

cpp

复制代码

class IPlugin { public: virtual ~IPlugin() {} virtual void Initialize() = 0; // 初始化插件 virtual void Execute() = 0; // 执行插件操作 virtual void Shutdown() = 0; // 关闭插件 };

2. 插件管理器类

创建 PluginManager 类来管理多个插件。该类可以动态加载 DLL、存储已加载插件的实例,并调用相应的接口方法。

 

cpp

复制代码

#include <vector> #include <string> #include <Windows.h> class PluginManager { public: void LoadPlugin(const std::string& dllPath); void UnloadPlugins(); void ExecuteAllPlugins(); private: struct PluginHandle { HMODULE hModule; IPlugin* instance; }; std::vector<PluginHandle> plugins; }; void PluginManager::LoadPlugin(const std::string& dllPath) { HMODULE hModule = LoadLibrary(dllPath.c_str()); if (hModule) { typedef IPlugin* (*CreatePluginFunc)(); auto CreatePlugin = (CreatePluginFunc)GetProcAddress(hModule, "CreatePluginInstance"); if (CreatePlugin) { IPlugin* plugin = CreatePlugin(); plugin->Initialize(); plugins.push_back({hModule, plugin}); } else { FreeLibrary(hModule); } } } void PluginManager::UnloadPlugins() { for (auto& plugin : plugins) { plugin.instance->Shutdown(); delete plugin.instance; FreeLibrary(plugin.hModule); } plugins.clear(); } void PluginManager::ExecuteAllPlugins() { for (auto& plugin : plugins) { plugin.instance->Execute(); } }

3. 插件 DLL 实现

插件 DLL 文件中实现 IPlugin 接口,并提供 CreatePluginInstance 导出函数。

 

cpp

复制代码

#include "IPlugin.h" class SamplePlugin : public IPlugin { public: void Initialize() override { // 初始化代码 } void Execute() override { // 执行插件的主要功能 } void Shutdown() override { // 资源清理 } }; extern "C" __declspec(dllexport) IPlugin* CreatePluginInstance() { return new SamplePlugin(); }

4. 插件的加载和管理

在主程序中,创建 PluginManager 的实例并加载所需的插件:

 

cpp

复制代码

int main() { PluginManager manager; manager.LoadPlugin("PluginA.dll"); manager.LoadPlugin("PluginB.dll"); manager.ExecuteAllPlugins(); manager.UnloadPlugins(); return 0; }

管理多个插件

  • 每个插件都通过路径加载,插件管理器可以灵活管理插件的数量。
  • ExecuteAllPlugins() 函数可以调用所有加载的插件方法,可以根据需要增加更复杂的管理操作,例如按插件类型调用或异步执行。

4o

您说:

#include "CShapeBase.h"这类头文件,主程序和dll都是一个文件,是吗

ChatGPT 说:

ChatGPT

在插件架构中,通常 主程序插件 DLL会共享某些头文件,比如接口类(如 IPlugin)和基类(如 CShapeBase)的定义,以确保两者之间的接口和数据结构保持一致。

为实现共享:

  1. 公共头文件:将CShapeBase.h等通用接口头文件放在一个公共的包含目录中,主程序和 DLL 项目都可以访问该目录中的文件。
  2. 主程序和 DLL 的分离:主程序和 DLL 不应在同一个源文件中实现。一般而言:
    • 主程序:包含插件管理器(PluginManager),并动态加载 DLL。
    • DLL:实现插件的功能,并包含从公共头文件中继承的接口和基类(如 CShapeBase 的实现)。

目录结构示例

 

less

复制代码

ProjectRoot/ ├── include/ │ ├── CShapeBase.h // 通用接口和基类头文件 │ └── IPlugin.h // 插件接口定义 ├── main_program/ // 主程序代码目录 │ ├── PluginManager.cpp │ └── main.cpp └── plugins/ // 插件代码目录 ├── PluginA/ │ ├── PluginA.cpp │ └── PluginA.def // 导出符号定义 └── PluginB/ ├── PluginB.cpp └── PluginB.def // 导出符号定义

在这种结构下:

  • 头文件:主程序和插件都可以包含 include/ 目录中的公共头文件。
  • 编译:主程序和 DLL 项目独立编译,但共享接口定义和基类头文件。
  • 加载:主程序通过插件管理器加载不同 DLL 插件的实例。

编译配置

  1. 主程序:将 include/ 目录配置为包含目录。
  2. DLL 项目:也需包含 include/ 目录,并实现导出的工厂函数(如 CreatePluginInstance())。

这样设置后,主程序和 DLL 都可以访问和使用 CShapeBase 类的定义,实现独立编译但共享结构的插件架构。

优点

  1. 代码解耦:将 CDrawTool 放入 DLL 中可以减少主程序的代码量,使代码更易维护。
  2. 便于更新:如果需要对 CDrawTool 类进行修改或更新,可以仅更新 DLL,而不必重新编译整个主程序。
  3. 扩展性:将绘图功能放在插件中,可以方便地为主程序添加更多功能,例如不同类型的绘图工具等。

实现要点

CDrawTool 类放到 DLL 中后,主程序需要使用动态链接库来加载和调用该类。实现中需要注意以下几点:

  1. 导出类:在 DLL 中将 CDrawTool 类标记为导出(__declspec(dllexport)),以便主程序可以访问该类。

     

    cpp

    复制代码

    #ifdef DRAWTOOL_EXPORTS #define DRAWTOOL_API __declspec(dllexport) #else #define DRAWTOOL_API __declspec(dllimport) #endif class DRAWTOOL_API CDrawTool { // 类定义 };

  2. 动态加载和接口设计:在主程序中,可以使用工厂函数(例如 CreateDrawToolInstance)来动态创建 CDrawTool 实例。工厂函数需要导出,以便主程序可以通过该函数获得 CDrawTool 的实例。

  3. 对象传递:确保主程序将 CWndCDC 等窗口资源传递给 DLL 中的 CDrawTool 实例,这样它就可以在主程序的窗口上绘图。

  4. 依赖管理:主程序和插件之间的类和数据结构应尽量保持一致,例如 CShapeBase 类和 EDrawShape 枚举等。

调用示例

假设 DLL 中导出一个工厂函数:

 

cpp

复制代码

extern "C" DRAWTOOL_API CDrawTool* CreateDrawToolInstance();

主程序可以这样使用:

 

cpp

复制代码

typedef CDrawTool* (*CreateDrawToolFunc)(); HINSTANCE hInst = LoadLibrary("DrawTool.dll"); CreateDrawToolFunc createFunc = (CreateDrawToolFunc)GetProcAddress(hInst, "CreateDrawToolInstance"); CDrawTool* pDrawTool = createFunc(); pDrawTool->SetDrawWnd(pMainWnd); // 传入主窗口实例 // 使用其他方法

这样,CDrawTool 类的所有实现都在插件 DLL 中完成,主程序无需直接依赖类的具体实现。

4o

您说:

那主界面class CCVideoWnd : public CStatic类里面如何使用CDrawTool它

ChatGPT 说:

ChatGPT

记忆已更新

要在主界面类 CCVideoWnd 中使用 CDrawTool(如果 CDrawTool 已移到插件 DLL 中),可以通过以下方式实现:

  1. 加载 DLL 和获取 CDrawTool 实例:在 CCVideoWnd 中,动态加载包含 CDrawTool 的 DLL,并通过导出函数来创建 CDrawTool 对象的实例。

  2. 使用导出函数创建对象:假设 DLL 中有一个导出函数,例如 CreateDrawTool,可以通过该函数创建 CDrawTool 的实例。

     

    cpp

    复制代码

    typedef CDrawTool* (*LPFN_CREATEDRAWTOOL)(); HMODULE hModule = LoadLibrary(_T("YourPluginDLL.dll")); if (hModule) { LPFN_CREATEDRAWTOOL pfnCreateDrawTool = (LPFN_CREATEDRAWTOOL)GetProcAddress(hModule, "CreateDrawTool"); if (pfnCreateDrawTool) { m_pDrawTool = pfnCreateDrawTool(); } }

  3. 调用 CDrawTool 成员函数:在 CCVideoWnd 中可以像操作普通对象一样调用 CDrawTool 的方法,但要确保 CDrawTool 的接口是公开的且可通过 DLL 边界调用。

  4. 释放资源:在 CCVideoWnd 的析构函数中销毁 CDrawTool 实例,并释放 DLL。

     

    cpp

    复制代码

    if (m_pDrawTool) { delete m_pDrawTool; m_pDrawTool = nullptr; } FreeLibrary(hModule);

通过这种方式,CCVideoWnd 类可以调用 DLL 中的 CDrawTool,而无需直接将 CDrawTool 放在主程序里。

1、中文简繁互换:在简体中文和繁体中文之间进行转换。 2、进制转换:在二进制、八进制、十进制、十六进制之间相互转换。 3、人民币大小写互换:在Excel中,很多时候需要将小写的金额数字转换成大写,而Excel提供的函数转换出来的格式并不符合中国人的习惯,所以... 4、数字签名:对Excel表格中的内容进行签名保护,主要是防止提供者提供的内容被非法修改。可以用于Excel公文的电子签名,实现真正的无纸办公... 5、保存为图片文件:相当于Excel的照相机功能(有过之而无不及)。可以将Excel中的单元格区域、Shape对象、图片、图表等(甚至是组合形式)以gif、jpg、bmp等各式保存到磁盘中。 6、全功能批注----真正所见即所得的批注编辑器。 7、VB/VBA代码归纳与重写:对VB/VBA代码进行混淆,大大降低代码的可读性,是一种保护VB/VBA代码的很有效的方法。详细的注释说明和一目了然的名称将有助于设计阶段的调试和查错,但是代码一旦发布后,这些优点将会使黑客轻而易举地破解你的成果,呵呵,用这个吧,保证黑客对您的VB/VBA代码一点兴趣和胃口都没有!! 8、解除Excel文档的内部密码。很多时候,我们需要设置Excel表格/工作簿的保护密码,可是随着时间的推移,这些密码很可能遗忘了,怎么办?很着急啊!!!哈哈,用这个保证在2分钟之内解决问题(换个角度:不要再自欺欺人了,Excel的内部密码形同虚设)。 9、信息加密/解密。对Excel文档中的一些敏感信息进行加密处理,即使文档被破解了,里面的信息仍然很安全。可以说这个功能是对Excel安全的一个有力补充。 10、工程代码锁定解锁器。可以撤销Excel的VBA保护密码(对word、Access同样有效) 11、控制和保存功能。这个功能能满足我们不用记一个密码就能非常有效地保护我们的Excel文档,而且可以免除来自微软的威胁。 12、Cookie管理器。在信息时代,没有网络怎么可以?上网时间长了,就会发现在临时文件夹中挤满了cookies,不但占据磁盘空间,而且还可能泄露秘密。用“清理cookie”命令吧,又觉得有些没有必要删,否则下次还得再输一遍;一个一个删吧,东西太多,想都不能想。怎么办??用这个啊!!只要一次性设置要保留的cookie并选中“退出Excel时自动清理”即可。以后只要退出Excel,你的cookies目录中就不会再有其它乱七八糟的cookie了。 13、超级预览。可以根据当前的选择内容自动调整预览对象。如果选中的是单元格区域,就只预览你选中的区域;如果选中的是图表,则仅预览选中的图表;如果只是一个单元格,则自动显示分页符... ... 14、屏幕锁定。当我们需要临时离开电脑而又不想关闭Excel文档时(并不局限于Excel文档,也可以是其它,但前提是要运行Excel),可以启动这个功能,这样其他人就不可能看到您不希望他们看到的东西。 15、尝试打开忘记密码的文件。暴力破解Excel的打开密码,注意:这个仅对拥有密码设计方案的人有效。 16、Excel加载项/宏管理器。对当前Excel环境下的加载宏/加载项/VBA加载项进行列表,并可以查看相关属性、修改运行状态,甚至是一键破解。 17、Excel对象管理器,可以批量转换Excel中的对象(图片、Shape、图表等)到图片文件; 18、在Excel中播放背景音乐、定时执行特定的程序、整点报时,一定很惬意... 19、屏幕录像及捕捉。哦,这个功能很强大啊。可以截取屏幕图像、录制屏幕变化、图片格式转换、批量bmp转成AVI文件、AVI文件转成动画GIF文件、图片标注... ...强大的不行啦,赶快去看看吧。快捷键:Ctrl+Alt+SpaceBar 或者 Ctrl+左WinKey(微软左徽标键) 20、DLL神探,DLL的最大威胁就是注入到系统进程中,让人防不胜防... 21、一键恢复Excel的系统菜单。这个功能... ... 22、Excel版简易游戏。只是几个可以在Excel中玩的游戏... 23、计划横道图(甘特图)。偶觉得还是用Excel来做横道图最方便了... ... 24、偶将呆板的网络调查和网络投票移植到OBS.DLL中了,变被动为主动! 。。。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值