问题提出原因、背景
在高可用云电脑的项目中,需要将云电脑中的所有文件同步到另一台云电脑中,这些文件中就有许多是Office文件。而在实际运行中发现,Office源文件的微小改动,都会使得整个Office文件都需要重新同步,例如,在Word文件的末尾中,添加一个逗号,整个Word文件都发生了变化(在磁盘层面观察)。这样同步传输时耗费的时间和网络资源都很大。
因此,需要调研Office的缓存机制,了解为何Office的微小改动会导致整个文件都发生变化,继而得出该问题的解决办法。
由第一篇“Office调研——Office的缓存机制”的文章中通过调研得出了Office的缓存、落盘机制,并且证明了是“由于Office软件在每次保存中,都将全量数据(包括增量)写入到新的文件中,所以从磁盘层面观察,无论是多微小的改动,都是产生了一个新文件”,导致Office的微小改动会导致整个文件都发生变化。
第二篇“Office调研——获取Office增量的三种方法的可行性”的文章中提出的三种方法都为可行的方法,但在实际的项目中,方法1因为云电脑中存在翼加密,Office软件解压和重新压缩时会因为加密而出现乱码,方法2需要改变前,改变后的两个静态的Office文件,也不太符合要求,最后方法3为项目需要且合适的方法。
本篇继续调研方法3利用VBA代码获取Office增量数据的具体实施办法。
1.问题描述
- 
如何利用VBA从内存中获取到 office 的增量的数据。
- 
如何将这一过程自动化执行,使得用户无感知。(即不用手动点击“宏”进行代码运行)
- 
如何将增量数据传输给agent,agent再传输给另一台机器,最终写入到另一台机器上的新的Office文件上。
2.调研整体逻辑树

3.问题1.获取增量的方法
3.1.方法:官方文档中寻找与比较相关的API接口,如有可直接使用
- 
Application.CompareDocuments (word)【不可行】- 
能够返回有修订记录的文档,不符合要求。
 
- 
- 
Windows.CompareSideBySideWith method (Excel)【不可行】- 
能够打开两个窗口,不符合要求。
 
- 
- 
在开发文档中没有找到 ppt 部分的,比较内容相关的函数接口。【不可行】
3.2.方法:VBA先获取到整个文本的内容,手写比较逻辑获取差异
- 
能够获取到的最小粒度:- 
word,一个段落
- 
excel,一个单元格
- 
ppt,一个shape
 
- 

- 
代码实现比较:- 
word,直接比较提取出来的 string 内容
- 
excel,直接比较提取出来的 string 内容
- 
ppt,暂时未找到办法比较 shape- 
Shape 中如果是text,可以提取出 string 来比较
- 
Shape 中如果是图片,还未找到办法比较,另外,图片存储在shape对象中,也无法提取出来(python-pptx库能提出来)
 
- 
 
- 
- 实现的逻辑

目前可以实现的效果:获取增量后在本地计算机中的另一个文档中进行写入。
结论:手写比较逻辑可行。
4.问题2.自动化的方法
4.1.方法:经过调研,可以通过官方文档中暴露的office事件的接口,进行访问。
4.1.1.office事件接口实现逻辑

4.1.2.已经实现的事件方法
- 
word:通过 App_WindowSelectionChange(ByVal Sel As Selection) 事件,实现自动检测变化内容- 
问题1:word 中光标会有些胡乱地跑动
 
- 
- 
excel:通过 Worksheet_SelectionChange(ByVal Target As Range) 事件,实现自动检测变化内容- 
问题2:excel 中,写完需要点一下单元格,才会进行同步
 
- 
- 
ppt:官方文档中暂时没找到对应的接口函数

4.1.3.针对 ppt 的自动化方法
- 
官方文档中提到的 DAO 数据库模式,可能会有新的解决方案。(等待调研)
- 
Stackoverflow,github 上查一查 看有无其他人已经实现过的内容。(等待调研)
5.问题3.如何将增量数据传输给agent
5.1.方法:(未验证)
- 将增量内容以文件的形式保存到磁盘中,agent读取该文件获得。(等待调研)
- 共享内存,管道等,进程之间传输数据的方法。(等待调研)
6.官方文档中提供的事件接口整理
6.1.Word
6.1.1.Application
| 事件函数(Application) | 作用 | 
|---|---|
| DocumentBeforeClose | 在打开的文档即将关闭之前发生 | 
| DocumentBeforePrint | 在打印打开的文档之前发生 | 
| DocumentBeforeSave | 在保存打开的文档之前发生 | 
| DocumentChange | 在创建新文档、打开已有文档或激活其他文档时发生 | 
| DocumentOpen | 在打开文档时发生 | 
| NewDocument | 在创建新文档时发生 | 
| Quit | 当用户退出 Microsoft Word 时发生 | 
| WindowActivate | 在激活文档窗口时发生 | 
| WindowBeforeDoubleClick | 在默认的双击操作发生之前,当文档窗口的编辑区域被双击时发生 | 
| WindowBeforeRightClick | 在默认右击操作发生之前,当文档窗口的编辑区域被右击时发生 | 
| WindowDeactivate | 在文档窗口成为非活动窗口时发生 | 
| WindowSelectionChange | 在活动窗口中的所选内容更改时发生 | 
| WindowSize | 在对应用程序窗口进行大小调整或移动时发生 | 
| XMLSelectionChange | 在当前所选内容的 XML 父节点更改时发生。 | 
| XMLValidationError | 文档中存在验证错误时发生 | 
6.1.2.Document对象
| 事件函数 | 作用 | 
|---|---|
| BuildingBlockInsert | 构建基块插入文档时发生 | 
| Close | 该事件在关闭文档时发生 | 
| ContentControlAfterAdd | 在将内容控件添加到文档之后发生 | 
| ContentControlBeforeContentUpdate | 更新在内容控件中,但仅当内容来自 Office XML 数据存储区的内容之前发生 | 
| ContentControlBeforeDelete | 在从文档中删除内容控件之前发生 | 
| ContentControlBeforeStoreUpdate | 在用内容控件的值更新文档的 XML 数据存储区之前发生 | 
| ContentControlOnEnter | 当用户进入内容控件时发生 | 
| ContentControlOnExit | 当用户离开内容控件时发生 | 
| New | 在创建基于模板的新文档时发生。 只有当它存储在模板中,将运行 新建 事件的过程 | 
| Open | 在打开文档时发生 | 
| XMLAfterInsert | 用户向文档中添加新 XML 元素时发生。 如果同时向文档中添加多个元素(例如,剪切和粘贴 XML 时),则插入的每个元素都会激发该事件 | 
| XMLBeforeDelete | 用户从文档中删除 XML 元素时发生。 如果同时从文档中删除了多个元素(例如,剪切和粘贴 XML 时),则删除的每个元素都会激发该事件 | 
6.2.excel
6.2.1.Application
| 事件函数 | 作用 | 
|---|---|
| AfterCalculate | 如果所有挂起的同步和异步刷新活动和所有结果计算活动均已完成,则会发生 AfterCalculate 事件。 | 
| NewWorkbook | 当新建一个工作簿时发生此事件。 | 
| SheetActivate | 当激活任何工作表时发生此事件 | 
| SheetBeforeDelete | 在删除任何工作表之前发生 | 
| SheetBeforeDoubleClick | 当双击任何工作表时发生此事件,此事件先于默认的双击操作发生 | 
| SheetBeforeRightClick | 右键单击任一工作表时发生此事件,此事件先于默认的右键单击操作 | 
| SheetCalculate | 在重新计算工作表时或在图表上绘制更改的数据之后发生此事件 | 
| SheetChange | 当用户或外部链接更改了任何工作表中的单元格时发生此事件 | 
| SheetDeactivate | 当任何工作表被停用时发生此事件。 | 
| SheetFollowHyperlink | 单击 Microsoft Excel 中的任何超链接时发生此事件。 有关工作表级别的事件,请参阅 FollowHyperlink 事件的帮助主题。 | 
| SheetLensGalleryRenderComplete | 在标注库的图标 (动态和静态) 完成呈现后发生 | 
| SheetPivotTableAfterValueChange | 在编辑或重新计算(对于包含公式的单元格)数据透视表中的单元格或单元格区域后发生。 | 
| SheetPivotTableBeforeAllocateChanges | 在将更改应用到数据透视表前发生 | 
| SheetPivotTableBeforeCommitChanges | 在向数据透视表的 OLAP 数据源提交更改之前发生。 | 
| SheetPivotTableBeforeDiscardChanges | 在放弃对数据透视表所做的更改之前发生。 | 
| SheetPivotTableUpdate | 在数据透视表的工作表更新之后发生此事件。 | 
| SheetSelectionChange | 任一工作表上的选定区域发生更改时,将发生此事件(但图表工作表上的选定区域发生改变时,不会发生此事件) | 
| SheetTableUpdate | 更新工作表上的表时发生。 | 
| WindowActivate | 工作簿窗口被激活时,将发生此事件 | 
| WindowDeactivate | 任何工作簿窗口被停用时将发生此事件。 | 
| WindowResize | 任何工作簿窗口调整大小时将发生此事件。 | 
| WorkbookActivate | 当激活任一工作簿时发生此事件。 | 
| WorkbookAddinInstall | 当工作簿作为加载宏安装时,发生此事件。 | 
| WorkbookAddinUninstall | 当任一作为加载宏的工作簿卸载时发生此事件。 | 
| WorkbookAfterRemoteChange | 在合并远程用户对工作簿的编辑之后发生 | 
| WorkbookAfterSave | 保存工作簿之后发生此事件 | 
| WorkbookAfterXmlExport | 在 Microsoft Excel 保存或导出指定工作簿中的 XML 数据之后发生此事件。 | 
| WorkbookAfterXmlImport | 在刷新现有 XML 数据连接或将新 XML 数据导入到任何打开的 Microsoft Excel 工作簿后发生 | 
| WorkbookBeforeClose | 当任一打开的工作簿关闭之前立即发生此事件 | 
| WorkbookBeforePrint | 在打印任一打开的工作簿之前发生此事件 | 
| WorkbookBeforeRemoteChange | 在合并远程用户对工作簿的编辑之前发生 | 
| WorkbookBeforeSave | 在保存任一打开工作簿之前发生此事件 | 
| WorkbookBeforeXmlExport | 在 Microsoft Excel 保存或导出指定工作簿中的 XML 数据之前发生此事件。 | 
| WorkbookBeforeXmlImport | 在刷新现有 XML 数据连接或将新 XML 数据导入到任何打开的 Microsoft Excel 工作簿之前发生 | 
| WorkbookDeactivate | 当打开的工作簿转为非活动状态时发生此事件 | 
| WorkbookModelChange | 更新数据模型时发生。 | 
| WorkbookNewChart | 在任何打开的工作簿中创建新图表时发生 | 
| WorkbookNewSheet | 在任何打开的工作簿中新建工作表时发生此事件。 | 
| WorkbookOpen | 当打开一个工作簿时发生此事件。 | 
| WorkbookPivotTableCloseConnection | 在数据透视表的连接关闭之后发生此事件。 | 
| WorkbookPivotTableOpenConnection | 在数据透视表的连接打开之后发生此事件。 | 
| WorkbookRowsetComplete | 当用户钻取记录集或对 OLAP 数据透视表调用行集操作时,将发生 WorkbookRowsetComplete 事件。 | 
6.2.2.workbook
| 事件函数 | 作用 | 
|---|---|
| Activate | 激活工作簿、工作表、图表工作表或嵌入式图表时发生此事件。 | 
| AddinInstall | 当工作簿作为加载项安装时发生。 | 
| AddinUninstall | 当工作簿作为加载宏卸载时,发生此事件。 | 
| AfterRemoteChange | 在合并远程用户对工作簿的编辑之后发生。 | 
| AfterSave | 保存工作簿之后发生此事件 | 
| AfterXmlExport | 在 Microsoft Excel 保存或导出指定工作簿中的 XML 数据之后发生此事件。 | 
| AfterXmlImport | 在刷新现有 XML 数据连接或将新 XML 数据导入指定的 Microsoft Excel 工作簿后发生。 | 
| BeforeClose | 在工作簿关闭之前发生。 如果工作簿已更改,则此事件在询问用户是否保存更改之前发生 | 
| BeforePrint | 在打印指定工作簿(或者其中的任何内容)之前,发生此事件 | 
| BeforeRemoteChange | 在合并远程用户对工作簿的编辑之前发生。 | 
| BeforeSave | 保存工作簿之前发生此事件。 | 
| BeforeXmlExport | 在 Microsoft Excel 保存或导出指定工作簿中的 XML 数据之前发生此事件。 | 
| BeforeXmlImport | 在刷新现有 XML 数据连接之前或将新 XML 数据导入 Microsoft Excel 工作簿之前发生。 | 
| Deactivate | 图表、工作表或工作簿被停用时发生此事件。 | 
| ModelChange | 在 Excel 数据模型更改后发生。 | 
| NewChart | 在工作簿中创建新图表时发生。 | 
| NewSheet | 当在工作簿中新建工作表时发生此事件。 | 
| Open | 打开工作簿时,发生此事件。 | 
| SheetActivate | 当激活任何工作表时发生此事件。 | 
| SheetBeforeDelete | 删除任何工作表时发生 | 
| SheetBeforeDoubleClick | 当双击任何工作表时发生此事件,此事件先于默认的双击操作发生 | 
| SheetBeforeRightClick | 右键单击任一工作表时发生此事件,此事件先于默认的右键单击操作 | 
| SheetCalculate | 在重新计算工作表时或在图表上绘制更改的数据之后发生此事件 | 
| SheetChange | 当用户或外部链接更改了任何工作表中的单元格时发生此事件 | 
| SheetDeactivate | 当任何工作表被停用时发生此事件。 | 
| SheetSelectionChange | 任一工作表上的选定区域发生更改时,将发生此事件(但图表工作表上的选定区域发生改变时,不会发生此事件) | 
| SheetTableUpdate | 更新工作表表后发生 | 
| WindowActivate | 工作簿窗口被激活时,将发生此事件。 | 
| WindowDeactivate | 任何工作簿窗口被停用时将发生此事件。 | 
| WindowResize | 任何工作簿窗口调整大小时将发生此事件。 | 
6.3.ppt
6.3.1.Application
| 事件函数 | 作用 | 
|---|---|
| AfterNewPresentation | 在创建演示文稿后发生。 | 
| AfterPresentationOpen | 在打开现有的演示文稿后发生 | 
| AfterShapeSizeChange | 在对象 (形状、图片、文本框、图表、SmartArt 之后发生,例如) 幻灯片上已调整大小 | 
| ColorSchemeChanged | 配色方案更改后发生此事件 | 
| NewPresentation | 在创建演示文稿后发生,同时将其添加到 Presentations 集合。 | 
| PresentationBeforeClose | 表示 演示文稿 对象之前关闭。 | 
| PresentationBeforeSave | 保存演示文稿前发生此事件 | 
| PresentationClose | 在即将关闭任意打开的演示文稿之前发生,同时将该演示文稿从 Presentations 集合中删除 | 
| PresentationCloseFinal | 最终 演示文稿 对象关闭时表示。 | 
| PresentationNewSlide | 在任意打开的演示文稿中新建幻灯片时发生,同时将该幻灯片添加到 Slides 集合中 | 
| PresentationOpen | 打开现有的演示文稿时发生,同时将该演示文稿添加到 Presentations 集合中。 | 
| PresentationPrint | 打印演示文稿前发生此事件。 | 
| PresentationSave | 保存任意打开的演示文稿前发生此事件。 | 
| PresentationSync | 在作为文档工作空间一部分的演示文稿的本地副本与服务器上的副本进行同步时发生此事件。 提供有关演示文稿的成功或失败的重要状态信息 | 
| ProtectedViewWindowActivate | 在激活任何“受保护的视图”窗口时发生 | 
| SlideSelectionChanged | 此事件发生的时间取决于当前视图 | 
| SlideShowBegin | 当启动幻灯片放映时发生此事件。 | 
| SlideShowEnd | 此事件在幻灯片放映结束后(即紧跟在最后一个 SlideShowNextSlide 事件发生后)发生 | 
| SlideShowNextBuild | 在单击鼠标时或计时动画,但在动画的对象变得可见之前发生 | 
| SlideShowNextClick | 下次在幻灯片上单击时发生 | 
| SlideShowNextSlide | 在即将切换到下一张幻灯片之前发生此事件。 对于第一张幻灯片,紧跟在 SlideShowBegin 事件发生后发生此事件 | 
| SlideShowOnNext | 当用户单击“下一张”以在当前幻灯片中移动时发生此事件 | 
| SlideShowOnPrevious | 当用户单击“上一张”以在当前幻灯片中移动时发生此事件。 | 
| WindowActivate | 当激活某个应用程序窗口或任意文档窗口时发生此事件 | 
| WindowBeforeDoubleClick | 当双击下表列出的视图中的项目时发生此事件 | 
| WindowBeforeRightClick | 用鼠标右键单击某个形状、 幻灯片、 备注页或某些文本时发生。 MouseUp 事件都会触发此事件 | 
| WindowDeactivate | 停用应用程序窗口或任意文档窗口时发生此事件 | 
| WindowSelectionChange | 当活动文档窗口中选取的文本、形状或幻灯片发生更改时(使用用户界面或使用代码),会发生此事件。 | 
7.综合结论
1. 问题1:如何利用VBA从内存中获取到 office 的增量的数据?
答:手写VBA代码实现比较逻辑,可行。
2. 问题2:如何将这一过程自动化执行,使得用户无感知?(即不用手动点击“宏”进行代码运行)
答:word和excel可以使用事件接口实现自动化,ppt需要另外寻找办法实现。
3. 问题3:如何将增量数据传输给agent,agent再传输给另一台机器,最终写入到另一台机器上的新的Office文件上?
答:目前未找到实现办法。
由于后续工作安排变动,本期“Office缓存机制调研”调研结束。
共三篇:
《Office调研——Office的缓存机制》
《Office调研——获取Office增量的三种方法的可行性》
《Office调研——用VBA代码获取Office增量数据》