Generell felhantering i
Visual Basic for Application

En färdig och väl fungerande programvara innehåller även rutiner för felhantering så att även oväntade situationer hanteras och inte vållar användarna problem i något avseende. Oavsett vad vi tycker att bygga in felhanteringsrutiner i program så är felhantering absolut nödvändig för en professionell programvara.

Artikeln beskriver på en grundläggande nivå hur vi kan hantera s k Run-Time errors som uppstår. Det finns tre typer av fel som kan förekomma:

  • Compiler Time errors - Uppstår vid själva kodskrivandet och vid testkörning av kod, där fel syntax, felaktigt anrop till funktioner och egenskaper ger upphov till felmeddelanden. Denna typ av fel är den enklaste att lösa.
  • Logic errors - Logiska fel i kod (buggar) är för det mesta de fel som orsakar mest huvudbry och som är mest svårupptäckta då koden till sitt yttre fungerar men ger felaktigt svar ändå.
  • Run-Time errors - Fel som uppstår när programmet körs. Kodens syntax är korrekt men stoppas till följd av att de yttre omständigheterna inte är de förväntade, såsom anrop av en fil som inte finns.

Identifiera Run-Time errors
Att identifiera dessa fel är i sig inte särskilt svårt. VBA sköter om det automatiskt genom att stoppa koden och visa felmeddelanden.

Att betatesta är dock alltid att rekommendera och det ska helst ske av en eller flera personer som inte har varit med i utvecklingen av programmet (än mindre av någon/några närstående).

Fånga upp Run-Time errors

Är det viktigaste momentet, dvs fel uppstår vid körning och programmet måste på ett eller annat sätt fånga upp felen genom felhantering.

Felhantering kan endast ske på procedurnivå och det är inte möjligt att skapa en generell felhanteringsrutin som aktiveras oavsett fel och i vilken procedur de uppstår.

Felhantering per definition går ut på att viss del av koden initialt är passiv. När ett eller flera fel uppstår så aktiveras koden och felen åtgärdas.

I VBA finns händelsen "On Error" att tillgå, vilken kan användas på följande tre sätt:

  • On Error GoTo Label
  • On Error Resume Next
  • On Error Goto 0

On Error Goto Label
Troligtvis den starkaste felhanteringshändelsen av de alla  då den ger flexibilitet och kontroll i hanterandet av fel. VBA tvingas att gå till en specifik del av koden när fel uppstår:

 On Error GoTo Felhantering

 Kill stFilnamn

 ExitHere:
 Exit Sub

Felhantering:
 MsgBox "Filen kan inte hittas!", vbInformation
 Resume ExitHere
End Sub

Det som är viktigt att komma ihåg är att ange Exit Sub före felhanteringsrutinen annars aktiveras den varje gång proceduren körs och att felhanteringsrutinen placeras sist i proceduren.

Generellt gäller att det endast ska finnas en "exit" i en sub-procedur eller funktion. I exemplet övergår kontrollen till huvudkoden genom "Resume ExitHere" efter det att felhanteringsrutinen har körts.

On Error Resume Next
Nackdelen med  "On Error GoTo Label" är att den kan kräva mycket kod för även mindre åtgärder. Vissa fel kan vara av den typ att det inte krävs någon åtgärd från eller information till användaren. Här kan då "On Error Resume Next" komma till pass.

Den instruerar VBA att hoppa över (ignorera) den felande delen av koden och exekvera nästa rad utan någon åtgärd:  

 On Error Resume Next

 Kill stFilnamn

On Error Goto 0
Varje gång någon av de två ovanstående händelserna exekveras så är dessa aktiva till dess att en annan felhanteringsrutin initieras eller den aktuella rutinen stoppas.

För att avsluta egna felhanteringsrutinerna och återställa de inbyggda felhanteringsrutinerna används denna händelse:

On Error Resume Next

 Kill stFilnamn

 On Error GoTo 0

Resume
Fyller en viktig funktion i det att den instruerar VBA att återgå till te x raden där felet uppstod eller någon annan plats i koden alternativt fortsätta exekveringen.

Den kan användas på följande tre sätt:

  • Resume - kontrollen av proceduren återgår till den rad som gav upphov till felet.
  • Resume Next - kontrollen av proceduren fortsätter till nästa rad och felet ignoreras.
  • Resume Label - Samma funktion som GoTo.

Vilket fel har uppstått?
Genom att använda oss av ett flertal egenskaper för objektet "Err"  kan vi erhålla viktig information om felen som uppstår:

  • Err.Description  - en beskrivning av felet fås.
  • Err.Number - det unika felnumret för felet erhålls.
  • Err.Source - källan (Application eller objekt) som orsakar felet fås.

Genom att identifiera vilken typ av fel som uppstår kan vi i felhanteringen också styra händelseförloppet.

Följande kod visar tre möjliga scenarios:

Felhantering:
  Select Case Err.Number
    Case 70
            kod...
    Case 71
            kod...
    Case Else
            kod...
  End Select
  Resume ExitHere:

If Err.Number <> 0 Then...
   ...kod
   Err.Clear

If Err.Number = 71 Then...
   ...kod
   Err.Clear

För en fullständig förteckning över felnummer se direkthjälpen.

Skapa egna "felobjekt"
Istället för att förlita oss på de fel som VBA genererar kan vi skapa egna "felobjekt", vilka vi kan ha nytta av när vi t ex skapar egna funktioner.

Egenskapen "Raise" tar tre argument:

  • Ett unikt felnummer visavi VBA egna serie av inbyggda felnummer..
  • En källa (textsträng) - Procedurnamn, Application eller annat objekt.
  • Ett (fel)meddelande (textsträng).
If lnAntal < 0 Or lnAntal > 100 Then
     Err.Raise 12345, "ProcedurNamn", _
         "Argumentet måste vara mellan 1 och 100."
End If

Alternativt kan vi för egenskapade funktioner använda oss av CVErr-funktionen. Den ger oss bl a möjlighet att generera samma felmeddelanden som de inbyggda funktioner kan visa:

Konstant Felnummer

Cellfelmeddelande

xlErrDiv0 2007 #Division/0!
xlErrNA 2042 #Saknas!
xlErrName 2029 #Namn?
xlErrNull 2000 #Skärning!
xlErrNum 2036 #Ogiltigt!
xlErrRef 2023 #Referens!
xlErrValue 2015 #Värdefel!

Funktionen kan användas på följande sätt och därmed styra vilket felmeddelande som ska visas:


If Err.Number <> 0 Then FÖRFATTARE = CVErr(xlErrNA)
 

Alternativ felhantering
Istället för att som ovan använda oss av händelsen "On Error" kan vi hantera fel på andra sätt.

Ett flertal av "IS"-funktionerna är inte explicit funktioner för felhantering utan snarast för validering men kan komma till pass även i detta sammanhang:

Om variabeln inte är numeriskt
If Not IsNumeric(lnTal) Then...

'Om variabeln är tom
If IsEmpty(lnTal) Then...

'Om variabeln saknar data
If IsNull(lnTal) Then...

'Om variabeln är datum
If IsDate(dDatum) Then...

'Om argument saknas
If Not isMissing(A) Then...

'Om argument är fel
If IsError(A) Then..

Använd inte Globala variabler
En felkälla som vi med fördel ska undvika så långt det är möjligt är Globala variabler. Dessa kan bl a innehålla skilda värden i olika moment och därmed vid användning ge upphov till fel. Denna typ av fel är synnerligen svåra att hantera.

Avslutningsvis rekommenderas att, precis som med övrig kod, även hålla felhanteringsrutinerna så enkla som möjligt.