设为首页收藏本站Access中国

Office中国论坛/Access中国论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

12下一页
返回列表 发新帖
查看: 1712|回复: 10
打印 上一主题 下一主题

[其它] [转帖]Visual Basic的调试和错误处理

[复制链接]
跳转到指定楼层
1#
发表于 2006-6-6 08:40:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
无论你怎样认真细致地编写代码,错误总会(可能会)发生。理论上讲,Visual Basic 过程根本不需要错误处理代码。然而不幸的是,有时会出现错误删除文件、磁盘驱动器空间满或网络驱动器意外断开等情况,这就存在导致代码中发生运行时错误的可能性。为处理这些错误,需要在你编写的过程中添加错误处理代码。

有时,错误还可能在代码内部发生;这种类型的错误通常被称作bug(错误)。小的错误会带来失败或不便。更严重的错误会造成应用程序对命令响应的中断,可能需要用户重新启动应用程序并造成未保存的所有工作被丢失。

对应用程序中的错误进行定位和更正的过程被称作调试。Visual Basic 提供一些帮助分析应用程序运行的工具。这些调试工具对于错误源的定位尤其有用,同时你还可使用这些工具试着对你编写的程序进行修改或者学习其他应用程序的工作方式。

本章对Visual Basic 中调试工具的使用进行了说明,解释了运行时错误(在代码正在运行时发生的错误,它是在试图进行非法操作时产生的)的处理方法。

注:本章中的信息适用于Microsoft Excel 97、Word 97和PowerPoint 97中的Visual Basic 编辑器。有关Microsoft Access 97中调试Visual Basic 代码和处理错误的信息,请参阅Microsoft Access 97和Microsoft Office 97开发者版中的“建立Microsoft Access 97应用程序”。另外,“建立Microsoft Access 97应用程序”的联机版本可从Microsoft Access 97和Microsoft Office 97 专业版CD-ROM的Value Pack目录下找到。

如何处理错误

理论上讲,Visual Basic 过程根本不需要错误处理。事实表明,硬件问题或用户的意外操作会导致运行时错误,从而停止代码的运行,并且用户通常无法恢复应用程序的运行。其他错误不会中断代码的运行,但会导致代码不按预想运行。

例如,下面程序中,若文件存在则返回真,若文件不存在则返回假,但程序中不包括错误处理代码。

Function FileExists (filename) As Boolean

   FileExists = (Dir(filename) <> "")

End Function

Dir函数返回第一个与指定文件名(有或没有通配符、驱动器名或路径)匹配的文件;如果未找到匹配文件,返回长度为零的字符串。

这个代码包含Dir调用可能出现的任何结果。然而,如果变量指定的驱动器号是非法的驱动器,会出现错误“驱动器无效”。如果指定的驱动器是软盘驱动器,该函数仅在软盘驱动器中有盘和软驱门关上的情况下运行正常,否则Visual Basic 会出现“磁盘未准备好”的错误提示,并且停止代码的运行。

例如,下面示例可解决诸如驱动器无效或软盘驱动器中无盘之类的驱动器问题。

Function FileExists (filename) As Boolean

   Dim Msg As String

   ' 打开错误陷井,这样错误处理程序可对检测到的任何错误作出响应。

   On Error GoTo CheckError   

      FileExists = (Dir(filename) <> "")

          ' 如果没有错误发生,不执行错误处理程序。

          Exit Function

CheckError:' 如果发生错误,转移至此。

   ' 定义代表Visual Basic 内部错误代码的常量。

   Const mnErrDiskNotReady = 71, mnErrDeviceUnavailable = 68

   ' vbExclamation, vbOK, vbCancel, vbCritical, and vbOKCancel 是

   ' VBA类型库中定义的常量。

   If (Err.Number = MnErrDiskNotReady) Then

          Msg = " 在软驱中插入软盘并关上软驱门。"

          ' 显示一个带有感叹号符和OK、Cancel按钮的消息框。

          If MsgBox(Msg, vbExclamation & vbOKCancel) = vbOK Then

             Resume

          Else

             Resume Next

          End If

   ElseIf Err.Number = MnErrDeviceUnavailable Then

          Msg = "该驱动器或路径中不存在:" & filename

      MsgBox Msg, vbExclamation

<
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 分享淘帖 订阅订阅
2#
 楼主| 发表于 2006-6-6 08:42:00 | 只看该作者
错误处理程序的设计

错误处理程序是在你编写的应用程序中捕获错误和作出响应的例程。你应在你认为可能出现错误的过程中添加错误处理程序(除非你可明确判定,否则应假定任何Visual Basic 语句都可能产生错误)。错误处理程序设计的步骤如下:

1. 设置或使一个错误陷井有效,以告诉应用程序发生错误时转移到何处(错误处理例程将运行)。

On Error语句使错误陷井有效,并为应用程序指定错误处理例程从标有标签处开始。

在前面的示例中,FileExists函数包含一个名为CheckError的错误处理例程。

2. 编写一个响应你可预测的所有错误的错误处理例程。如果在某个点上,控制流实际转移到陷井中,此时陷井处于激活状态。

CheckError例程使用一个If...Then...Else语句来响应Err对象的Number属性值(Number属性是响应Visual Basic 错误的一个数值参数),从而实现错误的处理。示例中,在产生“磁盘未准备好”的错误时,为用户显示要求关上软驱门的信息提示;在产生“驱动器无效”的错误时,为用户显示另一信息提示。如果发生其他错误,则显示相应的描述,并中止程序。

3. 退出错误处理例程。

出现“磁盘未准备好”的错误时,Resume语句使代码转回到发生错误的语句处。然后Visual Basic 将试着重新运行那个语句。如果条件未发生改变,就会再次发生错误,并转回到错误处理例程。

出现“驱动器无效”的错误时,Resume Next语句使代码转回到紧接着发生错误的语句之后的语句处。

本主题的余下部分对如何执行这些步骤进行了详细论述。在阅读这些步骤时,请参阅前面示例中的FileExists函数。

设置错误陷井

当Visual Basic 运行错误处理程序指定的On Error语句时,错误陷井被激活。当包含错误陷井的过程处于激活状态时,该错误陷井是有效的—也就是说,在运行Exit Sub、Exit Function、Exit Property、End Sub、End Function或End Property语句前,过程中的错误陷井是有效的。在任何给定的过程中,任何时候都只能有一个错误陷井有效,你可创建多个备用的错误陷井,并在不同时间内分别激活它们。使用On Error语句的特殊形式On Error GoTo 0来禁止某一错误陷井。

使用On Error GoTo line语句,设置从错误陷井跳转到一个错误处理程序中,其中line 参数指定识别错误处理代码的标签。在FileExists函数示例中的标签为CheckError(虽然冒号是标签的组成部分,但在On Error GoTo line语句中不用冒号)。

编写错误处理例程

编写错误处理例程的第一步是添加行标签,以标识错误处理例程的开始。行标签应具有一个描述性名称,而且必须在其后加上冒号。编写时的习惯做法是把错误处理代码置于过程的结尾处,即行标签在Eixt Sub 、Exit Function或Exit Property语句后。这可避免过程中无错误发生时错误处理代码的执行。

错误处理例程的主体包括实际处理错误的代码,通常采用Select Case或If ...Then...Else语句。你需要确定可能发生哪些错误,并为每个错误提供相应的处理措施,如在出现“磁盘未准备好”错误时,提示用户插入磁盘。通常需要使用Else或Case Else条件从句来提供一个处理任何预计外错误的选项,在前面的FileExists函数示例中,该选项是警告用户并结束应用程序。

Err对象的Number属性包含一个代表最近发生的运行时错误的数值代码。Err对象与Select Case或If...Then...Else语句的结合使用,可使你对发生的任何错误采取特定的措施。

退出错误处理例程

在FileExists函数示例中,错误处理程序使用了Resume语句,以从产生错误的语句处恢复运行;使用Resume Next语句,以从紧随产生错误语句的下一语句处恢复运行。还可采用其他方法来退出错误处理例程。你可根据情况使用下列表中的任何语句。

语句      描述

Resume [0]  程序从产生错误的语句恢复运行或从最近一次调用包含错误处理程序的过程的语句处恢复运行。使用该语句可在更正产生错误的条件后恢复运行。

Resume Next 程序从紧随产生错误的语句的下个语句恢复运行。如果错误发生在包含错误处理程序的过程以外,且被调用的过程不包含有效的错误处理程序,则从紧随调用发生错误的过程的语句之后的语句处恢复运行。

Resume line  程序在 line 参数指定的标签处恢复运行。line 参数是行标签(或非零行号),它必须和错误处理程序在同一个过程中。

Err.Raise Number:=number  触发运行时错误。当这个语句在错误处理例程中运行时,Visual Basic 搜索另一错误处理例程的调用列表(调用列表是被调用过程链,通过它,可到达当前的执行点。这方面的详细信息,参阅本章后面的“错误处理层次结构”)。

Resume与Resume Next间的差异

Resume 与Resume Next之间的差别在于:Resume是从产生错误的语句恢复应用程序的运行;Resume Next是从紧随产生错误的语句的下个语句恢复应用程序的运行。一般而言,对于错误处理程序可以更正的错误使用Resume,对于错误处理程
3#
 楼主| 发表于 2006-6-6 08:42:00 | 只看该作者
错误处理层次结构

一个有效的错误处理程序是由执行On Error语句激活且未被关闭(可由On Error GoTo 0语句关闭,也可从其所在的过程中退出)的错误处理程序。一个活动的错误处理程序是当前正执行的错误处理程序。错误处理程序只有在有效时才能被激活,但并不是所有有效的错误处理程序是活动的。例如,Resume 语句后,处理程序处于不活动状态,但它仍是有效的。

当缺少有效错误处理例程的过程中发生错误或者在活动的错误处理例程中发生错误时,Visual Basic 将在调用列表中搜索另一有效的错误处理例程。调用列表是一个指向当前执行过程的调用顺序表,它在“调用堆栈”对话框上显示。只有在中断模式中(暂停应用程序的执行),单击“视图”菜单上的“调用堆栈”来显示“调用堆栈”对话框。

调用列表的搜索

假定调用按下列顺序发生:

    某事件过程调用过程A。

过程A调用过程B。

过程B调用过程C。

当过程C正在执行,其他过程处于运行状态。如果在过程C中发生一个错误且其中没有一个有效的错误处理程序,那么Visual Basic 会在调用列表所列的运行过程中向后搜索—先搜索过程B,然后是过程A,最后是起始事件过程(到此为至)—并运行第一个搜索到的有效错误处理程序。如果在整个调用列表中未找到一个有效的错误处理程序,则会显示一个默认的意外错误信息并暂停执行。

如果Visual Basic 找到一个有效的错误处理例程,继续执行该例程,如同错误发生在包含错误处理程序的同一过程中一样。如果错误处理例程中的Resume或Resume Next语句运行,则按下表所示继续执行。

语句         结果

Resume      从Visual Basic 最近一次调用包含错误处理程序的过程的语句处恢复运行。在前面给定的调用列表中,如果过程A有一个包含Resume语句的有效错误处理程序,Visual Basic从调用过程B的语句恢复运行。

Resume Next  对最近一次调用包含错误处理程序的过程的语句,从紧随该语句之后的语句处恢复运行。在前面给定的调用列表中,如果过程A有一个包含Resume Next语句的有效错误处理程序,运行会返回到调用过程B语句的下一语句。

注意是从找到错误处理过程的过程中的语句处恢复运行,而没有必要从错误发生的过程中恢复运行。如果你没有考虑到这一点,你编写的代码可能按你无法预料的方式运行。为了便于调试代码,可采用简单的方法,即在发生错误时转入中断模式,这方面的内容见本章后面的“关闭错误处理”部分。

如果错误处理程序的错误范围未包括实际所遇到的所有错误,在包含有效错误处理程序的过程中会发生意外(预料外)错误。在这种情况下,除非错误处理程序运行Resume语句,不然过程会无止境运行下去。为预防这类情况的出现,可在处理程序的Case Else语句中使用Err对象的Raise方法,它通常在错误处理程序内重新生成一错误,从而强制Visual Basic 在调用列表中搜索能处理该错误的处理程序。

搜索调用列表的返回效果很难预测,这是因为搜索效果取决于可解决错误的处理程序中Resume和Resume Next语句的运行。Resume从调用包含错误处理程序的过程的语句恢复运行。Resume Next从紧随调用包含错误处理程序的过程的语句的下一语句恢复运行。

例如,在前面讨论的调用列表中,如果过程A有一个有效的错误处理程序,而过程B和过程C没有,那么发生在过程C中的一个错误将由过程A中的错误处理程序进行处理。如果过程A中的错误处理程序在退出前使用Resume语句,那么程序将从调用过程的语句继续运行(即进入过程B);如果过程A中的错误处理程序在退出前使用Resume Next语句,那么程序将从过程A中调用过程B的下一语句继续运行。在这两种情况中,错误处理程序都不直接返回到发生错误的源过程和语句。

复杂错误处理的准则

在编写包含多个模块的大型Visual Basic 应用程序时,错误处理代码可能变得相当复杂。请记住下面这些准则:

在进行代码的调试时,使用Err对象的Raise方法,可在所有错误处理程序中重新生成错误,以解决处理程序中无针对某特定错误的代码的情况。这使得应用程序可试着沿调用列表在其他错误处理例程中更正错误。另外,它可确保在发生代码不能处理的错误时,Visual Basic 会显示错误信息。在进行代码测试时,该技巧可帮助你发现那些未被充分处理的错误。

如果需要在完成错误处理后清除Err对象,使用Clear方法,这对于使用On Error Resume Next进行直接错误处理是有必要的。每当执行任意类型的 Resume 语句、Exit Sub、Exit Function、Exit Property或任何 On Error 语句时,Visual Basic 就会自动调用 Clear 方法。

如果不打算用调用列表中的另一过程来捕获错误,使用Stop语句以强行中断程序代码。使用Stop可使你对错误的内容进行检查,同时在开发环境下对代码进行修改。

编写一个失效保险(fail-safe)错误处理过程,以便代码中的所有错误处理程序可把该过程作为其解决不能处理的错误的最后方法。失效保险过程通过卸载窗体和
4#
 楼主| 发表于 2006-6-6 08:43:00 | 只看该作者
生成错误以测试错误处理

在进行应用程序测试时或者想要将某个特定条件当作是一个Visual Basic 运行时错误时,模拟错误是非常有用的。例如,也许你正使用在某个外部应用程序中定义的对象编写一个模块,并想在应用程序的余下部分中,把从对象中返回的错误当作实际的Visual Basic 错误。

为了测试所有可能的错误,可能需要在代码中生成一些错误。可使用Err对象的Raise方法在代码中生成一个错误。Raise方法中的一个变量列表可被Raise传递。当代码到达一个Resume语句时,自动调用Err 对象的Clear方法。为了将错误传递回调用堆栈的前一过程,有必要重新生成一个错误。

通过向错误提供错误代码,还可模拟任何Visual Basic 运行时错误。

自定义错误

有时,你可能想在Visual Basic 定义的错误外补充定义一些错误。例如,依靠调制解调器连接的应用程序在载波信号下降时可能会出现错误。如果想生成并捕获这个错误,你可将错误号赋给vbObjectError常量。

vbObjectError常量储存的数值间于其偏差值(Offset)和偏差值与512的总和之间。为确保自定义的错误号不与以后的Visual Basic 冲突,所用的数值高于该值。

为自定义错误号,可在模块的申明部分添加常量。

' 错误常量

Const gLostCarrier = 1 + vbObjectError + 512

Const gNoDialTone = 2 + vbObjectError + 512

然后,你可使用Raise方法来生成任何内部错误。对于这种情况,Err 对象的描述属性将返回一个标准的描述“应用程序定义的错误或对象定义的错误”。要提供自定义错误的描述,你需要把它作为一个参数添加到Raise 方法中。
5#
 楼主| 发表于 2006-6-6 08:43:00 | 只看该作者
直接错误处理

若在可能导致错误的每一行后立即检测错误,这就是直接错误处理。使用直接错误处理,可以编写在错误发生时返回错误号的函数和语句;在过程中产生一个Visual Basic 错误,并在调用过程中处理错误;或者编写一个返回Variant数据变量的函数,为调用过程指示所发生的错误。

返回错误号

返回错误号的方法有很多,其中最简单的方法是创建一个在错误发生时返回错误号的函数和语句,而不是返回某个变量。下面示例说明了如何在FileExists函数示例中使用这种方法,以指示某特定文件是否存在。

Function FileExists (p As String) As Long

   If Dir (p) <> " " Then

      FileExists = conSuccess   ' 返回一个常量,指示文件存在。

   Else

      FileExists = conFailure  ' 返回一个常量,指示失败。

   End If

End Function

Dim ResultValue As Long

ResultValue = FileExists ("C:\Testfile.txt")

If ResultValue = conFailure Then

   .

   .  ' 处理错误。

   .

Else

   .

   .  ' 继续进行程序。

   .

End If

直接错误处理的关键在于在每个语句或函数调用后立即检测错误。在这种方式中,你可设计一个处理程序,以准确预计可能出现的错误的类别,并采用相应的方法解决错误。这种方法不需要产生一个实际的运行时错误。

在调用过程中处理错误

指示错误情况的另一方法是在过程自身中生成一个Visual Basic 错误,并在调用过程的直接错误处理程序中处理这个错误。下面的示例说明在FileExists过程中,当操作不成功时产生的错误号。在调用该函数前,On Error Resume Next语句在错误发生时为Err对象属性赋值,但并不企图运行一个错误处理例程。

On Error Resume Next语句后紧跟错误处理代码。这个代码可检测Err 对象的属性,以确定是否有错误发生。如果Err.Number不为零,则已发生错误,根据Err对象的属性值,错误处理代码可采取相应的措施。

Function FileExists (p As String)

   If Dir (p) <> " " Then

      Err.Raise conSuccess      ' 返回一个常量,指示文件存在。

   Else

      Err.Raise conFailure    ' 产生错误号conFailure

   End If

End Function

Dim ResultValue As Long

On Error Resume Next

ResultValue = FileExists ("C:\Testfile.txt")

If Err.Number = conFailure Then

   .

   .  ' 处理错误。

   .

Else

   .

   .  ' 继续进行程序。

   .

End If

下一示例同时使用返回变量和一个传递的自变量,以指示错误的情况。

Function Power (X As Long, P As Integer, ByRef Result As Integer) _As Long

   On Error GoTo ErrorHandler

   Result = x^P

   Exit Function

ErrorHandler:

   Power = conFailure

End Function

' 调用Power函数。

Dim lngReturnValue As Long, lngErrorMaybe As Long

lngErrorMaybe = Power (10, 2, lngReturnValue)

If lngErrorMaybe Then

   .

   .  ' 处理错误。

   .

Else

   .

   .  ' 继续进行程序。

   .

End If

如果编写的函数只是简单地返回一个结果变量或返回一个错误代码,那么结果变量可能在错误代码的范围内,这样调用过程就无法区别是结果变量还是错误代码。返回变量和一个传递自变量的同时使用,可使你的程序确定函数调用是否失败,并采用适当的措施。

Variant数据类型的使用

返回内部错误信息的另一种方法是利用Visual Basic 的Variant数据类型及相关的一些函数。Variant具有一个标识符,可指示变量中包含数据的类型,并且Variant还可被标识为一个Visual Basic 错误代码。你可以编写一个函数来返回一个Variant,并使用标识符为调用过程指示所发生的错误。

下面示例说明如何编写Power函数,以返回一个Variant。

Function Power (X As Long, P As Integer) As Variant

   On Error GoTo ErrorHandler

   Power = x^P

   Exit Function

ErrorHandler:

   Power = CVErr(Err.Number) ' 将错误代码转换为标识的变量。

End Function

' 调用Power函数。

Dim varReturnValue As Variant

varReturnValue = Power (10, 2)

If IsError (varReturnValue) Then

   .

   .  ' 处理错误。

   .

Else

   .

   .  ' 继续进行程序。

   .

End If
6#
 楼主| 发表于 2006-6-6 08:44:00 | 只看该作者
集中化错误处理

在为你的应用程序添加错误处理代码时,你很快会发现自己在一遍一遍地处理同样的错误。仔细制定计划,编写一些错误处理代码可调用的过程,以便处理共同错误情况,从而缩短代码。

在下面的FileErrors函数中,当错误发生时会显示一条适当的消息,若可能,将允许用户通过选择按钮来确定程序的下一步动作。然后,代码返回给调用函数的过程。代码值指示程序的下一步动作。注意用户自定义的常量(如MnErrDeviceUnavailable)必须在某处进行定义(全局常量或者包含该过程的模块的模块级常量或者该过程内部常量)。

Function FileErrors As Integer

   Dim intMsgType As Integer, strMsg As String

   Dim intResponse As Integer

   ' 返回值          含义

   ' 0         Resume

   ' 1         Resume Next

   ' 2         Unrecoverable error(不可恢复的错误)

   ' 3         Unrecognized error(不可识别的错误)

   intMsgType = vbExclamation

   Select Case Err.Number

          Case MnErrDeviceUnavailable               ' 错误 68

             strMsg = "驱动器无效。"

             intMsgType = vbExclamation + 4

          Case MnErrDiskNotReady                        ' 错误 71

             strMsg = "在软驱中插入磁盘并关上软驱门。"

          Case MnErrDeviceIO                               ' 错误 57

             strMsg = "内部磁盘错误。"

             intMsgType = vbExclamation + 4

          Case MnErrDiskFull                                  ' 错误 61

         strMsg = "磁盘满,要继续吗?"

             intMsgType = vbExclamation + 3     

          Case ErrBadFileName, ErrBadFileNameOrNumber   ' Error 64 & 52

             strMsg = "文件名非法。"

          Case ErrPathDoesNotExist                 ' 错误76

             strMsg = "路径不存在。"

          Case ErrBadFileMode                                ' 错误54

             strMsg = "不能以该访问方式打开你的文件。"

          Case ErrFileAlreadyOpen                   ' 错误55

             strMsg = "文件已被打开。"

          Case ErrInputPastEndOfFile                ' 错误 62

             strMsg = "文件有一个非标准的文件结尾标志。 "

             strMsg = strMsg & "或者试图读取文件结尾标志后的内容。"

          Case Else

             FileErrors = 3

             Exit Function

   End Select

   intResponse = MsgBox (strMsg, strMmsgType, "磁盘错误")

   Select Case intRresponse

          Case 1, 4    ' OK(确定)和Retry(重试)按钮。

             FileErrors = 0

          Case 5               ' Ignore(忽略)按钮。

             FileErrors = 1

          Case 2, 3    ' Cancel(取消)和 End(结束)按钮。

             FileErrors = 2

          Case Else

             FileErrors = 3

   End Select

End Function

上面的函数可处理共同的文件和磁盘相关错误。如果错误与磁盘的输入/输出无关,函数将返回值3,那么调用这个过程的过程有两种处理错误的方法:一是自己处理错误,用Raise方法重新生成错误;二是调用另一过程来处理错误。

注:在你编写大型应用程序时,会发现在各个窗体和模块的多个过程中使用了相同的常量。将这些常量作为公用常量,并在单一的标准模块中作声明,这可以使代码得到更好的组织,并避免重复的输入相同的声明。

对于所有可能会出现读写磁盘错误的过程,使它们调用FileErrors过程可简化错误处理。例如,你可能使用应用程序来警告试图替换一个已存在的磁盘文件。相反,当你试图打开一个不存在的文件时,应用程序会警告你文件不存在,并询问你是否要创建该文件。对于这两种情况,在应用程序将文件名传递给操作系统时都可能会发生错误。
7#
 楼主| 发表于 2006-6-6 08:44:00 | 只看该作者
关闭错误处理

如果一个错误陷井在某过程中有效,当该过程完成运行时,错误陷井会被自动关闭。然而,有时你可能想在过程代码仍处于运行时关闭错误陷井。要关闭一个有效的错误陷井,可使用On Error GoTo 0语句。在Visual Basic 运行这个语句后,错误可被检测到但并不在过程中捕获。在过程中的任何地方可使用On Error GoTo 0关闭错误处理,甚至在错误处理例程内也可以。

使用错误处理程序调试代码

在进行代码调试时,如果代码产生的错误被一个错误处理程序捕获,你可能会发觉对代码行为的分析是令人含混的。你可以在工程的每个模块中的On Error行后添加注释,但这种方法也很麻烦。

取而代之的是,在调试时关闭错误处理程序,这样一旦发生错误,程序就进入中断模式。为此,在“选项”对话框(“工具”菜单)上的“通用”选项卡上选中“发生错误则中断”。若选中该选项,在工程中的任何地方发生错误,工程将进入中断模式,并在“监视”窗口中显示发生错误的代码。若未选中该选项,错误可能会也可能不会引起错误消息的显示,这取决于错误发生的位置。例如,错误可能是由应用程序所引用的外部对象引起的。如果显示提示消息,错误的起源将决定错误消息是否有意义
8#
 楼主| 发表于 2006-6-6 08:46:00 | 只看该作者
处理引用对象中的错误

如果在过程中引用了一个或多个对象,要确定错误在何处发生就变得比较困难,尤其是错误发生在另一应用程序的对象中。例如,假设一个应用程序由一个窗体模块(MyForm)组成,MyForm引用一个类模块(MyClassA),类模块又引用了一个Microsoft Excel 工作表对象。

如果工作表对象不能处理工作表中产生的某个特定错误,它会重新生成一个错误,Visual Basic 将这个错误传递给引用工作表的对象MyClassA。Visual Basic 自动将未捕获的Visual Basic 外的对象中产生的错误映射为错误代码440。

MyClassA对象要么能处理错误(最好能)要么能重新生成一个错误。过程间的接口要求任何对象在重新生成一个引用对象中出现的错误时,不能只简单地传递错误(传递错误代码440),而应将错误号与具体含义映射起来。当你重新映射错误时,如果错误处理程序可确定该错误与定义的Visual Basic 错误相类似(例如,溢出或被零除等),那么错误号可以是表明错误情况的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

错误号440捕获那些在Visual Basic 应用程序外的引用对象中产生的错误。在本示例中,错误只是简单地用9999传递,因为这种集中化的处理程序很难确定错误的原因。发生这种错误通常是致命的自动化错误(会导致某组件结束运行)的结果,或者是由于对象不能正确处理一个捕获的错误。只有出现致命错误,错误号440才会被传递。如果象前面在“直接错误处理”中讨论的那样为一个内部处理程序编写错误陷井,则有可能确定错误的产生原因并更正错误。

语句Case Is > vbObjectError and Is < vbObjectError + 65536捕获发生在Visual Basic 应用程序内部对象的错误和捕获发生在包含处理程序的同一对象中的错误。只有被对象定义了的错误才处于vbObjectError偏差值范围内。

提供给对象的错误代码清单应定义所有可能的错误代码及其含义,这样,编写的处理程序就能灵活解决预计的错误。实际的错误代码可被设计为无vbObjectError偏差值的形式,或者在添加偏差值后编排错误代码,在这种情况下,Case Else语句应减去vbObjectError而不是加上偏差值。另一方面,对象错误可以是显示在对象类型库中的常量,如“对象浏览器”所示。在这种情况下,在Case Else语句中使用错误常量而不是错误代码。

任何未处理的错误应以一个新号重新生成,如Case Else语句所示。在编写的应用程序中,你可设计一个处理程序来预测你所定义的新号。如果是一个公用类,你还需要在应用程序文档说明中对新错误处理代码添加注释。

最后的Case Else语句捕获并重新生成在处理程序中未被捕获的任何错误。由于这部分的错误陷井会捕
9#
 楼主| 发表于 2006-6-6 08:46:00 | 只看该作者
调试的方法

本章中讲述的调试技巧使用的是Visual Basic 提供的分析工具。Visual Basic 不能为你诊断或修正错误,但它可以提供工具,帮助你分析程序如何从过程的一部分执行到另一部分以及变量和属性值在语句运行时如何变化等。调试工具使你能查看应用程序的内部,帮助你确定发生的情况和原因。

Visual Basic 调试工具包括断点、中断表达式、监视表达式、逐语句或逐过程以及显示变量和属性的值。Visual Basic 还包括特殊的调试特征,如编辑-继续能力、设置下一运行语句和在应用程序处于中断模式时测试过程。

错误类型

为理解调试的重要性,应考虑下面三种你可能遇到的错误,具体描述如下:

编译错误:这是由不正确的代码编写引起的。如果你在设计时输入的关键字不正确,遗漏了一些必要的标点或者使用Next语句而没有与之对应的For 语句等,Visual Basic 会在编译代码时检测出这些错误。

运行时错误:在应用程序运行过程中,如果一个语句试图进行不可能执行的操作,会发生这类错误(并由Visual Basic 检测到)。这类错误的例子有被零除等。

逻辑错误:当应用程序未按预计的方式执行时发生这类错误。一个应用程序具有句法有效的代码,运行时未执行任何非法操作,但产生的结果不正确。只有测试应用程序并分析结果,你才能保证应用程序的运行是正确的。

调试工具如何提供帮助

    调试工具被设计成可帮助你进行逻辑错误和运行时错误的排故,并帮助你观察没有错误的代码的运行方式。

例如,在一长串的计算后可能产生不正确的结果。调试中的任务是确定何事、何处出了问题。也许你忘记初始化一个变量、也许是你选择了一个错误的运算或者使用了一个不正确的公式。

调试中并不存在“魔术棍”,也不存在固定的工作步骤。最基本的一点是,调试帮助你了解应用程序正在进行的运行情况。调试工具为你提供了应用程序当前状态的快速浏览,包括变量、表达式和属性的值以及活动的过程调用名。你对应用程序的工作理解得越透彻,也就能更快找到错误(Bug)。

在大多调试工具中,Visual Basic 在“调试”工具栏上提供了一些有用的按钮,其说明如下。

下表简要描述了每个工具的用途。本章讨论的是这些工具如何帮助你更有效地调试或分析应用程序。









调试工具



用途





运行/继续



从设计时切换到运行时(运行)或从中断模式切换到运行时(继续)。(在中断模式中,按钮的名称变为“继续”)。





中断



从运行时切换到中断模式。





重新设置



从中断模式或运行时切换到设计时。





运行到光标处



在模块中定义一行,Visual Basic 在此行暂停应用程序的执行。





逐语句



在应用程序中运行下一可执行代码行,并转入过程。





逐过程



在应用程序中运行下一可执行代码行,但不转入过程。





跳出



运行当前过程的余下部分,并在调用过程的下一行中断。





“本地”窗口



显示当前过程中变量的值。





“立即”窗口



当应用程序处于中断模式时,允许你运行代码或查询变量值。





“监视”窗口



显示选定表达式的值。





快速监视



当应用程序处于中断模式时,列出表达式的当前值。





调用堆栈



在中断模式中,显示一个对话框,其中列出所有被调用且未完成运行的过程。
10#
 楼主| 发表于 2006-6-6 08:47:00 | 只看该作者
避免产生错误(Bug)

在应用程序中,可采用下列方法避免产生错误:

仔细设计应用程序,记下相关事件以及代码对每一事件的响应方式。为每个事件过程和每个通用过程指定一个特定明确的目的。

加入大量的注释。在你返回并分析代码时,如果你已在注释中对每个过程的目的进行了说明,那么你就可以更好地理解代码。

在可能之处明显地引用对象。按照“对象浏览器”中的“类”对话框中列出的对象声明对象,而不是使用一个Variant或者通用对象数据类型。

编写一个应用程序中变量和对象的命名表,保证命名的一致性。

最易引起错误产生的一个因素是输入不正确的变量名或将一个控件与另一控件混淆。你可使用Option Explicit来避免把变量名拼错。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|站长邮箱|小黑屋|手机版|Office中国/Access中国 ( 粤ICP备10043721号-1 )  

GMT+8, 2024-9-25 22:21 , Processed in 0.087561 second(s), 34 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表