Différences de comportement de gestion des exceptions sous /CLR
Concepts de base utilisant des exceptions managées traite de la gestion des exceptions dans les applications managées. Dans cette rubrique, les différences de comportement standard de la gestion des exceptions et restrictions sont présentées en détail. Pour plus d'informations sur les fonctions de traduction d'exceptions, consultez The _set_se_translator Function.
Ignorer enfin d'un bloc
En code natif de C/C++, il permet d'ignorer un bloc definally de à l'aide de la gestion des exceptions structurées (SEH) bien qu'il déclenche un avertissement. Sous /clr, ignorer d'un bloc de finally génère une erreur :
// clr_exception_handling_4.cpp
// compile with: /clr
int main() {
try {}
finally {
return 0; // also fails with goto, break, continue
}
} // C3276
Déclenchement d'exceptions dans un filtre d'exceptions
Lorsqu'une exception est levée pendant le traitement d'un filtre d'exceptions dans le code managé, l'exception est interceptée et traitée comme si retourne la valeur 0 de filtre.
Ce comportement diffère du comportement en code natif où une exception imbriquée est générée, le champ d'ExceptionRecord dans la structure d'EXCEPTION_RECORD (retourné par GetExceptionInformation) a la valeur, les ensembles de champs d'ExceptionFlags le bit 0x10. La différence est illustrée dans l'exemple suivant.
// 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");
}
}
Sortie
Caught a nested exception
We should execute this handler if compiled to native
Rethrows dissocié
/clr ne prend pas en charge rethrowing une exception en dehors d'un gestionnaire CATCH (appelé rethrow dissocié). Les exceptions de ce type sont traitées comme rethrow standard C++. Si un rethrow est dissocié lorsqu'il y a une exception managée active, l'exception est encapsulée comme exception puis rethrown du actuel ++ c. Les exceptions de ce type peuvent être interceptées comme exception de type System::SEHException.
L'exemple suivant illustre un rethrown managé d'exception comme exception actuelle ++ c :
// 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" );
}
}
Sortie
caught an SEH Exception
Filtres d'exceptions et EXCEPTION_CONTINUE_EXECUTION
Si un filtre retourne EXCEPTION_CONTINUE_EXECUTION dans une application managée, il est considéré comme si le filtre retournait EXCEPTION_CONTINUE_SEARCH. Pour plus d'informations sur ces constantes, consultez TRY-excepté l'instruction.
L'exemple suivant illustre ces différences clés.
// 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);
}
Sortie
Counter=-3
The_set_se_translator (fonction)
La fonction de transcodage, définie par un appel à _set_se_translator, catch d'attribut affecte uniquement en code non managé. L'exemple suivant illustre la procédure à suivre pour réaliser cette limitation :
// 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();
}
Sortie
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
Voir aussi
Référence
Gestion des exceptions en Visual C++