维护二进制兼容性

Visual Basic 通过保留部件以前版本的类 ID 和接口 ID 信息来保持向后兼容性,这在“部件设计的一般准则”的“多态性、接口、类型库和 GUIDs”中介绍。这些信息不是保存在类型库中,而是保存在部件的其它地方。

在客户应用程序用部件的某个特定版本编译时,它所使用的每个对象的类 ID 和接口 ID 也同时被编译进去。在客户应用程序运行时,类 ID 被用来创建类的实例,接口 ID 被用来验证对被编译进客户应用程序的属性和方法的调用是否安全。

使用“二进制兼容”选项生成部件的新版本,那么新版本将包含类的增强版本的类 ID 和接口 ID,另外,还保留旧的客户应用程序在创建对象和使用对象的属性和方法时需要的类 ID 和接口 ID。

用部件新版本编译的新客户应用程序,可以使用增强特性,因为他们编译时使用了新的类 ID 和接口 ID。

例如,假设在部件的 1.0 版中,Widget 对象含有 Spin 属性,并编译了可以创建 Widget 对象并调用 Spin 方法的客户应用程序。

假设设置了“二进制兼容”选项并编译生成了部件的新版本,其 Widget 对象还包含 Oscillate 方法。Visual Basic 为增强的 Widget 创建新的类 ID 和接口 ID。增加方法不会破坏二进制兼容性,因此 Visual Basic 还保留了旧的 Widget 的类 ID 和接口 ID。

对于使用旧 ID 的以前编译的应用程序,它得到的是增强的 Widget— 更好的版本。因为新 Widget 仍旧含有旧应用程序要调用的 Spin 方法。

注意 “二进制兼容”只适用于类的缺省接口— 也就是说,类模块中增加的 Public Sub、Function 和 Property 过程。使用 Implements 添加的接口将被忽略。

不兼容的接口变动

假设不是增加 Oscillate 方法而是修改 Spin 方法的参数。如增加了一个 Direction 参数。

如果能够使用 Widget 类旧的类 ID 和接口 ID 编译部件,那么旧的客户应用程序就可能有麻烦了。虽然可以创建新的 Widget,但当它调用 Spin 方法时,会把错误的参数放进堆栈。最好情况下程序可能出错。更坏的结果可能是数据被破坏。

防止不兼容

如果选择“二进制兼容”选项,Visual Basic 将在编译部件的不兼容版本时发出警告。可以撤销那些使部件不兼容的编辑工作,或者换个文件名和工程名,以便在用户运行安装程序时新版本不会替换老版本。

如果忽视警告信息,并使用相同的文件名和工程名来编译部件的不兼容版本,那么 Visual Basic 会转储部件以前版本的所有类 ID 和接口 ID。

如果在一台计算机上安装不兼容的部件,而机器上还有一个使用早期版本编译的客户应用程序,不兼容的部件会覆盖早期版本。结果是,客户应用程序试图创建对象时,会收到430 号错误,“类不支持自动化或不支持期望的界面。”

这样做可以防止当应用程序试图调用不兼容接口的属性和方法时,可能发生的更严重的错误。

对后期绑定的客户应用程序的限制性保护

变量被声明为 As Object 时使用后期绑定,因为编译器不知道接口类 ID 和运行时赋给变量的接口。使用后期绑定的应用程序将使用 CreateObject 函数和可编程的 ID 来创建类的实例,如:

Dim obj As Object
Set obj = CreateObject("MyComponent.MyObject")

CreateObject 函数将在 Windows 的注册表中寻找类 ID,并用它来创建对象。这样创建的是对象的最新版本。

只要保持二进制兼容性,后期绑定的应用程序使用部件就不会有什么问题。

如果对对象使用相同的可编程 ID 生成部件的不兼容版本,后期绑定的客户应用程序仍旧能够创建对象,因为它是寻找类 ID 而不是把它编译进来。如果应用程序调用的方法的参数被修改,或者方法被删除,那么程序就会失败甚至数据被破坏。

详细信息 对 Visual Basic 兼容性的程度的介绍请参阅“二进制版本兼容性的级别”。关于这个特性的主题列表请参阅“版本兼容性”。背景信息和概念请参阅“部件设计的一般准则”中的“多态性、接口、类型库和 GUIDs”。