在使用一个或多个对象的应用程序中,确定错误发生在何处将会更困难,尤其是在错误发生在另一个应用程序的对象中时,情况更是如此。例如,图 13.4 所示为包含窗体模块的应用程序,窗体模块引用类模块,类模块轮流引用 Microsoft Excel Worksheet 的对象。
图 13.4 在窗体、类和 ActiveX 组件之间更新生成的错误
如果 Worksheet 对象不处理在 Worksheet 中出现的具体错误,却重新生成这个错误,则 Visual Basic 将错误传递到引用的对象 MyClassA。如果在外部对象中引发了错误,这个错误将在调用这个外部对象的过程中产生。
MyClassA 对象或者能处理错误(这当然最好),或者重新生成它。界面指出的是,对引用的对象所产生的错误,任何重新生成这个错误的对象不应该直接传播错误(传递该错误代码),而应该将错误号重新映射到有意义的东西上。在重新映射错误时,如果处理程序能确定该错误类似于 Visual Basic 定义的错误(例如,溢出或被零除),则该号可能是 Visual Basic 定义的号,它指示错误条件,否则可能是未定义的错误号。将新号添加到固定的 Visual Basic 常数 vbObjectError 中,以便通知其它处理程序,这个错误是由对象引起的。
只要可能,类模块应试着处理每一个在模块自身内出现的错误,也应试着处理出现在该模块所引用的一个对象中的错误,这些错误不被该对象处理。但是,有一些错误是类模块不能处理的,因为它不能预料到这些错误。也有这样的情况发生,这时类模块更适合于引用对象来处理错误,而不适合于被引用的对象。
当窗体模块中发生错误时,Visual Basic 会提出预定义的 Visual Basic 错误号中的一个。
注意 如果创建一个公共类,则应确保做到清楚地将所定义的每个非 Visual Basic 错误处理程序的意义编成文档。(不能在学习版中创建公共类)。引用该公共类的其它程序员需要知道如何处理由对象引起的错误。
当重新生成错误时,将不改变 Err 对象的其它属性。如果没有捕获所产生的错误,则可能显示 Source 和 Description 属性以帮助用户执行改正了的操作。
类模块可能包括以下错误处理程序,以适应它可能捕获的任何错误,重新生成它不能解决的错误:
MyServerHandler: Select Case ErrNum Case 7 '
处理内存溢出错误。.
.
.
Case 440 '
处理外部对象错误。Err.Raise Number:=vbObjectError + 9999
'
来自其它Visual Basic
对象的错误。Case Is > vbObjectError and Is < vbObjectError _
+ 65536
ObjectError = ErrNum
Select Case ObjectError
'
根据对象的错误代码的文档,该对象处理错误。Case vbObjectError + 10
.
.
.
Case Else
'
当对象错误重新生成时,重新映射错误。Err.Raise Number:=vbObjectError + 9999
End Select
Case Else
'
当对象错误重新生成时,重新映射错误。Err.Raise Number:=vbObjectError + 9999
End Select
Err.Clear
Resume Next
Case 440
语句捕获错误,该错误出现在 Visual Basic 应用程序之外的被引用对象中。在这个例子中,仅使用数值 9999 传播错误,因为用这种类型的集中化处理程序难于确定错误的原因。当错误发生时,通常是致命的自动错误的结果(一个错误是使部件结束执行),或者是由于对象不能正确地处理捕获的错误。不应传播错误 440,除非它是个致命的错误。如果为嵌入程序编写这样一种捕获,如同以前在“联机错误处理” (Inline Error Handling) 主题中讨论过的那样,则也许能够确定错误的原因并将其改正。
语句
Case Is > vbObjectError and Is < vbObjectError + 65536
捕获最初在 Visual Basic 应用程序内的对象中发生的错误,或在包含处理程序的相同对象中的错误。只有对象定义的错误才在 vbObjectError 偏移量的范围内。
为对象提供的错误代码文档应该定义可能的错误代码并确定它们的含义,以便所写的这部分处理程序可智能化地解决预期的错误。实际错误代码可能被归纳而没有 vbObjectError 偏移量,或者可能在添加偏移量后被归档,在这种情况下 Case Else 语句应该减去而不是增加 vbObjectError。另一方面,对象错误可以是显示在对象类型库中的常数,就象显示在 Object Browser 中一样。在那种情况下,在 Case Else 语句中使用错误常数而不使用错误代码。
任何未处理过的错误应该用新号重新生成,如 Case Else 语句中显示的那样。在应用程序中可以设计这样一种程序,它预先知道已定义的新号。如果这是一个公共类(在标准版中不可用),则在应用程序的文档中也应包含新的错误处理代码的解释。
最后一条 Case Else 语句捕获并重新生成任何其它错误,这些错误在处理程序的其它地方未被捕获。由于这部分捕获将抓住错误,这些错误也具有添加的 vbObjectError 常数,所以应该直接将这些错误重新映射到一个生成的“不可解决的错误”代码。应将代码添加到 vbObjectError 中,以便向任何处理程序指示这个错误源于被引用的对象。
当调试一个应用程序时,如果该应用程序引用一个在 Visual Basic 中建立的对象或引用一个在类模块中定义的类,就可能发现,它将使确定哪一个对象产生了错误变得混乱。为使这个调试变得 更轻松,可在“选项”对话框(可从“工具”菜单中得到)中的“通用”选项卡中在“添加类模块”选项中选择“中断”。利用已选择的选项,类模块中的错误或在另一个正在 Visual Basic 中运行的应用程序或工程中的对象,将使类进入调试程序的中断模式,从而进行错误分析。出现在编译的对象中的错误在中断模式下将不显示立即窗口;这样的错误最好由对象的错误处理程序来处理,或者由引用的模块来捕获。
详细信息 关于类模块选项中的中断的详细讨论,请参阅“用部件编程”中的“调试类模块”。