国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
VBA的錯誤處理

VBA的錯誤處理

2009年7月25日

本文摘自MSDN的MS Office97 Visual Basic Progammer’s Guider的第14章,調(diào)試部分沒有包括在這里。不知道哪位老兄翻譯的。對錯誤處理很有幫助的一篇文章。

無論你怎樣認真細致地編寫代碼,錯誤總會(可能會)發(fā)生。理論上講,Visual Basic過程根本不需要錯誤處理代碼。然而不幸的是,有時會出現(xiàn)錯誤刪除文件、磁盤驅動器空間滿或網(wǎng)絡驅動器意外斷開等情況,這就存在導致代碼中發(fā)生運行時錯誤的可能性。為處理這些錯誤,需要在你編寫的過程中添加錯誤處理代碼。

有時,錯誤還可能在代碼內(nèi)部發(fā)生;這種類型的錯誤通常被稱作bug(錯誤)。小的錯誤會帶來失敗或不便。更嚴重的錯誤會造成應用程序對命令響應的中斷,可能需要用戶重新啟動應用程序并造成未保存的所有工作被丟失。

對應用程序中的錯誤進行定位和更正的過程被稱作調(diào)試。Visual Basic 提供一些幫助分析應用程序運行的工具。這些調(diào)試工具對于錯誤源的定位尤其有用,同時你還可使用這些工具試著對你編寫的程序進行修改或者學習其他應用程序的工作方式。

本章對Visual Basic 中調(diào)試工具的使用進行了說明,解釋了運行時錯誤(在代碼正在運行時發(fā)生的錯誤,它是在試圖進行非法操作時產(chǎn)生的)的處理方法。

注:本章中的信息適用于Microsoft Excel 97、Word 97和PowerPoint 97中的Visual Basic 編輯器。有關Microsoft Access 97中調(diào)試Visual Basic 代碼和處理錯誤的信息,請參閱icrosoft Access 97和Microsoft Office 97開發(fā)者版中的“建立Microsoft數(shù)Access 97應用程序”。另外,“建立Microsoft Access 97應用程序”的聯(lián)機版本可從Microsoft Access 97和Microsoft Office 97 專業(yè)版CD-ROM的Value Pack目錄下找到。

如何處理錯誤

理論上講,Visual Basic 過程根本不需要錯誤處理。事實表明,硬件問題或用戶的意外操作會導致運行時錯誤,從而停止代碼的運行,并且用戶通常無法恢復應用程序的運行。

其他錯誤不會中斷代碼的運行,但會導致代碼不按預想運行。

例如,下面程序中,若文件存在則返回真,若文件不存在則返回假,但程序中不包括錯誤處理代碼。

Function FileExists (filename) As Boolean
FileExists = (Dir(filename) <> "")
End Function

Dir函數(shù)返回第一個與指定文件名(有或沒有通配符、驅動器名或路徑)匹配的文件;如果未找到匹配文件,返回長度為零的字符串。

這個代碼包含Dir調(diào)用可能出現(xiàn)的任何結果。然而,如果變量指定的驅動器號是非法的驅動器,會出現(xiàn)錯誤“驅動器無效”。如果指定的驅動器是軟盤驅動器,該函數(shù)僅在軟盤驅動器中有盤和軟驅門關上的情況下運行正常,否則Visual Basic 會出現(xiàn)“磁盤未準備好”的錯誤提示,并且停止代碼的運行。

例如,下面示例可解決諸如驅動器無效或軟盤驅動器中無盤之類的驅動器問題。

Function FileExists (filename) As Boolean
Dim Msg As String
' 打開錯誤陷井,這樣錯誤處理程序可對檢測到的任何錯誤作出響應。
   On Error GoTo CheckError
FileExists = (Dir(filename) <> "")
' 如果沒有錯誤發(fā)生,不執(zhí)行錯誤處理程序。
          Exit Function
CheckError:' 如果發(fā)生錯誤,轉移至此。
   ' 定義代表Visual Basic 內(nèi)部錯誤代碼的常量。
   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
Resume Next
Else
Msg = "意外錯誤#" & Str(Err.Number) & " 發(fā)生: " _ & Err.Description
'顯示帶有Stop(停止)符圖標和OK按鈕的消息框。
      MsgBox Msg, vbCritical
Stop
End If
Resume
End Function

在本示例代碼中,Err對象的Number屬性包含與發(fā)生的運行時錯誤相關的數(shù)字;Description屬性包含對錯誤的簡短描述。

若Visual Basic 產(chǎn)生“磁盤未準備好”錯誤,本示例代碼將顯示一個提示信息,告訴用戶選擇OK按鈕或Cancel按鈕。如果用戶選擇OK,Resume語句可返回發(fā)生錯誤的語句,并試著重新運行該語句。如果用戶已經(jīng)糾正了問題,則運行可順利進行,否則將返回到錯誤處理程序。

如果用戶選擇Cancel按鈕,Resume Next 語句從緊隨產(chǎn)生錯誤的語句的下個語句恢復運行(本例中為Exit Function語句)。

若產(chǎn)生“驅動器無效”錯誤,本示例代碼將顯示一個描述該問題的信息。隨后Resume Next語句使得該過程從緊隨產(chǎn)生錯誤的語句的下個語句恢復運行。

如果發(fā)生意外錯誤,將顯示對該錯誤的簡短描述,代碼停止在Stop語句。

你編寫的應用程序可以更正錯誤或者提示用戶修改引起錯誤的條件。要做到這點,需要使用諸如前一示例中說明的技巧。以下部分將詳細探討這些技巧。

錯誤處理程序的設計

錯誤處理程序是在你編寫的應用程序中捕獲錯誤和作出響應的例程。你應在你認為可能出現(xiàn)錯誤的過程中添加錯誤處理程序(除非你可明確判定,否則應假定任何Visual Basic 語句都可能產(chǎn)生錯誤)。錯誤處理程序設計的步驟如下:

  1. 設置或使一個錯誤陷井有效,以告訴應用程序發(fā)生錯誤時轉移到何處(錯誤處理例程將運行)。On Error語句使錯誤陷井有效,并為應用程序指定錯誤處理例程從標有標簽處開始。在前面的示例中,F(xiàn)ileExists函數(shù)包含一個名為CheckError的錯誤處理例程。
  2. 編寫一個響應你可預測的所有錯誤的錯誤處理例程。如果在某個點上,控制流實際轉移到陷井中,此時陷井處于激活狀態(tài)。CheckError例程使用一個If…Then…Else語句來響應Err對象的Number屬性值(Number屬性是響應Visual Basic 錯誤的一個數(shù)值參數(shù)),從而實現(xiàn)錯誤的處理。示例中,在產(chǎn)生“磁盤未準備好”的錯誤時,為用戶顯示要求關上軟驅門的信息提示;在產(chǎn)生“驅動器無效”的錯誤時,為用戶顯示另一信息提示。如果發(fā)生其他錯誤,則顯示相應的描述,并中止程序。
  3. 退出錯誤處理例程。出現(xiàn)“磁盤未準備好”的錯誤時,Resume語句使代碼轉回到發(fā)生錯誤的語句處。然后Visual Basic 將試著重新運行那個語句。如果條件未發(fā)生改變,就會再次發(fā)生錯誤,并轉回到錯誤處理例程。出現(xiàn)“驅動器無效”的錯誤時,Resume Next語句使代碼轉回到緊接著發(fā)生錯誤的語句之后的語句處。

本主題的余下部分對如何執(zhí)行這些步驟進行了詳細論述。在閱讀這些步驟時,請參閱前面示例中的FileExists函數(shù)。

設置錯誤陷井

當Visual Basic 運行錯誤處理程序指定的On Error語句時,錯誤陷井被激活。當包含錯誤陷井的過程處于激活狀態(tài)時,該錯誤陷井是有效的—也就是說,在運行Exit Sub、Exit Function、Exit Property、End Sub、End Function或End Property語句前,過程中的錯誤陷井是有效的。在任何給定的過程中,任何時候都只能有一個錯誤陷井有效,你可創(chuàng)建多個備用的錯誤陷井,并在不同時間內(nèi)分別激活它們。使用On Error語句的特殊形式On Error GoTo 0來禁止某一錯誤陷井。

使用On Error GoTo line語句,設置從錯誤陷井跳轉到一個錯誤處理程序中,其中l(wèi)ine 參數(shù)指定識別錯誤處理代碼的標簽。在FileExists函數(shù)示例中的標簽為CheckError(雖然冒號是標簽的組成部分,但在On Error GoTo line語句中不用冒號)。

編寫錯誤處理例程

編寫錯誤處理例程的第一步是添加行標簽,以標識錯誤處理例程的開始。行標簽應具有一個描述性名稱,而且必須在其后加上冒號。編寫時的習慣做法是把錯誤處理代碼置于過程的結尾處,即行標簽在Eixt Sub 、Exit Function或Exit Property語句后。這可避免過程中無錯誤發(fā)生時錯誤處理代碼的執(zhí)行。

錯誤處理例程的主體包括實際處理錯誤的代碼,通常采用Select Case或If …Then…Else語句。你需要確定可能發(fā)生哪些錯誤,并為每個錯誤提供相應的處理措施,如在出現(xiàn)“磁盤未準備好”錯誤時,提示用戶插入磁盤。通常需要使用Else或Case Else條件從句來提供一個處理任何預計外錯誤的選項,在前面的FileExists函數(shù)示例中,該選項是警告用戶并結束應用程序。

Err對象的Number屬性包含一個代表最近發(fā)生的運行時錯誤的數(shù)值代碼。Err對象與Select Case或If…Then…Else語句的結合使用,可使你對發(fā)生的任何錯誤采取特定的措施。

退出錯誤處理例程

在FileExists函數(shù)示例中,錯誤處理程序使用了Resume語句,以從產(chǎn)生錯誤的語句處恢復運行;使用Resume Next語句,以從緊隨產(chǎn)生錯誤語句的下一語句處恢復運行。還可采用其他方法來退出錯誤處理例程。你可根據(jù)情況使用下列表中的任何語句。

Resume [0] 程序從產(chǎn)生錯誤的語句恢復運行或從最近一次調(diào)用包含錯誤處理程序的過程的語句處恢復運行。使用該語句可在更正產(chǎn)生錯誤的條件后恢復運行。

Resume Next 程序從緊隨產(chǎn)生錯誤的語句的下個語句恢復運行。如果錯誤發(fā)生在包含錯誤處理程序的過程以外,且被調(diào)用的過程不包含有效的錯誤處理程序,則從緊隨調(diào)用發(fā)生錯誤的過程的語句之后的語句處恢復運行。

Resume line 程序在 line 參數(shù)指定的標簽處恢復運行。line 參數(shù)是行標簽(或非零行號),它必須和錯誤處理程序在同一個過程中。

Err.Raise Number:=number 觸發(fā)運行時錯誤。當這個語句在錯誤處理例程中運行時,Visual Basic 搜索另一錯誤處理例程的調(diào)用列表(調(diào)用列表是被調(diào)用過程鏈,通過它,可到達當前的執(zhí)行點。這方面的詳細信息,參閱本章后面的“錯誤處理層次結構”)。

Resume與Resume Next間的差異

Resume 與Resume Next之間的差別在于:Resume是從產(chǎn)生錯誤的語句恢復應用程序的運行;Resume Next是從緊隨產(chǎn)生錯誤的語句的下個語句恢復應用程序的運行。一般而言,對于錯誤處理程序可以更正的錯誤使用Resume,對于錯誤處理程序不能更正的錯誤使用Resume Next。你可編寫錯誤處理程序,使存在的運行時錯誤不會讓用戶看到或者為用戶顯示錯誤信息并允許用戶進行更正。

在下面的示例中,使用錯誤處理來進行其變量的“安全”除法,而不顯示可能發(fā)生的錯誤。進行除法時可能發(fā)生的錯誤如下表所示。

錯誤                                     原因

“被零除”                            分子為非零數(shù),但分母為零。
“溢出”                                分子、分母均為零(在浮點數(shù)除法中)。
“非法過程調(diào)用”              分子和/或分母是非數(shù)值變量(或不能被看作數(shù)值變量)。

對于所有這三種情況,下面示例為這些錯誤設置陷井并返回Null(空)。

Function Divide (numer, denom) as Variant
Const mnErrDivByZero = 11, mnErrOverFlow = 6, mnErrBadCall = 5
On Error GoTo MathHandler
Divide = numer / denom
Exit Function
MathHandler:
If Err.Number = MnErrDivByZero Or Err.Number = ErrOverFlow _
Or Err = ErrBadCall Then
Divide = Null '如果發(fā)生被零除、溢出或非法過程調(diào)用錯誤,返回Null。
   Else
' 顯示意外錯誤信息
      MsgBox "意外錯誤 " & Err.Number & ": " & _
Err.Description, vbExclamation
End If           ' 對于所有情況都繼續(xù)執(zhí)行Resume Next。
   Resume Next             ' 從Exit Function語句執(zhí)行。
End Function

在特定行恢復執(zhí)行

Resume Next還可用在循環(huán)中發(fā)生的錯誤,你可以重新啟動運行或使用Resume line語句控制程序轉到某特定行標簽處。

下面示例說明了Resume line 語句的使用。與前面的FileExists示例不同的是,這個函數(shù)允許用戶輸入文件名稱,當文件存在時函數(shù)返回該文件名稱。

Function VerifyFile As String
Const mnErrBadFileName = 52, mnErrDriveDoorOpen = 71
Const mnErrDeviceUnavailable = 68, mnErrInvalidFileName = 64
Dim strPrompt As String, strMsg As String, strFileSpec As String
strPrompt = "輸入檢查的文件名稱:"
StartHere:
strFileSpec = "*.*"      ' 以一默認的名稱開始。
   strMsg = strMsg & vbCRLF & strPrompt
'讓用戶更改默認名稱。
   strFileSpec = InputBox(strMsg, "文件查找", strFileSpec, 100, _100)
' 如果用戶刪除默認名稱,退出。
   If strFileSpec = "" Then Exit Function
On Error GoTo Handler
VerifyFile = Dir(FileSpec)
Exit Function
Handler:
Select Case Err.Number      ' 分析錯誤代碼并加載信息。
          Case ErrInvalidFileName, ErrBadFileName
strMsg = "你輸入的文件名稱無效,請重試一次。"
Case MnErrDriveDoorOpen
strMsg = "關上磁盤驅動器門,重試一次。"
Case MnErrDeviceUnavailable
strMsg = "你所指定的驅動器未找到,重試一次。"
Case Else
Dim intErrNum As Integer
intErrNum = Err.Number
Err.Clear                 ' 清除Err對象。
             Err.Raise Number:= intErrNum ' 重新生成錯誤。
   End Select
Resume StartHere     '跳轉回StartHere標簽,使用戶可重新輸入另一文件名。
End Function

如果找到一個與輸入的文件名相匹配的文件,函數(shù)返回該文件名。如果未找到匹配的文件,函數(shù)返回一個零長度的字符串。如果意料中的錯誤發(fā)生,一條信息將被指定給strMsg變量,并跳轉回標簽StartHere重新執(zhí)行,這使得用戶有機會輸入一個有效的路徑和文件名稱。

如果出現(xiàn)意外的錯誤,在Case Else中重新生成錯誤,使得調(diào)用列表中另一錯誤處理程序可捕獲錯誤。這樣做是有必要的,因為如果不重新生成錯誤,代碼就會繼續(xù)從Resume StartHere行運行,而如果重新生成錯誤,你可有效地防止錯誤的重復發(fā)生;新錯誤將被設置在調(diào)用堆棧的另一層。

錯誤處理層次結構

一個有效的錯誤處理程序是由執(zhí)行On Error語句激活且未被關閉(可由On Error GoTo 0語句關閉,也可從其所在的過程中退出)的錯誤處理程序。一個活動的錯誤處理程序是當前正執(zhí)行的錯誤處理程序。錯誤處理程序只有在有效時才能被激活,但并不是所有有效的錯誤處理程序是活動的。例如,Resume 語句后,處理程序處于不活動狀態(tài),但它仍是有效的。

當缺少有效錯誤處理例程的過程中發(fā)生錯誤或者在活動的錯誤處理例程中發(fā)生錯誤時,Visual Basic 將在調(diào)用列表中搜索另一有效的錯誤處理例程。調(diào)用列表是一個指向當前執(zhí)行過程的調(diào)用順序表,它在“調(diào)用堆棧”對話框上顯示。只有在中斷模式中(暫停應用程序的執(zhí)行),單擊“視圖”菜單上的“調(diào)用堆棧”來顯示“調(diào)用堆棧”對話框。

調(diào)用列表的搜索

假定調(diào)用按下列順序發(fā)生:

  1. 某事件過程調(diào)用過程A。
  2. 過程A調(diào)用過程B。
  3. 過程B調(diào)用過程C。

當過程C正在執(zhí)行,其他過程處于運行狀態(tài)。如果在過程C中發(fā)生一個錯誤且其中沒有一個有效的錯誤處理程序,那么 Visual Basic 會在調(diào)用列表所列的運行過程中向后搜索—先搜索過程B,然后是過程A,最后是起始事件過程(到此為至)—并運行第一個搜索到的有效錯誤處理程序。如果在整個調(diào)用列表中未找到一個有效的錯誤處理程序,則會顯示一個默認的意外錯誤信息并暫停執(zhí)行。

如果Visual Basic 找到一個有效的錯誤處理例程,繼續(xù)執(zhí)行該例程,如同錯誤發(fā)生在包含錯誤處理程序的同一過程中一樣。如果錯誤處理例程中的Resume或Resume Next語句運行,則按下表所示繼續(xù)執(zhí)行。

語句                       結果

Resume               從Visual Basic 最近一次調(diào)用包含錯誤處理程序的過程的語句處恢復運行。在前面給定的調(diào)用列表中,如果過程A有一個包含Resume語句的有效錯誤處理程序,Visual Basic從調(diào)用過程B的語句恢復運行。

Resume Next    對最近一次調(diào)用包含錯誤處理程序的過程的語句,從緊隨該語句之后的語句處恢復運行。在前面給定的調(diào)用列表中,如果過程A有一個包含Resume Next語句的有效錯誤處理程序,運行會返回到調(diào)用過程B語句的下一語句。

注意是從找到錯誤處理過程的過程中的語句處恢復運行,而沒有必要從錯誤發(fā)生的過程中恢復運行。如果你沒有考慮到這一點,你編寫的代碼可能按你無法預料的方式運行。為了便于調(diào)試代碼,可采用簡單的方法,即在發(fā)生錯誤時轉入中斷模式,這方面的內(nèi)容見本章后面的“關閉錯誤處理” 部分。

如果錯誤處理程序的錯誤范圍未包括實際所遇到的所有錯誤,在包含有效錯誤處理程序的過程中會發(fā)生意外(預料外)錯誤。在這種情況下,除非錯誤處理程序運行Resume語句,不然過程會無止境運行下去。為預防這類情況的出現(xiàn),可在處理程序的Case Else語句中使用Err對象的Raise方法,它通常在錯誤處理程序內(nèi)重新生成一錯誤,從而強制Visual Basic 在調(diào)用列表中搜索能處理該錯誤的處理程序。

搜索調(diào)用列表的返回效果很難預測,這是因為搜索效果取決于可解決錯誤的處理程序中Resume和Resume Next語句的運行。Resume從調(diào)用包含錯誤處理程序的過程的語句恢復運行。Resume Next從緊隨調(diào)用包含錯誤處理程序的過程的語句的下一語句恢復運行。

例如,在前面討論的調(diào)用列表中,如果過程A有一個有效的錯誤處理程序,而過程B和過程C沒有,那么發(fā)生在過程C中的一個錯誤將由過程A中的錯誤處理程序進行處理。如果過程A中的錯誤處理程序在退出前使用Resume語句,那么程序將從調(diào)用過程的語句繼續(xù)運行(即進入過程 B);如果過程A中的錯誤處理程序在退出前使用Resume Next語句,那么程序將從過程A中調(diào)用過程B的下一語句繼續(xù)運行。在這兩種情況中,錯誤處理程序都不直接返回到發(fā)生錯誤的源過程和語句。

復雜錯誤處理的準則

在編寫包含多個模塊的大型Visual Basic 應用程序時,錯誤處理代碼可能變得相當復雜。請記住下面這些準則:

  • 在進行代碼的調(diào)試時,使用Err對象的Raise方法,可在所有錯誤處理程序中重新生成錯誤,以解決處理程序中無針對某特定錯誤的代碼的情況。這使得應用程序可試著沿調(diào)用列表在其他錯誤處理例程中更正錯誤。另外,它可確保在發(fā)生代碼不能處理的錯誤時,Visual Basic 會顯示錯誤信息。在進行代碼測試時,該技巧可幫助你發(fā)現(xiàn)那些未被充分處理的錯誤。
  • 如果需要在完成錯誤處理后清除Err對象,使用Clear方法,這對于使用On Error Resume Next進行直接錯誤處理是有必要的。每當執(zhí)行任意類型的 Resume 語句、Exit Sub、Exit Function、Exit Property或任何 On Error 語句時,Visual Basic 就會自動調(diào)用 Clear 方法。
  • 如果不打算用調(diào)用列表中的另一過程來捕獲錯誤,使用Stop語句以強行中斷程序代碼。使用Stop可使你對錯誤的內(nèi)容進行檢查,同時在開發(fā)環(huán)境下對代碼進行修改。
  • 編寫一個失效保險(fail-safe)錯誤處理過程,以便代碼中的所有錯誤處理程序可把該過程作為其解決不能處理的錯誤的最后方法。失效保險過程通過卸載窗體和保存數(shù)據(jù),可有序地執(zhí)行應用程序的中斷。

生成錯誤以測試錯誤處理

在進行應用程序測試時或者想要將某個特定條件當作是一個Visual Basic 運行時錯誤時,模擬錯誤是非常有用的。例如,也許你正使用在某個外部應用程序中定義的對象編寫一個模塊,并想在應用程序的余下部分中,把從對象中返回的錯誤當作實際的Visual Basic 錯誤。

為了測試所有可能的錯誤,可能需要在代碼中生成一些錯誤。可使用Err對象的Raise方法在代碼中生成一個錯誤。 Raise方法中的一個變量列表可被Raise傳遞。當代碼到達一個Resume語句時,自動調(diào)用Err 對象的Clear方法。為了將錯誤傳遞回調(diào)用堆棧的前一過程,有必要重新生成一個錯誤。

通過向錯誤提供錯誤代碼,還可模擬任何Visual Basic 運行時錯誤。

自定義錯誤

有時,你可能想在Visual Basic 定義的錯誤外補充定義一些錯誤。例如,依靠調(diào)制解調(diào)器連接的應用程序在載波信號下降時可能會出現(xiàn)錯誤。如果想生成并捕獲這個錯誤,你可將錯誤號賦給vbObjectError常量。

vbObjectError常量儲存的數(shù)值間于其偏差值(Offset)和偏差值與512的總和之間。為確保自定義的錯誤號不與以后的Visual Basic 沖突,所用的數(shù)值高于該值。為自定義錯誤號,可在模塊的申明部分添加常量。

' 錯誤常量
Const gLostCarrier = 1 + vbObjectError + 512
Const gNoDialTone = 2 + vbObjectError + 512

然后,你可使用Raise方法來生成任何內(nèi)部錯誤。對于這種情況,Err 對象的描述屬性將返回一個標準的描述“應用程序定義的錯誤或對象定義的錯誤”。要提供自定義錯誤的描述,你需要把它作為一個參數(shù)添加到Raise 方法中。

直接錯誤處理

若在可能導致錯誤的每一行后立即檢測錯誤,這就是直接錯誤處理。使用直接錯誤處理,可以編寫在錯誤發(fā)生時返回錯誤號的函數(shù)和語句;在過程中產(chǎn)生一個Visual Basic 錯誤,并在調(diào)用過程中處理錯誤;或者編寫一個返回Variant數(shù)據(jù)變量的函數(shù),為調(diào)用過程指示所發(fā)生的錯誤。

返回錯誤號

返回錯誤號的方法有很多,其中最簡單的方法是創(chuàng)建一個在錯誤發(fā)生時返回錯誤號的函數(shù)和語句,而不是返回某個變量。下面示例說明了如何在FileExists函數(shù)示例中使用這種方法,以指示某特定文件是否存在。

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
.
.  ' 繼續(xù)進行程序。
   .
End If

直接錯誤處理的關鍵在于在每個語句或函數(shù)調(diào)用后立即檢測錯誤。在這種方式中,你可設計一個處理程序,以準確預計可能出現(xiàn)的錯誤的類別,并采用相應的方法解決錯誤。這種方法不需要產(chǎn)生一個實際的運行時錯誤。

在調(diào)用過程中處理錯誤

指示錯誤情況的另一方法是在過程自身中生成一個Visual Basic 錯誤,并在調(diào)用過程的直接錯誤處理程序中處理這個錯誤。下面的示例說明在FileExists過程中,當操作不成功時產(chǎn)生的錯誤號。在調(diào)用該函數(shù)前,On Error Resume Next語句在錯誤發(fā)生時為Err對象屬性賦值,但并不企圖運行一個錯誤處理例程。

On Error Resume Next語句后緊跟錯誤處理代碼。這個代碼可檢測Err 對象的屬性,以確定是否有錯誤發(fā)生。如果Err.Number不為零,則已發(fā)生錯誤,根據(jù)Err對象的屬性值,錯誤處理代碼可采取相應的措施。

Function FileExists (p As String)
If Dir (p) <> " " Then
Err.Raise conSuccess      ' 返回一個常量,指示文件存在。
   Else
Err.Raise conFailure    ' 產(chǎn)生錯誤號conFailure
   End If
End Function
 
Dim ResultValue As Long
On Error Resume Next
ResultValue = FileExists ("C:\Testfile.txt")
If Err.Number = conFailure Then
.
.  ' 處理錯誤。
   .
Else
.
.  ' 繼續(xù)進行程序。
   .
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
 
' 調(diào)用Power函數(shù)。

Dim lngReturnValue As Long, lngErrorMaybe As Long
lngErrorMaybe = Power (10, 2, lngReturnValue)
If lngErrorMaybe Then
.
.  ' 處理錯誤。
   .
Else
 
.  ' 繼續(xù)進行程序。
   .
End If

如果編寫的函數(shù)只是簡單地返回一個結果變量或返回一個錯誤代碼,那么結果變量可能在錯誤代碼的范圍內(nèi),這樣調(diào)用過程就無法區(qū)別是結果變量還是錯誤代碼。返回變量和一個傳遞自變量的同時使用,可使你的程序確定函數(shù)調(diào)用是否失敗,并采用適當?shù)拇胧?/p>

Variant數(shù)據(jù)類型的使用

返回內(nèi)部錯誤信息的另一種方法是利用Visual Basic 的Variant數(shù)據(jù)類型及相關的一些函數(shù)。Variant具有一個標識符,可指示變量中包含數(shù)據(jù)的類型,并且Variant還可被標識為一個 Visual Basic 錯誤代碼。你可以編寫一個函數(shù)來返回一個Variant,并使用標識符為調(diào)用過程指示所發(fā)生的錯誤。

下面示例說明如何編寫Power函數(shù),以返回一個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
 
' 調(diào)用Power函數(shù)。

Dim varReturnValue As Variant
varReturnValue = Power (10, 2)
If IsError (varReturnValue) Then
.
.  ' 處理錯誤。
   .
Else
.
.  ' 繼續(xù)進行程序。
   .
End If

集中化錯誤處理

在為你的應用程序添加錯誤處理代碼時,你很快會發(fā)現(xiàn)自己在一遍一遍地處理同樣的錯誤。仔細制定計劃,編寫一些錯誤處理代碼可調(diào)用的過程,以便處理共同錯誤情況,從而縮短代碼。

在下面的FileErrors函數(shù)中,當錯誤發(fā)生時會顯示一條適當?shù)南?,若可能,將允許用戶通過選擇按鈕來確定程序的下一步動作。然后,代碼返回給調(diào)用函數(shù)的過程。代碼值指示程序的下一步動作。注意用戶自定義的常量(如MnErrDeviceUnavailable)必須在某處進行定義(全局常量或者包含該過程的模塊的模塊級常量或者該過程內(nèi)部常量)。

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 = "內(nèi)部磁盤錯誤。"
intMsgType = vbExclamation + 4
Case MnErrDiskFull                                  ' 錯誤 61
         strMsg = "磁盤滿,要繼續(xù)嗎?"
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 & "或者試圖讀取文件結尾標志后的內(nèi)容。"
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

上面的函數(shù)可處理共同的文件和磁盤相關錯誤。如果錯誤與磁盤的輸入/輸出無關,函數(shù)將返回值3,那么調(diào)用這個過程的過程有兩種處理錯誤的方法:一是自己處理錯誤,用Raise方法重新生成錯誤;二是調(diào)用另一過程來處理錯誤。

注:在你編寫大型應用程序時,會發(fā)現(xiàn)在各個窗體和模塊的多個過程中使用了相同的常量。將這些常量作為公用常量,并在單一的標準模塊中作聲明,這可以使代碼得到更好的組織,并避免重復的輸入相同的聲明。

對于所有可能會出現(xiàn)讀寫磁盤錯誤的過程,使它們調(diào)用FileErrors過程可簡化錯誤處理。

例如,你可能使用應用程序來警告試圖替換一個已存在的磁盤文件。相反,當你試圖打開一個不存在的文件時,應用程序會警告你文件不存在,并詢問你是否要創(chuàng)建該文件。對于這兩種情況,在應用程序將文件名傳遞給操作系統(tǒng)時都可能會發(fā)生錯誤。

關閉錯誤處理

如果一個錯誤陷井在某過程中有效,當該過程完成運行時,錯誤陷井會被自動關閉。然而,有時你可能想在過程代碼仍處于運行時關閉錯誤陷井。要關閉一個有效的錯誤陷井,可使用On Error GoTo 0語句。在Visual Basic 運行這個語句后,錯誤可被檢測到但并不在過程中捕獲。在過程中的任何地方可使用On Error GoTo 0關閉錯誤處理,甚至在錯誤處理例程內(nèi)也可以。

使用錯誤處理程序調(diào)試代碼

在進行代碼調(diào)試時,如果代碼產(chǎn)生的錯誤被一個錯誤處理程序捕獲,你可能會發(fā)覺對代碼行為的分析是令人含混的。你可以在工程的每個模塊中的On Error行后添加注釋,但這種方法也很麻煩。

取而代之的是,在調(diào)試時關閉錯誤處理程序,這樣一旦發(fā)生錯誤,程序就進入中斷模式。

為此,在“選項”對話框(“工具”菜單)上的“通用”選項卡上選中“發(fā)生錯誤則中斷”。若選中該選項,在工程中的任何地方發(fā)生錯誤,工程將進入中斷模式,并在“監(jiān)視”窗口中顯示發(fā)生錯誤的代碼。若未選中該選項,錯誤可能會也可能不會引起錯誤消息的顯示,這取決于錯誤發(fā)生的位置。例如,錯誤可能是由應用程序所引用的外部對象引起的。如果顯示提示消息,錯誤的起源將決定錯誤消息是否有意義。

處理引用對象中的錯誤

如果在過程中引用了一個或多個對象,要確定錯誤在何處發(fā)生就變得比較困難,尤其是錯誤發(fā)生在另一應用程序的對象中。例如,假設一個應用程序由一個窗體模塊(MyForm)組成,MyForm引用一個類模塊(MyClassA),類模塊又引用了一個Microsoft Excel 工作表對象。

如果工作表對象不能處理工作表中產(chǎn)生的某個特定錯誤,它會重新生成一個錯誤,Visual Basic 將這個錯誤傳遞給引用工作表的對象MyClassA。Visual Basic 自動將未捕獲的Visual Basic 外的對象中產(chǎn)生的錯誤映射為錯誤代碼440。

MyClassA對象要么能處理錯誤(最好能)要么能重新生成一個錯誤。過程間的接口要求任何對象在重新生成一個引用對象中出現(xiàn)的錯誤時,不能只簡單地傳遞錯誤(傳遞錯誤代碼440),而應將錯誤號與具體含義映射起來。當你重新映射錯誤時,如果錯誤處理程序可確定該錯誤與定義的Visual Basic 錯誤相類似(例如,溢出或被零除等),那么錯誤號可以是表明錯誤情況的Visual Basic 定義數(shù)值,另外,錯誤號還可以是Visual Basic 未定義的錯誤號。在Visual Basic 常量vbObjectError中添加新數(shù)值,將對象產(chǎn)生的錯誤通知其他處理程序。

只要可能,應在一個類模塊中盡力處理模塊本身產(chǎn)生的所有錯誤,并還應盡力處理模塊所引用的對象中產(chǎn)生的對象不能處理的錯誤。然而,由于一些錯誤是不能預計的,因此仍存在一些不能處理的錯誤。另外,有些情況下,在引用對象中處理錯誤比在被引用對象中處理錯誤更適宜。

當錯誤在窗體模塊中發(fā)生時,Visual Basic 產(chǎn)生一個預先定義的Visual Basic 錯誤號。

注:如果你在創(chuàng)建一個公用類,要保證明確表述了你所定義的每個非Visual Basic 錯誤處理程序的含義。其他程序員在引用這個公用類時,需要知道如何處理你定義對象所產(chǎn)生的錯誤。

在重新生成一個錯誤時,保持Err對象的其他屬性不變化。如果未捕獲產(chǎn)生的錯誤,Source和Description屬性將被顯示出來,以幫助用戶采取更正措施。

處理從引用對象傳遞的錯誤

一個類模塊可包括下列錯誤處理程序,以解決任何可捕獲的錯誤和重新生成不能解決的錯誤。

 MyServerHandler:
Select Case ErrNum
Case 7        ' 處理內(nèi)存溢出錯誤
                 ..
Case 440    ' 處理外部對象錯誤
             Err.Raise Number:=vbObjectError + 9999
' 來自另一Visual Basic 對象的錯誤
          Case Is > vbObjectError and Is < vbObjectError + 65536
ObjectError = ErrNum
Select Case ObjectError
' 對象根據(jù)為其提供的錯誤號處理錯誤
             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 應用程序外的引用對象中產(chǎn)生的錯誤。在本示例中,錯誤只是簡單地用9999傳遞,因為這種集中化的處理程序很難確定錯誤的原因。發(fā)生這種錯誤通常是致命的自動化錯誤(會導致某組件結束運行)的結果,或者是由于對象不能正確處理一個捕獲的錯誤。只有出現(xiàn)致命錯誤,錯誤號440才會被傳遞。如果象前面在“直接錯誤處理”中討論的那樣為一個內(nèi)部處理程序編寫錯誤陷井,則有可能確定錯誤的產(chǎn)生原因并更正錯誤。

語句Case Is > vbObjectError and Is < vbObjectError + 65536捕獲發(fā)生在Visual Basic 應用程序內(nèi)部對象的錯誤和捕獲發(fā)生在包含處理程序的同一對象中的錯誤。只有被對象定義了的錯誤才處于vbObjectError偏差值范圍內(nèi)。

提供給對象的錯誤代碼清單應定義所有可能的錯誤代碼及其含義,這樣,編寫的處理程序就能靈活解決預計的錯誤。實際的錯誤代碼可被設計為無vbObjectError偏差值的形式,或者在添加偏差值后編排錯誤代碼,在這種情況下,Case Else語句應減去vbObjectError而不是加上偏差值。另一方面,對象錯誤可以是顯示在對象類型庫中的常量,如“對象瀏覽器”所示。在這種情況下,在Case Else語句中使用錯誤常量而不是錯誤代碼。

任何未處理的錯誤應以一個新號重新生成,如Case Else語句所示。在編寫的應用程序中,你可設計一個處理程序來預測你所定義的新號。如果是一個公用類,你還需要在應用程序文檔說明中對新錯誤處理代碼添加注釋。

最后的Case Else語句捕獲并重新生成在處理程序中未被捕獲的任何錯誤。由于這部分的錯誤陷井會捕獲添加或未添加vbObjectError常量的錯誤,因此,你應把這些錯誤與通用的“不可解決的錯誤”代碼相映射。這個代碼應添加到vbObjectError中,為任何處理程序指出發(fā)生在被引用對象中的錯誤。

調(diào)試被引用對象中的錯誤處理程序

當你在調(diào)試的應用程序引用了Visual Basic 創(chuàng)建的對象或引用了類模塊中定義的類時,你可能會發(fā)現(xiàn)不易確定錯誤是由哪個對象產(chǎn)生的。為簡化這個問題,你可選中“選項”對話框(“工具”菜單)上“通用”選項卡中的“在類模塊中中斷”。當選中該選項時,類模塊中的錯誤可導致這個類進入調(diào)試的中斷模式,使得你有機會對錯誤進行分析。

本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
n Error Resume Next是什么意思
VBA 程序之錯誤處理
關于vb中捕獲錯誤語句的使用
VB容錯處理策略(全)
VBA錯誤處理
《Visual Basic程序設計教程(第3版)》第8章 程序調(diào)試與錯誤處理
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服