在 Word 、 Excel 乃至其他支持 VBA 的 Office 組件中,在代碼中處理錯誤的方式通常都是使用“ On Error Goto 錯誤標簽”語句,然后在代碼的后面添加錯誤標簽及其中包含的錯誤處理代碼。下面總結了創建錯誤處理程序的步驟:
( 1 )在過程中可能導致錯誤的代碼行的前面添加錯誤處理語句 On Error Goto ErrHandler ,其中的“ ErrHandler ”為自定義的錯誤標簽名稱。
( 2 )在有可能導致錯誤的代碼行后面添加取消錯誤處理的語句 On Error Goto 0 ,這樣當遇到錯誤時,就不會跳轉到指定的錯誤標簽處,而是直接顯示錯誤提示窗口,其中包括【調試】、【結束】等按鈕。
( 3 )在宏的末尾(正常程序的末尾)添加代碼行 Exit Sub ,這樣可以避免程序未發生錯誤時執行錯誤處理程序。
( 4 )在代碼行 Exit Sub 的下一行添加一個錯誤標簽,該標簽由名稱和冒號組成,例如“ MyErr: ”。
( 5 )在錯誤標簽的下一行編寫錯誤處理代碼。如果要返回導致錯誤的代碼行后面的代碼行,可以使用 Resume Next 語句。
注意:可以在過程的末尾添加多個錯誤處理程序,但必須確保每個錯誤處理程序都以Resume Next 或 Exit Sub 語句結束,這樣可以避免從當前錯誤程序之后繼續執行其后的錯誤處理程序。
舉一個簡單的例子可能會更直觀地反映出上面所說的內容。在下面的代碼中,當檢測到工作簿中沒有指定的工作表時,將出現錯誤,並執行錯誤代碼,顯示一個包含錯誤號與錯誤描述的對話框。
1 Sub 檢測工作表是否存在 () 2 3 Dim wksname As String, msg As String 4 5 On Error GoTo MyErr 6 7 wksName = Worksheets("sx").Name 8 9 MyErr: 10 11 msg = " 錯誤 " & Err.Number & " : " & Err.Description 12 13 MsgBox msg 14 15 End Sub
注意:無論在導致問題的代碼行前面使用 On Error Resume Next 語句還是“ On Error Goto 標簽”語句,要想讓程序重新獲取其他錯誤信息,則都必須在導致問題的代碼行后面使用 On Error Goto 0 語句恢復正常的錯誤捕獲狀態。否則當前的錯誤處理程序將對后面的所有錯誤都起作用。例如,下面的代碼由於沒有使用 On Error Goto 0 語句,因此,在后面遇到錯誤時(兩次 x/y ),都會轉到標簽 MyErr 處執行錯誤處理程序。
Sub ErrTest() Dim x As Integer, y As Integer, z As Single x = 1 y = 0 On Error GoTo MyErr MsgBox x / y MsgBox x / y MsgBox " 繼續執行錯誤代碼行的下一行代碼 " Exit Sub MyErr: MsgBox " 第 1 次:除數不能為 0" Resume Next End Sub
而下面的代碼由於及時使用了 On Error Goto 0 語句,因此,在第 2 次錯誤發生時(即第 2 個 x/y ),系統將顯示內置錯誤消息,而不是運行 MyErr 標簽處的代碼。
1 Sub ErrTest1() 2 3 Dim x As Integer, y As Integer, z As Single 4 5 x = 1 6 7 y = 0 8 9 On Error GoTo MyErr 10 11 MsgBox x / y 12 13 On Error GoTo 0 14 15 MsgBox x / y 16 17 MsgBox " 繼續執行錯誤代碼行的下一行代碼 " 18 19 Exit Sub 20 21 MyErr: 22 23 MsgBox " 第 1 次:除數不能為 0" 24 25 Resume Next 26 27 End Sub
下面的代碼雖然未使用 On Error Goto 0 語句,但是在第 2 個錯誤發生前,添加了第2 個錯誤標簽,因此,兩個錯誤處理程序分別處理各自的錯誤。
1 Sub ErrTest2() 2 3 Dim x As Integer, y As Integer, z As Single 4 5 x = 1 6 7 y = 0 8 9 On Error GoTo MyErr1 10 11 MsgBox x / y 12 13 On Error GoTo MyErr2 14 15 MsgBox x / y 16 17 MsgBox " 繼續執行錯誤代碼行的下一行代碼 " 18 19 Exit Sub 20 21 MyErr1: 22 23 MsgBox " 第 1 次:除數不能為 0" 24 25 Resume Next 26 27 MyErr2: 28 29 MsgBox " 第 2 次:除數不能為 0" 30 31 Resume Next 32 33 End Sub
以上 3 段代碼在執行完錯誤處理程序后,都會返回發生錯誤的代碼之后繼續執行。對於本例來說,在執行完錯誤處理程序后,都會繼續執行“ MsgBox " 繼續執行錯誤代碼行的下一行代碼 " ”代碼行。
雖然我們不希望在程序運行時出現錯誤,但是有些時候我們可以利用錯誤來提高代碼的效率。例如,當用戶由於某些原因將工作簿中的某個工作表刪除,如果 VBA 程序中包括操作該工作表的代碼,那么當用戶運行該程序時,將導致錯誤發生。此時,可以利用錯誤來檢測要操作的工作表是否存在於工作簿中。代碼如下:
1 Sub 檢測工作表是否存在() 2 3 Dim WksName As String 4 5 On Error Resume Next 6 7 WksName = Worksheets("sx").Name 8 9 If Err.Number <> 0 Then 10 11 MsgBox prompt:=" 此工作簿中未找到工作表 sx", Title:=" 錯誤 " 12 13 End If 14 15 On Error GoTo 0 16 17 End Sub
注意:當使用 On Error Resume Next 語句后,應該及時在可能導致錯誤的代碼行之后使用 On Error Goto 0 語句恢復錯誤的捕獲,即恢復到錯誤檢查的正常狀態,以便可以獲悉其他任何可能發生的錯誤。另外,如果使用 On Error Resume Next 語句忽略了無法忽略的錯誤,將會立刻結束當前運行的過程。而更糟糕的是,如果宏 1 調用宏 2 ,但宏 2 發生了無法忽略的錯誤,那么將立刻結束宏 2 的運行,而繼續執行宏 1 中的下一行代碼,這種情況可能會使整個代碼包含了不可預知的錯誤,因此務必要小心。
Resume 語句
在錯誤處理程序結束后,恢復原有的運行。
語句 | 描述 |
Resume | 如果錯誤和錯誤處理程序出現在同一個過程中,則從產生錯誤的語句恢復運行。如果錯誤出現在被調用的過程中,則從最近一次調用包含錯誤處理程序的過程的語句處恢復運行 |
Resume Next | 如果錯誤和錯誤處理程序出現在同一個程序中,則從緊隨產生錯誤的語句的下個語句恢復運行。如果錯誤發生在被調用的過程中,則對最后一次調用包含錯誤處理程序的過程的語句(或 On Error Resume Next 語句),從緊隨該語句之后的語句處恢復運行。 |
Resume line | 在必要的 line 參數指定的 line 處恢復運行。line 參數是行標簽或行號,必須和錯誤處理程序在同一個過程中。 |
On Error 語句
啟動一個錯誤處理程序並指定該子程序在一個過程中的位置;也可用來禁止一個錯誤處理程序。
語句 | 描述 |
On Error GoTo line |
啟動錯誤處理程序,且該例程從必要的 line 參數中指定的line 開始。line 參數可以是任何行標簽或行號。如果發生一個運行時錯誤,則控件會跳到 line,激活錯誤處理程序。指定的 line 必須在一個過程中,這個過程與 On Error 語句相同; 否則會發生編譯時間錯誤。 |
On Error Resume Next | 說明當一個運行時錯誤發生時,控件轉到緊接着發生錯誤的語句之后的語句,並在此繼續運行。訪問對象時要使用這種形式而不使用 On Error GoTo。 |
On Error GoTo 0 | 禁止當前過程中任何已啟動的錯誤處理程序。
|
錯誤處理程序依靠 Err 對象的 Number 屬性中的值來確定錯誤發生的原因。在其它任何錯誤發生之前,或在調用一個可能會導致錯誤發生的過程之前,錯誤處理程序應該先測試或存儲 Err 對象中相關的屬性值。Err 對象中的屬性值只反映最近發生的錯誤。Err.Description 中包含有與 Err.Number 相關聯的錯誤信息。
On Error GoTo 0 停止在當前過程中處理錯誤。即使過程中包含編號為 0 的行,它也不把行 0 指定為處理錯誤的代碼的起點。如果沒有 On Error GoTo 0 語句,在退出過程時,錯誤處理程序會自動關閉。