[关闭]
@kevinZheng 2020-11-17T06:38:12.000000Z 字数 10879 阅读 3705

CorelDraw插件开发学习心得

coreldraw 插件


记录一下CorleDraw 插件开发遇到的一些情况和走过的弯路或者思路.
首先主要针对的是X4 和最新的2019 版本做的尝试.

插件形式介绍

插件格式和开发方式简介:
1. gms插件,使用vba宏编辑
2. cpg插件,需要C C++或其他能构建dll的语言使用com技术
3. addOn目录插件(泊坞窗形式),需要html语言定制界面也可以内嵌其他dll

gms插件

打开cdr 调出宏编辑就能编辑代码,新建项目需要外部新建或者复制gms文件到CorelDRAW X4 SP2\Draw\GMS目录.
目前尝试做了画册页眉页脚工具和中英文标点切换工具.gsm插件侧重点在自动化操作,根据cdr的功能操作进行组合代替人工重复劳动,页眉页脚工具就是利用查找\复制\删除等操作的组合来实现类似word中的页眉页脚功能可以批量处理相同内容,更新页码,自动加页码前后缀等等.标点工具就是根据查找和替换实现了中英文标点的替换.

cpg插件

使用c++更加灵活的制作各种功能的插件,更侧重功能性.可以设置按钮名称,显示图标和触发时机等.比如WelcomeScreen插件实现了在启动cdr时就出现弹框询问新建文档还是打开最后一次编辑的.或者可以根据操作的内容状态实时更新插件按钮是否可用状态例如ClearFill项目,当文档中没有物体需要填充时ClearFill的按钮时置灰的.目前想做的纸杯插件也是想在cpg插件中内嵌网页显示纸杯模板然后点击下载cdr模板文件并打开,保存之后可以通过上传文档到服务端生成杯片下载回本地和在线3D预览功能.遇到的问题就是vs2019中mfc无法插入webBroswer控件所以没法继续,考虑调整别的方案
参考代码ClearFill.cpp

#include "stdafx.h"
#include <tchar.h>
#import "VGCoreAuto.tlb" \
rename("GetCommandLine", "VGGetCommandLine") \
rename("CopyFile", "VGCore") \
rename("FindWindow", "VGFindWindow")
//#import "libid:95E23C91-BC5A-49F3-8CD1-1FC515597048" version("d.0") \
// rename("GetCommandLine", "VGGetCommandLine") \
// rename("CopyFile", "VGCore") \
// rename("FindWindow", "VGFindWindow")
#ifdef _MANAGED
#pragma managed(push, off)
#endif
BOOL APIENTRY DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
class CVGAppPlugin : public VGCore::IVGAppPlugin
{
private:
VGCore::IVGApplication *m_pApp;
ULONG m_ulRefCount;
long m_lCookie;
bool m_bEnabled;
bool CheckSelection();
void OnClearFill();
public:
CVGAppPlugin();
// IUnknown
public:
STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
STDMETHOD_(ULONG, AddRef)(void) { return ++m_ulRefCount; }
STDMETHOD_(ULONG, Release)(void) 
{
ULONG ulCount = --m_ulRefCount; 
if(ulCount == 0)
{
delete this;
}
return ulCount;
}
// IDispatch
public:
STDMETHOD(GetTypeInfoCount)(UINT *pctinfo) { return E_NOTIMPL; }
STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { return E_NOTIMPL; }
STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { return E_NOTIMPL; }
STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
// IVGAppPlugin
public:
STDMETHOD(raw_OnLoad)(VGCore::IVGApplication *Application);
STDMETHOD(raw_StartSession)();
STDMETHOD(raw_StopSession)();
STDMETHOD(raw_OnUnload)();
};
bool CVGAppPlugin::CheckSelection()
{
bool bRet = false;
if(m_pApp->Documents->Count > 0)
{
bRet = (m_pApp->ActiveSelection->Shapes->Count > 0);
}
return bRet;
}
void CVGAppPlugin::OnClearFill()
{
if(CheckSelection())
{
m_pApp->ActiveSelection->Fill->ApplyNoFill();
}
}
CVGAppPlugin::CVGAppPlugin() :
m_pApp(NULL),
m_lCookie(0),
m_ulRefCount(1),
m_bEnabled(false)
{
}
STDMETHODIMP CVGAppPlugin::QueryInterface(REFIID riid, void **ppvObject)
{
HRESULT hr = S_OK;
m_ulRefCount++;
if(riid == IID_IUnknown)
{
*ppvObject = (IUnknown *)this;
}
else if(riid == IID_IDispatch)
{
*ppvObject = (IDispatch *)this;
}
else if(riid == __uuidof(VGCore::IVGAppPlugin))
{
*ppvObject = (VGCore::IVGAppPlugin *)this;
}
else
{
m_ulRefCount--;
hr = E_NOINTERFACE;
}
return hr;
}
STDMETHODIMP CVGAppPlugin::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
switch(dispIdMember)
{
case 0x0011: //DISPID_APP_SELCHANGE
m_bEnabled = CheckSelection();
break;
case 0x0014: // DISPID_APP_ONPLUGINCMD
if(pDispParams != NULL && pDispParams->cArgs == 1)
{
_bstr_t strCmd(pDispParams->rgvarg[0].bstrVal);
if(strCmd == _bstr_t("ClearFill"))
{
OnClearFill();
}
}
break;
case 0x0015: // DISPID_APP_ONPLUGINCMDSTATE
if(pDispParams != NULL && pDispParams->cArgs == 3)
{
_bstr_t strCmd(pDispParams->rgvarg[2].bstrVal);
if(strCmd == _bstr_t("ClearFill"))
{
*pDispParams->rgvarg[1].pboolVal = m_bEnabled ? VARIANT_TRUE : VARIANT_FALSE;
}
}
break;
}
return S_OK;
}
STDMETHODIMP CVGAppPlugin::raw_OnLoad(VGCore::IVGApplication *Application)
{
m_pApp = Application;
if(m_pApp)
{
m_pApp->AddRef();
}
return S_OK;
}
STDMETHODIMP CVGAppPlugin::raw_StartSession()
{
try
{
m_pApp->AddPluginCommand(_bstr_t("ClearFill"), _bstr_t("Clear Fill"), _bstr_t("Clears fill from selected objects"));
VGCore::CommandBarControlPtr ctl = m_pApp->CommandBars->Item[_bstr_t("Standard")]->Controls->AddCustomButton(VGCore::cdrCmdCategoryPlugins, _bstr_t("ClearFill"), 0, VARIANT_TRUE);
_bstr_t bstrPath(m_pApp->Path + _bstr_t("Plugins\\ClearFill.bmp"));
ctl->SetCustomIcon(bstrPath);
m_lCookie = m_pApp->AdviseEvents(this);
}
catch(_com_error &e)
{
MessageBox(NULL, e.Description(), _T("Error"), MB_ICONSTOP);
}
return S_OK;
}
STDMETHODIMP CVGAppPlugin::raw_StopSession()
{
try
{
m_pApp->UnadviseEvents(m_lCookie);
m_pApp->RemovePluginCommand(_bstr_t("ClearFill"));
}
catch(_com_error &e)
{
MessageBox(NULL, e.Description(), _T("Error"), MB_ICONSTOP);
}
return S_OK;
}
STDMETHODIMP CVGAppPlugin::raw_OnUnload()
{
if(m_pApp)
{
m_pApp->Release();
m_pApp = NULL;
}
return S_OK;
}
//dll外部调用的入口 插件挂载的方式 AttachPlugin约定的名称
extern "C" __declspec(dllexport) DWORD APIENTRY AttachPlugin(VGCore::IVGAppPlugin **ppIPlugin)
{
*ppIPlugin = new CVGAppPlugin;
return 0x100;
}

addOn目录

最简单的html定制UI 可以通过iframe内嵌网站.
AppUI.xslt代码示例

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:frmwrk="Corel Framework Data">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<!-- Use these elements for the framework to move the container from the app config file to the user config file -->
<frmwrk:uiconfig>
<!-- The Application Info should always be the topmost frmwrk element -->
<frmwrk:applicationInfo userConfiguration="true" />
</frmwrk:uiconfig>
<!-- Copy everything -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="uiConfig/items">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<!-- Define the button which shows the docker -->
<itemData guid="83f642c6-e2af-49c8-931e-b514c8723a8c" dynamicCommand="MyWebDocker.Macros.ShowMyWebDocker" dynamicCategory="2cc24a3e-fe24-4708-9a74-9c75406eebcd" userCaption="MyWebDocker"/>
<!-- Define the web control which will be placed on our docker -->
<itemData guid="58bd727f-d48b-47c9-8ba3-fec36db4450e"
type="browser"
href="[VGAppAddonsDir]/MyWebDocker/MyWebDocker.html"
enable="true"/>
</xsl:copy>
</xsl:template>
<xsl:template match="uiConfig/dockers">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<!-- Define the web docker -->
<dockerData guid="4afe8c0b-7ffd-415f-98be-8c613998a51b"
userCaption="MyWebDocker"
wantReturn="true"
focusStyle="noThrow">
<container>
<!-- add the webpage control to the docker -->
<item dock="fill" margin="0,0,0,0" guidRef="58bd727f-d48b-47c9-8ba3-fec36db4450e"/>
</container>
</dockerData>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

MyWebDocker.html 就是html的标准写法嵌入iframe页面即可
嵌入dll的层次结构:AppUI->gms宏命令->dll
嵌入dll插件关键代码如下:
AppUI.xslt

<?xml version="1.0"?>
<!--
Copyright (c) 2014 Sanich.
Originally made available on https://cdrpro.ru
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:frmwrk="Corel Framework Data">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<frmwrk:uiconfig>
<frmwrk:applicationInfo userConfiguration="true" />
</frmwrk:uiconfig>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="uiConfig/items">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
 <!-- docker调用,通过DropShadowDocker.DSdocker.Docker调用gms脚本插件 -->
<itemData guid="66d260f1-ef25-437a-a58d-dad6cea56e34"
dynamicCommand="DropShadowDocker.DSdocker.Docker"
dynamicCategory="2cc24a3e-fe24-4708-9a74-9c75406eebcd"
userCaption="DropShadow"
userToolTip="Show or hide DropShadow docker">
<userSmallBitmap xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="bin.base64">
    //8BABAAV0NtblVJX1VJSXRlbUJtcAAAAAAAAAAAKAAAAAAEAAAAAQAAKAAAABAAAAAQAAAA
    AQAIAAAAAAAAAQAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAIAAAIAAAACAgACAAAAAgACAAICA
    AADAwMAAwNzAAPDKpgDw+/8ApKCgAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8A
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcH
    BwcHBwcHBwsLCwsLCwsLCwcHBwcHDAwMDAwMDAwMDAsHBwcHBwwKCgoKCgoKCgwLBwcHBwcM
    CgoKCgoKCgoMCwcHBwcHDAoKCgoKCgoKDAsHBwcHBwwKCgoKCgoKCgwLBwcHBwcLExMTExMT
    ExMLCwcHBwcHCxMTExMTExMTCwsHBwcHBwsTExMTExMTEwsLBwcHBwcLExMTExMTExMLBwcH
    BwcHCwsLCwsLCwsLCwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcH
    BwcHBwcHBwcHBwcH8PDwAKCgoADw8PAAAAAAAA==
</userSmallBitmap>
</itemData>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

DrowShadowDocker.gms 主要完成插件安装卸载功能和插件显示隐藏的状态切换

Private Const MACRONAME = "DropShadowDocker"
' 脚本名称
Private Const CLASSNAME = "DropShadow.Docker"
' dll 类名,要跟dll的类名一致
Private Const nGUID = "a105a407-9fe6-4979-b8bc-0272b7801a24"
' guid 必须一致
    ' Copyright (c) 2014 Sancho.
    ' Originally made available on http://macros.cdrpro.ru
    Private Sub GlobalMacroStorage_Start()
      If GetSetting("cdrpro.ru", "macrosX7", MACRONAME & "Installed", "0") = "0" Then
        Dim msg&: msg = MsgBox("Install " & MACRONAME & "?", vbOKCancel, MACRONAME & " installer")
        If msg = "1" Then Call Install
      End If
    End Sub
    ' 安装
    Public Sub Install()
      Dim dllPath$
      If InStr(1, AppWindow.Caption, "64", vbTextCompare) > 0 Then
        dllPath = SetupPath & "Programs64\Addons\" & MACRONAME & "\" & MACRONAME & ".dll"
      Else
        dllPath = SetupPath & "Programs\Addons\" & MACRONAME & "\" & MACRONAME & ".dll"
      End If
      If FileSystem.Dir(dllPath) = "" Then
        dllPath = CorelScriptTools.GetFileBox("Assembly File (*.dll)|*.dll", "Open Assembly File", 0, , , "C:\", "Open")
      End If
      If Trim(dllPath) = "" Then Exit Sub
      '插件安装关键代码
      Call FrameWork.AddDocker(nGUID, CLASSNAME, dllPath)
      SaveSetting "cdrpro.ru", "macrosX7", MACRONAME & "Installed", "1"
      MsgBox MACRONAME & " installed!", vbInformation, MACRONAME & " installer"
    End Sub
    ' 卸载
    Private Sub Delete()
      Application.FrameWork.RemoveDocker nGUID
    End Sub
    ' 插件调用,切换显示状态
    Public Sub Docker()
      If (Application.FrameWork.IsDockerVisible(nGUID)) Then
        Application.FrameWork.HideDocker nGUID
      Else
        Application.FrameWork.ShowDocker nGUID
      End If
    End Sub

参考地址:

https://community.coreldraw.com/share/b/insider/posts/custom-dockers-in-coreldraw addOn插件参考
https://www.cnblogs.com/o594cql/p/4480669.html cpg插件参考
http://forum.oberonplace.com/showthread.php?t=1880&highlight=Plugins cpg插件参考

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注