Unterschiede im Ausnahmebehandlungsverhalten unter /CLR

Grundlegende Konzepte in der Verwendung verwalteter Ausnahmen erläutert die Ausnahmebehandlung in verwalteten Anwendungen. In diesem Thema werden unterschiede vom Standardverhalten der Ausnahmebehandlung und einige Einschränkungen ausführlich erläutert. Weitere Informationen finden Sie unter The _set_se_translator Function.

Springen aus einem endgültigen Block

In systemeigenem C/C++-Code ist das Springen aus einem __finally-Block mithilfe der strukturierten Ausnahmebehandlung (SEH) zulässig, obwohl eine Warnung erzeugt wird. Unter "/clr" verursacht das Springen aus einem endgültigen Block einen Fehler:

// clr_exception_handling_4.cpp
// compile with: /clr
int main() {
   try {}
   finally {
      return 0;   // also fails with goto, break, continue
    }
}   // C3276

Auslösen von Ausnahmen innerhalb eines Ausnahmefilters

Wenn während der Verarbeitung eines Ausnahmefilters innerhalb von verwaltetem Code eine Ausnahme ausgelöst wird, wird die Ausnahme abgefangen und behandelt, als ob der Filter "0" zurückgibt.

Dies ist im Gegensatz zum Verhalten im systemeigenen Code, bei dem eine geschachtelte Ausnahme ausgelöst wird, das ExceptionRecord-Feld in der EXCEPTION_RECORD-Struktur (wie von GetExceptionInformation zurückgegeben) festgelegt wird, und das ExceptionFlags-Feld legt das 0x10 Bit fest. Im folgenden Beispiel wird dieser Unterschied im Verhalten veranschaulicht:

// clr_exception_handling_5.cpp
#include <windows.h>
#include <stdio.h>
#include <assert.h>

#ifndef false
#define false 0
#endif

int *p;

int filter(PEXCEPTION_POINTERS ExceptionPointers) {
   PEXCEPTION_RECORD ExceptionRecord =
                     ExceptionPointers->ExceptionRecord;

   if ((ExceptionRecord->ExceptionFlags & 0x10) == 0) {
      // not a nested exception, throw one
      *p = 0; // throw another AV
   }
   else {
      printf("Caught a nested exception\n");
      return 1;
    }

   assert(false);

   return 0;
}

void f(void) {
   __try {
      *p = 0;   // throw an AV
   }
   __except(filter(GetExceptionInformation())) {
      printf_s("We should execute this handler if "
                 "compiled to native\n");
    }
}

int main() {
   __try {
      f();
   }
   __except(1) {
      printf_s("The handler in main caught the "
               "exception\n");
    }
}

Ausgabe

Caught a nested exception
We should execute this handler if compiled to native

Nicht zugeordnete Rethrows

/clr unterstützt kein Erneutes Drosseln einer Ausnahme außerhalb eines Catch-Handlers (auch als nicht zugeordnetes Rethrow bezeichnet). Ausnahmen dieses Typs werden als C++-Standardumthrow behandelt. Wenn beim Auftreten einer aktiven verwalteten Ausnahme eine nicht zugeordnete Neubefüllung auftritt, wird die Ausnahme als C++-Ausnahme umschlossen und dann erneut gekrappt. Ausnahmen dieses Typs können nur als Ausnahme vom Typ SEHExceptionabgefangen werden.

Im folgenden Beispiel wird eine verwaltete Ausnahme als C++-Ausnahme veranschaulicht:

// clr_exception_handling_6.cpp
// compile with: /clr
using namespace System;
#include <assert.h>
#include <stdio.h>

void rethrow( void ) {
   // This rethrow is a dissasociated rethrow.
   // The exception would be masked as SEHException.
   throw;
}

int main() {
   try {
      try {
         throw gcnew ApplicationException;
      }
      catch ( ApplicationException^ ) {
         rethrow();
         // If the call to rethrow() is replaced with
         // a throw statement within the catch handler,
         // the rethrow would be a managed rethrow and
         // the exception type would remain
         // System::ApplicationException
      }
   }

    catch ( ApplicationException^ ) {
      assert( false );

      // This will not be executed since the exception
      // will be masked as SEHException.
    }
   catch ( Runtime::InteropServices::SEHException^ ) {
      printf_s("caught an SEH Exception\n" );
    }
}

Ausgabe

caught an SEH Exception

Ausnahmefilter und EXCEPTION_CONTINUE_EXECUTION

Wenn ein Filter in einer verwalteten Anwendung zurückgegeben EXCEPTION_CONTINUE_EXECUTION wird, wird er so behandelt, als ob der zurückgegebene Filter zurückgegeben wird EXCEPTION_CONTINUE_SEARCH. Weitere Informationen zu diesen Konstanten finden Sie unter try-except-Anweisung.

Im folgenden Beispiel wird dieser Unterschied veranschaulicht:

// clr_exception_handling_7.cpp
#include <windows.h>
#include <stdio.h>
#include <assert.h>

int main() {
   int Counter = 0;
   __try {
      __try  {
         Counter -= 1;
         RaiseException (0xe0000000|'seh',
                         0, 0, 0);
         Counter -= 2;
      }
      __except (Counter) {
         // Counter is negative,
         // indicating "CONTINUE EXECUTE"
         Counter -= 1;
      }
    }
    __except(1) {
      Counter -= 100;
   }

   printf_s("Counter=%d\n", Counter);
}

Ausgabe

Counter=-3

Die _set_se_translator-Funktion

Die Übersetzerfunktion, die durch einen Aufruf _set_se_translatorfestgelegt wird, wirkt sich nur auf Fänge im nicht verwalteten Code aus. Im folgenden Beispiel wird diese Einschränkung veranschaulicht:

// clr_exception_handling_8.cpp
// compile with: /clr /EHa
#include <iostream>
#include <windows.h>
#include <eh.h>
#pragma warning (disable: 4101)
using namespace std;
using namespace System;

#define MYEXCEPTION_CODE 0xe0000101

class CMyException {
public:
   unsigned int m_ErrorCode;
   EXCEPTION_POINTERS * m_pExp;

   CMyException() : m_ErrorCode( 0 ), m_pExp( NULL ) {}

   CMyException( unsigned int i, EXCEPTION_POINTERS * pExp )
         : m_ErrorCode( i ), m_pExp( pExp ) {}

   CMyException( CMyException& c ) : m_ErrorCode( c.m_ErrorCode ),
                                      m_pExp( c.m_pExp ) {}

   friend ostream& operator <<
                 ( ostream& out, const CMyException& inst ) {
      return out <<  "CMyException[\n" <<
             "Error Code: " << inst.m_ErrorCode <<  "]";
    }
};

#pragma unmanaged
void my_trans_func( unsigned int u, PEXCEPTION_POINTERS pExp ) {
   cout <<  "In my_trans_func.\n";
   throw CMyException( u, pExp );
}

#pragma managed
void managed_func() {
   try  {
      RaiseException( MYEXCEPTION_CODE, 0, 0, 0 );
   }
   catch ( CMyException x ) {}
   catch ( ... ) {
      printf_s("This is invoked since "
               "_set_se_translator is not "
               "supported when /clr is used\n" );
    }
}

#pragma unmanaged
void unmanaged_func() {
   try  {
      RaiseException( MYEXCEPTION_CODE,
                      0, 0, 0 );
   }
   catch ( CMyException x ) {
      printf("Caught an SEH exception with "
             "exception code: %x\n", x.m_ErrorCode );
    }
    catch ( ... ) {}
}

// #pragma managed
int main( int argc, char ** argv ) {
   _set_se_translator( my_trans_func );

   // It does not matter whether the translator function
   // is registered in managed or unmanaged code
   managed_func();
   unmanaged_func();
}

Ausgabe

This is invoked since _set_se_translator is not supported when /clr is used
In my_trans_func.
Caught an SEH exception with exception code: e0000101

Siehe auch

Ausnahmebehandlung
safe_cast
Ausnahmebehandlung in MSVC