Excel Workbook wird immer mit Fehler beendet

  • Excel

Es gibt 23 Antworten in diesem Thema. Der letzte Beitrag () ist von maexchen1999.

    Excel Workbook wird immer mit Fehler beendet

    Hallo!
    Ich habe ein Problem: ich habe ein Excel-Workbook erstellt, um damit Szenarien für Personalverrechnung zu rechnen.
    Das funktioniert auch alles so weit gut. Wenn ich aber das Workbook beenden will, wird immer eine Fehlermeldung angezeigt: Die Methode Sheets für das Objekt "Global" ist fehlgeschlagen.
    Im "Betrieb" läuft alles normal, nirgends gibt es Probleme. Wenn ich aber beende, erscheint diese Fehlermeldung. Wenn ich dann den Debugging-Modus aufrufe, wird auf die Zeile "Sheets("Abrechnung").Select" verwiesen, wobei "Abrechnung" das aktuell auf dem Bildschirm angezeigte Tabellenblatt ist.
    Wenn ich die Arbeitsmappe dagegen nur schließe, ohne Excel zu beenden, erscheint auch KEINE Fehlermeldung!
    Ich habe das schon ein wenig eingegrenzt: es gibt auf diesem Tabellenblatt eine Combobox, die u.a eine Programmierung bei Change() eingetragen hat. und dort bleibt er dann eben immer stehen.
    Dabei ist völlig irrelevant, ob tatsächlich eine Änderung durchgeführt wurde, anscheinend wird beim Beenden IMMER diese Funktion dieser Combobox durchlaufen, selbst wenn das Dokument nach dem Öffnen sofort wieder geschlossen wird, und ich weiß nicht, warum das so ist.
    Es handelt sich dabei um eine Combobox, die aus dem Menü "ActiveX-Steuerelemente" erstellt wurde.
    Es ist auch völlig egal, ob der Blattschutz aktiviert ist, oder nicht.
    Ich habe Office 2010 unter Win7 x64 in Verwendung.
    Für jede Hilfe bin ich dankbar, da ich da wirklich anstehe.
    Schon jetzt vielen Dank im Voraus für alle Tipps und Hilfen.

    Zur Info hier noch der Code, der anscheinend die Probleme auslöst:


    Private Sub Abrechnungsmonat1_Change()
    Dim adr As Range
    Dim Amonat, SZ
    Dim Anz As Integer
    Sheets("Abrechnung").Select
    Range("M6:P6").Value = "Jahressechstel vor Abr. " & [Abrechnungsmonat1].Column(1)
    SZ = Range("J12").Value
    Amonat = Range("C5").Value
    Sheets("Abrechnung").Select
    Anz = Application.WorksheetFunction.CountIf(Range("C2:C13"), ">0")
    'MsgBox Anz
    Sheets("Jahressechstel").Select
    If Amonat > Application.WorksheetFunction.CountIf(Sheets("Jahressechstel").Range("C2:C13"), ">0") Then
    x = MsgBox("Es wurde noch nicht für alle vergangenen Monate das Jahressechstel eingetragen!", vbOKOnly + vbInformation, "Fehlende Eingaben")
    End If
    Msechstel = Application.WorksheetFunction.Index(Worksheets("Jahressechstel").Range("C2:c13"), Amonat)
    If Msechstel = 0 Or IsNull([Msechstel]) Then
    x = MsgBox("Soll das Jahressechstel für den Monat " & Abrechnungsmonat1.Column(1) & " eingetragen werden?", vbYesNo + vbQuestion, "Jahressechstel eintragen")
    If x = 6 Then
    Worksheets("Abrechnung").Select
    Range("E18").Select
    Application.WorksheetFunction.Index(Worksheets("Jahressechstel").Range("C2:F13"), Amonat, 1) = ActiveCell.Value
    Application.WorksheetFunction.Index(Worksheets("Jahressechstel").Range("C2:F13"), Amonat, 1).Value = CDbl(Format(Application.WorksheetFunction.Index(Worksheets("Jahressechstel").Range("C2:F13"), Amonat, 1), "##,##0.00 "))
    End If
    End If
    Sheets("Abrechnung").Select
    Range("Q6").Select
    ActiveCell.Value = CDbl(Format(Application.WorksheetFunction.Index(Worksheets("Jahressechstel").Range("C2:F13"), Amonat, 2), "##,##0.00 "))
    Range("E12").Select
    Ende:
    End Sub

    Zur Info: in der Zeile 6 range("M6:P6") [==> M 6 : P 6, ich habe es hier wegen dem Smiley mit Abstand geschrieben] ist insofern korrekt, als es sich um eine verbundene Zelle handelt ...
    Sheets("Abrechnung").Select
    Range("M66").Value = "Jahressechstel vor Abr. " & [Abrechnungsmonat1].Column(1)
    Diese Programmiermethode ist auch absolut unsauber und vom Macro-Recorder übernommen.
    Abgesehen von der Tatsache, dass sie viel Overhead erzeugt, kommt es natürlich auch zu Fehler, wenn das Arbeitsblatt nicht selektierbar ist, weil z.B. das Programm beendet wird.
    Wenn du die Objekte direkt adressierst, passiert so etwas nicht:

    Visual Basic-Quellcode

    1. Sheets("Abrechnung").Range("M66").Value = "Jahressechstel vor Abr. " & [Abrechnungsmonat1].Column(1)
    Methoden oder Properties, die "Active" oder "Select" beinhalten sind bei guter Programierung bis auf wenige Ausnahmen völlig tabu. Auch dieses Konstrukt:
    Range("E18").Select
    Application.WorksheetFunction.Index(Worksheets("Jahressechstel").Range("C2:F13"), Amonat, 1) = ActiveCell.Value
    Application.WorksheetFunction.Index(Worksheets("Jahressechstel").Range("C2:F13"), Amonat, 1).Value = CDbl(Format(Application.WorksheetFunction.Index(Worksheets("Jahressechstel").Range("C2:F13"), Amonat, 1), "##,##0.00 "))
    lässt sich wesentlich eleganter darstellen:

    Visual Basic-Quellcode

    1. Range("C2").Offset(Amonat-1, 0) = Range("E18").Value
    2. ...
    3. Range("C2:F13").NumberFormat="##,##0.00 " 'kompletten Bereich auf einmal formatieren
    Nicht auf den Macro-Recorder vertrauen, sondern versuchen, das Objektmodell zu verstehen und die Objekte direkt ansprechen!
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

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

    Hallo!
    Danke für die schnelle Antwort. Ich muß dazu sagen, dass ich mit VB Excel noch nicht wirklich viel Erfahrung habe, daher bin ich umso dankbarer für die Hilfe. Wollte Dir ja gestern schon zurückschreiben, aber gerade beim Verfassen der Antwort war auf einmal die Verbindung zum Server des Forums weg ...
    Ich habe das Problem zwischenzeitlich gelöst, es fehlte lediglich der Zusatz "ThisWorkbook" bei den "Range-Zeilen". Trotzdem war Deine Rückmeldung eine große Hilfe, die Performance wurde wesentlich dadurch verbessert. Ich denke, es wird wohl doch noch einige Zeit dauern, bis ich hier im Forum vom "Konsumenten" zum "Ratgeber" für andere werden kann.
    Jetzt habe ich nur noch ein kleines Problem: Wie kann ich es schaffen, dass am Ende der Prozedur der Cursor auf eine bestimmte Zelle gestellt wird? mit "Select" funktioniert das nämlich nicht, da erhalte ich beim Beenden wieder die "ursprüngliche" Fehlermeldung, im "Betrieb" funktioniert es allerdings.
    Vielen Dank nochmal im Vorhinein für Deine Hilfe! :)

    maexchen1999 schrieb:

    Wie kann ich es schaffen, dass am Ende der Prozedur der Cursor auf eine bestimmte Zelle gestellt wird?
    Wenn du die ganzen Activates und Selects nicht verwendest, bleibt der Cursor da, wo er am Anfang war.
    Falls du bei Verarbeitungsende den Cursor gezielt platzieren willst, um dem Anwender auf die richtige Zelle zu lotsen, ist das eine der wenigen Ausnahmen, wo du die Methoden verwenden darfst.

    Visual Basic-Quellcode

    1. Sheets("Abrechnung").Activate
    2. Range("A1").Select
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Hallo!
    Danke für die Info. Aber das habe ich schon versucht, das klappt nicht - wie gesagt, im Betrieb funktioniert das mit "select" wunderbar, nur nicht beim Beenden. Da kommt immer eine Fehlermeldung, in dem Fall, wenn ich es so mache, wie von Dir vorgeschlagen: die Activate-Methode des Worksheet-Objektes konnte nicht ausgeführt werden (Laufzeitfehler 1004)
    Hier nun nochmal der Code, wie er jetzt im Moment aussieht:
    Private Sub Abrechnungsmonat_Change()
    Dim adr As Range
    Dim Amonat, SZ
    Dim Anz As Integer

    ThisWorkbook.Sheets("Abrechnung").Range("M6:P6").Value = "Jahressechstel vor Abr. " & [Abrechnungsmonat].Column(1)
    SZ = ThisWorkbook.Sheets("Abrechnung").Range("J12").Value
    Amonat = ThisWorkbook.Sheets("Abrechnung").Range("C5").Value 'Abrechnungsmonat
    Anz = Application.WorksheetFunction.CountIf(ThisWorkbook.Sheets("Jahressechstel").Range("C2:C13"), ">0") 'Eingetragene Monate
    'MsgBox "Abrechnungsmonat: " & Amonat
    'MsgBox "Monatsanzahl: " & Anz
    If Amonat - Anz > 1 Then
    x = MsgBox("Es wurde noch nicht für alle vergangenen Monate das Jahressechstel eingetragen!" & Chr(13) & _
    Chr(13) & "Die Abrechnung für den Monat " & Abrechnungsmonat.Column(1) & " ist daher noch nicht möglich!", vbOKOnly + vbInformation, "Fehlende Eingaben")
    [Abrechnungsmonat] = derzeit_Abrechnungsmonat
    GoTo Ende
    End If
    If Amonat - Anz = 1 Then
    Msechstel = Application.WorksheetFunction.Index(ThisWorkbook.Sheets("Jahressechstel").Range("C2:c13"), Amonat)
    If Msechstel = 0 Or IsNull([Msechstel]) Then
    x = MsgBox("Soll das Jahressechstel für den Monat " & Abrechnungsmonat.Column(1) & " eingetragen werden?", vbYesNo + vbQuestion, "Jahressechstel eintragen")
    If x = 6 Then
    ThisWorkbook.Sheets("Jahressechstel").Range("C2").Offset(Amonat - 1, 0) = ThisWorkbook.Sheets("Abrechnung").Range("E18").Value
    End If
    End If
    End If
    ThisWorkbook.Sheets("Abrechnung").Range("Q6").Value = CDbl(Format(Application.WorksheetFunction.Index(Worksheets("Jahressechstel").Range("C2:F13"), Amonat, 2), "##,##0.00 "))
    ThisWorkbook.Sheets("Abrechnung").Activate
    ThisWorkbook.Sheets("Abrechnung").Range("E12").Select
    Ende:
    End Sub

    Sorry, wenn ich Dich da nochmal belästige ... :(
    Du führst den Code in einem Change-Event aus.
    Wenn du das Programm schließt, kann es sein, dass zum Eintreten des Events das Worksheet bereits nicht mehr sichtbar und damit auch nicht mehr aktivierbar ist.
    Das solltest du prüfen, bevor du anfängst.
    Vielleicht hilft

    Visual Basic-Quellcode

    1. If Not Worksheets("Abrechnung").Visible Then Exit Sub


    Teste mal beim Schließen, in welcher Reihenfolge die Events auftreten.
    Ich vermute, dass Workbook_BeforeClose (im Modul Arbeitsmappe) als erstes geworfen wird.
    Wenn du dort ein

    Visual Basic-Quellcode

    1. Application.DisableEvents
    einträgst, treten die restlichen Events erst gar nicht mehr auf.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

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

    Hallo! Danke für Deine Bemühungen, aber auch das war leider nicht erfolgreich:

    Private Sub Workbook_BeforeClose(Cancel As Boolean)
    Application.disableevents
    End Sub

    wird mit der Meldung Objekt unterstützt diese Eigenschaft oder Methode nicht (Laufzeitfehler 438) abgebrochen, und der zweite Eintrag löst die leider schon sattsam bekannte Fehlermeldung Die Methode 'Worksheets' für das Objekt '_Global' ist fehlgeschlagen (Laufzeitfehler 1004) aus ...

    Vielleicht sollte ich mich doch damit anfreunden, dass ich entweder den Curser nicht verschieben kann, oder beim Beenden mit der Fehlermeldung leben muß - beides begeistert mich nicht wirklich ...

    Danke trotzdem für Deine Hilfen und Bemühungen, ich traue mich ja schon gar nicht mehr zu fragen, ob Du vielleicht trotzdem noch eine Idee hast - oder würde es vielleicht was bringen, wenn Du Dir das Ding mal ansiehst?
    Hallo!
    Danke, das war auch wieder ein guter Tipp, jetzt bin ich erneut einen Schritt weiter!
    Die Fehlermeldung bezüglich "Select" kommt jetzt beim Beenden nicht mehr, dafür bekomme ich jetzt - und das interessanterweise gleich 2x! - eine Msgbox-Meldung aus dem Change-Event:

    If Amonat - Anz > 1 Then
    x = MsgBox("Es wurde noch nicht für alle vergangenen Monate das Jahressechstel eingetragen!" & Chr(13) & _
    Chr(13) & "Die Abrechnung für den Monat " & Abrechnungsmonat.Column(1) & " ist daher noch nicht möglich!", vbOKOnly + vbInformation, "Fehlende Eingaben")
    [Abrechnungsmonat] = derzeit_Abrechnungsmonat
    GoTo Ende
    End If


    Die dürfte doch jetzt beim Beenden gar nicht mehr abgefragt werden, oder?

    Der ganze Code von diesem Event steht weiter oben ...
    dafür bekomme ich jetzt - und das interessanterweise gleich 2x! - eine Msgbox-Meldung aus dem Change-Event
    Du musst dir halt vergegenwärtigen, wann das Event überall geworfen werden kann.
    Eben z.B. auch am Schluss, wenn das Objekt geleert wird.
    Und all diese Eventualitäten musst du abfangen.

    Welche Art von Objekt ist denn AbrechnungsMonat1?

    Nochmals zum Ablauf:

    Das Workbook_BeforeClose wird aufgerufen und dort setzt du EnableEvents=False
    Danach wird trotzdem das Abrechnungsmonat1_Change geworfen?

    Das wäre sehr merkwürdig.
    Hast du mal Breakpoints gesetzt, ob das Change tatsächlich nach dem Abschalten der Events in BeforeClose geworfen wird?
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    petaod schrieb:

    Du musst dir halt vergegenwärtigen, wann das Event überall geworfen werden kann.

    Eben z.B. auch am Schluss, wenn das Objekt geleert wird.

    Und all diese Eventualitäten musst du abfangen.


    Ja , da wirst Du sicher recht haben, aber mein Problem ist, dass ich eben mit Excel VB (noch) nicht wirklich viel Erfahrung habe und mich da nicht so auskenne - deswegen stehe ich ja vor den Problemen und bin für die Hilfe wirklich dankbar ... :)

    petaod schrieb:

    Das Workbook_BeforeClose wird aufgerufen und dort setzt du EnableEvents=False

    Danach wird trotzdem das Abrechnungsmonat1_Change geworfen?

    So habe ich es derzeit eingetragen, und anscheinend wird danach trotzdem noch das Change-Event durchlaufen - warum, weiß ich nicht ... :(

    petaod schrieb:

    Hast du mal Breakpoints gesetzt, ob das Change tatsächlich nach dem Abschalten der Events in BeforeClose geworfen wird?

    Sorry, klingt jetzt vielleicht blöd - aber wie macht man das? Bitte nicht vergessen, Du sprichst leider mit einem Anfänger ... :S

    Abrechnungsmonat1 ist eine Combo-Box, activeX-Steuerelement

    FloFuchs schrieb:

    Du setzt im Code deinen Cursor in die Zeile, wo du willst dass das Prgramm anhält. Dann drückst du "F9" dann wird die Zeile rot markiert.

    Und die Programm ausführung da gestoppt

    Du bist wirklich ein Mensch mit Engelsgeduld ... :)
    Aber es ist tatsächlich so, dass das Change -Event trotz der Einstellungen immer noch beim Beenden durchlaufen wird ... :(
    Ich bin übrigens gerade daraufgekommen, dass diese doppelte Fehlermeldung nur dann kommt, wenn ich den "Beenden"-Button, den ich gesetzt habe, betätige. Wenn ich die Arbeitsmappe über das "X" rechts oben beende, habe ich immer noch die Fehlermeldung bezüglich "select" (Die Select-Methode des Range-Objektes konnte nicht ausgeführt werden ==> Laufzeitfehler 1004)