使用的环境
计算机环境:Windows11Excel版本:Excel2016家庭与学生版
组件对象模型COM
在vba进行自动化控制的背后驱动力量是组件组件对象模型COM。Microsoft 组件对象模型(COM)是一种平台无关的二进制互操作标准,用于构建可交互的软件组件,是 OLE、ActiveX 等技术的基础。COM 并非编程语言或应用框架,而是定义了对象交互的规范:组件功能通过接口(方法集合)暴露,且所有访问必须经由接口指针;所有接口均继承自基础接口 IUnknown(提供查询、引用计数等核心能力)。该标准不约束实现语言或结构,仅要求语言支持指针操作,从而支持多语言编写的组件在进程内、进程间乃至远程计算机上协同工作(通过 DCOM 扩展),并内置安全机制保障系统与组件完整性。其“编译后生效”的二进制契约特性,确保了跨语言、跨环境的稳定互操作。
绑定
对于控制应用程序与自动控制对象(服务器)来说,你必须将你的VBA过程中可用的对象和服务器实际的自动控制对象联系起来,这个过程就叫做绑定。绑定是将代码中的函数调用与具体实现地址关联的过程,如同书籍装订:写作时写“参见第X章”,装订后才填入准确页码,确保引用有效。对于 COM 对象,绑定通过虚函数表(v 表)实现:
每个 COM 对象持有一个 v 表(函数地址数组);
调用方法时,按接口定义的固定顺序(编译时确定)在 v 表中定位对应偏移量,跳转至该地址执行。这一机制使不同语言编写的组件能通过统一的二进制接口稳定交互,是 COM 实现跨语言、跨进程互操作的核心基础。
有两种类型的绑定:后期绑定和前期绑定。对绑定方式的选择对应用程序表现影响很大。
前期绑定
早期绑定(v表绑定)不仅适用于 IUnknown,也适用于对象的自定义方法(如 Refresh、Parent 等)。其前提是:调用方必须预先知晓该接口的虚函数表(v表)结构。在 Visual Basic 等语言中,实现方式是:
- 添加对应组件的类型库引用(如“Microsoft Excel 对象库”);
- 将变量声明为具体类型(如 Dim app As Excel.Application)。
编译器据此在编译阶段确定每个方法在 v 表中的固定偏移量,生成直接跳转指令。这种方式调用效率高、支持智能提示与编译时类型检查,是 COM 互操作中性能最优的绑定方式。若无类型信息(如声明为 Object),则退化为运行时通过 IDispatch 的后期绑定。
如果想要使用前期绑定自动化执行Excel,需要提前从引用中添加对 Microsoft Excel 对象库 的引用
Dim oExcel As Excel.ApplicationSet oExcel = CreateObject("Excel.Application") oExcel.Visible = True
优势:代码提示与自动补全:输入后自动显示对象的属性方法(如wdApp.会弹出Visible、Documents等选项),大幅降低语法错误。执行效率高:提前编译对象类型,运行速度比后期绑定快约30%。缺点:版本兼容性差:必须确保所有用户电脑安装了目标程序,若用户电脑安装的Office版本与开发时引用的版本不一致,会直接报错“找不到对象库”。
新版本的office需要勾选信任VBA工程对象模型。
后期绑定
COM 中的 IDispatch 接口实现了后期绑定(又称延迟绑定),调用方法或属性时,名称在运行时才被解析。过程分两步:
- GetIDsOfNames:将方法/属性名(字符串)转换为唯一标识符(DISPID);
这如同读书时需临时翻目录查页码,而非书本装订时已印好固定页码(对比早期绑定)。若一个 COM 对象同时提供自定义接口(支持编译时早期绑定)和 IDispatch 接口,则称为双接口(dual interface),兼顾效率与灵活性。在 Visual Basic 中,将变量声明为 Object 类型即触发后期绑定,由 IDispatch 在运行时动态解析调用。
不需要提前在引用中添加对象库。
Dim oExcel AsObjectSet oExcel = CreateObject("Excel.Application") oExcel.Visible = True
核心优势:
跨版本兼容,无论用户安装Word 2010/2016/365,只要支持"Word.Application"接口,代码即可运行。
零配置分发:无需手动引用对象库,直接复制代码即可运行(尤其适合给非技术用户的程序)。
灵活性高:可根据条件动态切换对象类型,如If...Then判断后创建Excel或Word对象。
局限性:
无代码提示:变量声明为Object后,输入.不会显示属性/方法,需手动记忆语法(如wdApp.Selection不能拼错)。
不支持枚举常量:如Word的wdAlignParagraphCenter需替换为数值1,可读性下降。