它表面上在做什么
从用户视角,流程很短:- 在 MathType 里定好目标样式(字体、字号、间距等偏好)
- 回到 Word,打开批量格式化
- 选择「整篇文档」或「仅选区」
- 等进度跑完
公式在 Word 里究竟是什么
理解批量格式化,先要理解 MathType 公式在 Word 中的存在形式。 它们通常不是 Word 原生公式(OMML),而是 OLE 嵌入对象。OLE(Object Linking and Embedding)是 Windows 上一套老资格的对象嵌入协议:宿主程序(这里是 Word)保存一块「属于别的程序」的数据;需要编辑时,再把控制权交给那个程序(这里是 MathType)。 在对象模型里,这类公式大致长这样:- 出现在文档的
InlineShapes(行内嵌入图形)集合中 - 带有
OLEFormat - 程序标识(ProgID)通常是
Equation.DSMT4
点下批量格式化之后:逐步发生了什么
官方批量格式化(包括 SDK 里无界面版本的FormatEquations)本质上是一个循环。对文档里每一个目标公式,大致重复下面几步。
1. 在 Word 里定位下一个公式
插件或 VBA 遍历当前文档(或选区)里的嵌入对象,筛出 ProgID 为Equation.DSMT4 的项。每找到一个,就进入单公式处理。
2. 连上 MathType
Word 侧并不是直接「调用一个纯函数改样式」。常见链路是:MT6.DLL 的职责很具体:管理与 MathType 的连接,必要时启动 MathType,再把请求转过去。API 层对应的是连接/断开一类调用(如 MTAPIConnect / MTAPIDisconnect,或经 WLL 封装的 MTInitAPI / MTTermAPI)。
也可以从 OLE 对象本身出发:对公式执行 DoVerb,按注册表里的 verb 把 MathType 服务器拉起来,再通过 IDataObject / IOleObject 读写数据。殊途同归——都要唤醒并占用 MathType 这个进程。
3. 取出公式数据
连接建立后,需要把「这个公式现在是什么」交给 MathType。常见路径包括:- 把公式内容放到剪贴板,再让 MathType 从剪贴板读取
- 或通过 OLE 的
IDataObject::GetData取出 MTEF(MathType 内部格式)、MathML 等
4. 按新偏好生成结果
MathType 套用你在批量格式化里指定的偏好源——文档内偏好、MathType 默认偏好、剪贴板上的样例公式,或偏好文件——对当前公式做变换。 注意:这一步的产品语义是「格式化」,实现上往往更接近 用新偏好重新生成一份公式结果,而不是在原对象上做一次轻量属性更新。5. 写回 Word:删旧,插新
这是整条链路里最「笨」、也最影响体感的一步。 处理完一个公式后,Word 里原来的 OLE 对象通常会被 删除,再在同一位置 插入 一个符合新配置的新公式对象。版面要重排,对象集合要更新,文档要变脏。然后循环进入下一个公式,从头再来。 所以批量格式化的真实节奏是:「与 MathType 通信」到底指什么
日常说「插件要和 MathType 通信」,容易让人联想到网络 API。这里不是。 这里的通信是 同一台机器上的进程间协作,建立在 Windows 的 COM / OLE 之上:
一次成功的单公式格式化,至少涉及:
- Word 对象模型操作(找 shape、删、插)
- COM/OLE 激活与数据交换
- 有时还有系统剪贴板作为中转
为什么它只能逐个做
「不支持多线程」「不能多文档同时跑」听起来像功能缺失,其实更像架构后果。 第一,MathType 服务器倾向于被独占使用。官方 API 里能看到类似「MathType 已在使用中」的错误状态。设计假设是:一边连着一个 MathType,把活干完,而不是开一堆 worker 同时改公式。 第二,Office 自动化和 OLE 嵌入对象,通常活在串行友好的环境里。
Word 的对象模型、UI 线程、嵌入对象的激活与关闭,对并发本来就挑剔。两个线程同时删插同一文档里的 shape,或同时抢同一条 OLE 会话,很容易变成不可预期的状态。 第三,剪贴板是共享资源。
如果格式化路径依赖剪贴板中转,那它在系统级就是全局的。两个任务同时「把公式放进剪贴板再取出来」,会互相踩。 第四,删旧插新依赖文档的当前结构。
每处理完一个公式,文档的 shapes 集合和布局都可能变。下一步「下一个公式」的定位,建立在上一步完成之后的文档状态上。这天然是队列,不是 map-reduce。 于是批量格式化的并行度,基本上就是:一次一个公式,通常还一次一个文档。
为什么在普通电脑上特别卡
慢,不只是因为 MathType「老」。是宿主、通信、写回三层叠在一起。 Word 本身就重。批量过程中,Word 要反复参与定位、删除、插入、刷新显示。文档越大、公式越多、机器越普通,UI 卡顿和内存压力越明显。你以为在跑 MathType,其实很大一部分时间 Word 也在干活。 跨进程往返很贵。
每个公式都可能触发:激活服务器、读数据、写数据、关闭会话。对用户来说是「改个字号」;对系统来说是一次完整的 OLE 事务。 删插比原地修改更伤。
如果只是改对象内部的样式字段,成本会小得多。删掉再插入,等于让 Word 不断重构局部文档结构。这是可观察的:公式很多时,进度不是「匀速算一下」,而更像「一下一下地砸文档」。 把这三件事放在一起,批量格式化的体验就稳定地落在:能用,但沉,而且很难靠「再等等」变成现代工具该有的那种安静后台任务。
这套设计从哪来,卡在哪
站在 MathType 诞生和流行的年代看,这套路径说得通:- 公式是专用编辑器的私有对象
- Word 通过 OLE 托管第三方内容是主流做法
- 「交给原厂程序处理,再嵌回来」是可靠的集成方式
- 在弱机器上批量处理数百个公式依然流畅
- 多文档队列、多线程加速
- 不打开 Word UI 也能离线改格式
读懂之后,你会怎么选
如果你只是偶尔改十来个公式,官方批量格式化仍然是最省事的选择:路径成熟,结果符合 MathType 自己的规则。 如果你经常面对这些情况——- 单文档公式数量很大
- 需要一次处理很多文档
- 机器配置一般,开着 Word 批量跑会明显拖死工作节奏
- 想把格式化嵌进自己的工具链,而不是盯着 Word 进度条