Laufzeitfehler trotz On Error

  • Excel

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von ai5g.

    Laufzeitfehler trotz On Error

    Hi,

    ich brauche für eine Routine die Möglichkeit zu überprüfen, ob ein dynamisches Array initialisiert ist. Eigentlich sollte es ja möglich sein, einfach mit Ubound die Länge des Arrays abzufragen und den im Falle eines leeren Arrays auftretenden Laufzeitfehler 9 mit einem On Error statement abzufangen. Leider funktioniert genau das bei mir nicht ;( (Excel 2010, Win 7), es kommt trotz des On Error statements der Laufzeitfehler. Kann mir jemand verraten, warum das nicht klappt?

    Beipsiel:

    VB.NET-Quellcode

    1. Public Sub test6()
    2. Dim ar() As String, laenge As Long
    3. On Error Resume Next
    4. laenge = UBound(ar) 'Hier kommt Laufzeitfehler 9: Index außerhalb des gültigen Bereichs
    5. If Err.Number <> 0 Then laenge = -1
    6. Debug.Print laenge
    7. End Sub


    Alternativ würde mir auch ein anderer Weg helfen, mit dem ich leere dynamische Arrays erkennen kann.

    Ich habe auch Ansätze gefunden, welche die Funktionen
    Private Declare Sub GetSafeArrayPointer Lib "msvbvm60.dll" Alias "GetMem4" (ar() As Any, ptr As Long)
    oder
    Private Declare Function SafeArrayGetDim Lib "oleaut32.dll" (ByRef ar() As Any) As Long
    verwenden. Diese Funktionieren im Prinzip auch, sie versagen aber, wenn das Array in einem Variant verpackt ist (was in meinem Fall leider vorkommt):

    VB.NET-Quellcode

    1. Private Declare Sub GetSafeArrayPointer Lib "msvbvm60.dll" Alias "GetMem4" (ar() As Any, ptr As Long)
    2. Private Declare Function SafeArrayGetDim Lib "oleaut32.dll" (ByRef ar() As Any) As Long
    3. Public Sub test2()
    4. Dim ar() As String, ptr As Long
    5. GetSafeArrayPointer ar, ptr
    6. Debug.Print ptr
    7. Debug.Print SafeArrayGetDim(ar)
    8. Dim var As Variant
    9. var = ar
    10. GetSafeArrayPointer var, ptr 'Hier stoppt der Kompiler: unverträglicher Typ: Datenfeld oder benutzerdefinierter Typ erwartet
    11. Debug.Print ptr
    12. Debug.Print SafeArrayGetDim(var) 'Hier stoppt der Kompiler: unverträglicher Typ: Datenfeld oder benutzerdefinierter Typ erwartet
    13. End Sub


    Und dann habe ich noch eine Möglichkeit mit "not not" gefunden:

    VB.NET-Quellcode

    1. Public Sub test3()
    2. Dim ar() As String, laenge As Long
    3. If (Not Not ar) = 0 Then laenge = -1 Else laenge = UBound(ar) 'Funktioniert!
    4. Debug.Print laenge
    5. Dim var As Variant: var = ar
    6. If (Not Not var) = 0 Then laenge = -1 Else laenge = UBound(var) 'Laufzeitfehler '13': Typen unverträglich
    7. Debug.Print laenge
    8. End Sub


    Diese Möglichkeit versagt auch wieder bei dem in variant verpackten array. Woran liegt das eigentlich? ich dachte, dass das Variant durch die Zuweisung in diesem Fall zu einem Array of strings wird:
    Debug.Print IsArray(var) ' liefert "Wahr"
    Debug.Print IsEmpty(var) 'liefert "falsch"
    Debug.Print IsNull(var) 'liefert auch "falsch"

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „ai5g“ ()

    Gefunden auf stackoverflow und leicht geändert:

    Visual Basic-Quellcode

    1. Dim ar() As String, laenge As Long
    2. If (Not ar) = -1 Then
    3. MsgBox "empty"
    4. Else
    5. MsgBox UBound(ar)
    6. End If
    7. ReDim ar(3)
    8. If (Not ar) = -1 Then
    9. MsgBox "empty"
    10. Else
    11. MsgBox UBound(ar)
    12. End If


    =>

    Visual Basic-Quellcode

    1. Dim ar() As String, laenge As Long
    2. '...
    3. If (Not ar) = -1 Then
    4. laenge = -1
    5. Else
    6. laenge = UBound(ar)
    7. End If
    8. Debug.Print laenge

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    @cry.baby: mir ist schon klar, warum ich kein ubound bei einem leeren Array abfragen kann, ich verstehe aber nicht, warum ich den Fehler nicht mit "On Error" abfangen kann; das Programm steigt trotzdem mit dem Laufzeitfehler aus.

    @VaporiZed: Das hatte ich auch gerade so ähnlich gefunden und zeitgleich mit Deiner Antwort im obigen Post ergänzt :-). Leider Funktioniert das aber auch nicht in alle Fällen. Folgende Beispiel:
    Ich rufe die fragliche Funktion (hier: "safeUbound") nämlich über eine andere Funktion (hier: "test4") auf; das ganze steigt dann wieder mit Laufzeitfehler aus.

    VB.NET-Quellcode

    1. Public Function safeUbound(var As Variant) As Long
    2. If (Not var) = -1 Then ''Laufzeitfehler '13': Typen unverträglich
    3. safeUbound = -1
    4. Else
    5. safeUbound = UBound(var)
    6. End If
    7. End Function
    8. Public Sub test4()
    9. Dim ar() As String, laenge As Long
    10. Debug.Print safeUbound(ar)
    11. ReDim ar(3)
    12. Debug.Print safeUbound(ar)
    13. End Sub

    Hmm, das ist jetzt komisch. Vorhin auf dem Bürorechner (Excel 2010, Win 7 x64) ist Excel-VBA mit einem Laufzeitfehler trotz "On Error" ausgestiegen, auf meinem Rechner zuhause (Win 10 x64, Office 2016) funktioniert das.Kann man das irgendwo einstellen, dass "On Error" ignoriert wird??
    On Error Resume Next vermeide ich grundätzlich. Das ist nicht sauber kontrollierbar.

    Visual Basic-Quellcode

    1. Public Sub test6()
    2. Dim ar() As String, laenge As Long
    3. On Error GoTo Done
    4. laenge = UBound(ar) 'Hier kommt Laufzeitfehler 9: Index außerhalb des gültigen Bereichs
    5. Done:
    6. If Err.Number <> 0 Then laenge = -1
    7. Debug.Print laenge
    8. End Sub
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Erneut stackoverflow

    Visual Basic-Quellcode

    1. Function safeUbound(Arr As Variant) As Long
    2. On Error Resume Next
    3. Dim IsInitialized As Boolean
    4. IsInitialized = IsArray(Arr) And Not IsError(LBound(Arr, 1)) And LBound(Arr, 1) <= UBound(Arr, 1)
    5. If IsInitialized Then
    6. safeUbound = UBound(Arr)
    7. Else
    8. safeUbound = -1
    9. End If
    10. End Function
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    @petaod: Diese Variante hatte ich am Bürorechner auch probiert, aber diese ist mit Laufzeitfehler ausgestiegen. Hier bei mir zuhause geht aber auch diese Variante. Scheint fast, als sei das Fehlerhandlingübernehmen am Bürorechner abgeschaltet.

    ai5g schrieb:

    Scheint fast, als sei das Fehlerhandlingübernehmen am Bürorechner abgeschaltet.
    Das kann natürlich sein.
    Aber wer macht sowas?

    Reparieren kannst du das im VBA-Editor unter Extras .. Optionen .. Allgemein
    Hier sind die Varianten beschrieben:
    bettersolutions.com/vba/error-…g/break-on-all-errors.htm
    Aktiviere "Bei nicht verarbeiteten Fehlern"
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „petaod“ ()

    "On Error Resume Next" kann nicht alle Fehler abfangen. Es gibt Fehler die nicht mit "On Error" abzufangen sind wenn eine Einstellung im VBA-Editor nicht richtig gesetzt ist.
    VBA-Editor->Extras->Optionen->Allgemein->Unterbrechen bei Fehlern -> Häkchen setzen bei "Bei nicht verarbeiteten Fehlern".

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „mumpel“ ()

    Vielen Dank @petaod und @'mumpel!!!

    Hab's mal zuhause ausprobiert, damit kann ich das Problem hier nachstellen. Ich wusste gar nicht, dass man die eigene Fehlerbehandlung wirklich abschalten kann. Ich vermute mal, damit werde ich das Problem am Bürorechner auch los. Hat mir ganz schön Kopfweh gemacht.

    Kann mir vielleicht auch noch jemand sagen, was sich an der Variable ändert, wenn ich wie oben in meinen Beispielen "test2()" und "test3()" die eigentliche Variable ar() vor der weiteren Verarbeitung einen an Variant (dim var as variant : var=ar ...) übergebe (was in der Praxis eben vorkommt, wenn ich das array an eine andere Funktion übergebe)? Mit varType und isArray bekomme ich nämlich in beiden Fällen (für ar und var) die gleichen Ergebnisse, trotzdem verhalten sich beide Varianten, z.B. bei Übergabe an GetSafeArrayPointer im Beispiel test2, unterschiedlich. Ich hatte das mal "array verpack in ein variant" genannt, aber so richtig verstehe das eigentlich nicht - kann man so ein Array auch wieder aus dem Variant auspacken (um im Bild zu bleiben ;-))?