嵌套的 __try...__except 子句,这是如何工作的?
Nested __try...__except clauses, how does this work?
我正在处理一个函数和一个子函数,子函数在函数内被调用。两者都有一个 __try .. __except
子句,我想看看函数的一般异常处理,以及子函数的具体异常处理,换句话说:
int function(){
__try{
do_something();
return subfunction();
} __except (Exception_Execute_Handler_Something()){
show("general exception");
}
int subfunction(){
__try{
return do_something_else();
} __except (Exception_Execute_Handler_Something_Else()){
show("specific case");
}
在这种情况下:
当 do_something()
出错时,我看到 "general exception".
当do_something_else()
出错的时候,我也看到了"general exception",这不是我想要的
我要的是:
当do_something()
出错时,我想看到“一般异常。
do_something_else()
出问题的时候,想看"specific case".
根据 Ben Voight 的评论进行编辑
确实有一个异常过滤器,目前正在检查异常代码以决定是否继续,如您所见:
if (Exception->ExceptionCode == STATUS_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
然而,我对异常处理的两个输入参数ExceptionRecord
和ContextRecord
的结构and/or内容一无所知。在此,我举例说明这些参数在我的特定情况下是什么样的:
异常记录:
- ExceptionRecord 0x0eecdec8 {ExceptionCode=3221225620 ExceptionFlags=0 ExceptionRecord=0x00000000 <NULL> ...} _EXCEPTION_RECORD *
ExceptionCode 3221225620 unsigned long // I guess this means division by zero
ExceptionFlags 0 unsigned long
+ ExceptionRecord 0x00000000 <NULL> _EXCEPTION_RECORD *
ExceptionAddress 0x002c1993 {<Application>.exe!CClass::Main_Method(CInputClass & params), Line 46} void *
NumberParameters 0 unsigned long
+ ExceptionInformation 0x0eecdedc {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} unsigned long[15]
上下文记录:
- ContextRecord 0x0eecdf18 {ContextFlags=65543 Dr0=0 Dr1=0 ...} _CONTEXT *
ContextFlags 65543 unsigned long
Dr0 0 unsigned long
Dr1 0 unsigned long
Dr2 0 unsigned long
Dr3 0 unsigned long
Dr6 0 unsigned long
Dr7 0 unsigned long
- FloatSave {ControlWord=0 StatusWord=0 TagWord=0 ...} _FLOATING_SAVE_AREA
ControlWord 0 unsigned long
StatusWord 0 unsigned long
TagWord 0 unsigned long
ErrorOffset 0 unsigned long
ErrorSelector 0 unsigned long
DataOffset 0 unsigned long
DataSelector 0 unsigned long
+ RegisterArea 0x0eecdf50 "" unsigned char[80] // all are zero
Spare0 0 unsigned long
SegGs 43 unsigned long
SegFs 83 unsigned long
SegEs 43 unsigned long
SegDs 43 unsigned long
Edi 80923496 unsigned long
Esi 250405956 unsigned long
Ebx 0 unsigned long
Edx 0 unsigned long
Ecx 0 unsigned long
Eax 1 unsigned long
Ebp 250405884 unsigned long
Eip 2890131 unsigned long
SegCs 35 unsigned long
EFlags 66118 unsigned long
Esp 250405880 unsigned long
SegSs 43 unsigned long
+ ExtendedRegisters 0x0eecdfe4 "\x2 \x1" unsigned char[512] // at first sight, not readable
现在我的问题变成了:
如果我已经在另一个 __try..__except
子句中,我会 return EXCEPTION_CONTINUE_SEARCH
.
有谁知道我可以使用所提到的 ExceptionRecord
或 ContextRecord
属性中的哪一个来确定我是否已经在另一个 __try..__except
子句中?
再补充一些信息后重新编辑
我刚刚找到 EXCEPTION_DISPOSITION
,出现在 C:\Program Files (x86)\Microsoft Visual Studio17\Professional\VC\Tools\MSVC.16.27023\include\excpt.h
中。这包含函数 _except_handler()
,其中 returns 是一个 EXCEPTION_DISPOSITION
枚举,它可以是 ExceptionNestedException
(我相信这就是我要找的那个)。
所以现在问题变成了:
What parameters do I need to fill in in the function _except_handler()
in order to know if I'm dealing with a nested exception (or does somebody know an easier way to get this done)?
您编写的代码无法编译。而不是:
__except { ... }
你需要:
__except (EXCEPTION_EXECUTE_HANDLER) { ... }
然后它就如愿以偿了。
#include <iostream>
#include <Windows.h>
int do_something_else()
{
*(reinterpret_cast<int*>(0)) = 1;
return 0;
}
int do_something()
{
return 0;
}
int subfunction();
int32_t ReportCrash(LPEXCEPTION_POINTERS ExceptionInfo) //exception and context pointers are hrere
{
return EXCEPTION_EXECUTE_HANDLER;
}
int function()
{
__try
{
do_something();
return subfunction();
}
__except (ReportCrash(GetExceptionInformation()))
{
std::cout << ("general exception");
}
return 0;
}
int subfunction()
{
__try
{
return do_something_else();
}
__except (ReportCrash(GetExceptionInformation()))
{
std::cout << ("specific case");
}
return 0;
}
int main()
{
std::cout << "Hello World!\n";
function();
}
详情为here
你可以使用 RaiseException。
#define SUBCODE 0x1000
int Filter(LPEXCEPTION_POINTERS exceptionPointers,DWORD& code) {
code = exceptionPointers->ExceptionRecord->ExceptionCode;
return EXCEPTION_EXECUTE_HANDLER;
}
int function(){
DWORD code;
__try{
do_something();
return subfunction();
} __except ( Filter( GetExceptionInformation(), code ) ){
if (code == SUBCODE) {
show("specific case");
} else {
show("generic code");
}
}
}
int subfunction(){
__try{
return do_something_else();
} __except (EXCEPTION_EXECUTE_HANDLER){
RaiseException( SUBCODE , 0, 0 , NULL );
}
}
EXCEPTION_RECORD 结构有一个名为 ExceptionRecord 的成员,它是指向另一个 EXCEPTION_RECORD 的指针...这就是您判断是否有嵌套异常的方式。
我正在处理一个函数和一个子函数,子函数在函数内被调用。两者都有一个 __try .. __except
子句,我想看看函数的一般异常处理,以及子函数的具体异常处理,换句话说:
int function(){
__try{
do_something();
return subfunction();
} __except (Exception_Execute_Handler_Something()){
show("general exception");
}
int subfunction(){
__try{
return do_something_else();
} __except (Exception_Execute_Handler_Something_Else()){
show("specific case");
}
在这种情况下:
当 do_something()
出错时,我看到 "general exception".
当do_something_else()
出错的时候,我也看到了"general exception",这不是我想要的
我要的是:
当do_something()
出错时,我想看到“一般异常。
do_something_else()
出问题的时候,想看"specific case".
根据 Ben Voight 的评论进行编辑
确实有一个异常过滤器,目前正在检查异常代码以决定是否继续,如您所见:
if (Exception->ExceptionCode == STATUS_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
然而,我对异常处理的两个输入参数ExceptionRecord
和ContextRecord
的结构and/or内容一无所知。在此,我举例说明这些参数在我的特定情况下是什么样的:
异常记录:
- ExceptionRecord 0x0eecdec8 {ExceptionCode=3221225620 ExceptionFlags=0 ExceptionRecord=0x00000000 <NULL> ...} _EXCEPTION_RECORD *
ExceptionCode 3221225620 unsigned long // I guess this means division by zero
ExceptionFlags 0 unsigned long
+ ExceptionRecord 0x00000000 <NULL> _EXCEPTION_RECORD *
ExceptionAddress 0x002c1993 {<Application>.exe!CClass::Main_Method(CInputClass & params), Line 46} void *
NumberParameters 0 unsigned long
+ ExceptionInformation 0x0eecdedc {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} unsigned long[15]
上下文记录:
- ContextRecord 0x0eecdf18 {ContextFlags=65543 Dr0=0 Dr1=0 ...} _CONTEXT *
ContextFlags 65543 unsigned long
Dr0 0 unsigned long
Dr1 0 unsigned long
Dr2 0 unsigned long
Dr3 0 unsigned long
Dr6 0 unsigned long
Dr7 0 unsigned long
- FloatSave {ControlWord=0 StatusWord=0 TagWord=0 ...} _FLOATING_SAVE_AREA
ControlWord 0 unsigned long
StatusWord 0 unsigned long
TagWord 0 unsigned long
ErrorOffset 0 unsigned long
ErrorSelector 0 unsigned long
DataOffset 0 unsigned long
DataSelector 0 unsigned long
+ RegisterArea 0x0eecdf50 "" unsigned char[80] // all are zero
Spare0 0 unsigned long
SegGs 43 unsigned long
SegFs 83 unsigned long
SegEs 43 unsigned long
SegDs 43 unsigned long
Edi 80923496 unsigned long
Esi 250405956 unsigned long
Ebx 0 unsigned long
Edx 0 unsigned long
Ecx 0 unsigned long
Eax 1 unsigned long
Ebp 250405884 unsigned long
Eip 2890131 unsigned long
SegCs 35 unsigned long
EFlags 66118 unsigned long
Esp 250405880 unsigned long
SegSs 43 unsigned long
+ ExtendedRegisters 0x0eecdfe4 "\x2 \x1" unsigned char[512] // at first sight, not readable
现在我的问题变成了:
如果我已经在另一个 __try..__except
子句中,我会 return EXCEPTION_CONTINUE_SEARCH
.
有谁知道我可以使用所提到的 ExceptionRecord
或 ContextRecord
属性中的哪一个来确定我是否已经在另一个 __try..__except
子句中?
再补充一些信息后重新编辑
我刚刚找到 EXCEPTION_DISPOSITION
,出现在 C:\Program Files (x86)\Microsoft Visual Studio17\Professional\VC\Tools\MSVC.16.27023\include\excpt.h
中。这包含函数 _except_handler()
,其中 returns 是一个 EXCEPTION_DISPOSITION
枚举,它可以是 ExceptionNestedException
(我相信这就是我要找的那个)。
所以现在问题变成了:
What parameters do I need to fill in in the function
_except_handler()
in order to know if I'm dealing with a nested exception (or does somebody know an easier way to get this done)?
您编写的代码无法编译。而不是:
__except { ... }
你需要:
__except (EXCEPTION_EXECUTE_HANDLER) { ... }
然后它就如愿以偿了。
#include <iostream>
#include <Windows.h>
int do_something_else()
{
*(reinterpret_cast<int*>(0)) = 1;
return 0;
}
int do_something()
{
return 0;
}
int subfunction();
int32_t ReportCrash(LPEXCEPTION_POINTERS ExceptionInfo) //exception and context pointers are hrere
{
return EXCEPTION_EXECUTE_HANDLER;
}
int function()
{
__try
{
do_something();
return subfunction();
}
__except (ReportCrash(GetExceptionInformation()))
{
std::cout << ("general exception");
}
return 0;
}
int subfunction()
{
__try
{
return do_something_else();
}
__except (ReportCrash(GetExceptionInformation()))
{
std::cout << ("specific case");
}
return 0;
}
int main()
{
std::cout << "Hello World!\n";
function();
}
详情为here
你可以使用 RaiseException。
#define SUBCODE 0x1000
int Filter(LPEXCEPTION_POINTERS exceptionPointers,DWORD& code) {
code = exceptionPointers->ExceptionRecord->ExceptionCode;
return EXCEPTION_EXECUTE_HANDLER;
}
int function(){
DWORD code;
__try{
do_something();
return subfunction();
} __except ( Filter( GetExceptionInformation(), code ) ){
if (code == SUBCODE) {
show("specific case");
} else {
show("generic code");
}
}
}
int subfunction(){
__try{
return do_something_else();
} __except (EXCEPTION_EXECUTE_HANDLER){
RaiseException( SUBCODE , 0, 0 , NULL );
}
}
EXCEPTION_RECORD 结构有一个名为 ExceptionRecord 的成员,它是指向另一个 EXCEPTION_RECORD 的指针...这就是您判断是否有嵌套异常的方式。