程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> Visual Basic語言 >> VB6 >> VBA中的錯誤處理

VBA中的錯誤處理

編輯:VB6

從理論上講,VBA沒有提供任何的錯誤處理機制,這種被用在微軟Office產品中的以Visual Basic語言為基礎的腳本語言根本就不要任何的錯誤處理,當程序出現錯誤或產生異常情況時,VBA會自動定位到出錯的代碼行,然後提示用戶出錯的可能原因。這是典型的腳本語言的錯誤提示,聯想到javascript語言,在浏覽器中如果出現腳本錯誤,浏覽器會給出提示信息,但這並不影響整個程序的正常運行,最多也就是出現錯誤之後的腳本不被繼續解釋而已。不過即便如此,javascript還是提供了較為良好的錯誤處理機制,例如常見的try catch語句和alert提示,以及後來支持的debugger調試信息等,javascript在支持面向對象語言特性的同時也逐漸改善了它的錯誤處理和調試方法。

然而Visual Basci卻沒有這麼幸運,從誕生之初,Visual Basic就沒有提供一個比較好的錯誤處理機制,盡管我們在實際應用中總會遇到這樣或那樣的運行時錯誤(例如錯誤刪除文件、磁盤驅動器空間不夠、網絡通信發生異常等),但是對於Visual Basic的過程來說根本就沒有錯誤處理,當錯誤產生時程序便停止運行,直到異常被清除。有關比較詳細的介紹Visual Basic的錯誤處理和調試方法的文章,讀者可以參考下面這個鏈接。

http://www.officexy.com/Articles/office/VBABasic/20061026103436501.htm

VBA的語言特性類似於Visual Basic,應該說它們屬於同一家族,所以,用來在Visual Basic中處理程序異常的方法也同樣可以被用在VBA中。

在Visual Basic中,常用的程序錯誤處理的方式是設置或使用錯誤陷阱,以告訴應用程序當錯誤發生時轉移到何處(或處理當錯誤發生時要運行的代碼),通過在代碼中定義標簽來告知應用程序當錯誤發生時要轉到的地方。這一點和C系列語言的錯誤處理方式是相同的。基本步驟如下:

1.設置一個有效的錯誤陷阱,以告訴應用程序發生錯誤時轉移到何處繼續運行。Visual Basic中的On Error語句可以使錯誤陷阱有效,並為應用程序指定錯誤處理的入口。

2.在錯誤程序的入口處編寫響應錯誤的具體實現,如繼續嘗試執行之前的代碼、或告知用戶出錯的具體原因以讓用戶嘗試去解決等。

3.退出錯誤處理。

有關如何使用Visual Basic的錯誤處理和On Error語句的具體含義,讀者可以仔細閱讀上面給出的那個鏈接的文章,裡面有非常詳細的介紹。我在這裡會結合實際應用來講講在VBA中如何具體使用錯誤處理。

先看一個簡單的示例。

Private Sub CommandButton1_Click()
On Error GoTo Err_Handle
Dim a As Integer
Dim b As Integer
Dim c As Integer
a = 10
b = 0
c = a / b '除數為0會導致運行時錯誤
MsgBox c
End Sub
Err_Handle:
MsgBox Err.Description
End Sub

在上述過程中,我們首先通過On Error語句設置了一個錯誤陷阱,該錯誤陷阱將自動被激活,同時錯誤陷阱指向了代碼中定義的標簽Error_Handle。當過程被調用時,如果出現異常,程序會自動運行標簽所指向的代碼段,這裡會給用戶一個提示。Err對象為系統對象,其中包含了當錯誤發生時的描述信息和錯誤編號,根據Err對象提供的這些簡單信息我們也許可以告知用戶應用程序發生了什麼事情,從而最終找出出錯的具體原因。

在Visual Basic中,我們通過On Error語句設置並激活了一個錯誤陷阱,直到程序退出過程或方法,該錯誤陷阱會一直有效。也就是說,我們需要給每一個過程或方法在需要的時候設置單獨的錯誤陷阱,這個有點類似於C的代碼中在需要的地方插入try catch語句,錯誤處理程序在過程或方法內部定義的標簽開始的地方,在程序運行時如果錯誤沒有出現,則標簽之後的代碼應該不會被執行到,因此我們通常都需要在錯誤處理代碼前插入退出語句,例如End Sub或方法的返回語句。

幸運的是我們通常沒有必要為每一個過程或方法定義錯誤陷阱,在VBA中,往往只有一少部分過程或方法需要定義錯誤陷阱,但是不排除復雜的VBA應用程序,當代碼量達到上千行,過程或方法上百個時,應該不亞於一個小的VB系統,這個時候編寫一個專門的錯誤處理函數還是很有必要的。在需要進行錯誤處理的過程或方法中設置好錯誤陷阱和用於處理錯誤的標簽,然後在標簽後調用錯誤處理函數並傳入Err對象,由錯誤處理函數專門處理程序中各種不同的錯誤。這個程序看起來大致是下面這個樣子。

'-----Err number-----
Private Const ErrNoPermissions = -2147217900
Private Const ErrCannotLocateURL = -2146697211
Private Const ErrDbDenyConnect = -2147217843
Private Const ErrCannotFoundDbProvider = 3706
'--------------------
' Errors handle:
' Return Description
' 0 Resume
' 1 Resume Next
' 2 Error
Function ErrorsHandle() As Integer
Dim intMsgType As Integer, intResponse As Integer, strMsg As String
Dim myDoc As Worksheet
Set myDoc = ActiveSheet

Select Case Err.Number
Case ErrCannotLocateURL ' Error -2146697211
strMsg = "Cannot connect to the website specified.Please make sure the URL is correct and

the website is available."
intMsgType = vbRetryCancel
Case ErrNoPermissions ' Error -2147217900
myDoc.Protect 'Protect the sheet if current user doesn't have permissions to access the dat

a
strMsg = "User " & glUserName & " doesnt have permissions to access the data."
intMsgType = vbExclamation
Case ErrCannotFoundDbProvider ' Error 3706
strMsg = "Please ensure 'Microsoft SQL Server Native Client for SQL2005' installed at first

." & _
"You can download at :http://download.microsoft.com/download/4/4/D/" & _
"44DBDE61-B385-4FC2-A67D-48053B8F9FAD/sqlncli.msi"
intMsgType = vbExclamation
Case ErrDbDenyConnect ' Error -2147217843
myDoc.Protect 'Protect the sheet if current user doesn't have permissions to connect the da

tabase
strMsg = "Database login failed for user '" & glUserName & "'."
intMsgType = vbExclamation
Case Else
strMsg = "Fatal error." & Err.Description & ".The error number is " & Err.Number
intMsgType = vbCritical
End Select
intResponse = MsgBox(strMsg, intMsgType)
Select Case intResponse
Case 4, 6 ' Retry And Yes
ErrorsHandle = 0
Case 5 ' Ignore
ErrorsHandle = 1
Case Else ' Cancel and Abort
ErrorsHandle = 2
End Select
End Function

稍微做一下解釋。當程序發生錯誤時,Err對象的Number屬性會返回一個錯誤代碼,ErrorsHandle函數得到這個錯誤代碼並通過Select Case語句逐一比對錯誤代碼,找到事先定義好的錯誤處理方法從而返回給用戶最准確的信息。程序的一開始定義了一組常量用來描述錯誤代碼所表示的具體含義,在Select Case語句中根據不同的錯誤代碼返回給用戶不同的錯誤描述信息,並且根據錯誤的種類彈出不同類型的提示框(如確定、重試、取消等),這個是由MsgBox常數所決定的,該常數分為很多種類,可以彈出各種不同類型的提示框,讀者可以自己查閱Office幫助文檔。如果需要,我們可以隨時在Select Case語句中補充更多的內容來定制內容更豐富的錯誤處理方法,而只需要確認何種錯誤代碼代表何種具體的錯誤信息即可,這個錯誤信息我們也可以通過Err.Description屬性來獲取,盡管這個描述信息通常都並不那麼精確。最後ErrorsHandle函數會返回三種不同的結果(當然如果需要你可以讓這個函數返回更多的值),用以表示調用它的過程或方法如何繼續處理,是終止程序運行,還是嘗試再次運行,或者忽略錯誤繼續運行下面的代碼等。下面是調用的代碼。

Public Enum DebugMode
Release = 0
Debugger = 1
End Enum

Public Mode As DebugMode

Private Sub CommandButton1_Click()
Mode = DebugMode.Release 'Change the Mode value to Debugger or Release
If Mode = Release Then
On Error GoTo Error_Handle
End If

' TODO Something

Exit Sub

Error_Handle:
errNum = ErrorsHandle
If errNum = 0 Then
Resume
ElseIf errNum = 1 Then
Resume Next
Else
Exit Sub
End If
End Sub

我省略了過程中的具體實現,實際上你可以在這個過程中實現任何功能,只要程序出錯,ErrorsHandle方法就會被調用,並且按照事先定義好的錯誤處理方法告知用戶錯誤產生的具體原因並詢問用戶如何進行下一步操作。Resume Next語句會跳過錯誤行繼續運行下面的代碼,Resume語句則會嘗試再次運行出錯的代碼,其次則是直接退出過程結束程序。為了方便代碼的調試,我在程序的最開始設置了一個開關,該開關是一個枚舉變量,擁有兩個值Release和Debugger,值為Release時設置錯誤陷阱,值為Debugger時不設置錯誤陷阱,這個時候VBA會自動定位到出錯的代碼行並要求用戶調試代碼(事實上用戶根本就不會調試任何代碼,這個一般都是留給開發人員來用的)。這樣,每次我只需要修改這個枚舉變量的值就可以在調試模式和非調試模式之間切換,而不需要每次都注釋掉很多代碼,畢竟在程序開發過程中調試是非常重要的,我們往往都需要知道程序究竟發生了什麼。

這種錯誤處理的方式我在VBA應用中經常會用到,唯一不方便的就是我們需要在每一個可能出錯的過程或方法中設置錯誤陷阱並調用錯誤處理函數,可能還要做一些額外的操作,例如上面講到的設置調試模式的開關、判斷錯誤處理函數的返回值並進行相應的操作等。

其實,On Error語句除了在VBA中被用來進行錯誤處理外,還有一些特殊的用途,下面是一個例子。

'Check whether the key in the collection of
Public Function KeyExists(col As Collection, Key) As Boolean
On Error Resume Next
Dim x As Variant
x = col.Item(Key)
KeyExists = Not (Err.Number = 5)
On Error GoTo 0
End Function

VBA支持集合類型的對象,如Dim country As New Collection,我們可以往集合對象中添加項或移除項,以及查找特定的項。但是VBA中的集合對象功能很有限,它居然沒有提供判斷集合中的Key(關鍵字)是否存在的方法。對於集合來說,這個方法非常重要,當你往集合中添加項時,如果Key重復,VBA是會拋出異常的,因此我們需要自己編寫一個用來檢測集合中的Key是否存在的方法。借助於On Error和Resume Next語句可以實現這個功能,我們可以反復查找集合中的項,如果要查找的項不存在則會拋出異常,這時利用Resume Next語句繼續執行下一條語句繼續進行查找,直到找到要查找的項。On Error GoTo 0用來關閉錯誤陷阱。

類似於這樣的應用還有很多,我們可以自己控制當程序出錯時如何進行下一步操作,從而更方便的管理我們自己的應用程序。

另外,VBA的編輯器也提供了一些輔助功能幫助我們調試代碼,如常用的在代碼中設置斷點、添加和切換書簽,以及運行時的對象監視等,讀者可以自己去體會。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved