VBA Error Handling

giaiphapvba

Administrator
Thành viên BQT
VBA không thể sử dụng được Try-Catch hay sao?
Ủa nói gì kỳ vậy, tất nhiên làkk hông thể rồi. Nếu là VB.NET thì được.
Nói như vậy chẳng phải là ta không thể điều khiển lỗi bằng VBA hay sao?
Do đó, trong topic này chúng ta sẽ tiêu chuẩn hóa xử lý lỗi đối với VBA.
Mã:
' Thu tuc chinh o tren
Sub Main()
    ErrorMethod

    MsgBox "Ket thuc"
End Sub

' Xu ly loi o duoi
Sub ErrorMethod()
    Err.Raise 513, "Co loi gi do da xay ra"
End Sub
Các bạn hãy thử chạy code trên.
(Còn nữa)
Nguồn tham khảo và dịch:
 
  • Love
Reactions: CRV

giaiphapvba

Administrator
Thành viên BQT
Khi bạn chạy code ở trên bạn sẽ thấy rằng có lỗi xảy ra.
Bạn cần đăng nhập để thấy đính kèm

Cụ thẻ, Err.Raise khi được thực thi, nó là một phương thức cưỡng chế tạo ra lỗi. Trong trường hợp ví dụ ở trên, phương thức ErrorMethod sẽ bị dừng giữa chừng.
Phần đầu Module, thủ tục Main chưa được kiểm soát lỗi (Error Handling). Vì có lỗi xảy ra nên hàm Msgbox đã không hoạt động được, khiến cho thủ tục Main bị dừng giữa chừng. Đây là một lỗi phổ biến.

Để kiểm soát lỗi, chúng ta sẽ dùng các câu lệnh dưới đây:

1. On Error Goto LabelName
2. On Error Resume Next

Điểm khác nhau ở hai lệnh trên đó là:
1. On Error Goto LabelName: Xử lý ở phần nhãn được chỉ định (LabelName) sẽ được gọi.
2. On Error Resume Next: Phớt lờ lỗi xảy ra, chạy tới dòng code tiếp theo.
Chúng ta sẽ sửa lại thủ tục Main trong ví dụ ở trên, cụ thể là:
Mã:
' Thu tuc chinh o tren
Sub Main()
    On Error GoTo OnError

    ErrorMethod

    MsgBox "Ket thuc"
    Exit Sub
OnError:
    MsgBox "Mot loi gi do da xay ra"
End Sub

' Xu ly loi o duoi
Sub ErrorMethod()
    Err.Raise 513, "Co loi gi do da xay ra"
End Sub
Tại thời điểm ErrorMethod được gọi, nó sẽ phát sinh lỗi, và do đó xử lý ở phần nhãn OnError sẽ được gọi.
Chúng ta cũng có thể sử dụng On Error Resume Next như sau:
Mã:
' Thu tuc chinh o tren
Sub Main()
    On Error Resume Next

    ErrorMethod

    If Err.Number = 0 Then
        MsgBox "Ket thuc"
    Else
        MsgBox "Mot loi da xay ra"
    End If
End Sub

' Xu ly loi o duoi
Sub ErrorMethod()
    Err.Raise 513, "Co loi gi do da xay ra"
End Sub
Tại thời điểm xảy ra lỗi, nếu bạn thêm các xử lý tiếp theo như hình dưới đây, có khả năng sẽ phát sinh thêm những lỗi mà chúng ta không thể kiểm soát:
Mã:
' Thu tuc chinh o tren
Sub Main2()
    On Error Resume Next

    ErrorMethod

    ' Dua them cac xu ly khac vao day
    OtherMethod

    If Err.Number = 0 Then
        MsgBox "Ket thuc"
    Else
        MsgBox "Mot loi da xay ra"
    End If
End Sub

' Xu ly loi o duoi
Sub ErrorMethod()
    Err.Raise 513, "Co loi gi do da xay ra"
End Sub
On Error Resume Next sẽ phớt lờ lỗi, nó khiến chúng ta khó kiểm soát hết các tình huống không mong muốn, có đúng là trong trường hợp có lỗi như thế này thì được phép phớt lờ hay không. Do đó, tôi nghĩ bạn nên dùng On Error Goto, cách làm này cho chúng ta sự an toàn.
(Còn nữa)
 

giaiphapvba

Administrator
Thành viên BQT
Trong phần trên, chúng ta đã thực hiện điều khiển lỗi ở đầu chương trình.
Ở phần này, chúng ta sẽ truyền thông tin lỗi tới cuối chương trình.
Mã:
Sub ErrorMethod()
    Err.Raise 513, "mot cai gi do da xay ra"
End Sub
Khi ghi thông tin ra file, nếu như có lỗi xảy ra thì file sẽ không được đóng (close), như vậy nó vẫn ở trong trạng thái mở (open).
Trong kịch bản này, chúng ta cần có điều khiển lỗi, khi có lỗi xảy ra sẽ tiến hành đóng file.
Mã:
Sub ErrorMethodWithIO()
    On Error GoTo Dispose

    Open "path\to\file" For Input As #1

    Err.Raise 513, "Khi doc file, co dieu gi do da xay ra"
Dispose:
    ' Loi xay ra nen can dong file
    Close #1
End Sub
Với xử lý này, chúng ta sẽ không cần lo lắng về việc close file. Vậy điều gì sẽ xảy ra nếu ta gọi thủ tục trên ở ngay đầu chương trình?
Mã:
Sub Main()
    On Error GoTo OnError

    ErrorMethodWithIO

    MsgBox "Ket thuc chuong trinh"
    Exit Sub
OnError:
    MsgBox "Co gi do da xay ra" & vbCrLf & Err.Number
End Sub
Với cách viết code nhu thế này, chúng ta sẽ nhận được thông báo "Ket thuc chuong trinh", và lỗi sẽ được truyền xuống dưới. Tuy nhiên chúng ta sẽ không biết khi có lỗi thì lỗi đó là gì, do đó chúng ta cần phải sửa code một chút.
Mã:
Sub ErrorMethodWithIO()
    On Error GoTo Dispose

    Open "path\to\file" For Input As #1

    Err.Raise 513, "Co gi do da xay ra"
Dispose:
    Close #1

    ' Dieu khien loi
    If Err.Number <> 0 Then
        Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    End If
End Sub
Tôi có một chú ý cho các bạn, hãy xem code dưới đây:
Mã:
Sub ErrorMethodWithIO()
    On Error GoTo Dispose

    ' Chu y!!!!!!!!!!
    Err.Raise 514, "Loi xay ra truoc khi doc file"

    Open "path\to\file" For Input As #1

    Err.Raise 513, "Co gi do da xay ra"

Dispose:
    Close #1

    ' Dieu khien loi
    If Err.Number <> 0 Then
        Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    End If
End Sub
Trong chương trình trên, tôi đã cố ý tạo ra lỗi trước khi đọc file.
Khi có lỗi xảy ra, chương trình nhảy tới nhãn Dispose , và lệnh Close được thực thi. Tuy nhiên thì lúc này file thậm chí còn chưa được mở ra (open).
Như vậy, lỗi ban đầu (514) thì đã được điều khiển, nhưng sau đó lại phát sinh một lỗi khác (file không mở nhưng cũng thực hiện đóng!).
Do đó, ở đây ta cần xử lý công phu một chút.
Mã:
Sub ErrorMethodWithIO()
    Err.Raise 514, "Loi xay ra truoc khi doc file"

    ' Truoc khi doc file neu co loi thi chuyen toi nhan Dispose
    On Error GoTo Dispose

    Open "path\to\file" For Input As #1

    Err.Raise 513, "Loi gi do xay ra"
Dispose:
    Close #1

    ' Dieu khien loi
    If Err.Number <> 0 Then
        Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    End If
End Sub
 
Top