在工作中我们要实现一个功能,需要创建MS Office 和 WPS 兼容插件,也就是创建一个DLL,可以同时兼容office和wps。这样带来的好处就是只需要维护同一份代码,大大降低维护的工作!

1. 我们先看看要创建office插件都有哪些技术可以用

  • VSTO

VSTO = Visual Studo Tools for Office,基于.net framework框架的Office开发技术。相对于传统的VBA(Visual Basic Application)开发,VSTO为中高级开发人员提供了更加强大的开发平台和语言,并部分解决了传统Office开发中的诸多问题(难于更新、可扩展性差、难以维护、安全性低等),开发人员可以使用熟悉的技术来构建更加灵活的、强大的、跨平台的企业级解决方案。

下图是我的机器上VS2013的创建项目:

主要采用C#语言开发,功能强大,感兴趣的同学可以去google更多相关知识。

我的需求是要创建可兼容两大办公软件平台的插件,很显然这种技术在WPS下不大可能支持,而且对于XP系统的用户,我们不可能让用户再去安装一个几百M的.net框架,毕竟国内使用XP的量还比较大。因此这个方案不属于我们的要求,继续寻找中。。。

  • Shared Add-in

这是VS2010的项目创建截图:

在扩展插件项目下,有两种类型的插件可以创建。

1) Visual Studio Add-in 顾名思义,这个项目类型是用于创建 Visual Studio IDE插件的项目,不是我们的菜。

2) Shared Add-in 字面意思是共享插件 项目,这个正是我们所需要的插件类型。

Shared Add-in 的官方解释:Conversely, a Shared add-in can be loaded only into Microsoft Office applications such as Microsoft Word, Microsoft Publisher, Microsoft Visio, and Microsoft Excel. 大意是,Shared add-in可以被MS Office系列软件调用。

进一步研究后得知,Shared Add-in 也就是com插件技术,在wps的最新版本上支持这种com插件,这样就初步满足了我们要的全平台兼容插件。

2. 开始创建我们的插件

创建项目

点击OK后,会出来一个创建向导,第一步是可以选择你要使用的语言,如果用C#语言可能会导致引入.net的依赖,这不是我们所希望,我们希望创建的插件尽可能是本地代码,所以我们选择了使用C++/ATL。

选择要支持的哪些软件,可选项很多。这里选择软件的意义,就是增加一些接口和注册表项,这里的选择对WPS系列软件的支持没有影响,推荐这里选一个就好了,后面我们会使用手工自定义的方式来做。

填写你的插件名字和描述。

如果你希望在应用程序启动时通知你的插件,你就勾选那个选项。

最后确认你的选择没有问题后,点击 Finish就能创建你的插件了。

3. 认识插件项目

下图是创建项目后文件分布,rpc文件夹是我自己创建的,请忽略。

我们主要会对以下文件进行修改:

Addin.rgs文件 - 注册脚本(Register Script, 简 称RGS),该文件会主要用于将插件注册到相应注册表中。在ATL中,COM服务程序的注册是在工程编译连接的最后阶段,由ATL辅助完成的。在手工的COM编程中,服务程序的注册是比较麻烦的工作。在ATL中,系统通过读取在建立工程过程中形成的注册脚本文件来完成注册工作。

Connect.h\cpp 文件 - 插件的事件通知接口均在该文件中定义。

其它文件几乎不用动,都是一些自动生成的代码。

4. 连接插件事件

Office系列软件的版本很多,从Office2003 到 Office2013 都有,好消息是,com插件是向下兼容的,不同版本间的不同点在于高版本一搬会增加更多的事件通知,根据你需要的事件通知来选择你要从哪个版本的office系列开始支持。

我需要监控office打开某个文件的事件通知,选择了从Office10版本开始进行支持,该事件可以被全部版本兼容。

1) 添加com库类型文件

安装office07后,在安装目录下office10目录中,其中com库对应关系如下:

word - MSWORD.OLB

PPT - MSPPT.OLB

EXCEL – EXCEL.exe

其中EXCEL比较特殊,com库存在于其exe之中,其它office软件也有相应的com库,这里就不一一列出了。

把上述文件copy出来到你的目录中。

2)引入com库文件到项目

有了上述com类型库文件后,我们就可以引入需要的com了。在Connect.h增加好下代码:

#import "..\3rdparty\Office12\MSO.DLL" rename_namespace("Office2010") rename("RGB","RGB2"), rename("DocumentProperties","DocumentProperties2")

MSO.DLL是我们要用到的office系列com库的公共库文件,必须要先引入该库。

引入VBA,主要是为了防止编译不过去:

#import "..\3rdparty\VBA6\VBE6EXT.OLB"

同样方法,引入实际com:

#import "..\3rdparty\Office12\MSWORD.OLB" rename_namespace("MSWord"), rename("ExitWindows","WordExitWindows"),rename("FindText","WordFindText"), named_guids

#import "..\3rdparty\Office12\excel.tlb" rename_namespace("MSExcel"), rename("DialogBox","ExcelDialogBox"), rename("RGB", "ignorethis"), rename("DialogBox", "ignorethis"), rename("ReplaceText", "EReplaceText"), rename("CopyFile","ECopyFile"), rename("FindText", "EFindText"), rename("NoPrompt", "ENoPrompt") exclude("IFont","IPicture")

#import "..\3rdparty\Office12\MSPPT.OLB" rename_namespace("MSPowerPoint"), rename("RGB", "ignorethis")

编译代码,会在项目目录下生成众多相关文件。tlh、tli文件:他们是vc++编译器解析tlb文件生成的标准c++文件。因为odl和tlb并不是C++标准的东东,有必要把它们翻译成标准的 C++类型,使得C++开发者可以使用。相信vb和j++也会把tlb翻译成自己语言兼容的类型描述信息。

tlh相当于类型申明(头文件)
tli相当于定义实现(CPP文件)

编译上面的com时,你的本机必须要安装了相应的office版本,否则很有可能会出错。由于我们的代码是在单独的构建机上编译,为了避免在纯净的构建机上安装office10软件,我做了些处理,直接使用解析后的文件。类似于如下代码:

#include "..\3rdparty\Office12\include\msword.tlh"
#include "..\3rdparty\Office12\include\excel.tlh"
#include "..\3rdparty\Office12\include\msppt.tlh"

wps相关:

#include "..\3rdparty\wps-office6\include\ksoapiv8.tlh"
#include "..\3rdparty\wps-office6\include\wpsapiv8.tlh"
#include "..\3rdparty\wps-office6\include\etapiv8.tlh"
#include "..\3rdparty\wps-office6\include\wppapiv8.tlh"

tlh文件中,有相应tli文件的绝对位置,这个可能在其它机器上编译不通过,因此需要手动修改为引用相对地址,根据编译错误,很好修改。

3)连接com事件

通过上述步骤后,已经可以使用com中的事件了。首先实现一个模板类:

typedef IDispEventSimpleImpl</*nID =*/ MSWord_ID, CConnect, &__uuidof(MSWord::ApplicationEvents2)> MSWordDispEventImpl;

MSWord_ID : 随意定义一个ID即可,用于下面区分不同事件。

CConnect增加一个继承类MSWordDispEventImpl,增加如下一个消息循环:

BEGIN_SINK_MAP(CConnect)

// msword events
    SINK_ENTRY_INFO(/*nID =*/ MSWord_ID, __uuidof(MSWord::ApplicationEvents2), /*dispid =*/ 0x4, OnDocumentOpen, &DocumentOpenInfo)

END_SINK_MAP()

其中:

dispid - 事件ID号,查询MSDN官方文档,或者tlh中会有相关ID

OnDocumentOpen - 事件响应函数,函数类型:void __stdcall OnDocumentOpen(LPDISPATCH  ptr); 这里的参数类型要根据这个事件实际的参数类型来创建

DocumentOpenInfo – 参数类型信息,_ATL_FUNC_INFO DocumentOpenInfo = {CC_STDCALL,VT_EMPTY,1,{VT_DISPATCH|VT_BYREF}};,具体参数信息,可以查询其它相关文档

上面操作完成后,CConnect已经可以收到Word打开文档的事件通知,关于该事件的详细触发时间点,可以查询相关MSDN文档。在OnDocumentOpen函数体中,你已经可以写下你想要的功能代码了。

其它各种事件采用相同方式完成即可。

4)注册插件

在AddIn.rgs文件中加入如下代码,完成注册过程:

HKLM
{
    Software
    {
        Microsoft
        {
            Office
            {
                Word
                {
                    Addins
                    {
                        ForceRemove 'YourAddin.Connect'
                        {
                            val Description = s 'Yourdesc'
                            val FriendlyName = s 'YourName'
                            val LoadBehavior = d '3'
                        }
                    }
                }

Excel
                {
                    Addins
                    {
                        ForceRemove 'YourAddin.Connect'
                        {
                            val Description = s ''Yourdesc''
                            val FriendlyName = s 'YourName'
                            val LoadBehavior = d '3'
                        }
                    }
                }
            }
        }
    }

}

有关rgs文件语法说明,需要参考其它相关文件。

5)调试插件

插件写好,我们得要调试插件。首先你运行的vs必须是要以“管理员”方式启动的,把插件库设置为启动项,在启动参数里写入world.exe的绝对目录,启动调试后就可以调试插件中的事件响应了。

6. 总结

本篇是是对Office的插件技术实现的描述,特点是实现了兼容wps的插件事件。优点在于使用C++语言实现,生成的插件dll体积小,不依赖于.net ,方便安装使用;缺点是c++语言,对ATL com的知识也有一定要求,开发难道较高。

创建MS Office 和 WPS 兼容插件的更多相关文章

  1. 怎么用OCR图文识别软件在MS Office中创建PDF文件

    ABBYY PDF Transformer+是一款可创建.编辑及将PDF文件转换为其他可编辑格式的OCR图文识别软件,不仅可以从纸质文档.图像文件和任何其他流行格式创建PDF文件(相关文章请参考如何从 ...

  2. (翻译)OpenDocument and Open XML security (OpenOffice.org and MS Office 2007)

    标题:Open Document 和 Open XML安全性(OpenOffice.org and MS Office 2007) 摘要,OpenDocument 和 Open XML 都是 Offi ...

  3. java读取pdf和MS Office文档

    有时候PDF中的文字无法复制,这可能是因为PDF文件加密了,不过使用PDFBox开源软件就可以把它读出来. 还有一个用于创建PDF文件的项目----iText. PDFBox下面有两个子项目:Font ...

  4. 跟着未名学Office – 整体了解 Ms Office 2010

    目录 MS Office 2010    2 Microsoft Office System    2 Ribbon(功能区)    2 文件选项卡    3 SmartArt    3 屏幕截图   ...

  5. MS Word2016加载EndnoteX6插件

    我的软件环境是:Win10 x64.MS Office 2016 x64.Endnote X6 32位. 在安装完MSO和Endnote后,Word中未能自动加载Endnote插件.现将启用方法记录如 ...

  6. C#将Word转换成PDF方法总结(基于Office和WPS两种方案)

    有时候,我们需要在线上预览word文档,当然我们可以用NPOI抽出Word中的文字和表格,然后显示到网页上面,但是这样会丢失掉Word中原有的格式和图片.一个比较好的办法就是将word转换成pdf,然 ...

  7. MS OFFICE 2010破解版安装

    受人所托发布一个MS OFFICE 2010破解版的傻瓜安装教程,刚好新本本也没有安装,安装过程中截了几个图就搞定了. 安装包: http://www.itopdog.cn/soft/office20 ...

  8. [转]设置MS Office Word for mac的默认显示比例

    由于mac os的分辨率比较大,在PC上显示正常的word文档(显示比例100%),在mac下打开会很小,需要经常调整显示比例,如调到125%.130%或150%,可以通过下面方法来设置默认显示比例, ...

  9. MS OFFICE WORD 绝招

    以MS OFFICE WORD 2010为例. 1.WORD 文件夹连接线(标准称呼:前导符)为什么有的稀,有的密? 答案:文件夹格式字体不同. 2.首页.文件夹页.正文有的要页眉,有的不要,首页不要 ...

随机推荐

  1. MySQL Order By Rand()效率

    最近由于需要大概研究了一下MYSQL的随机抽取实现方法.举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RA ...

  2. I-frame、B-frame、P-frame及DTS、PTS的关系(转)

    基本概念: I frame :帧内编码帧 又称intra picture,I 帧通常是每个 GOP(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,做为随机访问的参考点,可以当成图象. ...

  3. 隐藏apache版本号 PHP版本号

    httpd-default.conf ServerTokens Prod ServerSignature Off php.ini expose_php Off 重启服务器

  4. SSO单点登录在web上的关键点 cookie跨域

    概述 其实WEB单点登录的原理挺简单的,抛开那些复杂的概念,简单来讲讲如何实现一个最基本的单点登录 首先需要有两个程序 例如:http://www.site-a.com 我们简称A http://ww ...

  5. poj2528(线段树+离散化)Mayor's posters

    2016-08-15 题意:一面墙,往上面贴海报,后面贴的可以覆盖前面贴的.问最后能看见几种海报. 思路:可以理解成往墙上涂颜色,最后能看见几种颜色(下面就是以涂色来讲的).这面墙长度为1~1000 ...

  6. dom 按着shift多选

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  7. CentOS(RedHat) 6.2 Samba share权限拒绝访问

    在实现<CentOS(RedHat) 6.2下Samba配置>的过程中,发现CentOS 6.2的Samba share总是没有权限写文件,已经试过在Windows XP/Windows  ...

  8. C++11右值引用

    [C++11右值引用] 1.什么是左值?什么是右值? 左值是表达式结束后依然存在的对象:右值是表达式结束时就不再存在的对象. 2.std::move的作用是什么? std::move用于把任意类型转化 ...

  9. SD卡中的命令CMD

    SD卡中的命令是SD控制器和SD卡之间的桥梁,它封装了SD卡的实现细节,不影响SD卡中FLASH的读写变更. 命令的长度是48位,它的字段如图: SD校准定义的CMD如下:

  10. easyui问题小记

    在easyui1.4.3版本中,(其他版本不知道是不是也是这样的),绑定在datagridview上面的数据最好不要是带有特殊符号的字段,不然会导致部分的属性不好用,比如这样的字段  START_DA ...