ðH geocities.com /Vienna/Stage/4793/excp6.htm geocities.com/Vienna/Stage/4793/excp6.htm delayed x ØÕJ ÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÈ 0¤£ Ð1 OK text/html ÏBmo Ð1 ÿÿÿÿ b‰.H Mon, 18 Dec 2000 15:42:06 GMT æ Mozilla/4.5 (compatible; HTTrack 3.0x; Windows 98) en, * ØÕJ Ð1
|
SEH - Structured Exception HandlingSEH ist ein Satz von Funktionen, die Windows, also das Betriebssystem, bereitstellt. In Visual C++ werden diese Funktionen und Services in nicht standardisierten Schlüsselwörtern bzw. Routinen gekapselt. SEH ist also nicht auf C++ beschränkt, sondern kann über die WinAPI angesprochen werden. Doch hier beschränken wir uns auf die Implementation im VC++.
Um diese Spracherweiterung nutzen zu können, muß man unter Projekt Settings unter C++/Customize den Schalter "Disable Lanugage Extensions" ausgeschaltet lassen. Weiterhin bietet Microsoft das Headerfile excpt.h, welches von windows.h einbezogen wird. Dort sind interne als auch folgende Definitionen zu finden:
SyntaxDie Hauptstruktur innerhalb SEH ist der try-Block. Er kann wie folgt aussehen: __try { statements } handlerwobei handler entweder __except (filterexpression) { statements } // exception handleroder __finally { statements } // termination handlersein kann. Um einen try-Block zu verlassen kann man folgendes kodieren: __try {... __leave; ... } Hinweise:
SemantikDie fünf Phasen einer Exception werden mit SEH wie folgt abgebildet.
Eine Exception wird vom User wie folgt geworfen: VOID RaiseException( DWORD dwExceptionCode, // exception codeDWORD dwExceptionFlags, // continuable exception flag DWORD nNumberOfArguments, // number of arguments in array CONST DWORD *lpArguments // address of array of arguments );
dwExceptionCode Hier kann ein selbstdefinierter Exceptioncode übergeben werden.. Innerhalb des exception blocks des Handlers kann auf dieser Code mit der Funktion GetExceptionCode() abgefragt werden.. Hinweis: Das System löscht das 28. Bit von dwExceptionCode. Dieses Bit ist ein reserviertes Exceptionbit, welches das System für eigene Zwecke benutzt. Zum Beispiel würde dwExceptionCode mit dem Wert 0xFFFFFFFF nach dem Aufruf von RaiseException eine Meldung liefern, daß der Wert nun 0xEFFFFFFF ist. dwExceptionFlags Spezifiziert die Exception Flags. Der Wert Null bezeichnet eine fortführbare Exception bzw. EXCEPTION_NONCONTINUABLE für eine nichtfortführbare. Versucht man bei einer nichtfortführbaren Exception trotzdem die Fortführung, kriegt man eine EXCEPTION_NONCONTINUABLE_EXCEPTION um die Ohren gehauen. nNumberOfArguments Die Anzahl der Argumente im lpArguments Array. Die Anzahl darf EXCEPTION_MAXIMUM_PARAMETERS nicht übersteigen. Der Parameter wird ignoriert, wenn lpArguments NULL ist. lpArguments Pointer auf ein Array von 32-bit Argumenten. Dieser Parameter kann NULL sein. Diese Argumente können userspezifische Daten enthalten, um im Exceptionhandler korrekt verarbeitet werden zu können. Exceptionhandling und FilterSobald eine Exception geworfen bzw. "geraised" wird, werden alle Exceptionhandler, also die Handler mit __except, den Callerstack hinauf gesucht und deren Filterwert geprüft. Was passiert, ist vom filter value abhängig. <excpt.h> definiert drei filter values:
Hinweis: EXCEPTION_CONTINUE_EXECUTION sollte vorsichtig verwendet werden! Auch wenn das Aufsetzen an der Stelle, an der die Exception auftrat, ein nettes Feature ist, sollte man es nicht ohne folgende Warnung benutzen. Abhängig vom Compiler könnte es sein, daß z.B. für die Anweisung *lpBuffer = 'J'; zwei Maschinenbefehle generiert werden. Die erste lädt den Inhalt von lpBuffer in ein Register, und die zweite versucht, ein 'J' in die Adresse zu schreiben. Die zweite Anweisung löst nun die Ausnahme aus. Der dafür vorgesehene Filter fängt diese Ausnahme ab, korrigiert den Wert in lpBuffer und weist das System an, die zweite Anweisung zu wiederholen. Das Problem hier ist, daß der Inhalt des Registers nicht mit dem neuen Wert aktualisiert wird und das erneute Ausführen der Anweisung damit wieder eine Ausnahme auslöst. Moderne Compiler werden dieses Problem handlen können, aber trotzdem kann es sein, daß man bei gewissen unerklärbaren Fehlern bis in den Assemblercode schauen muß, um diese zu erkennen. TerminationhandlingWie es der Name schon sagt, werden Terminationhandler, also die mit dem Schlüsselwort __finally, gerufen, wenn eine termination exception geworfen wird. Ihre Rolle ist hauptsächlich das Aufräumen und sie könnten mit dem Destruktorcode eines Objekts verglichen werden. Dieser Vergleich hinkt aber, da diese Handler nicht nur im Falle einer Exception, sondern auch im normalen Programmverlauf verarbeitet werden. Dieser Umstand bedeutet auch, daß so ein Handler nicht unbedingt weiß, ob er aufgrund einer geworfenen exception bzw. einer korrekten Verarbeitung durchlaufen wird. Um zu bestimmen, warum diese Funktion gerufen wurde, gibt es die Funktion AbnormalTermination(). Diese liefert TRUE, wenn keine Exception geworfen wurde, sonst FALSE. Hinweis: Diese Funktion kann ausschließlich im Handler benutzt werden und nicht in einer Funktion, die in dem Handler gerufen wird.
[1]
Dies führt bei SEH-Verfechtern zu Verwirrung, während die andere Alternative
Standard C++ Programmierern Kopfzerbrechen bereitet, da sie hinter try ihr C++
Schlüsselwort erwarten. Deswegen wird angeraten, wenn man dieses Headerfile
nutzt, #undef try zu kodieren und statt den Pseudoschlüsselwörtern die tatsächlichen
Schlüsselwörter zu nutzen (also __try statt try).
|