W internecie możemy bez problemu znaleźć opracowania, które opisują działanie poszczególnych instrukcji obsługujących błędy w VBA. W tym tekście chciałbym dokonać pewnej syntezy, ale też pokazać, kiedy należy (a kiedy nie powinno się) używać tych poleceń.
On Error Resume Next
Polecenie, które nakazuje ignorować wszystkie błędy i wykonywać dalsze linie kodu.
Jest to instrukcja, która jest bardzo mocno nadużywana przez osoby, które dopiero zaczynają swoją przygodę z programowaniem w VBA.
W praktyce spotykam się z wieloma przypadkami, w których makro rozpoczyna się od linii On Error Resume Next. Celem takiego podejścia jest wykonanie makra za wszelką cenę do końca (od A do Z), czyli wyeliminowanie problemu wyskakujących okienek, które sygnalizują błędy i przerywają jego działanie. Oczywiście taka programistyczna partyzantka jest wysoce naganna, ponieważ nie daje nam informacji czy jakikolwiek błąd w ogóle się pojawił. W efekcie może się okazać, że np. nie zaczytaliśmy danych z pliku zewnętrznego (bo został on przypadkiem usunięty) lub zaczytaliśmy je źle (bo zmienił się układ kolumn).
Użytkownik jest zadowolony, że makro się wykonało, ale nie wie czy wykonało się prawidłowo. Jest to podejście nie do zaakceptowania ponieważ może wprowadzać innych w błąd!
Rodzi się pytanie. Gdzie i kiedy zatem stosować instrukcję On Error Resume Next? Odpowiedź jest dość prosta. Można włączyć ją na chwilę (na jedną lub kilka linii kodu), głównie po to, aby skrócić nieco działanie makra np.
a) chcemy skasować konkretny arkusz w pliku, więc zamiast sprawdzać czy taki arkusz w ogóle istnieje, można od razu spróbować go usunąć (jeśli arkusza nie ma w pliku, to nic się nie stanie).
On Error Resume Next
Application.DisplayAlerts = False
wksArkusz.Delete
Application.DisplayAlerts = True
On Error GoTo ObslugaBledu
b) chcemy dodać unikatowy element do kolekcji, ale nie wiemy czy go już tam nie ma
On Error Resume Next
colKodyProduktow.Add Item:=sNazwaProduktu, Key:=sKodProduktu
On Error GoTo ObslugaBledu
c) chcemy sprawdzić, w którym wierszu znajduje się szukany wpis
On Error Resume Next
lPozycjaReferencji = 0
lPozycjaReferencji = WorksheetFunction.Match( _
sReferencja, wksCeny.Range("A:A"), 0)
On Error GoTo ObslugaBledu
d) chcemy celowo sprawdzić czy wystąpił błąd, aby wykonać dalsze instrukcje
On Error Resume Next
Set wkbBudzet = Workbooks("Budżet_Roczny.xlsx")
If Err <> 0 Then
If Err.Number = 9 Then
Set wkbBudzet = Workbooks.Open( _
Filename:="D:\Excel\Prowadzenie firmy\Budżet_Roczny.xlsx", _
ReadOnly:=False, UpdateLinks:=False)
End If
Err.Clear
End If
On Error GoTo ObslugaBledu
On Error GoTo Etykieta
Powyższa instrukcja jest stosowana zazwyczaj na samym początku makra i bardzo często ponawiana po poleceniu On Error Resume Next.
Informuje ona, że w przypadku wystąpienia błędu, procedura powinna przejść do etykiety, która znajduje się zazwyczaj na końcu makra i pełni dwie funkcje:
- wyświetla informację na temat błędu – dobrze aby ta informacja była jak najbardziej pełna i zawierała:
– numer i opis błędu,
– nazwę modułu i procedury (bardzo ważne jest również aby ustalić linię kodu – znacznie łatwiej jest wtedy taki błąd namierzyć i wdrożyć działania naprawcze) - przechodzi do innej etykiety, która „sprząta” (przywraca ustawienia domyślne, zeruje zmienne obiektowe itp.) i kończy działanie makra.
Rodzi się pytanie. Czy każde makro powinno zawierać taką obsługę błędów z przejściem do etykiety? Wg mnie nie każde, ale zdecydowana większość. Wyjątkiem mogą być bardzo proste makra, co do których jesteśmy pewni, że nigdy nie wygenerują błędu (np. zmiana ustawień właściwości dla obiektu Application).
Poniżej wklejam fragment makra, które stara się przypisać zmienną wkbBudzet do otwartego pliku Budżet_Roczny.xlsx. Takiego pliku nie mam nawet na dysku, zatem makro wygeneruje błąd w linii nr 2 i przejdzie do etykiety nazwanej ObslugaBledu. Najpierw wyświetli odpowiedni komunikat, a potem przejdzie do drugiej etykiety nazwanej Wyjscie.
Public Sub PobierzDaneZBudzetuRocznego()
Dim wkbBudzet As Workbook
Const sPROC As String = "PobierzDaneZBudzetuRocznego"
'Aktywuj obsługę błędów na starcie
1 On Error GoTo ObslugaBledu
'Przypisz zmienną obiektową do pliku z budżetem
2 Set wkbBudzet = Workbooks("Budżet_Roczny.xlsx")
Wyjscie:
3 Set wkbBudzet = Nothing
4 On Error GoTo 0
5 Exit Sub
ObslugaBledu:
6 Application.ScreenUpdating = True
7 If gbDEBUG_TRYB Then Stop
8 MsgBox "Wystąpił błąd nr " & Err.Number & " (" & Err.Description & ")." & _
vbCr & vbCr & "Linia kodu nr " & Erl & " w procedurze " & _
"'" & sPROC & "' modułu '" & msMODUL & "'.", vbInformation, "BŁĄD!"
9 Resume Wyjscie
End Sub
On Error GoTo 0
To polecenie przywraca domyślny dla VBA sposób traktowania błędów, czyli możemy powiedzieć, że wyłącza obsługę błędów użytkownika.
Podobnie jak polecenie On Error GoTo Etykieta często występuje w parze z On Error Resume Next. Osobiście jednak używam tej instrukcji bardzo rzadko, ponieważ wolę mieć kontrolę nad tym, w jaki sposób obsługiwane są błędy.
Innym atrybutem On Error GoTo 0 jest zerowanie obiektu Err, który przechowuje informację na temat ostatniego błędu.