SetUnhandledExceptionFilter



  • Hallo zusammen

    Ich wollte mit SetUnhandledExceptionFilter einen Exceptionhandler registrieren um im Fehlerfall einen Minidump zu schreiben.
    In einer Konsolenanwendung ist dies auch kein Problem und funktioniert.
    Wenn ich dies allerdings in einer Formularanwendung mache passiert nichts, d.h. mein Exceptionhandler wird nicht aufgerufen.
    Meine Vermutung ist, daß es keine unbehandelten Exceptions gibt, da die VCL ihren eigenen verwendet.

    Kann dies jemand bestätigen, bzw erklären?

    Vielen dank im voraus.
    MfG Stephan



  • Stephan schrieb:

    Kann dies jemand bestätigen

    Ja - das ist dieser hier.

    Für deine Zwecke bietet sich etwa JclDebug hervorragend an.



  • Hallo audacia

    Ich hab von deinem Artikel zwar nicht alles verstanden, jedoch nun ist mir klar das es ein, sagen wir mal, "Builder Problem" ist und nicht an meinem Code liegt.

    JCL Debug verwende ich bereits (Experte für Exception Dialog, oder so ähnlich).
    Und genau diesen wollte ich um ein paar Funktionen wie MiniDump erweiteren. MiniDump deshalb, da ich bei JCL immer Debuginformationen (TDS, MAP, JDBG) mitgeben muss. Oder gibt es hier mittlerweile andere Möglichkeiten?

    Habe versucht den MiniDump über Application->OnException zu generieren, allerdings bekomme ich von Exception nicht die Info EXCEPTION_POINTERS welche für MiniDumpWriteDump benötigt wird. Hat hierfür jemand eine Lösung?

    Dann noch eine andere Frage, ist es möglich in Delphi eine Funktion aus einer C bzw H Datei aufzurufen?

    MfG Stephan



  • Stephan schrieb:

    Habe versucht den MiniDump über Application->OnException zu generieren, allerdings bekomme ich von Exception nicht die Info EXCEPTION_POINTERS welche für MiniDumpWriteDump benötigt wird. Hat hierfür jemand eine Lösung?

    Um SetUnhandledExceptionFilter benutzen zu können, müßtest du die unkonditionellen try-except-Statements in der VCL umgehen. Der einzige Weg, der mir dazu einfällt, wäre durch einen Detour (alternativ kannst du natürlich die VCL neukompilieren 🤡 ). So spontan finde ich nur die Handler in TApplication.Run und TWinControl.MainWndProc; die müßtest du zur Laufzeit ersetzen.

    (Das ist allerdings nur spekulativ, da ich selbst noch nicht in die Versuchung gekommen bin, es auszuprobieren. Keine Ahnung, ob das so funktioniert, aber einen Versuch wäre es wohl wert.)

    Stephan schrieb:

    Dann noch eine andere Frage, ist es möglich in Delphi eine Funktion aus einer C bzw H Datei aufzurufen?

    Wenn Delphi-Units und C++-Module im gleichen Projekt sind, dann nicht direkt, nur auf Umwegen. Der üblichste Umweg ist dabei die Definition eines Interfaces oder einer abstrakten Basisklasse in Delphi und eine implementierende Klasse in C++, die dann in den Delphi-Code durchgereicht wird.



  • Hallo audacia

    audacia schrieb:

    Stephan schrieb:

    Dann noch eine andere Frage, ist es möglich in Delphi eine Funktion aus einer C bzw H Datei aufzurufen?

    Wenn Delphi-Units und C++-Module im gleichen Projekt sind, dann nicht direkt, nur auf Umwegen. Der üblichste Umweg ist dabei die Definition eines Interfaces oder einer abstrakten Basisklasse in Delphi und eine implementierende Klasse in C++, die dann in den Delphi-Code durchgereicht wird.

    Habe versucht über interface eine Funtkion aus C++ in Delphi einzubinden, jedoch ohne Erfolg.

    Delphi Unit test.pas

    unit test;
    
    interface
    
    uses classes, SysUtils;
    	function EthernetInfo(sInfo: TStrings): integer; stdcall;
    
    implementation
    	function EthernetInfo(sInfo: TStrings): integer; stdcall; external;
    
    end.
    

    C++ Implementierung eth.cpp

    #include <winsock2.h>
    #include <iphlpapi.h>
    #include <vcl.h>
    #include "LogClass.h"
    
    #define MALLOC(x)   HeapAlloc(GetProcessHeap(), 0, (x))
    #define FREE(x)     HeapFree(GetProcessHeap(), 0, (x))
    
    #pragma comment(lib, "Iphlpapi.lib")
    extern "C" int __stdcall  EthernetInfo(TStrings *sInfo)
    {
        /* Declare and initialize variables */
        DWORD dwSize = 0;
        DWORD dwRetVal = 0;
    
        int i = 0;
        int n = 1;
    
        String sTmp;
    
        // Set the flags to pass to GetAdaptersAddresses
        ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
    
        // default to unspecified address family (both)
        ULONG family = AF_UNSPEC;
    
        LPVOID lpMsgBuf = NULL;
    
        PIP_ADAPTER_ADDRESSES pAddresses = NULL;
        ULONG outBufLen = 0;
    
        PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
        PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
    
        outBufLen = sizeof (IP_ADAPTER_ADDRESSES);
        pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen);
    
        // Make an initial call to GetAdaptersAddresses to get the
        // size needed into the outBufLen variable
        if (GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW)
        {
    ...
    }
    

    Als Fehler kommt beim Compilieren
    [DCC Fehler] test.pas(6): E2065 Ungenügende Forward- oder External-Deklaration: 'EthernetInfo'

    Kannst Du mir hier eventuell helfen?

    MfG Stephan



  • Wenn ich Interface sage, meine ich ein Interface, nicht die Interface-Sektion.

    Hier mal ein Beispiel (ungetestet, quick&dirty):

    unit MyCppIntfUnit;
    
    interface
    
    uses
      Classes;
    
    type
      ICppCallback = interface
      ['{E638C3EA-88A3-4CEC-B8EF-89428A0D3477}']
        function EthernetInfo (sInfo: TStrings): Integer;
        ...
      end;
    
    var
      CppCallback: ICppCallback;
    
    implementation
    
    end;
    
    // COMUtils.hpp
    
    #ifndef _COMUTILS_HPP
    #define _COMUTILS_HPP
    
    #include <windows.h>
    
    #define DO_QUERYINTERFACE(I)            \
        if (IID == __uuidof (I))            \
        {                                   \
            AddRef ();                      \
            *Obj = static_cast <I*> (this); \
            return S_OK;                    \
        }
    
    template <typename I>
        class TCppInterfacedObject : public I
    {
    private:
        ULONG refCount;
    public:
        TCppInterfacedObject (void)
         : refCount (0)
        {}
        virtual ~TCppInterfacedObject (void)
        {}
        HRESULT __stdcall QueryInterface (const GUID& IID, void** Obj)
        {
            *Obj = 0;
            DO_QUERYINTERFACE (I)
            DO_QUERYINTERFACE (IUnknown)
            return E_NOINTERFACE;
        }
        ULONG __stdcall AddRef (void)
        { return InterlockedIncrement ((volatile LONG*) &refCount); }
        ULONG __stdcall Release (void)
        {
            ULONG result = InterlockedDecrement ((volatile LONG*) &refCount);
            if (result == 0)
                delete this;
            return result;
        }
    };
    
    #endif // _COMUTILS_HPP
    
    // CppCallback.cpp
    
    #include <vcl.h>
    #pragma hdrstop
    
    #include "MyCppIntfUnit.hpp"
    #include "COMUtils.hpp"
    #include "EthernetInfo.h"
    
    class TCppCallback : public TCppInterfacedObject <ICppCallback>
    {
    public:
        int __fastcall EthernetInfo (TStrings* sInfo)
        { return ::EthernetInfo (sInfo); }
        ...
    };
    
    void registerCppCallback (void)
    {
        CppCallback = new TCppCallback;
    }
    
    #pragma startup registerCppCallback
    


  • Hallo aduacia

    Ok, dann war dies wohl ein Missevrständnis. Dachte, daß dies einfacher geht.
    So ganz habe ich das Beispiel noch nicht begriffen, werds mir jedoch nochmals genauer anschauen.

    Nochmals vielen Dank.
    MfG Stephan



  • audacia schrieb:

    Stephan schrieb:

    Habe versucht den MiniDump über Application->OnException zu generieren, allerdings bekomme ich von Exception nicht die Info EXCEPTION_POINTERS welche für MiniDumpWriteDump benötigt wird. Hat hierfür jemand eine Lösung?

    Um SetUnhandledExceptionFilter benutzen zu können, müßtest du die unkonditionellen try-except-Statements in der VCL umgehen. Der einzige Weg, der mir dazu einfällt, wäre durch einen Detour (alternativ kannst du natürlich die VCL neukompilieren 🤡 ). So spontan finde ich nur die Handler in TApplication.Run und TWinControl.MainWndProc; die müßtest du zur Laufzeit ersetzen.

    Zwischenzeitlich habe ich etwas neues gelernt:

    Mit System::JITEnable kannst du einstellen, wie sich die RTL bei unbehandelten Exceptions verhält. Mehr Kontext und ein kleines Beispiel dazu habe ich hier eingefügt.


Anmelden zum Antworten