C#开发word(wps)插件(com加载项)作为一个web前端开发,不搞点后端的东西玩玩也说不过去。除了常见的node

转载地址https://juejin.cn/post/6844903992846204936

作为一个web前端开发,不搞点后端的东西玩玩也说不过去。除了常见的nodejs 或者java以外,最近收到需求,要搞一个word(wps)插件,用于方便总裁办的同事发布写一些公文,格式化版头,标题,附件等。所以最近也一直在研究这方面的知识。奈何网上参考的文献太少,太杂。于是这里…

前言

作为一个web前端开发,不搞点后端的东西玩玩也说不过去。除了常见的nodejs 或者java以外,最近收到需求,要搞一个word(wps)插件,用于方便总裁办的同事发布写一些公文,格式化版头,标题,附件等。所以最近也一直在研究这方面的知识。奈何网上参考的文献太少,太杂。于是这里我便总结一下开发全过程,供大家参考交流。

一、需求确认

关于word(wps)插件,要实现的最终效果,无非如下两种:

  • 1.自定义宏.生成一个xxx.dotm模板文件。打开这个模板文件,界面如下:

  • 2.com加载项.生成一个xxx.dll写入到word关键路径,使得word能读取xx.dll,并在word的菜单栏能展示你自定义的菜单

对比上述两种方案,我们发现,通过com加载项来实现word(wps)插件对使用者来说是相当简洁和便利的,一目了然。因此,我们确定需求,就按照这个来实现,产出xxx.dll等相关文件。

二、技术方案确定

因为这些基于microsoft office的上做的二次开发,必须要基于window系统,参考我微软的技术栈开发。微软的技术主要的无非两种:

  • vb (开发工具visual basic 6.0)
  • C# (开发工具visual studio 9)

两者无所谓好坏,但我个人对vb不太感冒,而且气语法跟java的有点点差异的,因此技术选型选择C#。

于此同时,本次我是基于金山软件wps(国内很多公司,尤其是国企央企等电话都会统一安装wps)开发的插件,调用word的接口方法跟microsoft office一模一样。因此开发环境准备如下:

  • 操作系统 win7~win10
  • wps 10.8.0.6370-个人专业版
  • Microsoft Visual Studio 2019 Community/professional(都行,哪个免费下载哪个)
  • Microsoft.NET 的Framework版本 v4.0.30319

三、本地开发

1、新建项目

建议安装完 Microsoft Visual Studio后以管理员身份运行启动

选中解决方案下的项目---【右键】---【属性】,开始如下设置:

【生成】---勾选【为com互操作注册】

【调试】---选中【启动外部程序】---选择wps安装路径

我这里是wps文字,因此选中后的完成路径是:

C:\Program Files (x86)\Kingsoft\WPS Office\10.8.0.6370\office6\wps.exe

如果你们是基于wps 表格

C:\Program Files (x86)\Kingsoft\WPS Office\10.8.0.6370\office6\et.exe

wps ppt 的话

C:\Program Files (x86)\Kingsoft\WPS Office\10.8.0.6370\office6\wpp.exe

【签名】--【新建签名】

图中的xx_officialDocument.pfx就是此处下拉框选则【新建】后当场生成的。

至此,新建项目完毕,

2、添加引用

因为我们要掉office的相关接口,所以就必须引用office 和kingsoft 相关的dll,即类库,

Upgrade WPS Office 3.0 Object Library对应的是WPS文字、Upgrade WPS Spreadsheets 3.0 Object Library对应的是WPS表格。

提示:若添加后提示引用出错,可以尝试的解决方法有:

  • 以Administrator账户登录Windows
  • 以管理员身份运行Visual Studio
  • 在Administrator账户中,以管理员身份安装WPS Office
  • WPS Office个人版需要运行专业版中的 WPSOfficePIA.exe 以注册所引用的程序集 安装WPS Office专业版,安装时WPS会自动注册相关程序集

引用添加完毕后,我们可以看到我们总共依赖了哪些引用

3、新增资源文件

在Properties上右键→添加→新建项→找到“资源文件”→输入或保持默认名称→添加

打开Resource1.resx后--【添加资源】---【添加新文本文件】---【输入MyRibbon】

这个MyRibbon.txt文件就是一个xml菜单文件,配置你在wps中的菜单的显示

4、编辑资源(菜单)文件

双击MyRibbon.txt后进入编辑,输入如下文本

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
	<ribbon startFromScratch="false">
		<tabs>
			<tab id="MyTab" label="wps中菜单名字" visible="true" insertAfterMso="TabDeveloper">
				<group id="rhgroup" label= "红头设置"> 
					<button id="rh" label="通用红头" onAction="setCommonRH2" getImage="GetRibbonImage" size="large"/>
					<button id="Test4" label="专会" onAction="setSMRH2" getImage="GetRibbonImage" size="large"/>
					<button id="Test5" label="上行文" onAction="setUpLineRH2" getImage="GetRibbonImage" size="large"/>
				    <button id="Test6" label="人事任免" onAction="setHRRH2" getImage="GetRibbonImage" size="large"/>
				</group>
			    <group id="Test" label= "段落格式设置">
					<button id="Test" label="公文标题" onAction="setOfficialTitle" getImage="GetRibbonImage" size="large"/>
					<button id="Test" label="一级标题" onAction="set1Title" getImage="GetRibbonImage" size="large"/>
					<button id="Test" label="二级标题" onAction="set2Title" getImage="GetRibbonImage" size="large"/>
					<button id="Test" label="正文" onAction="setMainPara" getImage="GetRibbonImage" size="large"/>
					<button id="Test" label="附件" onAction="setAttachIn" getImage="GetRibbonImage" size="large"/>
				</group>
				<group id="Test" label= "附件(后附)"> 
					<button id="Test" label="附件(后附)" onAction="setAttachAfter" getImage="GetRibbonImage" size="large"/>
				</group>
				<group id="Test" label= "间距调整"> 
					<button id="Test" label="加大间距" onAction="addFontSpace" getImage="GetRibbonImage" size="large"/>
					<button id="Test" label="减小间距" onAction="reduceFontSpace" getImage="GetRibbonImage" size="large"/>
				</group>
			</tab>
		</tabs>
	</ribbon>
</customUI>
  • tabs表示选项卡,id是“MyTab”,显示的名称是“我的插件”,在“开发工具”选项卡之后插入本选项卡
  • group表示选项卡中的组,id是“Test”,名称是“组名称”
  • button表示命令按钮,id是“Test”,名称是“Hello”,回调“Test”事件,从“GetRibbonImage”事件中获取按钮图标,按钮显示大尺寸 Id、Label、onAction、getImage引号中的字符可以自定义,且保证唯一性

关于这个ribbon,详情可以参考微软官方文档: Customizing the 2007 Office Fluent Ribbon for Developers (Part 1 of 3)

5、修改主类

这里的主类,就是我们一开始把Class1.cs该成了OfficialDocument.cs这个文件。当然你可以命名为其他。

打开了OfficialDocument.cs: 文件最上方就是我们引用的类,都写进来

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AddInDesignerObjects;
using Office;
using System.Windows.Forms;

继续往下写

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AddInDesignerObjects;
using Office;
using System.Windows.Forms;
// namespace [yourProjectName] 视具体情况改成你的项目名
namespace yourProjectName
{
    public class Class1 : IDTExtensibility2, IRibbonExtensibility
    {
    {
    }
}

有红色的波浪线,提示我们有错,不过没关系,鼠标悬浮在上面,点击黄色灯泡图标的下拉箭头---【实现接口】,visual studio 会自动实现其接口。IRibbonExtensibility 这个也一样这么操作一下。

得到修复后的代码如下:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AddInDesignerObjects;
using Office;
using System.Windows.Forms;
using System;

namespace yourProjectName
{
    public class Class1 : IDTExtensibility2, IRibbonExtensibility
    {
    
        public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
        {
            throw new NotImplementedException();
        }

        public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom)
        {
            throw new NotImplementedException();
        }

        public void OnAddInsUpdate(ref Array custom)
        {
            throw new NotImplementedException();
        }

        public void OnStartupComplete(ref Array custom)
        {
            throw new NotImplementedException();
        }

        public void OnBeginShutdown(ref Array custom)
        {
            throw new NotImplementedException();
        }

        public string GetCustomUI(string RibbonID)
        {
            throw new NotImplementedException();
        }
    }
}

在OnConnection事件中初始化app和wordDoc对象

public class Class1 : IDTExtensibility2, IRibbonExtensibility
    {

        public static Word.Application app = null;
        public static object wps;
        public static Word.Document wordDoc;
        Object Nothing = System.Reflection.Missing.Value;
        public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
        {
            wps = Application;
            app = wps as Word.Application;

            wordDoc = app.Documents.Add(ref Nothing, ref Nothing, ref Nothing, ref Nothing);
            //wordDoc = app.ActiveDocument;
            wordDoc.PageSetup.PaperSize = Word.WdPaperSize.wdPaperA4;
            wordDoc.PageSetup.TopMargin = app.CentimetersToPoints(3.7f); // 37mm,对应104.9磅(1磅约等于0.3572mm)
            wordDoc.PageSetup.BottomMargin = app.CentimetersToPoints(3.5f);
            wordDoc.PageSetup.LeftMargin = app.CentimetersToPoints(2.8f);
            wordDoc.PageSetup.RightMargin = app.CentimetersToPoints(2.7f);
        }
        ...
    
    }

在GetCustomUI事件中调用在Resource1.resx中添加的MyRibbon.txt,获取菜单配置文件

public string GetCustomUI(string RibbonID)
        {
            return Properties.Resource1.MyRibbon;
        }

添加事件试试。我们在MyRibbon.txt文件中的每一项按钮里面,都有一个onAction,这个就是绑定的事件。需要我们在Class1.cs文件中去实现

<button id="Test" label="加大间距" onAction="addFontSpace" getImage="GetRibbonImage" size="large"/>

我们来实现一个addFontSpace,当你点击这个按钮的时候,就触发了此事件

public void reduceFontSpace(IRibbonControl ctrl)
        {
            MessageBox.Show("you click reduceFontSpace")
            //float former = app.Selection.Font.Spacing;
            //app.Selection.Font.Spacing = former - 0.3f;
        }

提示:MessageBox需要引用System.Windows.Forms。引用方法如下:

四、注册表操作

在第三部中,我们实现了一个自定义的菜单,并期望其加到wps的菜单栏中,具体展示结果如下

怎么样才能展示这个菜单呢?

在【开发工具】---【com加载项】选中我们的实现的com加载项(wps专业版才有【开发工具】这个菜单选项):

那么问题又来了,怎么样才能在这里显示这么多的com加载项来供我们选中? 这里我们要自定义Zxxx.OfficialDocument这个com加载项,就必须操作注册表,在启动wps的时候会自动读取相关的内容(实际情况会更复杂)。现在来实现实现一个reg文件,操作注册表

1、新增reg文件

新增一个空的txt记事本文件→ 修改后缀名,另存为install.reg→ 右键此文件编辑→ 拷贝如下代码:

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USERSOFTWAREMicrosoftOfficeWordAddinsZhjk.OfficialDocument]
"FriendlyName"="Zhjk.OfficialDocument"
"Description"="【自定义中文描述方便他人理解】"
"LoadBehavior"=dword:00000003
"CommandLineSafe"=dword:00000001
[HKEY_CURRENT_USERSoftwareKingsoftOfficeWPSAddinsWL]
"Zhjk.OfficialDocument"=""

需要注意的是:

[HKEY_CURRENT_USERSOFTWAREMicrosoftOfficeWordAddinsZhjk.OfficialDocument]

这里 [HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\Word\Addins固定不变,后面的xxx1.xxx2,表示 xxx1是你项目的名,xxx2是你cs入口文件的类名,本例中就是yourProjectName.Class1

以上,写入注册表信息install.reg文件完成。

但是,如果你想清理掉这个注册表信息,你可以手动在命令行输入regedt,打开操作界面,你也可以专门生成一个unistall.reg文件,双击实行即可。 unistall.reg 内容如下:

Windows Registry Editor Version 5.00
[-HKEY_CURRENT_USERSOFTWAREMicrosoftOfficeWordAddinsZhjk.OfficialDocument]
[HKEY_CURRENT_USERSoftwareKingsoftOfficeWPSAddinsWL]
"Zhjk.OfficialDocument"=-

注意减号(横杠)“-”,还有xxx1.xxx2(本例子中是Zhjk.OfficialDocument)要与你安装的install.reg里面的保持一致。若开发的是WPS文字、WPS表格的外接程序,则注册路径中HKEY_CURRENT_USER\SOFTWARE\Microsoft后面:WPS文字对应的是Word和WPS;WPS表格对应的是Excel和ET

某些电脑可能要用管理权权限来运行这个reg文件

2、验证注册表写入

命令行输入 regedit

沿着这个HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\Word\Addins路径一直打开目录,如果看到如下,即说明写入注册表成功

五、开发环境启动调试

之前做了那么多准备工作,现在可以启动调试,看看我们的wps 文字到底有没有按照预定的情况加载自定义菜单。 打开visual studio 界面,在degug模式下,点击启动按钮:

然后自动自动wps文字(如果此前你打开了wps文字应用,或者word,请先关掉)

看到此界面,说明我们的自定义com加载项本地调试成功。

六、C# 操作word(wps)版面格式,字体样式等

详情请见我的另一篇文章。

七、基础dll强签名

1、生成WPS演示所需的PIA

部署之前,我们要先对我们的dll签名,保证系统信任此文件

  • 首先、D盘新建一个PIA文件夹,打开WPS的安装文件夹,找到ksoapi.dll和wpsapi.dll,拷贝到PIA文件夹中。(如果你是ppt的com插件,就把wppapi.dll拷贝过来,如果是excel,那么就拷贝etapi.dlll)。
  • 开始菜单中,找到visual studio 2019 文件目录,点击 开发人员命令提示符(Developer Command Prompt for vs 2019)

  • 进入到PAI路径下

  • 输入TlbImp wpsapi.dll(低版本的visual studio 可能需要输入执行两次命令: 一次是TlbImp ksoapi.dll,再执行TlbImp wpsapi.dll) 后回车,会在PIA文件夹中生成三个dll:
Office.dll
VBIDE.dll
Word.dll

后面我们需要这三个dll。

2、强签名

若用户是WPS专业版则不需要,为了兼容性,推荐进行强签名。 另外,如果项目中引用了第三方未签名的dll,则必须进行强签名才能引用。

  • 输入sn -k zhjk.pfx后回车,生成随机密钥对

  • 输入ildasm Office.dll/out:Office.il后回车,采用反汇编工具ildasm生成中间语言。

  • 输入ilasm /dll /res:Office.res /key:zhjk.pfx Office.il /out:Office.dll后回车,采用汇编工具ilasm(注意不要看成ildasm)重新生成dll

  • Word.dll的强签名操作按照此前类推,输入以下命令
ildasm Word.dll /out:Word.il

ilasm /dll /res:Word.res /key:zhjk.pfx Word.il /out:Word.dll

可以看到强签名后的文件如下:

Word.dll、Office.dll这两个强签名的,就是我们后面需要的文件。

八、Release 打包生成应用dll

1、再visual studio 中debug模式改成release,生成(为COM互操作注册)、调试(启动外部程序)跟dubug模式下保持一致

2、关闭所有的wps文字文档,然后点击“启动”,这样可以得到Release模式下的dll,在工程的bin/Release目录下

3、将刚才的强签名生成的Word.dll、Office.dll拷贝到工程的bin/Release目录下

凑齐这么多dll等相关的文件,我们可以召唤神龙了。

九、生产部署

在此前的步骤中,我们拿到了强签名的dll 和Release 模式下应用生曾的dll,

Zhjk.dll
Zhjk.pdb
Zhjk.tlb
Word.dll
Office.dll

现在开始对window系统进行操作了。

1、此前创建的安装install.reg和卸载unistall.reg注册表文件也复制过来,就在当前bin/Reease路径下新建一个reg文件夹存放这两个reg文件。

2、将NETFX 4.0 Tools文件夹复制过来

这个文件夹路径

C:Program Files (x86)Microsoft SDKsWindowsv10.0Abin

一般来说,安装了visual studio 后,本地会有这个文件夹,里面包含一些我们需要用到的工具类。因为是生产并部署,其他人员电脑未必有这个文件夹,因此我们准备好这个文件夹,放入我们的部署包里面,方便其他人安装。

3、执行安装

你可以在命令行,一行行输入命令来实现。这里我们推荐用批处理命令。 把所有的命令都放在一个xxx.bat文件里。

这里我们的在当前Release目录下新增一个install.bat,里面内容如下:

@echo off
@set baseDir=%~dp0

regedit /s %baseDir%regZhjk.OfficialDocument.reg

C:WindowsMicrosoft.NETFrameworkv4.0.30319RegAsm %baseDir%Zhjk.dll /tlb:%baseDir%Zhjk.tlb

@SET GACUTIL="%baseDir%NETFX 4.8 Toolsgacutil.exe"

%GACUTIL% -i %baseDir%Zhjk.dll

%GACUTIL% -i %baseDir%Word.dll

%GACUTIL% -i %baseDir%Office.dll

pause

同样,再建一个卸载的bat批处理命令文件 uninstall.bat:

@echo off
@set baseDir=%~dp0
Echo 1.从缓存中移除程序集

@SETGACUTIL="%baseDir%NETFX 4.8 Toolsgacutil.exe"

rd /s /QC:WindowsMicrosoft.NETassemblyGAC_MSILZhjk

rd /s /QC:WindowsMicrosoft.NETassemblyGAC_MSILWord

rd /s /QC:WindowsMicrosoft.NETassemblyGAC_MSILOffice

Echo 2.注销类型

C:WindowsMicrosoft.NETFrameworkv4.0.30319RegAsm /u %baseDir%Zhjk.dll /tlb:%baseDir%Zhjk.tlb

Echo.

Echo 3.清除注册表

regedit /s %baseDir%regZhjk.OfficialDocument-delete.reg

pause

%~dp0是bat文件当前文件夹路径;RegAsm是程序集注册工具,需要用户先安装Microsoft .Net Framework 4.0;gacutil.exe是全局程序集缓存工具,用户电脑一般没有,所以需要我们将NETFX 4.8 Tools文件夹附带在安装包里

4、完善安装报的一些说明文档,最终将Release发给你想要的用户,让他们点击install.bat进行插件安装。(做好前提准备工作,比如.net framework版本必须升级到4.x)

最终输出包如下:

posted on   杨went  阅读(870)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示