REDM基础教程21-插件机制
DM的插件中install一般封装的是注册机制
g_pDMApp->Register(DMRegHelperT<xxxx>(),true);
1.基本原理
插件的基本实现原理流程如下:
插件加载器通过外部dll接口或内部加载两种模式, 把IDMPlugin对象加入到内部队列中。
IDMPlugin提供了加载、初始化、反初始化、卸载四个接口函数,插件加载器在不同的时机, 会遍历它内部IPlugin对象队列并调用对应的接口函数。
IDMPlugin的接口函数内部一般封装了扩展代码,例如:在加载接口函数中,扩展实现一个LOG写入到文件类, 并通过注册管理器注册到内部, 替换掉内部原始的LOG打印输出类。
1.1.内部加载
直接内部调用:
theApp.InstallPlugin(IDMPlugin对象)
1.2.外部dll接口
外部的dll插件必须有如下两个固定的导出函数, 在加载、卸载外部dll插件时分别被调用。
dllStartPlugin函数一般所做的操作是调用InstallPlugin安装dll内所有的自实现IDMPlugin对象。
dllStopPlugin函数一般所做的操作是调用UninstallPlugin卸载dll内所有的自实现IDMPlugin对象。
通过LoadPlugin加载外部dll插件流程如下:
可以看到,LoadPlugin最终是调用了IDMPlugin::install函数
DM也封装了另一个LoadPlugins接口, 通过Xml解析遍历加载外部dll插件列表
2.Plugin_Expand插件示例
1.Plugin_Expand\src\Plugin_ExpandExp.cpp导出了dllStartPlugin和dllStopPlugin接口,它们所做的工作是加载和卸载IDMPlugin,代码如下:
static Plugin_Expand* plugin; extern "C" void PLUGINEXPAND_EXPORTS dllStartPlugin(void) throw() { plugin = new Plugin_Expand(); DMApp::getSingleton().InstallPlugin(plugin); } extern "C" void PLUGINEXPAND_EXPORTS dllStopPlugin(void) { DMApp::getSingleton().UninstallPlugin(plugin); delete plugin; }
2.Plugin_Expand是IDMPlugin的实现体。
class Plugin_Expand:public IDMPlugin { public: Plugin_Expand(void); ~Plugin_Expand(void); const wchar_t* GetName() const; void Install(); void Uninstall(); void Initialise(); void Shutdown(); };
3.由前面的框架图可知
DMApp::getSingleton().InstallPlugin(plugin);
最终调用的是:
void Plugin_Expand::Install() { g_pDMApp->Register(DMRegHelperT<DM3DAnimate>(),true); g_pDMApp->Register(DMRegHelperT<DMLineAnimate>(),true); g_pDMApp->Register(DMRegHelperT<DMScreenAnimate>(),true); g_pDMApp->Register(DMRegHelperT<DMResZipImpl>(),true); g_pDMApp->Register(DMRegHelperT<DMResMultZipImpl>(),true); #ifdef USE_DMSKIA_RENDER_ DMCode iErr = g_pDMApp->Register(DMRegHelperT<DMSkiaRenderImpl>(),true); DMASSERT_EXPR(DMSUCCEEDED(iErr), L"注册DMSkiaRenderImpl失败!"); iErr = g_pDMApp->SetDefRegObj(DMSkiaRenderImpl::GetClassName(),DMSkiaRenderImpl::GetClassType()); DMASSERT_EXPR(DMSUCCEEDED(iErr), L"设置DMSkiaRenderImpl为默认Render对象失败!"); #endif }
这里做了什么呢?参考前一节注册类机制,它加入了3D特效、skia绘制引擎、zip打包Res资源、多zip打包Res资源、
我们来看下DMDemo中使用Plugin_Expand的3D特效吧:(你可以试着删除Plugin_Expand_d/Plugin_Expand.dll,3D特效就会无效)
2.1.怎么安装插件
DMDemo\src\DMDemo.cpp中:
theApp.LoadPlugins(L"dmpluginsd.cfg");
而dmpluginsd.cfg的内容如下:
<?xml version="1.0" encoding="utf-8"?> <body> <!--directory指明了plugin存放在哪个文件夹内,相对于exe路径--> <directory name="..\plugins\"> <item name="Plugin_Expand_d"/> </directory> </body>
directory可以指定多个,以加载不同文件夹下的dll,如下所示:
<?xml version="1.0" encoding="utf-8"?> <body> <!--directory指明了plugin存放在哪个文件夹内,相对于exe路径--> <directory name="..\plugins1\"> <item name="A"/> <item name="B"/> </directory> <directory name="..\plugins2\"> <item name="C"/> <item name="D"/> </directory> </body>
当然,你也可以简单粗暴的使用:
theApp.LoadPlugin("d:\\Plugin_Expand.dll");
2.2.skia绘制引擎
skia的优势是绘制速度快,缺点是体积较大,minsizerel大约1M左右
1.cmake中勾选开启USE_SKIA_宏,也就是代码中增加了USE_DMSKIA_RENDER_宏
void Plugin_Expand::Install() { ... #ifdef USE_DMSKIA_RENDER_ DMCode iErr = g_pDMApp->Register(DMRegHelperT<DMSkiaRenderImpl>(),true); DMASSERT_EXPR(DMSUCCEEDED(iErr), L"注册DMSkiaRenderImpl失败!"); iErr = g_pDMApp->SetDefRegObj(DMSkiaRenderImpl::GetClassName(),DMSkiaRenderImpl::GetClassType()); DMASSERT_EXPR(DMSUCCEEDED(iErr), L"设置DMSkiaRenderImpl为默认Render对象失败!"); #endif }
2.加载Plugin_Expand插件即可,如果你不想要其他注册,就把它们删除掉即可。
对于插件里的注册类,你可以抽离出来,比如放在你的exe代码中,然后调用g_pDMApp->Register(DMRegHelperT<xxxx>(),true);
2.3.zip打包Res资源
或者在Plugin_Expand::Install()中加入:
g_pDMApp->SetDefRegObj(DMResZipImpl::GetClassName(),DMResZipImpl::GetClassType());// 把zip打包设置为默认
或者
g_pDMApp->SetDefRegObj(DMResMultZipImpl::GetClassName(),DMResZipImpl::GetClassType());// 把多zip打包设置为默认
文章作者:hgy413
本文地址:https://hgy413.com/5320.html
版权所有 © 转载时必须以链接形式注明作者和原始出处!