Problem mit try bei WordApp



  • Ja ich dachte aber, dass man den Fehler mit try abfangen kann, sodass nicht das gesamte Programm abstürzt!

    Das komische daran ist ja auch, dass das Programm auch manchmal ohne Fehler die Prozedur durchläuft. Also ich habe jetzt die Prozedur zig-mal getestet, immer mit denselben Eingaben, und es kommen zu ca. 50% diese Fehler ...



  • Dein Programm stürzt nicht ab, zumindest nicht in dem Quelltextausschnitt den du gezeigt hast (was jetzt auch immer abstürzen genau ist 😉 ).
    Dein Try/Catch funktioniert auf jeden Fall, evtl. bekommst du die Exception trotzdem zu sehen, da du das Programm in der IDE startest, und die zeigt sie dir trotz Try/Catch.
    Des weiteren machst du ja wieder ein Throw im Try/Catch, also produzierst du selber einen "Absturz" mit der Meldung "scheiße, geht nicht!"....

    mfg
    xXx



  • ja würde dann wenigstens meine Nachricht "scheiße, geht nicht!" kommen, macht sie aber nicht, denn der alte Fehler tritt auf (bzw. einer von den beiden oben genannten Fehlern). Meinst du, wenn ich das Programm nicht aus der IDE heraus sondern als eigenständige exe starte, dass dann das try funktionieren könnte?

    Ich habe mal die Fehler hochgeladen, die ich bekomme (Der 1. und der 3. tauchen am häufigsten auf!)

    http://img139.imageshack.us/gal.php?g=wordappfehler1.jpg



  • Hallo

    Ja, Exception in try-catch-Blocken werden immer noch von der IDE des Builders angezeigt. Erst ohne IDE bekommt du das von dir gewünschte komplette Verschlucken der Exception, wenn du dann noch dein eigenes throw wegläßt.
    Aber denk dran : Nur weil du eine Exception unterdrückst, hast du das eigentlich auslösende Problem noch lange nicht gelöst.

    bis bald
    akari



  • ja ich hatte das zum Testen gedacht, hätte dies geklappt, wollte ich eine Schleife draus bauen, die wartet, bis der Fehler nicht mehr auftaucht. Ich habe halt die Annahme, dass WordApp->Disconnect() nicht Sequentiell aufruft. Denn ich bin die Befehle der WordApp oft genug mit dem Debugger durchgegangen und da traten diese Fehler NIE auf ...

    Edit: Nach diesen Fehler bekomme ich übrigends immer eine "Abnormal program termination".



  • MichelM schrieb:

    Ich habe mal die Fehler hochgeladen, die ich bekomme (Der 1. und der 3. tauchen am häufigsten auf!)

    http://img139.imageshack.us/gal.php?g=wordappfehler1.jpg

    Hast du mal die in der Fehlermeldung angegebene Codezeile näherer Beachtung gewürdigt? Sie sollte so aussehen:

    // word_xp_srvr.cpp, l. 910ff
    Word_xp::DocumentsPtr __fastcall TWordApplication::get_Documents(void)
    {
      Word_xp::DocumentsPtr prop;
      OLECHECK(GetDefaultInterface()->get_Documents(&prop)); // <--
      return prop;
    }
    

    Wenn du nach der Definition von OLECHECK() suchst, wirst du in utilcls.h fündig:

    // utilcls.h, l. 125ff
    #if !defined(NO_PROMPT_ON_HRCHECK_FAILURE)
    #define PROMPT_ON_HRCHECK_FAILURE 1
    #endif
    ...
      // utilcls.h, l. 150ff
    // Helper used to throw an exception
    template <class T>
    #if defined(ComobjHPP)
    void DebugHlpr_THROW(T* msg, HRESULT hr, T* file, bool /*assertFailed*/)
    {
      // NOTE: This does not retrieve rich error information, the way Delphi and VB environments
      //       do.
      //
      //       You can specialize [T = TCHAR] 'DebugHlpr_THROW' to retrieve rich error
      //       information and throw a VCL exception class, if you're using VCL classes already,
      //       or throw a custom exception class.
      //
      //       NOTE: Use the assertFailed parameter to distinguish between Assertion and
      //             OLECHECK failures. (Maybe throw something different??)
      throw Comobj::EOleException(msg, hr, file, _T(""), 0);
    }
    ...
      // utilcls.h, l. 173ff
    // Implementation of OLECHECK - Throw an exception if !SUCCEEDED(hr)
    template <class T>
    HRESULT DebugHlpr_HRCHECK(HRESULT hr, T* expr, T* file, int line)
    {
      if (!SUCCEEDED(hr))
      {
        TCHAR szMsg[_MAX_PATH*2];
        TCHAR lfile[_MAX_PATH*2];
    
        if (file)
          ::wsprintf(lfile, (sizeof(TCHAR)==sizeof(T)) ? _T("%s") : _T("%S"), file);
        else
          ::wsprintf(lfile, _T(""));
    
        LPVOID msg = 0;
        if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, hr,
                            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), LPTSTR(&msg), 0, 0) && (msg != 0))
        {
          ::wsprintf(szMsg, (sizeof(TCHAR)==sizeof(T)) ?
                            _T("'%s': %s @ %s/%d") : _T("'%S': %s @ %s/%d") ,
                            expr, LPTSTR(msg), lfile, line);
          ::LocalFree(msg);
        }
        else
          ::wsprintf(szMsg, (sizeof(TCHAR)==sizeof(T)) ?
                            _T("(%s) Error: %lX (%ld) @ %s/%d") : _T("(%S) Error: %lX (%ld) @ %S/%d"),
                            expr, LONG(hr), LONG(hr), file, line);
    
    #if !defined(PROMPT_ON_HRCHECK_FAILURE)
        int i = IDYES;
    #else
        int i = DebugHlpr_PROMPT(_T("HRCHECK: "), szMsg);
    #endif
        if (i == IDYES)
          DebugHlpr_THROW(szMsg, hr,lfile, false);
        else if (i == IDCANCEL)
          ::DebugBreak();
        // NOTE: IDNO - implies we keep chugging along
      }
    
      return hr;
    }
    ...
      // utilcls.h, l. 263ff
    #if !defined(OLECHECK)
    #define OLECHECK(hrexpr) DebugHlpr_HRCHECK(hrexpr, #hrexpr, __FILE__, __LINE__)
    #endif
    

    Das ermöglicht die folgenden Schlüsse:

    - Wenn du in den Projektoptionen NO_PROMPT_ON_HRCHECK_FAILURE definierst, wird keine Messagebox angezeigt, sondern direkt eine Exception geworfen.

    - DebugHlpr_HRCHECK<>() und DebugHlpr_THROW<>() sind Template-Funktionen. Wie der Kommentar in DebugHlpr_THROW<>() erwähnt, ist es möglich, sie mittels einer Template-Spezialisierung für TCHAR "umzubiegen" (mir fällt gerade keine schöne deutsche Entsprechung für "to override" ein) und etwa mit einer Exception zu reagieren, die mittels GetErrorInfo() detaillierte Informationen zum Fehler abruft.



  • Weiß denn jemand, warum der Fehler auftritt?

    Das NO_PROMPT_ON_HRCHECK_FAILURE hab ich in den Projektoptionen definiert. Aber das mit den Templatefunktionen hab ich noch nicht richtig verstanden. Ich glaube, verstanden zu haben, dass man mittels GetErrorInfo() sich die genaue Art von Fehler ermittelt.

    Und DebugHlpr_THROW() ist sowas ähnliches wie das throw() bei try ?



  • MichelM schrieb:

    Weiß denn jemand, warum der Fehler auftritt?

    Das kann ich dir leider nicht sagen; ich kenne mich mit der OLE-Schnittstelle von Word nicht aus. Vermutlich könnte man aber mit GetErrorInfo() mehr herausfinden.

    MichelM schrieb:

    Das NO_PROMPT_ON_HRCHECK_FAILURE hab ich in den Projektoptionen definiert.

    Dann sollte ja deine Anwendung wenigstens nicht mehr mit "abnormal program termination" abstürzen.

    MichelM schrieb:

    Aber das mit den Templatefunktionen hab ich noch nicht richtig verstanden. Ich glaube, verstanden zu haben, dass man mittels GetErrorInfo() sich die genaue Art von Fehler ermittelt.

    Ja, so etwa. Ich werde mal schauen, ob ich dazu ein schönes Beispiel finde.

    MichelM schrieb:

    Und DebugHlpr_THROW() ist sowas ähnliches wie das throw() bei try ?

    DebugHlpr_THROW() ist eine Funktion, deren Definition ich oben auch zitiert habe. Sie tut, wie du dort sehen kannst, tatsächlich nichts anderes, als ein "throw" (das eigentlich ein Sprachkonstrukt ist) mit einem bestimmten Exception-Typ zu initiieren.



  • audacia schrieb:

    MichelM schrieb:

    Aber das mit den Templatefunktionen hab ich noch nicht richtig verstanden. Ich glaube, verstanden zu haben, dass man mittels GetErrorInfo() sich die genaue Art von Fehler ermittelt.

    Ja, so etwa. Ich werde mal schauen, ob ich dazu ein schönes Beispiel finde.

    Es ist im Grunde recht einfach. Ich habe das mal exemplarisch implementiert, und es funktioniert für dich so:

    - In den Quelldateien, wo du mit den OLE-Automationsobjekten arbeitest, füge irgendwo folgende Deklaration ein:

    template <>
        HRESULT DebugHlpr_HRCHECK (HRESULT hr, const char* expr, const char* file, int line);
    

    - Füge ferner diese Datei deinem Projekt hinzu.

    Damit solltest du eine aussagekräftigere Fehlermeldung bekommen, nämlich genau die Fehlermeldung, die Word selbst verursacht.

    (Die Implementierung ist eigentlich auch ganz übersichtlich:

    Comobj::EOleSysError* __fastcall _createSafeCallException (HRESULT hr)
    {
        typedef DelphiInterface<IErrorInfo> _di_IErrorInfo;
    
        _di_IErrorInfo errorInfo;
        System::WideString source, desc, helpFile;
        DWORD helpCtx = 0;
        if (GetErrorInfo (0, &errorInfo) == S_OK)
        {
            errorInfo->GetSource (&source);
            errorInfo->GetDescription (&desc);
            errorInfo->GetHelpFile (&helpFile);
            errorInfo->GetHelpContext (&helpCtx);
            return new Comobj::EOleException (desc, hr, source, helpFile, helpCtx);
        }
        else
            return new Comobj::EOleSysError ("", hr, 0);
    }
    
    template <>
        HRESULT DebugHlpr_HRCHECK (HRESULT hr, const char* expr, const char* file, int line)
    {
        if (!SUCCEEDED (hr))
            throw _createSafeCallException (hr);
        return hr;
    }
    

    Die Einschränkung mit "eigentlich" mache ich, weil die Datei, die ich oben verlinkt habe, optional noch ein wenig mit Assemblercode zaubert, um den Call-Stack etwas zu beschönigen. Das kann ggf. den Komfort erhöhen, braucht dich aber nicht weiter kümmern.)



  • Anmerkung aus Gründen der Vollständigkeit:
    Der von mir beschriebene Workaround mittels Spezialisierung von DebugHlpr_HRCHECK<>() ist ab C++Builder XE nicht mehr nötig, da die VCL jetzt standardmäßig eine solche Spezialisierung verwendet. Bei OLE-Fehlern wird also nicht mehr diese Debug-Message-Box angezeigt, sondern eine Exception mit der richtigen Fehlermeldung geworfen.


Anmelden zum Antworten