_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 GetExceptionCodeGetExceptionInformation 函数所返回的值。

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

另请参阅

异常处理例程
set_terminate
set_unexpected
terminate
unexpected