绑定对 ActiveX 部件性能的影响

绑定是指确定要设置的属性或方法调用属于哪个对象变量的过程。这构成了属性或方法调用的一部分开销。

过程调用所需的时间取决于两个因素:

作为部件的设计人员,应尽可能最小化第一项。至于第二项,则不是设计人员能完全控制的。

方法调用的开销取决于 Visual Basic 为该方法调用使用的绑定类型,后者又取决于客户端应用程序声明对象变量的方式,而这又取决于该客户端应用程序的开发者。

为了确保使用部件的开发者能获得最佳的性能,该部件的帮助文件中应该包含这个主题的信息。

注意 绑定会影响所有的属性和方法调用,包括部件内的对象互相发出的调用。因此绑定也会影响部件的内部性能。

绑定的类型

在自动化中主要有两种绑定类型:后期绑定和前期绑定。前期绑定又分为两种类型,分别称之为 DispID 绑定和 vtable 绑定。后期绑定最慢,vtable 绑定最快。

后期绑定

若将一个变量声明为 As Object 或 As Variant,Visual Basic 在编译时就无法确定该变量将引用哪种类型的对象。因此,Visual Basic 必须使用后期绑定,在运行时确定对象的属性和方法能否使用该变量。

注意 后期绑定也可用于声明为 As Form 或 As Control 的变量。

若使用后期绑定,则每次调用属性或方法时,Visual Basic 都要将成员名传给该对象 IDispatch 接口的 GetIDsOfNames 方法。GetIDsOfNames 返回该成员的派遣 ID,或 DispID。Visual Basic 再将该 DispID 传给 IDispatch 接口的 Invoke 方法来调用该成员。

对进程外部件而言,这意味着一次额外的跨进程方法调用,结果是调用开销翻番。

注意 不可以直接调用 IDispatch 接口的任何方法,因为在 Visual Basic 类型库中这个接口被标记为隐式的,而且受到限制。

前期绑定

如果在编译时 Visual Basic 能够知道属性或方法所属的对象,就可以预先查找该成员在类型库中的 DispID 或 vtable 地址。这样就无须在运行时调用 GetIDsOfNames。

当显式声明了变量的类时,例如 As Widget,该变量就只能存放该类的对象的引用。Visual Basic 就可以为该变量调用的所有属性和方法使用前期绑定。

建议在 Visual Basic 和应用程序中使用这种方法来声明对象变量。

重点 使用前期绑定还是后期绑定完全取决于声明变量的方式。对象的创建方式对此没有任何影响。

提示 前期绑定有效地减少了设置或获取属性值所需的时间,因为调用开销在整个调用时间中占相当大的比例。

vTable 绑定

vtable 绑定是最快的前期绑定方式。在这种方式下,Visual Basic 使用了虚拟函数表或 vtable 中的偏移量。Visual Basic 尽可能地使用 vtable 绑定。

Visual Basic 类模块创建的对象支持所有三种绑定方式,因为它们有双重接口(从 IDispatch 派生出 vtable 接口)。

如果客户端应用程序使用类名显式地声明变量,Visual Basic 对象将总是属于 vtable 范围。使用 vtable 绑定调用 Visual Basic 创建的进程内部件的方法所需的开销与调用 DLL 中的函数所需开销差不多。

注意 对进程内部件而言,vtable 绑定的开销远小于使用 DispID 绑定所需开销。对进程外部件而言,改善没有这么大,因为开销的主要部分来自方法参数的调度。

DispID 绑定

如果部件具有类型库但不支持 vtable 绑定,Visual Basic 将使用 DispID 绑定。在编译时,Visual Basic 将查找属性和方法的 DispID,从而在运行时不必在调用 Invoke以前调用 GetIDsOfNames。

注意 尽管可以确认是否使用了前期绑定(通过明确地声明变量的类类型),但是使用 DispID 绑定还是使用 vtable 绑定则是由部件决定的。使用 Visual Basic 编写的部件总是支持 vtable 绑定的。