Lucrul cu erorile din timpul execuției - Runtime Errors

În ciuda ajutorului oferit de VBA pentru verificarea erorilor de limbaj și de compilare, erorile de rulare rămân un fapt neplăcut. Mai devreme sau mai târziu, e posibil să aveți erori de rulare în cod. Cea mai bună tactică pentru a face față acestora este să adăugați instrucțiuni de eroare - bucăți de cod care să surprindă erorile care apar în timpul executării, să le analizeze și să ia măsuri pentru a rezolva problema.

Un instrument de gestionare a erorilor este o măsură preventivă, care permite codului să gestioneze elegant problemele, în loc să se blocheze cu un mesaj de eroare.

Când se scrie cod de manipulare a unei erori - Error Handler?

Luați în considerare scrierea de cod pentru gestionarea erorilor în următoarele circumstanțe:

  • Când o eroare de execuție poate determina codul să eșueze dezastruos. Pentru o procedură care aranjează câteva obiecte pe un diapozitiv în PowerPoint, este puțin probabil să aveți nevoie de un instrument de gestionare a erorilor. În schimb, pentru o procedură care creează, șterge sau mută fișiere, veți dori probabil un instrument de gestionare a erorilor.
  • După ce ați făcut tot posibilul pentru a asigura cea mai bună codificare și gestionare a erorilor, ar trebui să încercați, de asemenea, să anticipați o acțiune neașteptată a utilizatorului. Și gestionați erorile utilizatorilor. Utilizatorii pot face unele lucruri foarte neobișnuite atunci când rulează macrocomenzi.
  • Atunci când programul accesează periferice sau obiecte din afara aplicației în sine - starea lor este imprevizibilă în timpul proiectării. În această situație, puteți identifica anumite erori care pot să apară și care pot fi detectate. De exemplu, când utilizatorul încearcă să deschidă un fișier, pot apărea anumite erori cunoscute - poate că fișierul nu există sau este folosit în mod curent de un alt computer sau se află pe o unitate de rețea, unitatea de dischetă, unitatea CD -ROM sau o unitate detașabilă care nu este disponibilă la momentul respectiv. De asemenea, puteți avea erori dacă utilizatorul încearcă să utilizeze o imprimantă sau un alt dispozitiv la distanță (de exemplu, un scaner sau o cameră digitală) care nu este conectat în prezent, este oprit sau nu este configurat corect. În mod similar, orice procedură care tratează un anumit obiect dintr-un document (de exemplu, un grafic în Excel) va avea probleme dacă acel obiect nu este disponibil.

Luați în considerare detectarea erorilor în locul anticipării lor

În unele cazuri, este mai simplu să surprindeți o eroare rezultată dintr-o procedură decât să anticipați și să încercați să eliminați multe și diferite condiții care ar putea duce la generarea erorii. De exemplu, în loc să verificați dacă există un fișier înainte de a încerca să deschideți sau să manipulați fișierul, nu trebuie decât să capturați orice fel de eroare care apare dacă fișierul nu este detectat.

Detectarea unei erori

Detectarea (Trapping) unei erori înseamnă capturarea ei în cod în timpul rulării, astfel încât să puteți scrie programare care gestionează eroarea. Instrucțiunea On Error din VBA se declanșează atunci când există o eroare de rulare și permite scrierea de cod care răspunde la eroare.

De obicei, se împiedică ca o eroare să oprească codul VBA, dar se pot anticipa și anumite erori și pot fi folosite pentru a determina un curs de acțiune adecvat de urmat din punctul în care apar.

Pentru a surprinde o eroare, utilizați instrucțiunea On Error. Sintaxa obișnuită pentru On Error este următoarea:

On Error GoTo line

Aici, line este o etichetă care specifică linia la care va fi trimisă execuția atunci când apare o eroare de execuție. De exemplu, pentru a o trimite la linia cu eticheta ErrorHandler, puteți folosi o structură ca aceasta:

Sub ErrorDemo()
  On Error GoTo ErrorHandler
   'aici, comenzi obisnuite in cod
Exit Sub
ErrorHandler:
  'aici, comenzile de manipulare a erorii
End Sub

Eticheta pe care o utilizați pentru a identifica instrumentul de gestionare a erorilor poate avea orice nume de etichetă valid - nu trebuie neapărat să fie numită ErrorHandler sau ceva similar. Unii oameni consideră că o etichetă descriptivă (poate una care identifică tipul sau tipurile de eroare așteptate, cum ar fi EroareNiciunFisierDeschis) este mai clară pe termen lung decât un nume generic; alții preferă să meargă cu un nume generic, cum ar fi HandleErr.

De obicei, veți dori să plasați mai rapid prinderea erorilor, mai aproape de partea de început a unei proceduri, astfel încât să fie activă și gata să acopere erorile pentru toate liniile de cod de sub ea pe toată durata procedurii. Dacă este necesar, într-o procedură puteți plasa mai multe detectări de eroare diferite, introducând mai multe instrucțiuni On Error acolo unde sunt necesare, dar numai una poate fi activată la un moment dat. (Activat înseamnă că o detectare de eroare a fost pornită printr-o instrucțiune On Error. Când apare o eroare și execuția se ramifică la codul pentru detectare de erori, acel cod este cel activ.)

Inserarea mai multor instrumente de gestionare a erorilor într-o procedură poate fi utilă atunci când aveți de-a face cu declarații care pot provoca diferite tipuri de erori care ar trebui să fie blocate. În exemplul următor, prima instrucțiune On Error direcționează execuția către ErrorHandler1, iar a doua instrucțiunea On Error direcționează execuția către ErrorHandler2:

Sub ErrorDemo2()

On Error GoTo ErrorHandler1 
  'aici, comenzi 
On Error GoTo ErrorHandler2 
  'aici, comenzi
Exit 
Sub ErrorHandlerl:
  'comenzi pentru primul detector de erori
Sub ErrorHandler2:
  'comenzi pentru al doilea detector de erori
End Sub

Fiecare instrument de gestionarea erorilor este limitat la procedura în care apare, astfel încât să puteți crea diferite instrumente de gestionare a erorilor pentru diferite proceduri și să le activați pe rând pe măsură ce rulează procedurile.

Deoarece instrumentul de gestionare a erorilor apare ca și cod în procedură, trebuie să vă asigurați că acesta nu rulează atunci când nu a apărut nicio eroare. Puteți face acest lucru folosind o instrucțiune Exit Sub din linia chiar deasupra instrucțiunii de gestionare a erorilor (aceasta încheie executarea procedurii) sau o instrucțiune GoTo care direcționează execuția către o etichetă dincolo de codul de gestionare a erorilor. Instrucțiunea Exit Sub este mai bună dacă alegeți să plasați detectorul de erori la sfârșitul procedurii sale, care este o practică standard și de obicei are sens. Declarația GoTo se poate dovedi mai ușor de utilizat dacă alegeți să plasați detectorul de erori în altă parte a procedurii.

Pentru o funcție, utilizați o instrucțiune Exit Function în locul instrucțiunii Exit Sub. Pentru o proprietate dintr-un modul de clasă, utilizați o declarație Exit Property.

Următorul exemplu folosește o instrucțiune Exit Sub pentru a determina ca executarea să se încheie înainte de gestionarea erorilor, dacă nu apare nicio eroare:

Sub ErrorDemo3()
On Error GoTo ErrorHandler 
  'comenzi care ar putea fi cauza unei erori 
Exit Sub 
ErrorHandler:
  'comenzi care manipulează eroarea
End Sub

Următorul exemplu utilizează o instrucțiune GoTo pentru a omite instrumentul de gestionare al erorilor - care este plasat în codul procedurii - dacă nu apare o eroare. Atunci când execuția ajunge la comanda GoTo SkipErrorHandler, aceasta se ramifică pe eticheta SkipErrorHandler, ocolind astfel codul în gestionarea erorilor:

Sub ErrorDemo4()
On Error GoTo ErrorHandler 
  'comenzi care ar putea cauza o eroare
GoTo SkipErrorHandler 
ErrorHandler:
'comenzi care manipuleaza eroarea
SkipErrorHandler:
'alte comenzi
End Sub

Unii programatori nu folosesc declarațiile GoTo pentru cazuri ca în cel de-al doilea exemplu. Având în vedere că această declarație GoTo face ca procedura să fie mai greu de urmărit, este posibil să fiți de acord cu acest lucru. (Utilizarea GoTo în declarația On Error este însă inevitabilă.)

Dezactivarea urmăririi unei erori

Reamintim că un detector de eroare funcționează numai pentru procedura în care apare, iar VBA o dezactivează atunci când execuția codului din procedură s-a încheiat. De asemenea, dacă doriți, puteți dezactiva un detector de eroare înainte de sfârșitul procedurii în care apare folosind următoarea instrucțiune:

On Error GoTo 0

De ce ați face asta? Puteți dezactiva un detector de erori în timp ce testați o procedură pentru a vă permite să identificați erorile care apar după un anumit punct, păstrând în același timp detectorul de erori pentru prima parte a procedurii.

Reluarea execuției după eroare

Puteți folosi instrucțiunea Resume pentru a relua executarea unei proceduri după detectarea erorii sau manipularea ei folosind cod de manipulare eroare. Comanda Resume are trei forme: Resume, Resume Next și Resume nr_linie.

Folosirea comenzii Resume

Instrucțiunea Resume face ca execuția să fie reluată de la aceeași linie care a provocat eroarea. Utilizați Resume cu o rutină de gestionare a erorilor care detectează și rezolvă problema care a determinat eșecul declarației. De exemplu, consultați gestionarea erorilor din codul de mai jos, care se execută atunci când VBA nu poate aplica un stil specificat în Word.

Detectarea unei erori pentru stil

1. Sub StyleError()
2.
3.  On Error GoTo Handler
4. 
5.  Selection.Style = "Rezumat_lucrare"
6.
7.   'aici se scrie restul procedurii
8.
9.   'iesire din procedura odata ce executarea ajunge aici
10. Exit Sub
11.
12. Handler:
13.
14.  If Err = 5834 Then
15.   ActiveDocument.Styles.Add _
        Name:="Rezumat_lucrare", Type:=wdStyleTypeParagraph
16.   Resume
17.  End If
18.
19. End Sub

Iată cum funcționează procedura StyleError de mai sus:

  • Linia 1 începe procedura, iar linia 19 o încheie. Liniile 2, 4, 6, 8, 11, 13 și 18 sunt goale.
  • Linia 3 folosește comanda On Error pentru a elimina o posibilă eroare, care este rezolvată cu eticheta Handler de pe linia 12.
  • Linia 5 aplică stilul numit Rezumat_lucrare la selecția curentă. Dacă operația se încheie cu succes, execuția va continua pe linia 7, care, în acest caz, conține doar un comentariu.
  • Linia 9 este un comentariu, iar pe linia 10 se află comanda Exit Sub pentru a încheia executarea procedurii înainte de manipularea erorii.
  • Dacă comanda Selection.Style de pe linia 5 duce la o eroare, execuția codului este trimisă la eticheta Handler de pe linia 12, iar captatorul de eroare este activat. Linia 14 compară valoarea erorii cu numărul 5834, număr de eroare care apare atunci când stilul specificat nu există. Dacă ele sunt egale, linia 15 adaugă stilul lipsă la document, iar comanda Resume de pe linia 16 reia execuția codului de la linia la care a apărut eroarea, linia 5. Pentru că acum stilul este valabil, comanda Selection.Style rulează fără erori.

Cum se găsesc numerele pentru erori VBA și explicațiile lor

Pentru a găsi numerele pentru erori, iată trei abordări:

  • Accesați pagina Web:

http://msdn2.microsoft.com/en-us/library/Aa264975(VS.60).aspx

  • Căutați în sistemul VBA Help după cuvintele trappable errors.
  • Provocați în mod deliberat eroarea și notați numărul și descrierea ei din caseta de dialog cu mesajul de eroare afișat de VBA.

Folosirea comenzii Resume Next

Resume Next determină reluarea execuției cu următoarea declarație de după declarația care a provocat eroarea. Puteți utiliza Resume Next în oricare dintre următoarele circumstanțe:

  • Cu o rutină de gestionare a erorilor care ignoră eroarea și permite să continue executarea fără a executa declarația erorii
  • Ca o simplă instrucțiune On Error Resume Next care face ca execuția să continue la următoarea declarație după instrucțiunea care a provocat o eroare, fără a utiliza un manipulator de erori pentru a remedia eroarea

Ca exemplu al primei circumstanțe, dacă stilul specificat în exemplul precedent nu este disponibil, puteți utiliza o instrucțiune Resume Next pentru a sări aplicarea stilului:

Sub StyleError2()
  On Error GoTo Handler
  Selection.Style = " Rezumat lucrare "
   'aici se scrie restul procedurii
   'iesire din procedura daca executia a ajuns pana aici
Exit Sub
 
Handler:
  Resume Next
End Sub

Descrierile Resume și Resume Next se aplică dacă eroarea a apărut în procedura care conține gestionarea erorilor. Dar dacă eroarea s-a produs într-o procedură diferită de procedura care conține gestionarea erorilor, Resume determină reluarea execuției cu ultima instrucțiune care a transferat execuția (apelată) din procedura în care se află handler; Resume Next determină reluarea execuției cu instrucțiunea de după ultima declarație care a apelat procedura care conține gestionarea erorilor.

Folosirea unei comenzi Resume Line

Resume line face ca execuția să fie reluată de la linia specificată. Se folosește o etichetă pentru a indica linia, care trebuie să se afle în aceeași procedură cu manipulatorul de eroare.

De exemplu, dacă o procedură a încercat să deschidă un anumit fișier, puteți crea un instrument de gestionare a erorilor simplu care utilizează o instrucțiune linie Resume line, ca în codul următor. Această procedură funcționează în Word. Pentru ca acesta să funcționeze cu alte aplicații, înlocuiți numerele de eroare corespunzătoare de pe linia 15.

Reluarea execuției de la o linie specificată

1. Sub Handle_Error_Opening_File()
2.
3.   Dim strFName As String
4.
5.   StartHere:
6.
7.    On Error GoTo ErrorHandler
8.    strFName = InputBox("Introduceti numele fisierului care va fi deschis.", _
          "Deschidere fisier")
9.    If strFName = "" Then End
10.     Documents.Open strFName
11.   Exit Sub
12.
13.  ErrorHandler:
14.
15.  If Err = 5174 Or Err = 5273 Then MsgBox _
     "Fisierul " & strFName & " nu exista." & vbCr & "Va rog introduceti numele din nou.", _ 
        vbOKOnly + vbCritical, "Eroare fisier"
16.  Resume StartHere
17.
18. End Sub

Iată cum funcționează codul:

  • Linia 1 începe procedura, iar linia 18 o încheie.
  • Linia 2 este goală (spacer). Linia 3 declară variabila strFName de tip String. Linia 4 este goală.
  • Linia 5 conține eticheta StartHere, de la care va fi reluată executarea programului după comanda Resume de pe linia 16. Linia 6 este goală.
  • Linia 7 folosește comanda On Error pentru a activa manipularea erorii ErrorHandler.
  • Linia 8 afișează caseta în care utilizatorul trebuie să introducă numele fișierului care a fi deschis și stochează numele în variabila strFName, iar linia 9 încearcă deschiderea fișierului. Linia 10 verifică dacă variabila strFName este goală (empty string) și, în acest caz, încheie executarea programului.
  • Dacă fișierul există și poate fi deschis, execuția trece pe linia 11, pe care se află comanda Exit Sub care încheie procedura. Altfel, este generată o eroare, iar execuția este trimisă la eticheta ErrorHandler de pe linia 13, pe care manipularea erorii devine activă.
  • Linia 14 este goală. Linia 15 compară valoarea erorii cu numărul 5174 (eroarea care apare dacă VBA nu poate găsi fișierul) și cu 5273 (eroarea care apare dacă numele documentului sau calea nu sunt valabile în Word). Dacă una dintre numere se potrivesc, linia 15 afișează o casetă mesaj în care anunță eroarea și cere introducerea corectă a numelui.
  • Comanda Resume de pe linia 16 reia execuția de la eticheta StartHere de pe linia 5.
  • Linia 17 este goală.

Încercați inserarea unei variabile contor pentru a opri utilizatorii să repete aceeași eroare

Pentru unele proceduri, puteți construi un mecanism de contorizare pentru a împiedica utilizatorii să repete aceeași eroare la nesfârșit, deoarece nu înțeleg ce este greșit. Prin creșterea unei variabile de contor de fiecare dată când este invocat instrumentul de gestionare a erorilor și verificarea numărului rezultat, puteți alege să efectuați o acțiune diferită după o serie de încercări nereușite de a executa o anumită acțiune.

Nu puteți utiliza o instrucțiune Resume în altă parte decât într-o rutină de gestionare a erorilor (sau o instrucțiune On Error Resume Next). Dacă faceți acest lucru, VBA raportează o eroare.

Obținerea descrierii unei erori

Pentru a vedea descrierea unei erori curente, întoarceți proprietatea Description pentru obiectul Err:

MsgBox Err.Description

În general, mesajele de eroare ale sistemului de operare și ale limbajului de programare au tendința de a fi mai scurte, criptice și de mai puțin ajutor utilizatorului final decât persoanelor care au construit sistemul de operare sau limbajul. Gândiți-vă de două ori înainte de a afișa unul dintre aceste mesaje de eroare unui utilizator final. Mesajul de eroare ar putea spune "Eroare în timpul executării" 5941 ": Membru solicitat al colecției nu există." ("Run-time error '5941': The requested member of the collection does not exist.")

După cum vă puteți imagina, majoritatea utilizatorilor ar fi învinuiți datorită acestui mesaj; unii ar intra în panică.

De obicei, este mai eficient să scrieți și să afișați un mesaj de eroare mai detaliat. Ar trebui să explicați care este problema și, de preferință, dacă se poate, ce poate face utilizatorul pentru a o rezolva.

Declanșarea propriilor erori

Ca parte a testării, puteți simula în mod deliberat erorile, astfel încât să puteți vedea cât de bine le rezolvă gestionarul de erori.

Pentru a determina declanșarea unei erori, utilizați metoda Raise a obiectului Err, specificând doar argumentul număr. Numărul este un argument de tip Long care reprezintă numărul erorii pe care doriți să o provocați. De exemplu, următoarea afirmație "declanșează" eroarea 5121:

Err.Raise 5121