CorelDRAWX4的C++插件开发(四十一)纯C++插件开发(5)实现六个纯虚函数
- 这一节我们实现六个剩余的纯虚函数,先上代码
HRESULT __stdcall CongLingKaiShi::QueryInterface(REFIID riid, void** ppvObject) {//如果查询的IID接口是自动化调度接口IDispatch或未知接口IUnknown或插件IVGAppPlugin则统统返回IVGAppPlugin接口if (riid == IID_IDispatch || riid == IID_IUnknown || riid == __uuidof(VGCore::IVGAppPlugin)) { *ppvObject = (VGCore::IVGAppPlugin*)this;return S_OK;}//其它接口一律返回无return E_NOINTERFACE;
}HRESULT __stdcall CongLingKaiShi::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) {switch (dispIdMember) {//在CDR中鼠标点击任意插件时触发该DISPID号0x0014case 0x0014://pDispParams是函数传参结构体,如果它存在且cArgs(参数的总数)为1个时继续判定if (pDispParams != NULL && pDispParams->cArgs == 1) {//pDispParams(函数传参结构体)的rgvarg(参数数组)中的第一个[0]参数的名称和我的按钮名一样时触发if (_bstr_t(pDispParams->rgvarg[0].bstrVal) == _bstr_t("CongLingCeShi")) {MessageBox(hAppWnd,_bstr_t("C++插件调用成功:"), _bstr_t("提示"), MB_OK);}}break;case 0x0015:// 设置工具栏的显隐状态if (pDispParams != NULL && pDispParams->cArgs == 3 ) {//名称里面前八个字母是CongLing的时候才修改为显示图标std::string lpszText = _com_util::ConvertBSTRToString(pDispParams->rgvarg[2].bstrVal);if (lpszText.substr(0, 8) == "CongLing") {*pDispParams->rgvarg[1].pboolVal = VARIANT_TRUE;}}break;}return S_OK;
}HRESULT __stdcall CongLingKaiShi::raw_OnLoad(VGCore::IVGApplication* Application) {//获取CDR的根结构体ApplicationcorelApp = Application;//获得CDR主窗口的句柄hAppWnd = reinterpret_cast<HWND>(corelApp->AppWindow->Handle);//获取本DLL的HINSTANCE句柄myInstance = GetModuleHandle(LPCWSTR(strrchr(__FILE__, '\\') + 1));//myInstance = GetModuleHandle(L"CongLingKaiShi.cpg"); 上一行等价于这行return S_OK;
}HRESULT __stdcall CongLingKaiShi::raw_StartSession() {//设一个值=true 默认要新建插件面板bool createBar = true;//如果已有同名面板则改为不新建for (int i = 1; i <= corelApp->CommandBars->Count; i++) {if (corelApp->CommandBars->Item[i]->Name == _bstr_t("CongLingToolBar")) {createBar = false;break;}}//根据该值判定是否新建面板if (createBar) {//新建工具栏 最后一个值设为TRUE是永久化,改动了位置大小等状态都会记忆VGCore::CommandBarPtr CongLingToolBar = corelApp->CommandBars->Add(_bstr_t("CongLingToolBar"), VGCore::cuiBarPosition::cuiBarFloating, VARIANT_TRUE); CongLingToolBar->Visible = TRUE;//显示工具栏}//设定一个按钮corelApp->AddPluginCommand(_bstr_t("CongLingCeShi"), _bstr_t("测试"), _bstr_t("用来测试各种功能的"));//添加该按钮(最后一个参数:是否设为临时按钮)VGCore::CommandBarControlPtr ctl = corelApp->CommandBars->Item[_bstr_t("CongLingToolBar")]->Controls->AddCustomButton(VGCore::cdrCmdCategoryPlugins, _bstr_t("CongLingCeShi"), 1, VARIANT_TRUE);//注册调度接口IDispatchzhuCe = corelApp->AdviseEvents(this);return S_OK;
}HRESULT __stdcall CongLingKaiShi::raw_StopSession() {corelApp->UnadviseEvents(zhuCe);//注销调度接口return S_OK;
}HRESULT __stdcall CongLingKaiShi::raw_OnUnload() {delete this;//回收结构体return S_OK;
}
- 好了, 以上我们就实现了剩余所有的纯虚函数
- 第一个函数是
QueryInterface
,就是未知接口中的第一个查询接口,第一个参数是一个riid
,就是UUID,也就是主程序跑过来问我们有没有这个ID号的接口,这时CDR问的一般就是IDispatch接口,所以我们把这个IID_IDispatch
写在第一位进行判定,在我的实际测试中,未知接口IID_IUnknown 和IVGAppPlugin接口都没有被访问过所以我写在第二位和第三位,也是为了程序的健壮性而写上去的,只要第满足第一个 ,那么第二和第三个就不会再判断了,不会浪费算力. - 然后我们返回一个接口到
*ppvObject = (VGCore::IVGAppPlugin*)this;
,这里面的*ppvObject
就是一个实际的需要填写的回传值[out],主程序会得到这个*ppvObject
,所以我们必须把*ppvObject
赋值为程序所需要的接口,(VGCore::IVGAppPlugin*)this
就相当于返回CongLingKaiShi
这个结构体的地址,this
就是代表的本体CongLingKaiShi, 因为CongLingKaiShi包含了这三个接口.我不管你呼叫的是哪个,反正到这里面找就对了 - 然后第二个函数
Invoke
是最后第七个函数,也是实现功能最重要的函数,在注册了IDispatch之后主程序就会访问我们这个QueryInterface来查找IDispatch,然后在IDispatch里面运行这个Invoke
- 然后对
switch (dispIdMember)
对这个DISPID
也就是ID号进行读取,我们只需要判断它是否为0x0014
就行了,当用户在CDR主程序的插件上点击了鼠标左健就会触发这个0x0014
的Invoke函数,所以我们接着再判断一下参数结构体pDispParams
是否被定义了,且里面的参数个数是1pDispParams->cArgs == 1
这个cArgs 就是参数结构体当中记录参数个数的成员,当都满足之后,我们再接着判断其中这个参数的名称是否是我们按钮名称if (_bstr_t(pDispParams->rgvarg[0].bstrVal) == _bstr_t("myCeShi"))
,如果是myCeShi那就说明按中了我们的插件按钮,然后我们把想要执行的代码放在其中即可. - 我随便写了一个弹窗
MessageBox(hAppWnd,_bstr_t("C++插件调用成功:"), _bstr_t("提示"), MB_OK);
调用效果如下图
- 接下来就是
raw_OnLoad
函数,首先获取CDR的根结构体Application,这个在第三十二章中详细说明了 - 然后获取CDR主窗口的句柄
hAppWnd = reinterpret_cast<HWND>(corelApp->AppWindow->Handle);
Handle是一个长整数LONG,我们对它进行强制符号转换为HWND,一个窗口句柄,这样子我们使用模态弹窗就非常方便了 - 然后获取本DLL的HINSTANCE句柄,
myInstance = GetModuleHandle(LPCWSTR(strrchr(__FILE__, '\\') + 1));
实际上就是这一行myInstance = GetModuleHandle(L"CongLingKaiShi.cpg");
是一样的效果,GetModuleHandle是通过文件名获取句柄的函数,所以要把文件名进行传参,这这LPCWSTR(strrchr(__FILE__, '\\') + 1)
这种写法,就是用了一个预定义宏__FILE__
,这里面就是一个从盘符开始到后缀的全部的一个名称,所以只要把路径去掉即可,strrchr(__FILE__, '\\')
在全路径查到最右的一个\
路径反斜杠的下标指针,然后加上+ 1
就返回CongLingKaiShi.cpg
这一串的第一个字母C
的下标指针,所以就得到了我们想要的文件名了,LPCWSTR()
这是把这个字符串改成双字节的UNICODE模式用以符合GetModuleHandle的传参要求加上去的. - 如果不想这么复杂直接用
myInstance = GetModuleHandle(L"CongLingKaiShi.cpg");
是一样的效果,但是建议用上面一种写法哈,这样子更改了文件名也不会出错 - 接下来在
raw_StartSession
函数中我们要开始新建插件面板和按钮了 - 我们一个循环当中一个个判定插件面板的名称
corelApp->CommandBars->Item[i]->Name
是否是_bstr_t("CongLingToolBar")
,如果已经有了这个面板我们就不需要新建, 把createBar
的值改成false;
- 然后判定
if (createBar)
,当然第一次运行的时候这个值一定是true,从第二次往后都会是false,因为面板新建一次就是永久的,所以必须这样子写不然会遇上每运行一次程序就新增一个面板的BUG - case 0x0015: 是设计插件按钮的显隐状态,我们用了一个判定只有前面八字个母匹配了CongLing就让这个按钮设置为显示状态
- 面板新建完之后,就设定一个按钮
AddPluginCommand
函数,第一个参数是按钮的程序名称,第二个参数是图标名称,第三个参数是鼠标悬停名称 - 然后就是把这个按钮添加进面板当中的函数
AddCustomButton
,第一个参数是按钮的模式,有两种一种是GMS另一种就是我们自己定义的,我使用VGCore::cdrCmdCategoryPlugins
,第二参数是按钮的程序名称,第三个参数是插入位置,最后一个:是否设为临时按钮.我们在制作插件的时候应该要设为VARIANT_TRUE
临时状态, - 当然如果做成了成品定型了的话就可以设成
FALSE
,只要在第一次启动时添加一次就可以了 - 在启动的最后我们开始注册调度接口
zhuCe = corelApp->AdviseEvents(this);
- 在我们关闭CDR主程序的时候会运行
raw_StopSession
,这时我们注销本插件corelApp->UnadviseEvents(zhuCe);
- 最后在卸载时
delete this;
回收结构体在堆区的内存空间 - 以上就是纯C++插件的全部的比较精简的代码展示了,我们把所有代码组合起来顺序如下,头文件->声明->插件结构体->六个虚函数实体->暴露导出函数,用这个顺序组合文件,然后编译即可,然后就得到一个CPG后缀的文件
- 然后把这个CPG文件放到CDR的主路径下
CorelDRAW X4\Draw\Plugins
大家根据自己的安装路径来修改如下图
CorelDRAWX4的C++插件开发(四十一)纯C++插件开发(5)实现六个纯虚函数相关推荐
- C++经验(四)-- 基类构造函数和析构函数中调用virtual虚函数?
class Base {public:Base();virtual void oneFunction() = 0;... };Base::Base() {...oneFunction(); }clas ...
- 2021年大数据Spark(四十一):SparkStreaming实战案例六 自定义输出 foreachRDD
目录 SparkStreaming实战案例六 自定义输出-foreachRDD 需求 注意: 代码实现 SparkStreaming实战案例六 自定义输出-foreachRDD 需求 对上述案例的结果 ...
- CorelDRAWX4的C++插件开发(四十)纯C++插件开发(4)继承插件结构体IVGAppPlugin和自动化接口IDispatch
因为在注册插件的时候,是要传一个名为IDispatch*这样子的一个参数,所以我们可以看到插件在注册的时候默认就是要求这是一个实现了自动化的接口(IDispatch,如下图所示,是后面将要展示的代码, ...
- CorelDRAWX4的VBA插件开发(四) 用一个例子了解CORELDRAW-X4的四个基本对象
CorelDRAWX4的VBA插件开发(四) 用一个例子了解CORELDRAW-X4的四个基本对象 1.打开第一章的界面如下图: 2.把之前的代码稍作修改 Sub 第一个插件()Dim zongShu ...
- 【Visual C++】游戏开发笔记四十一 浅墨DirectX教程之九 为三维世界添彩:纹理映射技术(一)...
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/zhmxy555/article/details/8523341 作者:毛星云(浅墨 ...
- android 视频沉浸式,Android项目实战(四十一):游戏和视频类型应用 状态栏沉浸式效果...
原文: Android项目实战(四十一):游戏和视频类型应用 状态栏沉浸式效果 需求: 手机app ,当打游戏或者全屏看视频的时候会发现这时候手机顶部的状态栏是不显示的,当我们从手机顶端向下进行滑动或 ...
- 实验四十一、×××(IPSec)的配置
实验四十一.×××(IPSec)的配置 一. 实验目的 1. 掌握手工配置密钥建立××× 的配置 2. 理解密钥在隧道建立过程中的作用 二. 应用环境 IPSec 实现了在网络上的数据机密性.完整性和 ...
- OpenCV学习笔记(四十一)——再看基础数据结构core OpenCV学习笔记(四十二)——Mat数据操作之普通青年、文艺青年、暴力青年 OpenCV学习笔记(四十三)——存取像素值操作汇总co
OpenCV学习笔记(四十一)--再看基础数据结构core 记得我在OpenCV学习笔记(四)--新版本的数据结构core里面讲过新版本的数据结构了,可是我再看这部分的时候,我发现我当时实在是看得太马 ...
- 四十一、深入Java中的 File类
@Author:Runsen @Date:2020/6/6 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘课严重,专业排名 ...
最新文章
- 人人都是作曲家:基于深度神经网络的音乐风格迁移
- 小白也能看懂的教程:微信小程序在线支付功能开通详细流程(图文介绍)
- 【MATLAB】数据类型 ( 执行代码 | 清空命令 | 注释 | 数字 | 字符 | 字符串 )
- 图形大小_PS图形复制——等距复制、旋转复制、大小变换复制
- 计算机应用与科学专业简介,计算机应用技术学科专业简介
- “约见”面试官系列之常见面试题之第七十七篇之vuex中mutation和action的详细区别 (建议收藏)
- Web框架——Flask系列之Flask-SQLAlchemy数据库的基本操作(九)
- 飞秋2010下载在未来讲差异化
- 检查数组中的子字符串– Java,Python和Swift
- java map size 不准确_java1.7以前ConcurrentHashMap的size方法
- Springboot的工作机制:2 @SpringBootApplication背后的秘密
- 反编译工具ILSpy的下载与使用
- npm install报错问题解决以及人人开源前端报错问题解决
- postman下载excel出现乱码
- linux 蓝牙 iphone,Linux On iPhone 7 现在可运行 Wayland
- 将结构体转换为二进制
- canva五角星空html,使用canvas绘制一个五角星
- STM32Cube和HAL库使用初体验-第5季第2部分-朱有鹏-专题视频课程
- 5款不妨一试的硬盘碎片整理工具
- AJAX学习前奏----JS基础加强