Problemet: Der er opstået en kørselsfejl og fejlen fanges i en On Erro GoTo xx --- Exit sub xx: Call Fejlbehandling end sub --- I Fejlbehandling vises en msg med fejlen, og hvor osv. og mulighed for at sende en e-mail.
Problemet er at koden så kører videre når msg lukkes, jeg tror selv det er fordi fejlen opstår inde i flere på hinanden procedure kald, så det kun er det procedure kald der fejler der afbrydes, men er ikke sikker.
Kan jeg stoppe al videre kodeafvikling når fejl-msg lukkes? Det eneste jeg kan komme på er End men det lukker jo også formen ned.
blackadder: Ja, men det er ikke velegnet til det, det stopper koden hvor Stop er og åbner kodevinduet - ikke rigtig noget bruger kan forholde sig til. Så hellere et End.
kabbak: Det er ikke i Fejlbehandling() kørslen evt. går galt, men fx i 3. niveau af procedure der kaldes af hinanden. Problemet med at håndtere fejl på denne måde (hvis det er et problem ;-) er jo at fejlen så bliver behandlet og derefter kører koden færdig i niveau 2 og til sidst nivaue 1 som bruger har sat i gang måske med klik på en knap.
Jeg talte med en programør der sagde noget om at man i Fejlbehandling skal generere en ny fejl som betyder at koden sendes til Fejlbehandling igen i niveau 2 og igen i niveau 1. På den måde kan man kontrollere at koden kører til ende uden at udføre noget - det bliver nok for langhåret for mig.
Så det jeg har gjort er i Fejlbehandling til sidst at lave forskellige indstillinger og afslutte så godt det er muligt og så et End til sidst så det ikke bare siger "pluf" og det hele ligger på gulvet.
Her er et forslag, nu har jeg ikke lavet det i en Userform, men prinsippet er det samme.
Der er den devideringsfejl i makro2, så kan du teste i en modul i excel.
Option Explicit Dim Fejl As Boolean, Sted As String
Public Sub Kør_makroer() Fejl = False Sted = "Makro1" Call Makro1 If Fejl Then Exit Sub Sted = "Makro2" Call Makro2 If Fejl Then Exit Sub ' sådan kan du gøre imellem de forskellige makrokald 'Sted = "Makro3" 'call Makro3 'If Fejl Then Exit Sub ' o.s.v
Sted = "" End Sub
Public Sub Makro1() Dim A As Integer On Error GoTo xx A = 10 / 0 ' noget kode Exit Sub xx: Call Fejlbehandling End Sub
Public Sub Makro2() On Error GoTo xx ' noget kode Exit Sub xx: Call Fejlbehandling End Sub
Public Sub Fejlbehandling() MsgBox " der skete en fejl i makroen " & Sted & " , programmet stopper" Fejl = True End Sub
Ja, men det er det samme som det jeg siger (så vidt jeg kan se) - der sker en kørselsfejl et eller andet sted, fejlen fejbehandles, og kørslen sendes tilbage til at fortsætte i proceduren efter det kald til procedure der skabte fejlen.
Det er der "problemet" opstår - at kunne stoppe al videre kodeafvikling i fejlbehandling.
(Jeg ved både hvilken procedure der fejler og i hvilken linie det går galt. Det er disse informationer jeg bruger i fejlbehandling.)
I VBA fungerer fejlbehandling således at hvis en undersub ikke har en fejlfanger, ryger fejlen videre op til næste niveau. Hvis man tænker sig at du får en fejl på niveau 3, og du har en fejlfanger her, vil den stoppe kodeafvikling på dette niveau. Det betyder at du skal have fejlfangeren på det niveau du vil stoppe på.
Private Sub CommandButton1_Click() On Error GoTo fiel Call test1 msgbox "Ingen fejl overhovedet" Exit Sub fiel: MsgBox "stop fejl :" & Err.Number End Sub
Her er så to "undersubs"
Sub test1() Call test2 MsgBox "ingen fejl i test1" End Sub
Sub test2() s = 7 / 0 MsgBox "Ingen fejl i test2" End Sub
Hvis du ændrer koden i userformen og fanger alle fejl der, kan du gøre således. Bemærk at fejlkoderne skal du have fundet først :-) Userformen lukker ikke ned
Private Sub CommandButton1_Click() On Error GoTo fiel Call test1 MsgBox "Ingen fejl overhovedet" Exit Sub fiel: Select Case Err.Number Case 7: MsgBox "Ikke mere hukommelse" Case 11: MsgBox "STOP. Division med nul" Case 13: MsgBox "VBA Typefejl" Case Else: End Select End Sub
Bak: Jeg har en 'fejlfanger' i alle procedurer, men fælles for dem alle er at de sender (efter at have indsamlet info vedr. fejlen) videre til min: Private Sub Fejlbehandling()
Det som sker i niveau 3 er at fejlen bliver fanget, sendt ned til labels Niveau3_Error: Her sendes den videre med fejloplysningerne til Fejlbehandling
Når Fejlbehandling er færdig vil koden køre Niveau2 færdig og også køre Niveau1 færdig.
Er det fordi fejlbehandlingen foregår udenfor sub'en at den vender tilbage til de foregående niveauer? Eller på en anden måde. Vil koden stoppe hvis fejlbehandlingen foregår indenfor samme sub? - Det ville jeg dog være ked af da det er uoverskuligt at rette til. Jeg har 500 procedurer
Det sidste er at fejlfangeren for alle subs er samlet i den sub hvor de startes, altså øverste niveau.
Hvis der er fejlfangere på de nedre niveauer ex niv. 3 vil niveau 2 fortsætte sin kode når fejlfangeren på niv 3 er færdig. I min model med kun en central fejlfanger på øverste niv. stopper koden øjeblikkelig og går dertil.
Nu siger du noget der ligner det den flinke mand jeg har omtalt tidligere sagde, men jeg ved ikke på hvilket niveau koden sendes afsted. De forskellige procedurer kan nås fra flere andre procedurer, eller bruger handlinger, og der kan på denne måde opstå flere niveauer afhængig af hvor meget data skal behandles.
Jeg tror ikke jeg tør "fritage" forskellige "underprocedurer" for fejlbehandling - men det er vist heller ikke det du mener ;-)
On Error GoTo 0 Exit Sub UserForm_Initialize_Error: Dim Fejl As String Fejl = "UserForm_Initialize of Form" Call Fejlbehandling(Fejl) End Sub
******************* Private Sub Fejlbehandling(Fejlbesked As String) Dim errSv As String errSv = MsgBox("Ups - der skete en fejl. Procedure er stoppet. " & vbLf _ & vbLf _ & "Tekniske oplysninger:" & vbLf _ & " " & Fejlbesked & vbLf _ & " Line " & Erl & vbLf _ & " Err " & Err.Number & vbLf _ & " Error " & Err.Description & " " & vbLf _ & vbLf _ & vbLf & "Du kan hjælpe med fejlrettelser ved at sende en e-mail til kks@ishoejby.dk med fejlen. " _ & vbLf & vbLf & "Vil du sende fejlbeskeden?", vbCritical + vbYesNo + vbDefaultButton1, "Fejl") If errSv = vbYes Then
KLIP
MsgBox "Fejlen har medført at programmet af sikkerhedsgrunde afbrydes, og vender tilbage til Excel. " & vbLf _ & vbLf _ & "Du skal starte programmet igen for at det kan afsluttes korrekt.", vbExclamation, "Procedurefejl"
KLIP
Her afslutter jeg programmet så godt jeg kan og klargører Excel med det rigtige faneblad
Når du nu har så mange subs, er det nok smartest hvis fejlfangeren tager sig af det hele. Prøv at teste denne metode, hvor fejlen behandles i første gennemløb og der derefter sætter en brugerdefineret fejlkode, som gør at der intet sker i de næste gennemløb.
'Denne konstant skal med, Behøver ikke være 1200 Const FAKEERROR# = 1200
Private Sub Fejlbehandling(Fejlbesked As String) Dim errSv As String 'Check om det er første gangs fejl If Err.Number <> FAKEERROR# Then
errSv = MsgBox("Ups - der skete en fejl. Procedure er stoppet. " & vbLf _ & vbLf _ & "Tekniske oplysninger:" & vbLf _ & " " & Fejlbesked & vbLf _ & " Line " & Erl & vbLf _ & " Err " & Err.Number & vbLf _ & " Error " & Err.Description & " " & vbLf _ & vbLf _ & vbLf & "Du kan hjælpe med fejlrettelser ved at sende en e-mail til kks@ishoejby.dk med fejlen. " _ & vbLf & vbLf & "Vil du sende fejlbeskeden?", vbCritical + vbYesNo + vbDefaultButton1, "Fejl") If errSv = vbYes Then
'KLIP
MsgBox "Fejlen har medført at programmet af sikkerhedsgrunde afbrydes, og vender tilbage til Excel. " & vbLf _ & vbLf _ & "Du skal starte programmet igen for at det kan afsluttes korrekt.", vbExclamation, "Procedurefejl"
'KLIP
'Her afslutter jeg programmet så godt jeg kan og klargører Excel med det rigtige faneblad
End If 'sæt ny falsk fejl, der får den til at hoppe direkte gennem sub'en næste gang Err.Raise FAKEERROR# End Sub
Det ser interessandt ud, men der sker en fejl i 2. gennemløb. Debug kommer op med følgende:
---------------------- Run-time error '1200':
Could not set the Width property. Invalid property value. Enter a value greater than or equal to zero. ---------------------- (Den sidste bemærkning er fejlen som jeg har genereret for at prøve koden.)
1. gennemløb ser rigtig ud. If Err.Number <> FAKEERROR# Then (=True) Koden gør det den skal og hopper tilbage i sub og går igen ned i "fejlfanger" hvor den sendes til Fejlbehandling for 2. gang.
2. gennemløb er If Err.Number <> FAKEERROR# Then (=False) og koden hopper ned til Err.Raise FAKEERROR# hvilket jo er rigtig nok, men den kommer altså med denne Run-time error og går i stå på linien: Err.Raise FAKEERROR#
Jeg tror nok jeg kan se ideen i det ;-) og dit eksempel forløber jo fuldstændig som det jeg spørger om - husk lige et svar!
Jeg har dog et problem i at skulle afgøre hvad der er "Niveau1".
Hvis jeg ændre 'fejlfangeren' alle de steder hvor der kan være et direkte bruger input / hændelse, hvad sker der så hvis den procedure bliver kaldt automatisk?
Jeg bør måske ændre måden bruger kalder en procedure til: Private Sub CommandButton1_Click() On Error GoTo fejl Call DeleProcedure_Bruger_og_VBAkode Exit Sub fejl: If Err.Number <> lFAKE_ERROR Then Call Fejlfanger End Sub
Dermed bliver DeleProcedure_Bruger_og_VBAkode aldrig niveau1 - ville det være fornuftigt?
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.