кидание исключиния из winapi callback
От: rusted Беларусь  
Дата: 28.08.08 08:51
Оценка:
можно ли кидать исключения (обычные C++) из callback-ов winapi?

простой тест с WndProc показывает что с моей стороны все работает — деструкторы вызываются, исключение ловится. Но ведь WndProc вызывается из DispatchMessage, которая вряд ли подозревает что ее могут вот так прервать и она может не удалить какие-то свои данные.
Re: кидание исключиния из winapi callback
От: Pasternak  
Дата: 28.08.08 09:01
Оценка: 2 (1)
Здравствуйте, rusted, Вы писали:

R>можно ли кидать исключения (обычные C++) из callback-ов winapi?


R>простой тест с WndProc показывает что с моей стороны все работает — деструкторы вызываются, исключение ловится. Но ведь WndProc вызывается из DispatchMessage, которая вряд ли подозревает что ее могут вот так прервать и она может не удалить какие-то свои данные.


Исключения не должны пересекать границы модуля. Т.е. за пределы callback-ов winapi никакие исключения выпускать нельзя. Но при этом внутри самой функции исключениями пользоваться можно, но опять же, на границе они все должны быть перехвачены и обработаны.
Re: кидание исключиния из winapi callback
От: Кодт Россия  
Дата: 28.08.08 09:48
Оценка: 2 (1)
Здравствуйте, rusted, Вы писали:

R>можно ли кидать исключения (обычные C++) из callback-ов winapi?


Можно, но хорошего из этого ничего не выйдет.

R>простой тест с WndProc показывает что с моей стороны все работает — деструкторы вызываются, исключение ловится. Но ведь WndProc вызывается из DispatchMessage, которая вряд ли подозревает что ее могут вот так прервать и она может не удалить какие-то свои данные.


Если С++ные исключения реализованы поверх структурных, то произойдёт следующее:
— возбуждается структурное исключение
— С++ная программа обрабатывает его, разматывая стек
— дальше уже сам виндоуз обрабатывает его (если он это собирался делать)
Тут возможны 3 варианта:
1. Исключение проигнорировано (либо внутри винапишного кода не был добавлен хэндлер, либо хэндлер пробросил исключение дальше). Тогда оно прилетит к следующему хэндлеру в твоём коде, вызывавшем апишную функцию. Дальше всё в порядке.
2. Исключение поглощено, а апишная функция продолжила работу либо вернула код ошибки. Как следствие, объект С++ного исключения утёк, а сама механика C++ных исключений осталась в промежуточном состоянии. Дальнейшее поведение не определено.
3. Исключение проигнорировано, но обработчиков больше нет (например, это был бросок из функции потока). Программа с треском валится.
Перекуём баги на фичи!
Re[2]: кидание исключиния из winapi callback
От: Alexander G Украина  
Дата: 28.08.08 11:58
Оценка: +2
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, rusted, Вы писали:


К>Если С++ные исключения реализованы поверх структурных, то произойдёт следующее:

К>- возбуждается структурное исключение
К>- С++ная программа обрабатывает его, разматывая стек
К>- дальше уже сам виндоуз обрабатывает его (если он это собирался делать)
К>Тут возможны 3 варианта:
К>1. Исключение проигнорировано (либо внутри винапишного кода не был добавлен хэндлер, либо хэндлер пробросил исключение дальше). Тогда оно прилетит к следующему хэндлеру в твоём коде, вызывавшем апишную функцию. Дальше всё в порядке.
К>2. Исключение поглощено, а апишная функция продолжила работу либо вернула код ошибки. Как следствие, объект С++ного исключения утёк, а сама механика C++ных исключений осталась в промежуточном состоянии. Дальнейшее поведение не определено.
К>3. Исключение проигнорировано, но обработчиков больше нет (например, это был бросок из функции потока). Программа с треском валится.

Можно ещё уточнить по первому пункту, что код внутри windows может быть exception-safe, а может и не быть, тогда возможна, например, утечка памяти вместо "всё в порядке", несмотря на то, что исключение вернулось. Думаю, среди кучи WinAPI колбэков и вызовов COMовских интерфейсов из кода Windows такие случаи найдутся.
Русский военный корабль идёт ко дну!
Re[2]: кидание исключиния из winapi callback
От: Юрий Жмеренецкий ICQ 380412032
Дата: 28.08.08 18:30
Оценка: 43 (4)
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, rusted, Вы писали:


R>>можно ли кидать исключения (обычные C++) из callback-ов winapi?


К>Можно, но хорошего из этого ничего не выйдет.


К>Тут возможны 3 варианта:

...

Видел еще такое:
Выпущенное из WndProc(WM_CREATE) исключение(EXCEPTION_ACCESS_VIOLATION) трансформировалось(в специфических условиях) в другое исключение с кодом STATUS_SXS_EARLY_DEACTIVATION внутри функции DeactivateActCtx. Имхо, это связано с утечкой контекстов активации внутри CreateWindow в присутствии исключений.

Можно сделать #define ISOLATION_AWARE_ENABLED 1
и походить отладчиком внутри CreateWindow. Там будет сюрприз в виде обертки IsolationAwareCreateWindowEx(A/W).

Так более наглядно:
//...
for(;;) 
{
  try
  {
    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
    
    if(!hWnd) // Приблизительно после 1000 итераций вернется NULL
    {
      Sleep(INFINITE); // Тормозим, чтобы понаблюдать за результатами
      return FALSE;
    }

  }catch(...)
  {
  }
}
//...

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message) 
  {
    case WM_CREATE:                  // вызывается из CreateWindow
      throw std::exception("boom"); 
    break;
...

PS. этот код убивает W2k3 Server, блокируя создание любых окон до завершения процесса. Помогает только _заранее_ открытая консоль + 'taskkill /IM test.exe /F'.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.