_set_se_translator
设置每线程回调函数以将 Win32 异常(C 结构化异常)转换为 C++ 类型化异常。
语法
_se_translator_function _set_se_translator(
_se_translator_function seTransFunction
);
参数
seTransFunction
指向您编写的 C 结构化异常转换器函数的指针。
返回值
返回指向由 _set_se_translator
注册的上一个转换器函数的指针,以便稍后能还原上一个函数。 如果之前未设置函数,则可使用返回值还原默认行为;此值可以为 nullptr
。
注解
_set_se_translator
函数提供一种将 Win32 异常(C 结构化异常)作为 C++ 类型异常处理的方法。 若要使每个 C 异常均由 C++ catch
处理程序处理,请先定义一个可以使用或从中派生的 C 异常包装器类,以将特定的类类型归于 C 异常。 若要使用此类,请安装自定义 C 异常转换器函数,该函数在每次引发 C 异常时由内部异常处理机制调用。 在转换器函数内,您可以引发可由匹配的 C++ catch
处理程序捕获的任意类型异常。
使用 _set_se_translator
时,必须使用 /EHa
选项。
若要指定自定义转换函数,请调用 _set_se_translator
并将你的转换函数的名称作为其参数。 对于具有 try
块的堆栈上的每个函数调用,将调用编写的转换器函数一次。 没有默认的转换器函数。
转换器函数只能是引发 C++ 类型的异常。 如果它在引发之外还执行了任何操作(例如,写入到日志文件),你的程序可能不会按预期那样运行,因为转换器函数的调用次数与平台相关。
在多线程环境中,单独为每个线程维护转换器函数。 每个新线程都需要安装它自己的转换器函数。 因此,每个线程都负责处理它自己的转换。 _set_se_translator
特定于一个线程;另一个 DLL 可安装不同的转换函数。
您编写的 seTransFunction
函数必须是本机编译的函数(而不是使用 /clr
编译的)。 它必须将一个无符号整数和一个指向 Win32 _EXCEPTION_POINTERS
结构的指针用作参数。 这些参数是通过调用 Win32 API GetExceptionCode
和 GetExceptionInformation
函数所返回的值。
typedef void (__cdecl *_se_translator_function)(unsigned int, struct _EXCEPTION_POINTERS* );
对于 _set_se_translator
,在动态链接到 CRT 时会有影响;进程中的另一个 DLL 可能调用 _set_se_translator
并将您的处理程序替换为它自己的处理程序。
在从托管代码(使用 /clr
编译的代码)或混合的本机和托管代码使用 _set_se_translator
时,转换器仅影响本机代码中生成的异常。 托管代码中生成的任何托管异常(例如,在引发 System::Exception
时)都不会通过转换器函数进行传送。 使用 Win32 函数 RaiseException
的托管代码中引发的异常或由系统异常(如被零除异常)引发的异常将通过转换器传送。
要求
例程 | 必需的标头 |
---|---|
_set_se_translator |
<eh.h> |
有关兼容性的详细信息,请参阅 兼容性。
示例:捕获 __try
异常错误
此示例包装调用以设置结构化异常转换器并在 RAII
类中还原旧的转换器 Scoped_SE_Translator
。 此类允许你将特定于范围的转换器作为单个声明引入。 在控件离开作用域后,类析构函数将还原原始转换器。
// 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.
示例:捕获 SE_Exception
错误
虽然 _set_se_translator
提供的功能在托管代码中不可用,但只要使用 /clr
指示本机代码,就可以在本机代码中使用此映射,即使本机代码正在 #pragma unmanaged
开关下编译也是如此。 如果要映射的托管代码中引发了结构化异常,则必须使用 #pragma unmanaged
标记生成和处理此异常的代码。 以下代码演示了可能的用途。 有关详细信息,请参阅 Pragma 指令以及 __pragma
和 _Pragma
关键字。
// 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