Exceptions global Abfangen



  • Guten Abend Freunde der Programmiererrasse,

    ich würde gerne alle Exceptions meiner Anwendung abfangen und z.B. in einer Datei speichern.

    Die einzigste Möglichkeit, welche mir jetzt eingefallen ist, wäre mit Try&Error 😉

    try{}catch(...)
    

    die jeweiligen Code-Blöcke zu umschreiben. Gibt es da nicht vielleich ein Interface oder ein Event, welches ich abfangen kann?

    Viele Grüße
    devmode



  • Hallo

    Ja try-catch ist schon nicht schlecht, immerhin gibts ja in der Hauptprojektdatei auch einen globalen try-catch Block. Da kannst du mit dem Loggen anfangen.

    Zusätzlich gibts in der VCL noch TApplication::OnException. Inwieweit das wirklich alle Exceptions bekommt weiß ich aber nicht.

    bis bald
    akari



  • Wie Akari bereits erwähnte, sind in jeder VCL-Anwendung bereits zwei Exception-Handler installiert: einer vor dem Aufruf von Event-Funktionen und einer in der WinMain (hier werden aber nur Exceptions gefangen, die das Terminieren des Programmes zur Folge haben).

    Ein Problem ist, daß die VCL nur von Sysutils::Exception abgeleitete Exception-Klassen erkennt und nicht die aus der Standard-Library. Das kannst du auf folgende Weise ändern:

    // vclutils.hpp
    
    #ifndef _UCL_VCLUTILS_HPP
    #define _UCL_VCLUTILS_HPP
    
    #define UCL_BEGIN_VCL_MESSAGE_MAP                   \
        virtual void __fastcall Dispatch(void *Message) \
        {                                               \
           try                                          \
           {                                            \
              switch  (((PMessage)Message)->Msg)        \
              {
    
    #ifdef _DEBUG
     #include <typeinfo>
    
     #define UCL_END_VCL_MESSAGE_MAP(base)   default:          \
                           base::Dispatch(Message);            \
                           break;                              \
              }                                                \
           }                                                   \
           catch (const std::exception& e)                     \
           { /* distribute std exceptions as VCL exceptions */ \
               throw Sysutils::Exception (AnsiString           \
                   (typeid (e).name ()) + ": " + e.what ());   \
           }                                                   \
           catch (const Sysutils::Exception& e)                \
           {                                                   \
               throw;                                          \
           }                                                   \
           catch (...)                                         \
           {                                                   \
               throw Sysutils::Exception                       \
                   ("Unknown exception occured");              \
           }                                                   \
       }
    #else
     #define UCL_END_VCL_MESSAGE_MAP(base)   default:          \
                           base::Dispatch(Message);            \
                           break;                              \
              }                                                \
           }                                                   \
           catch (const std::exception& e)                     \
           { /* distribute std exceptions as VCL exceptions */ \
               throw Sysutils::Exception (e.what ());          \
           }                                                   \
           catch (const Sysutils::Exception& e)                \
           {                                                   \
               throw;                                          \
           }                                                   \
           catch (...)                                         \
           {                                                   \
               throw Sysutils::Exception                       \
                   ("Unknown exception occured");              \
           }                                                   \
       }
    #endif
    
    #define UCL_DEFAULT_VCL_MESSAGE_MAP(base)                  \
            UCL_BEGIN_VCL_MESSAGE_MAP                          \
            UCL_END_VCL_MESSAGE_MAP(base)
    
    #endif // _UCL_VCLUTILS_HPP
    
    // MyUnit.h
    //---------------------------------------------------------------------------
    
    #ifndef MyUnitH
    #define MyUnitH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    
    #include "vclutils.hpp"
    //---------------------------------------------------------------------------
    class TMyForm : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
    private:	// Benutzer-Deklarationen
    public:		// Benutzer-Deklarationen
        __fastcall TMyForm(TComponent* Owner);
    
          // auf das hier kommt es an
        UCL_DEFAULT_VCL_MESSAGE_MAP (TForm)
    
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TMyForm *MyForm;
    //---------------------------------------------------------------------------
    #endif
    

    Damit ist die Dispatch-Funktion, die die Messages an die Event-Funktionen weiterleitet, in der Lage, von std::exception abgeleitete Exceptions zu fangen; solche Exceptions werden als Sysutils::Exception-Objekte erneut geworfen. Auf diese solltest du nun in Application::OnException reagieren können.
    Leider funktioniert das nicht, wenn Event-Funktionen von Komponenten aufgerufen werden, die sich in einer GroupBox o.ä. befinden.



  • Danke euch! Ich habe es einfacher hinbekommen. Einfach den OnException Event von Application abfangen. Habe jetzt keinen Code da, kommt aber noch.



  • devmode schrieb:

    Danke euch! Ich habe es einfacher hinbekommen. Einfach den OnException Event von Application abfangen.

    ... was ja genau das war, was wir dir vorgeschlagen hatten. Mein Code dient nur dazu, auch C++-Exceptions fangen zu können 😉



  • Da ich aktuell auch ein kleines Problem mit dem besch... Exceptionhandling im BCB 6.0 habe, erweitere ich mal die Frage.

    Kriegt man Exceptionhandling auch auf die "herkömmliche" Art und Weise hin, die man z.B. vom GCC oder vom MS-Compiler gewohnt ist?

    Zu meinem Anwendungsfall:

    Ich hab einen Formelinterpreter und der ist quasi gerade zu prädestiniert dafür, bei einem (Syntax)Fehler eine Exception zu werfen.

    Ich bin eigentlich nicht scharf darauf, das ganze über OnException abzuhandeln, zumal die Interpreter-Klasse eigentlich garnix mit VCL-Formularen und sonstigem Geraffel zu tun hat. Die wird nämlich auch von anderen Projekten genutzt.

    Ich will eigentlich einfach nur nach alter Gewohnheit eine Exception fangen und zwar genau dort, wo sie fliegt und nicht in irgendeinem mystischen Exceptionevent.



  • Hallo

    Selbstverständlich kannst du auch im Builder einen gewöhnlichen try-catch-Block verwenden, und du kannst auch std::exception werfen und nicht nur Exception. Wer behauptet denn das Gegenteil? 😕
    Also bitte informiere dich doch erstmal, bevor du dem Builder ein "besch... Exceptionhandling" vorwirfst.

    bis bald
    akari



  • Naja wenn ich eine Exception werfe, krieg ich erstmal vom BCB eine MessageBox auf die Nase gedrückt und erst dann lande ich im catch-Block....

    Und ich hab bisher nicht rausgefunden, wie ich das verhindern kann. Ich will doch einfach nur ne Exception werfen und abfangen.

    Und nein, ich will das Event nicht benutzen und auch keine Exceptions von SysUtils::Exception ableiten....



  • Hallo

    Ich zitiere mich selber aus meinem ersten Post dieses Threads :

    akari schrieb:

    Ja try-catch ist schon nicht schlecht, immerhin gibts ja in der Hauptprojektdatei auch einen globalen try-catch Block. Da kannst du mit dem Loggen anfangen.

    bis bald
    akari



  • Ich hab das schon gelesen, nur ist mir nicht ganz klar wie mir der globale try-catch-Block da weiterhelfen soll.

    In einer Klasse, weit jenseits jeglicher Formulare oder Komponenten fliegt eine Exception.

    Der globale Try-Catch-Block bleibt gänzlich unbeinflusst.

    Es knallt, die entsprechende Zeile im Code wird markiert und wenn ich weiterlaufen lasse, komme ich in meinen eigenen Catch-Block.

    Und da sind wir auch schon bei dem Problem. Nach der Exception müsste ich direkt in meinem Catch-Block landen und nicht erst eine MessageBox auf die Nase gedrückt bekommen.



  • Hallo

    Um dein Problem zu lösen, must du zwei Dinge beachten :
    1. Der globale try-catch-Block, der in einem Standard-VCL-Projekt angelegt wird, behandelt zunächst nur VCL-Exceptions. Aber du kannst diesen ja erweitern :

    try
            {
                     Application->Initialize();
                     Application->CreateForm(__classid(TForm1), &Form1);
                     Application->Run();
            }
            catch (Exception &exception)
            {
                     Application->ShowException(&exception);
            }
            catch (std::exception &exception) // Diesen Zweig hinzufügen
            {
               // Hier deine eigene Behandlung...
                     Application->MessageBox(exception.what(), "C++ Exception", MB_OK);
            }
    

    Das wurde in diesem Thread ja eigentlich auch angesprochen.

    2. Die Builder-IDE zeigt automatisch sofort jede Exception an, bevor die manuelle Behandlung ausgeführt wird, wenn das Projekt aus der IDE heraus gestartet wird. Das ist auch bei VCL-Exception so. Starte dein kompiliertes Programm mal ohne IDE, dann hast du nur deine eigene Exception-Behandlung. In den Projektoptionen gibt es irgendwo auch eine Einstellung, um diese Auto-Meldung der IDE zu unterdrücken. Benutz die Forumsuche, das wurde schon öfters besprochen.

    bis bald
    akari


Anmelden zum Antworten