_set_se_translator
Set a per-thread callback function to translate Win32 exceptions (C structured exceptions) into C++ typed exceptions.
Syntax
_se_translator_function _set_se_translator(
_se_translator_function seTransFunction
);
Parameters
seTransFunction
Pointer to a C structured exception translator function that you write.
Return value
Returns a pointer to the previous translator function registered by _set_se_translator
, so that the previous function can be restored later. If no previous function has been set, the return value can be used to restore the default behavior; this value can be nullptr
.
Remarks
The _set_se_translator
function provides a way to handle Win32 exceptions (C structured exceptions) as C++ typed exceptions. To allow each C exception to be handled by a C++ catch
handler, first define a C exception wrapper class that can be used, or derived from, to attribute a specific class type to a C exception. To use this class, install a custom C exception translator function that is called by the internal exception-handling mechanism each time a C exception is raised. Within your translator function, you can throw any typed exception that can be caught by a matching C++ catch
handler.
You must use the /EHa
option when you use _set_se_translator
.
To specify a custom translation function, call _set_se_translator
using the name of your translation function as its argument. The translator function that you write is called once for each function invocation on the stack that has try
blocks. There's no default translator function.
Your translator function should do no more than throw a C++ typed exception. If it does anything in addition to throwing (such as writing to a log file, for example) your program might not behave as expected because the number of invocations of the translator function is platform-dependent.
In a multithreaded environment, translator functions are maintained separately for each thread. Each new thread needs to install its own translator function. Thus, each thread is in charge of its own translation handling. _set_se_translator
is specific to one thread--another DLL can install a different translation function.
The seTransFunction
function that you write must be a native-compiled function (not compiled with /clr
). It must take an unsigned integer and a pointer to a Win32 _EXCEPTION_POINTERS
structure as arguments. The arguments are the return values of calls to the Win32 API GetExceptionCode
and GetExceptionInformation
functions, respectively.
typedef void (__cdecl *_se_translator_function)(unsigned int, struct _EXCEPTION_POINTERS* );
For _set_se_translator
, there are implications when dynamically linking to the CRT; another DLL in the process might call _set_se_translator
and replace your handler with its own.
When you use _set_se_translator
from managed code (code compiled with /clr
) or mixed native and managed code, the translator affects exceptions generated in native code only. Any managed exceptions generated in managed code (such as when raising System::Exception
) aren't routed through the translator function. Exceptions raised in managed code using the Win32 function RaiseException
or caused by a system exception like a divide by zero exception are routed through the translator.
Requirements
Routine | Required header |
---|---|
_set_se_translator |
<eh.h> |
For more compatibility information, see Compatibility.
Example: Catch __try
exception error
This sample wraps the calls to set a structured exception translator and to restore the old one in an RAII
class, Scoped_SE_Translator
. This class lets you introduce a scope-specific translator as a single declaration. The class destructor restores the original translator when control leaves the scope.
// crt_settrans.cpp
// compile with: cl /W4 /EHa crt_settrans.cpp
#include <stdio.h>
#include <windows.h>
#include <eh.h>
#include <exception>
class SE_Exception : public std::exception
{
private:
const unsigned int nSE;
public:
SE_Exception() noexcept : SE_Exception{ 0 } {}
SE_Exception( unsigned int n ) noexcept : nSE{ n } {}
unsigned int getSeNumber() const noexcept { return nSE; }
};
class Scoped_SE_Translator
{
private:
const _se_translator_function old_SE_translator;
public:
Scoped_SE_Translator( _se_translator_function new_SE_translator ) noexcept
: old_SE_translator{ _set_se_translator( new_SE_translator ) } {}
~Scoped_SE_Translator() noexcept { _set_se_translator( old_SE_translator ); }
};
void SEFunc()
{
__try
{
printf( "In __try, about to force exception\n" );
int x = 5;
int y = 0;
int *p = &y;
*p = x / *p;
}
__finally
{
printf( "In __finally\n" );
}
}
void trans_func( unsigned int u, EXCEPTION_POINTERS* )
{
throw SE_Exception( u );
}
int main()
{
Scoped_SE_Translator scoped_se_translator{ trans_func };
try
{
SEFunc();
}
catch( const SE_Exception& e )
{
printf( "Caught a __try exception, error %8.8x.\n", e.getSeNumber() );
}
}
In __try, about to force exception
In __finally
Caught a __try exception, error c0000094.
Example: Catch SE_Exception
error
Although the functionality provided by _set_se_translator
isn't available in managed code, it's possible to use this mapping in native code, even if that native code is in a compilation under the /clr
switch, as long as the native code is indicated using #pragma unmanaged
. If a structured exception is being thrown in managed code that is to be mapped, the code that generates and handles the exception must be marked #pragma unmanaged
. The following code shows a possible use. For more information, see Pragma directives and the __pragma
and _Pragma
keywords.
// crt_set_se_translator_clr.cpp
// compile with: cl /W4 /clr crt_set_se_translator_clr.cpp
#include <windows.h>
#include <eh.h>
#include <stdio.h>
#include <exception>
int thrower_func( int i ) {
int y = 0;
int *p = &y;
*p = i / *p;
return 0;
}
class SE_Exception : public std::exception
{
private:
const unsigned int nSE;
public:
SE_Exception() noexcept : SE_Exception{ 0 } {}
SE_Exception( unsigned int n ) noexcept : nSE{ n } {}
unsigned int getSeNumber() const noexcept { return nSE; }
};
class Scoped_SE_Translator
{
private:
const _se_translator_function old_SE_translator;
public:
Scoped_SE_Translator( _se_translator_function new_SE_translator ) noexcept
: old_SE_translator{ _set_se_translator( new_SE_translator ) } {}
~Scoped_SE_Translator() noexcept { _set_se_translator( old_SE_translator ); }
};
#pragma unmanaged
void my_trans_func( unsigned int u, PEXCEPTION_POINTERS )
{
throw SE_Exception( u );
}
void DoTest()
{
try
{
thrower_func( 10 );
}
catch( const SE_Exception& e )
{
printf( "Caught SE_Exception, error %8.8x\n", e.getSeNumber() );
}
catch(...)
{
printf( "Caught unexpected SEH exception.\n" );
}
}
#pragma managed
int main() {
Scoped_SE_Translator scoped_se_translator{ my_trans_func };
DoTest();
}
Caught SE_Exception, error c0000094
See also
Exception handling routines
set_terminate
set_unexpected
terminate
unexpected