引用本文(DOI: 10.5281/zenodo.21615450)
本文保存于 Zenodo。以下同时提供始终指向最新版本的 DOI,以及固定于您正在阅读版本的 DOI。
小村 豪(2026)。《COM / ActiveX / OCX 是什么 - 区别与关系一并梳理》。小村软件有限公司。https://doi.org/10.5281/zenodo.21615450 https://comcomponent.com/zh-CN/blog/2026/03/13/000-what-is-com-activex-ocx/
- DOI(最新版本)
- 10.5281/zenodo.21615450
- DOI(此版本)
- 10.5281/zenodo.22281965
COM / ActiveX / OCX 这 3 个词,在 Windows 的遗留项目里基本上都是成套出现的。
- 厂商发来一个
.ocx - Access 或 VB6 的界面上放着来历不明的控件
- 别人刚说完“这是 COM”,转头又说“是 ActiveX”
- 紧接着
regsvr32、32bit / 64bit、IE 模式这些词一起涌上来
走到这一步,对话基本上就对不上了。原因是这些词本身相近,历史上的重叠也很大。 反过来说,只要能把这里分开理解,排查、迁移、解释的难度都会明显不同。
flowchart TB
accTitle: 对话对不上的成因
accDescr: COM、ActiveX、OCX 这些相近的词在同一个现场一起冒出来时对话就会对不上,而把哪个是底层、哪个是组件、哪个是文件分开理解之后,排查、迁移和解释都会变得容易。
mix["3 个词一起冒出来"] --> lost["对话对不上"]
split["分成底层、组件、文件"] --> clear["排查、迁移和解释都变轻松"]
图1:本文的目的只有一个 —— 把“哪个是底层、哪个是组件、哪个是文件”分开。
本文会按照能看出区别与关系的顺序,整理 COM 是什么、ActiveX 是什么、OCX 是什么。
尤其要讲清楚 哪个是底层、哪个是组件、哪个是文件。
目录
- 先给结论(一句话)
- 本文所说的 COM / ActiveX / OCX
- 先用一张图收拢
- 3.1. 关系图
- 3.2. 术语的最短整理
- 什么是 COM
- 4.1. 一句话说
- 4.2. COM 中重要的东西
- 4.3. 术语的一行笔记
- 什么是 ActiveX
- 5.1. 一句话说
- 5.2. ActiveX 并非浏览器专用
- 什么是 OCX
- 6.1. 一句话说
- 6.2. 与
.dll有什么不同
- 用表格整理区别
- 它们被用在哪里
- 为什么容易被混淆
- 现在的实务中该怎么看
- 常见误解
- 排查时的检查要点
- 总结
- 参考资料
图中实线表示始终成立的关系,虚线表示带条件的关系(成立条件写在详情页各关系的说明中)。关系的完整列表(共 18 条,附依据与确信度)以及主要概念的定义,汇总在知识地图详情页(日文)。数据:JSON-LD / Turtle
1. 先给结论(一句话)
先说一个粗糙但好用的说法:
- COM 是底层。它是 Windows 上组件之间互相打交道用的二进制契约
- ActiveX 是以 COM 为基础的组件语境。尤其容易以“嵌入宿主使用的控件”这种形式出现
- OCX 是 ActiveX 控件里常见的实现文件。你会以文件扩展名的形式遇到它
- 也就是说,按 COM = 机制、ActiveX = 组件的语境、OCX = 文件 来理解,思路会清楚很多
ActiveX = 老浏览器上那个危险的东西这个记忆对了一半,还差一半。ActiveX 并非浏览器专用OCX = ActiveX在口语里常被当作几乎同义的说法,但严格来说这是把概念和文件扩展名混在了一起- 现在的新开发不会把它放在主角的位置,但在既有的 Windows 应用、Office、Access、设备 SDK、内部 Web 里还是会遇到
一切要从把这 3 件事分开来想开始。
- 它说的是 COM 的事 吗
- 它说的是 ActiveX 控件的事 吗
- 还是只是 看到
.ocx文件才这么叫
想明白这一点,迷雾会散去不少。
flowchart TB
accTitle: 一开始要分开的 3 个问题
accDescr: 先分清眼前谈的是 COM 这个机制的事,还是 ActiveX 控件这个组件的事,或者只是看到 ocx 文件才这么叫。
q{"现在谈的到底是什么"}
q --> a["COM = 机制的事"]
q --> b["ActiveX = 组件语境的事"]
q --> c["OCX = 文件的事"]
图2:一犹豫就回到这 3 选 1。COM 是机制,ActiveX 是组件的语境,OCX 是文件。
2. 本文所说的 COM / ActiveX / OCX
这 3 个词在实务中常常被随意地混在一起用。 所以本文先把它们的含义固定下来。
- COM:Windows 的组件模型本身。接口、GUID、注册、调用的底层
- ActiveX:以 COM 为基础的、可嵌入的控件及其使用语境。实务上尤其常指 ActiveX 控件
- OCX:ActiveX 控件实现中常见的文件扩展名,
.ocx
稍作补充,历史上曾有一段时期,ActiveX 这个词用得更宽一些。
不过现在实务上说到 ActiveX 时让人头疼的地方,大多集中在 控件、嵌入、宿主、浏览器、注册 这一带。
所以本文基本上也按 ActiveX = 偏 ActiveX 控件的话题 来展开。
flowchart TB
accTitle: ActiveX 一词的宽度与本文的焦点
accDescr: 历史上 ActiveX 这个词曾用得更宽,但现在实务上让人头疼的是控件、嵌入、宿主、浏览器、注册这一带,所以本文把焦点收在偏 ActiveX 控件的话题上。
word["ActiveX 这个词"] --> wide["历史上也有更宽的含义"]
word --> now["现在头疼的是控件周边"]
now --> focus["本文按偏控件的方向展开"]
now -.-> items["嵌入、宿主、浏览器、注册"]
图3:承认这个词在历史上的宽度,同时把焦点固定在实务上让人头疼的“偏控件”一侧。
3. 先用一张图收拢
3.1. 关系图
先用一张图看全貌是最快的。如果所处环境显示不出图,图正下方的列表内容与图相同,请读那一部分。
flowchart LR
COM["COM<br/>二进制契约的底层"] --> OLE["OLE / Automation<br/>嵌入与自动化的机制"]
OLE --> AX["ActiveX<br/>以 COM 为基础的控件语境"]
AX --> CTRL["ActiveX 控件"]
CTRL --> OCX["OCX (.ocx)<br/>实现文件中常见的形态"]
HOST["宿主 / 容器<br/>IE / Access / VB6 / MFC / WinForms"] --> CTRL
图4:以 COM 为底层,OLE / Automation、ActiveX、OCX 层层叠加,宿主把控件放上去的关系图。
这里重要的是,COM 和 ActiveX 不是同一个词。
- COM 是底层
- OLE / Automation 是用于嵌入和自动化的机制
- ActiveX 是在其之上被使用的控件语境
- OCX 是那个控件实现中常见的文件
所以当有人问 ActiveX 就是 COM 吗,答案是 底层是 COM,但 ActiveX 并不是 COM 本身。
3.2. 术语的最短整理
| 词 | 先这样理解 |
|---|---|
| COM | 机制、契约、底层 |
| ActiveX | 以 COM 为基础的嵌入式组件语境 |
| ActiveX 控件 | 真正被放到宿主上的组件本身 |
| OCX | ActiveX 控件中常见的文件扩展名 |
| OLE / Automation | 嵌入、自动化、集成的机制 |
如果要用最短的方式记住,这样就够了。
- COM 是机制
- ActiveX 是组件的语境
- OCX 是文件
4. 什么是 COM
4.1. 一句话说
COM 是 Component Object Model 的缩写,是 Windows 上组件之间互相打交道用的 二进制契约。
这里说的二进制契约,指的不是源代码的写法或语言规范上的约定,而是 在编译之后的形态下依然成立的接口约定。 用 C++ 做出来的组件能被别的语言、别的应用使用,正是因为有这个契约。
贴近实务的感受来说,COM 与其说是 一种方便的库发布方式,不如说是 把实现隐藏起来、只靠契约对接的机制。
例如下面这些就是 COM 的典型(每个词的含义在 4.3 里各用一行做了汇总)。
- 用
IUnknown做引用计数 - 用
QueryInterface查找接口 - 用
IID、CLSID这类基于 GUID 的标识 - 以 DLL 的形式做进程内使用
- 以 EXE 的形式做跨进程使用
总之,COM 是 Windows 组件化文化的底层。
flowchart TB
accTitle: 二进制契约这一思路
accDescr: COM 不依赖源代码的方便或语言规范,而是用编译之后依然成立的约定即二进制契约来连接组件,所以用 C++ 做出来的组件能被别的语言和别的应用使用。
part["组件(实现隐藏起来)"] --> contract["二进制契约(公开的约定)"]
contract --> user["别的语言、别的应用"]
contract -.-> note["编译之后约定依然成立"]
图5:COM 的核心是“把实现隐藏起来、只靠契约对接”。所以组件能跨语言使用。
4.2. COM 中重要的东西
只看基本的话,COM 中下面这几点是重要的。
- 以接口为中心
- 先决定要公开什么,再谈实现
- 用 GUID 标识
- 类和接口都被唯一地标识
- 宿主与实现分离
- 调用方不必知道内部实现
- 能跨进程
- 不只是同一进程,作为别的进程里的组件也能使用
这些正是让 COM 没有沦为一项单纯的老技术的原因。 从相当早的年代起,它就扎实地拥有了 以契约为基础做复用的设计。
flowchart TB
accTitle: COM 中重要的 4 根支柱
accDescr: 以接口为中心的设计、用 GUID 做唯一标识、宿主与实现分离、能跨进程,这 4 点让 COM 成为以契约为基础的复用设计。
com["COM 的基本"] --> p1["以接口为中心"]
com --> p2["用 GUID 标识"]
com --> p3["宿主与实现分离"]
com --> p4["能跨进程"]
图6:支撑 COM 的 4 根柱子。它从很早的年代起就拥有以契约为基础的复用设计。
4.3. 术语的一行笔记
谈 COM 的时候,下面这些词会不加解释地飞过来。这里作为概念的入口,先每个词只记一行。想深入到设计本身的乐趣的读者,可以看 什么是 COM - 为什么 Windows COM 的设计至今仍然优雅。
| 术语 | 一行的含义 |
|---|---|
| 接口 | 组件承诺“这些可以调用”的一串函数。它与实现是分开的 |
IUnknown |
所有 COM 接口的底层接口。只有 QueryInterface / AddRef / Release 这 3 个方法 |
QueryInterface |
用来问手上的组件“你是不是也有这个接口”的方法。有的话就返回那个指针 |
| 引用计数 | 统计使用者数量的计数器。AddRef 时增加,Release 时减少,归零的那一刻组件被释放 |
| GUID | Globally Unique Identifier 的缩写,写成 {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} 形式的 128 bit 标识符。用来避免名字冲突 |
| CLSID | Class ID 的缩写,是指向“哪个组件(类)”的 GUID。注册表里的注册也用这个值来查 |
| IID | Interface ID 的缩写,是指向“哪个接口”的 GUID |
| ProgID | 给 CLSID 起的、面向人的别名。是形如 Excel.Application 的字符串,脚本之类要指定组件时会用到 |
| Type Library | 汇总了组件公开的接口和方法的类型信息的数据。VB6 或 .NET 引用组件时会读它 |
| Apartment(STA / MTA) | COM 的线程规约。STA 是“这个组件只从一条线程调用”,MTA 是“可以从多条线程同时调用”的约定,UI 组件基本都在 STA 一侧 |
本文只做到概念的梳理,不深入各项的细节。等需要谈实现的时候,把这张表里的词直接当作检索词,比较容易找到方向。
flowchart TB
accTitle: 以 IUnknown 为底层的基本动作
accDescr: 作为所有 COM 接口底层的 IUnknown,用 QueryInterface 询问别的接口,用 AddRef 和 Release 增减引用计数,归零的那一刻组件被释放,这就是它的基本动作。
iu["IUnknown(一切的底层)"] --> qi["用 QueryInterface 询问"]
qi --> got["持有就返回指针"]
iu --> rc["用 AddRef 和 Release 管理个数"]
rc --> zero["归零后释放组件"]
图7:位于术语表中心的 IUnknown 的 3 个方法,分成“询问”和“计数”两件事。
5. 什么是 ActiveX
5.1. 一句话说
把 ActiveX 理解为以 COM 为基础的 可复用软件组件,尤其是 嵌入宿主或容器中使用的控件,会比较好懂。
实务中说 ActiveX 时,相当高的概率是在说 ActiveX 控件。
例如按钮、表格、图表、日历、查看器、设备联动组件之类的东西就属于这一类。
与其把 ActiveX 当作 一项独自摆着架子的庞大技术,不如把它理解为 嵌入某个宿主之中工作的组件,这样不容易跑偏。
flowchart TB
accTitle: 嵌入宿主中工作的组件
accDescr: 实务中说到 ActiveX 有相当高的概率是在说 ActiveX 控件,也就是按钮、表格、图表、查看器、设备联动组件这类嵌入宿主或容器中工作的组件。
host["宿主 / 容器"] --> ctrl["ActiveX 控件"]
ctrl --> ex1["表格或日历"]
ctrl --> ex2["查看器或设备联动组件"]
ctrl -.-> note["不是独自站着的庞大技术"]
图8:把 ActiveX 理解为“嵌入之后工作的组件”,就不容易跑偏。
5.2. ActiveX 并非浏览器专用
ActiveX = Internet Explorer 那个东西 的印象相当强烈。
这并不算错,但 只有这些是不够的。
试着举出 ActiveX 控件被用过的地方。
- Access 表单
- VB6(Visual Basic 6.0)应用
- MFC(Microsoft Foundation Class 库)的容器
- Office / VBA 周边
- 从 WinForms 通过 COM 包装器使用
- Internet Explorer 及其兼容运维的语境
也就是说,ActiveX 是 并非浏览器专用、在 Windows 应用一侧也被长期使用的组件技术。
不明白这一点,就会把在内部 Web 上发现的 ActiveX 和嵌在 Access 界面里的 ActiveX 看成两码事。 实际上两者都是相当靠近 COM 的亲戚。
flowchart TB
accTitle: ActiveX 控件被用过的地方
accDescr: Access 表单、VB6 应用、MFC 的容器、Office 与 VBA 周边、从 WinForms 通过 COM 包装器使用,以及 Internet Explorer,ActiveX 并非浏览器专用,在 Windows 应用一侧也被长期使用。
ax["ActiveX 控件"] --> d["Access、VB6 和 MFC"]
ax --> o["Office 和 VBA 周边"]
ax --> w["WinForms 的 COM 包装器"]
ax --> ie["Internet Explorer 系"]
ie -.-> myth["出名的只有这里"]
图9:只是在 IE 上显眼而已,被用过的地方大半在 Windows 应用一侧。
6. 什么是 OCX
6.1. 一句话说
OCX 是 ActiveX 控件实现中常用的文件扩展名。
在 Windows 现场看到 .ocx,首先可以怀疑它是 嵌入式控件类的 COM 组件。
出现的场合大致是这些。
- 厂商 SDK 的发布物
- VB6 / Access / MFC 的老项目
- 安装程序中包含的注册对象文件
- 需要
regsvr32的组件
要记住的是,OCX 是文件的形态,而不是概念本身。
所以要粗略地回答 OCX 是什么,答案就是 作为 ActiveX 控件的实体经常遇到的一种文件。
6.2. 与 .dll 有什么不同
这里也是容易混乱的地方。
.ocx相当强烈地暗示着它是 ActiveX 控件.dll可能是普通的库,可能是 COM 服务器,也可能是 ActiveX 周边的依赖 DLL
看到 .ocx 基本就能判断这是偏 ActiveX 的话题,但只看到 .dll 还不知道它是什么来头。
实务上常见的是,
vendorcontrol.ocxvendorhelper.dllvendorcore.dll
像这样排在一起,主角是 OCX,由 DLL 在旁边辅助 的模式。
所以被问到 OCX 是不是 DLL 的一种 时,感觉上确实接近,但在排查的场合 把角色分开看 更安全。
flowchart TB
accTitle: 从扩展名能读出的信息差
accDescr: ocx 强烈暗示着它是 ActiveX 控件,而 dll 还不知道是普通的库、COM 服务器还是依赖 DLL。实务上常见主角是 OCX、由旁边的 DLL 辅助的模式。
q{"扩展名是什么"}
q -->|".ocx"| ax["基本能判断是偏 ActiveX 的"]
q -->|".dll"| unk["还不知道是什么来头"]
unk --> roles["是库、是 COM 服务器还是依赖"]
ax -.-> pair["主角 OCX 由旁边的 DLL 辅助的形态"]
图10:.ocx 能让人有个判断,但 .dll 不查清角色就不知道是什么来头。
7. 用表格整理区别
| 词 | 是什么 | 实务中常见的词 | 常见的实体 |
|---|---|---|---|
| COM | 组件模型、二进制契约的底层 | IUnknown、QueryInterface、CLSID、IID、Apartment |
.dll、.exe、注册信息 |
| ActiveX | 以 COM 为基础的控件语境 | 容器、嵌入、属性、事件 | ActiveX 控件 |
| ActiveX 控件 | 实际被放置的可复用组件 | 表格、日历、查看器、设备联动 | .ocx、.dll |
| OCX | ActiveX 控件中常见的文件扩展名 | regsvr32、工具箱、32bit / 64bit |
xxx.ocx |
| OLE / Automation | 嵌入与自动化的机制 | Office 集成、属性页、自动化 | 各种以 COM 为基础的功能 |
如果要靠这张表来记,先记住这些。
- COM 是地基工程
- ActiveX 是建在其上的组件文化
- OCX 是在现场捡到的文件
8. 它们被用在哪里
ActiveX / OCX 因为浏览器的记忆太强烈,容易被看成 古早的 Web 技术。
不过实际上它们被用得更广。
具体是这样一些地方。
- 桌面应用
- VB6
- MFC / C++
- Access 表单
- Office / VBA 周边
- 浏览器 / 内部 Web
- 嵌入 Internet Explorer 的查看器
- 签名组件
- 文件传输组件
- 外围设备联动组件
- 既有的 .NET 应用
- 从 WinForms 包装后使用的既有 ActiveX 控件
- 把既有 COM 资产当作 UI 组件继续沿用的情况
在这里最终还是回到 ActiveX 并非互联网专用 这个话题上。 只是因为它在 IE 上格外显眼才看起来像 Web 技术,就实际情况而言,把它看作 Windows 的嵌入式组件技术 在实务上更贴切。
flowchart TB
accTitle: 观感与实际情况的偏差
accDescr: 因为在 IE 上格外显眼,ActiveX 容易被看成古早的 Web 技术,但实际上桌面应用、内部 Web、既有的 .NET 应用都在广泛使用它,它本质上是 Windows 的嵌入式组件技术。
look["在 IE 上显眼的记忆"] --> web["看起来像古早的 Web 技术"]
real["实际的使用场所"] --> r1["桌面应用"]
real --> r2["浏览器与内部 Web"]
real --> r3["既有的 .NET 应用"]
r1 -.-> truth["实际上是 Windows 的嵌入式组件技术"]
图11:“古早的 Web 技术”这一观感,与“Windows 的嵌入式组件技术”这一实际情况之间的偏差。
9. 为什么容易被混淆
9.1. 明明词的层级不同,却出现在同一段对话里
- COM 说的是 底层 的事
- ActiveX 说的是 组件语境 的事
- OCX 说的是 文件 的事
层级本来就不同,实务中却在同一个现场同时冒出来,所以对话很容易搅成一团。
9.2. ActiveX 这个词稍微宽一些
COM 的含义相对固定。
而 ActiveX 不论在历史上还是在实务上,都用得稍微宽一些。
不同的人,可能指的是
- 控件本身
.ocx文件- 在 IE 上运行的老组件
- 一般意义上以 COM 为基础的嵌入式组件
其中的哪一个,说的人和听的人会有出入。 到了这一步,对话已经对不上了。
9.3. 一看到 .ocx 就想把它们全叫作 ActiveX
这种心情能理解。 平时这样说大体也能沟通。
不过在迁移或排查的场合,如果不把
- 它是不是 UI 组件
- 它在哪个宿主上运行
- 需不需要注册
- 32bit / 64bit 是怎么回事
- 有没有浏览器依赖
分开来看,后面就会实实在在地栽跟头。
flowchart TB
accTitle: 造成混淆的 3 个原因
accDescr: 层级不同的话题出现在同一段对话里、ActiveX 这个词稍微宽一些、一看到 ocx 就想把它们全叫作 ActiveX,这 3 点造成了混淆。
r1["层级不同的话题出现在同一段对话"] --> mixup["对话搅成一团"]
r2["ActiveX 这个词宽"] --> mixup
r3["看到 ocx 就全这么叫"] --> mixup
mixup -.-> risk["迁移和排查的场合会栽跟头"]
图12:混淆的真面目,是底层、组件、文件这些层级不同的东西同时出现在同一个现场。
10. 现在的实务中该怎么看
首先,发现了 COM / ActiveX / OCX,并不需要马上全盘否定。 不过,把它们全部一视同仁地对待也很危险。
浏览器一侧的 ActiveX 依赖
这一块优先用严格一点的眼光看更安全。
- 它不是现代浏览器开发的主流
- 在兼容运维的语境下会谈到 IE 模式,但最好把它看作 为了向后兼容的桥梁
- 不建议把它作为新项目的前提技术来依赖
判断时还需要时间轴。IE11 桌面应用已经退役,现在剩下的落脚点是 Microsoft Edge 的 IE 模式。关于这个 IE 模式,Microsoft 给出的方针是 至少支持到 2029 年,若要废止则提前 1 年公告。也就是说,2029 年不是“可以放着不管到那时的期限”,而是 要在那之前剥离完成的期限,应当据此倒推。剥离的步骤本身,另外写在 IE 模式依赖系统的脱离指南 里。
Web 一侧的 ActiveX 与其想“怎么延续寿命”,不如按“从哪里开始剥离” 来考虑更现实。
flowchart TB
accTitle: 浏览器一侧 ActiveX 的时间轴
accDescr: IE11 桌面应用已经退役,剩下的落脚点是 Edge 的 IE 模式,Microsoft 给出的方针是至少支持到 2029 年、若要废止则提前 1 年公告。2029 年不是可以放着不管的期限,而是要剥离完成的期限,应当据此倒推。
ie11["IE11 桌面版已退役"] --> iem["剩下的落脚点是 Edge 的 IE 模式"]
iem --> y2029["至少支持到 2029 年"]
y2029 --> plan["按剥离完成的期限倒推"]
y2029 -.-> notice["若要废止则提前 1 年公告的方针"]
图13:2029 年不是宽限,而是截止日。浏览器一侧要按“从哪里开始剥离”来考虑。
桌面一侧的 ActiveX / OCX 依赖
这一块可以判断得更现实一些。
- 在既有宿主中稳定运行
- 发布对象范围有限
- 厂商维护或自主维护的前景可预期
- 注册、依赖 DLL、位数(bitness)的前提都已掌握
这些条件都齐了的话,保留 的判断是很正常的。
反过来,如果
- 想把 32bit 的 OCX 原样加载到 64bit 一侧
- 只想把周边改成 .NET
- 每次发布和注册都出问题
- 还残留着浏览器依赖
那么把 保留 / 封装 / 替换 分开考虑更安全。
现在的实务中被追问的,不是 是不是 ActiveX 所以就是坏的,而是 要把边界划在哪里。
与其把它看作老技术,不如把它看作 既有系统的对接面,会更好处理。
flowchart TB
accTitle: 桌面一侧判断的分岔
accDescr: 稳定运行、发布范围有限、维护有前景、前提已掌握这些条件齐了,保留的判断就很正常;而出现位数冲突、周边要 .NET 化、发布环节出问题或浏览器依赖时,就把保留、封装、替换分开考虑。
q{"条件齐了吗"}
q -->|"稳定运行且前提已掌握"| keep["保留的判断也很正常"]
q -->|"有卡住的地方"| split["把保留、封装、替换分开"]
split -.-> view["作为对接面把边界划在哪里"]
图14:桌面一侧要区分轻重来判断。被追问的不是好坏,而是边界的位置。
11. 常见误解
误解 1: COM = ActiveX
不是。 COM 是底层,ActiveX 是在其之上被使用的控件语境。
误解 2: ActiveX = Internet Explorer
不是。 它在 IE 上出名是事实,但 ActiveX 并非浏览器专用。
误解 3: ActiveX = OCX
实务中被当作相当接近的意思使用,但严格来说不同。 ActiveX 说的是语境或组件,OCX 是作为文件扩展名遇到的实体。
误解 4: OCX 不就是普通的 DLL 吗
粗略说是接近,但在排查时最好不要这么粗略。
光凭 .dll 读不出角色,而 .ocx 有相当浓的控件味道。
误解 5: COM 已经是死掉的技术
至少在 Windows 的世界里,这么说太粗暴了。 它只是从台前稍微退了一点,在设计和互操作的语境中现在也还会出现。
flowchart TB
accTitle: 常见误解的纠正方式
accDescr: COM 不是 ActiveX 本身而是底层,ActiveX 并非 IE 专用,ActiveX 与 OCX 是概念与文件的差别,COM 也不是死掉的技术,这里汇总这些误解的纠正方式。
m1["COM = ActiveX ?"] --> a1["COM 是底层,是另一回事"]
m2["ActiveX = IE 专用 ?"] --> a2["在桌面上也仍是现役"]
m3["ActiveX = OCX ?"] --> a3["概念与文件的差别"]
m4["COM 死了 ?"] --> a4["互操作中现在也会出现"]
图15:这 5 个误解,都是从把层级的差别混在一起而产生的。
12. 排查时的检查要点
发现 COM / ActiveX / OCX 之后,按顺序确认下面这些,就不容易迷路。
- 它是什么组件
- 是 UI 控件吗
- 是查看器吗
- 是设备联动吗
- 是 Office / Access 集成吗
- 它在哪里运行
- 是 Access / VBA 吗
- 是 VB6 / MFC 吗
- 是 WinForms 吗
- 是 IE / IE 模式吗
- 文件和标识符是什么
.ocx/.dll/.exe- ProgID
- CLSID
- Type Library
- 注册和发布是怎么做的
- 需不需要
regsvr32 - 有没有依赖 DLL
- 需不需要管理员权限
- 需不需要
- 位数(bitness)对得上吗
- 是 32bit
- 是 64bit
- 需不需要在同一进程中运行
- 将来怎么处理
- 就这样保留
- 划出边界封装起来
- 直接替换
12.1. 用什么来查
上面 6 点说的是“看什么”,所以这里把“打开哪里”也一并列出来。不知道这些的话,即使有检查清单,第一步也会卡住。
| 想查的东西 | 用的工具、看的地方 |
|---|---|
那个 .dll / .ocx 是不是能自注册的 COM 服务器 |
用 Visual Studio 附带的 dumpbin /exports 文件名 查看,如果导出了 DllRegisterServer,就是自注册型的 COM 服务器。regsvr32 调用的正是这个函数 |
| 注册和注销的做法 | regsvr32 文件名 注册,regsvr32 /u 文件名 注销。需要管理员权限。在 64bit Windows 上,%SystemRoot%\System32\regsvr32.exe 是 64bit 用的,%SystemRoot%\SysWOW64\regsvr32.exe 是 32bit 用的,要配合组件的位数来选 |
| 从 CLSID 查实体文件 | 注册表 HKEY_CLASSES_ROOT\CLSID\{CLSID}\InprocServer32 的默认值,就是进程内服务器(DLL / OCX)的路径。跨进程的组件则看 LocalServer32 |
| 从 ProgID 查 CLSID | HKEY_CLASSES_ROOT\ProgID名\CLSID 的默认值就是 CLSID。反过来也可以从 CLSID 一侧看 ProgID 子键 |
| 32bit 组件的注册位置 | 在 64bit Windows 上,32bit 用的注册会写到 HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WOW6432Node\CLSID 下面。注意不要只看 64bit 一侧就判定“没有注册” |
| 列出它公开的接口 | 如果有 Windows SDK 中包含的 OLE/COM Object Viewer(oleview.exe),就能列出已注册的类和 Type Library。某些版本的 SDK 不再附带它,没有的话就从注册表和开发环境一侧的引用设置去追 |
| 宿主一侧的位数 | 在任务管理器的“详细信息”选项卡里,右键点击列标题并加上“平台”列,就能看出每个进程是 32 位还是 64 位。32bit 的 OCX 无法直接加载到 64bit 进程中 |
| 注册或依赖 DLL 的解析失败了 | 用 Process Monitor 跟踪注册表和文件的访问,就能看到它在找哪个键、哪个 DLL 时失败了。用法汇总在 Process Monitor(ProcMon) 实践指南 里 |
不看这一带就喊出 因为有 ActiveX,所以全部重新实现,会把过去的坑一个不落地踩一遍。
先把上面 6 点和工具的对应关系填满,再去决定第 10 章的“保留 / 封装 / 替换”更安全。
flowchart TB
accTitle: 排查的顺序
accDescr: 依次确认它是什么组件、在哪里运行、文件和标识符是什么、注册和发布是怎么做的、位数是否对得上,然后再决定保留、封装还是替换。
s1["看它是什么组件"] --> s2["看它在哪里运行"]
s2 --> s3["理清文件和标识符"]
s3 --> s4["确认注册和发布"]
s4 --> s5["确认位数"]
s5 --> s6["决定保留、封装还是替换"]
图16:不要一上来就跑去重新实现,按这个顺序填满之后再定方针更安全。
13. 总结
要用最粗略、但在实务中有用的方式来说 COM / ActiveX / OCX 的区别,就是这样。
- COM 是底层
- ActiveX 是以 COM 为基础的嵌入式组件语境
- OCX 是 ActiveX 控件中常见的文件
一旦能把这 3 件事分开来想,
- 这只是个
.ocx吗 - 是整个 COM 的问题吗
- 是依赖浏览器的 ActiveX 吗
- 还是在桌面上可以保留的组件
就会变得清楚很多。
遗留技术之所以难,不是因为名字老,而是 底层、组件、文件出现在同一段对话里。 不过,只要结构看清楚了,它其实是个出乎意料地容易处理的问题。
14. 参考资料
- 什么是 COM - 为什么 Windows COM 的设计至今仍然优雅
- 现在该怎么处理 ActiveX / OCX - 保留、封装、替换的判断表
- 组件对象模型 (COM) - Microsoft Learn
- ActiveX 控件 - Win32 apps - Microsoft Learn
- ActiveX Controls - MFC - Microsoft Learn
- ActiveX Control - Access VBA - Microsoft Learn
- 什么是 Internet Explorer (IE) 模式 - Microsoft Learn
- IE 与 Edge 的生命周期 FAQ - Microsoft Learn(至少把 IE 模式支持到 2029 年的方针)
- regsvr32 - Windows 命令 - Microsoft Learn
- CLSID 键 - Win32 apps - Microsoft Learn
- 注册表重定向器 - Win32 apps - Microsoft Learn
- 在 Internet Explorer 模式 (IE 模式) 下使用 DevTools - Microsoft Learn
相关文章
共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。
COM/OCX/ActiveX 开发中容易踩坑的注册与位数陷阱
本文从实务角度整理 COM、OCX、ActiveX 开发中容易踩坑的 32bit/64bit、Visual Studio 2022、regsvr32/Regasm、管理员权限、HKCR、STA/MTA 等问题。
ActiveX / OCX 现在该如何处理 - 保留、封装、替换的判断表
本文整理发现 ActiveX / OCX 时应该选择保留、封装还是替换,涵盖 32bit / 64bit、注册、浏览器依赖、供应商维护等因素。
什么是 OLE 对象 —— 嵌入与链接的机制以及业务文档中的陷阱
在 Word 中嵌入 Excel 表格的功能,本质就是 OLE 对象。本文从嵌入与链接的区别、复合文件与结构化存储、In-Place Activation 的机制,一直讲到链接断开、文件膨胀与安全对策,全部立足于实务视角。
剪贴板与拖放的工作原理——在业务应用中正确处理 OLE 数据传输
粘贴 Excel 表格会散架、关掉复制源就贴不上,根源都是剪贴板把同一内容放成多种格式的机制。本文讲解标准格式、延迟渲染、OLE 拖放,直到剪贴板历史与云同步的策略。
委托开发 Windows 应用程序前该梳理的事项
在委托外包开发 Windows 应用程序之前,梳理现有软件改造、设备联动、COM/ActiveX、发布与更新、维护等需要注意的要点。
相关主题
与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。
Windows 技术主题
汇整 KomuraSoft LLC 关于 Windows 开发、故障调查与既有资产活用文章的主题中心。
ActiveX 迁移
整理保留、包装或替换 COM / ActiveX / OCX 资产的阶段性判断的主题页面。
与本主题相关的服务
本文与以下服务页面相关联,欢迎从最接近的入口查看。
既有资产活用 & 迁移支持
梳理 COM / ActiveX / OCX 区别的话题,很适合作为思考如何盘活既有资产、如何迁移的入口。
技术咨询 & 设计评审
如果是想先把术语和边界的含义统一之后再定方针的项目,可以作为技术咨询与设计评审来推进梳理。
常见问题
汇总了咨询这一主题时常见的问题。
- OCX 文件是什么?
- OCX 是 ActiveX 控件实现中常用的文件扩展名。在 Windows 现场看到 .ocx,首先可以怀疑它是嵌入式控件类的 COM 组件。它经常以厂商 SDK 的发布物、VB6 / Access / MFC 的老项目、安装程序中包含的注册对象文件、需要 regsvr32 的组件这些形式出现。记住 OCX 是文件的形态而不是概念本身,就不容易混乱。
- COM 和 ActiveX 有什么不同?
- COM 是 Windows 上组件之间互相打交道用的二进制契约,也就是底层。ActiveX 是以 COM 为基础的可复用软件组件,尤其常指嵌入宿主或容器中使用的控件这一语境。按 COM = 机制、ActiveX = 组件的语境、OCX = 文件来理解,思路会更清楚。ActiveX 的底层是 COM,但 ActiveX 并不是 COM 本身。
- ActiveX 是 Internet Explorer 专用的技术吗?
- 不是。它在 IE 上出名是事实,但 ActiveX 控件在 Access 表单、VB6 应用、MFC 的容器、Office / VBA 周边、从 WinForms 通过 COM 包装器使用等 Windows 应用一侧也被长期使用。把它看作 Windows 的嵌入式组件技术而不是浏览器专用技术,在实务上更贴切。另外,浏览器一侧的 ActiveX 依赖,现在与其想怎么延续它的寿命,不如按从哪里开始剥离来考虑更现实。
- OCX 和 DLL 有什么不同?
- .ocx 是相当强烈地暗示着 ActiveX 控件的扩展名,而 .dll 可能是普通的库,可能是 COM 服务器,也可能是 ActiveX 周边的依赖 DLL。实务上常见的模式是以 vendorcontrol.ocx 为主角,由 vendorhelper.dll 之类的 DLL 在旁边辅助。要问 OCX 是不是 DLL 的一种,感觉上确实接近,但在排查或迁移的场合,把角色分开看更安全。