Вложенные __try ...__ кроме пунктов, как это работает? - PullRequest
2 голосов
/ 24 мая 2019

Я имею дело с функцией и подфункцией, подфункция вызывается внутри функции.Оба имеют __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");
  }

Inв этом случае:
Когда do_something() идет не так, я вижу «общее исключение».
Когда do_something_else() идет не так, я также вижу «общее исключение», а это не то, что я хочу.

Что я хочу:
Когда do_something() идет не так, я хочу видеть «общее исключение».
Когда do_something_else() идет не так, я хочу видеть «конкретный случай».

Редактировать после замечания Бена Войта

Действительно, существует фильтр исключений, и в настоящее время проверяется код исключения для принятия решения о том, продолжать или нет, как вы можете видеть здесь:

if (Exception->ExceptionCode == STATUS_ACCESS_VIOLATION)
  return EXCEPTION_CONTINUE_SEARCH;

Однако я совершенно ничего не знаю о структуре и / или содержании ExceptionRecord и ContextRecord, двух входных параметров обработки исключений. Приведу пример того, как эти параметры выглядят вмой конкретный случай:

Исключительная запись:

-   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:

-   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 Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\include\excpt.h.Он содержит функцию _except_handler(), которая возвращает перечисление EXCEPTION_DISPOSITION, которое может быть ExceptionNestedException (я считаю, что это то, что я ищу).
Так что теперь вопрос превращается в:

Какие параметры мне нужно заполнить в функции _except_handler(), чтобы узнать, имею ли я дело с вложенным исключением (или кто-нибудь знает более простой способ сделать это)?

Ответы [ 3 ]

1 голос
/ 14 июня 2019
#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();
}

Подробности здесь

1 голос
/ 18 июня 2019

Вы можете использовать RaiseException.

Подробнее см. Использование структурированной обработки исключений (SEH) .

#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 );
  }
}
1 голос
/ 24 мая 2019

Ваш код как написано не компилируется. Вместо:

__except { ... }

вам нужно:

__except (EXCEPTION_EXECUTE_HANDLER) { ... }

Тогда все работает как нужно.

Живая демоверсия

...