можно ли кидать исключения (обычные C++) из callback-ов winapi?
простой тест с WndProc показывает что с моей стороны все работает — деструкторы вызываются, исключение ловится. Но ведь WndProc вызывается из DispatchMessage, которая вряд ли подозревает что ее могут вот так прервать и она может не удалить какие-то свои данные.
Здравствуйте, rusted, Вы писали:
R>можно ли кидать исключения (обычные C++) из callback-ов winapi?
R>простой тест с WndProc показывает что с моей стороны все работает — деструкторы вызываются, исключение ловится. Но ведь WndProc вызывается из DispatchMessage, которая вряд ли подозревает что ее могут вот так прервать и она может не удалить какие-то свои данные.
Исключения не должны пересекать границы модуля. Т.е. за пределы callback-ов winapi никакие исключения выпускать нельзя. Но при этом внутри самой функции исключениями пользоваться можно, но опять же, на границе они все должны быть перехвачены и обработаны.
Здравствуйте, rusted, Вы писали:
R>можно ли кидать исключения (обычные C++) из callback-ов winapi?
Можно, но хорошего из этого ничего не выйдет.
R>простой тест с WndProc показывает что с моей стороны все работает — деструкторы вызываются, исключение ловится. Но ведь WndProc вызывается из DispatchMessage, которая вряд ли подозревает что ее могут вот так прервать и она может не удалить какие-то свои данные.
Если С++ные исключения реализованы поверх структурных, то произойдёт следующее:
— возбуждается структурное исключение
— С++ная программа обрабатывает его, разматывая стек
— дальше уже сам виндоуз обрабатывает его (если он это собирался делать)
Тут возможны 3 варианта:
1. Исключение проигнорировано (либо внутри винапишного кода не был добавлен хэндлер, либо хэндлер пробросил исключение дальше). Тогда оно прилетит к следующему хэндлеру в твоём коде, вызывавшем апишную функцию. Дальше всё в порядке.
2. Исключение поглощено, а апишная функция продолжила работу либо вернула код ошибки. Как следствие, объект С++ного исключения утёк, а сама механика C++ных исключений осталась в промежуточном состоянии. Дальнейшее поведение не определено.
3. Исключение проигнорировано, но обработчиков больше нет (например, это был бросок из функции потока). Программа с треском валится.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, rusted, Вы писали:
К>Если С++ные исключения реализованы поверх структурных, то произойдёт следующее: К>- возбуждается структурное исключение К>- С++ная программа обрабатывает его, разматывая стек К>- дальше уже сам виндоуз обрабатывает его (если он это собирался делать) К>Тут возможны 3 варианта: К>1. Исключение проигнорировано (либо внутри винапишного кода не был добавлен хэндлер, либо хэндлер пробросил исключение дальше). Тогда оно прилетит к следующему хэндлеру в твоём коде, вызывавшем апишную функцию. Дальше всё в порядке. К>2. Исключение поглощено, а апишная функция продолжила работу либо вернула код ошибки. Как следствие, объект С++ного исключения утёк, а сама механика C++ных исключений осталась в промежуточном состоянии. Дальнейшее поведение не определено. К>3. Исключение проигнорировано, но обработчиков больше нет (например, это был бросок из функции потока). Программа с треском валится.
Можно ещё уточнить по первому пункту, что код внутри windows может быть exception-safe, а может и не быть, тогда возможна, например, утечка памяти вместо "всё в порядке", несмотря на то, что исключение вернулось. Думаю, среди кучи WinAPI колбэков и вызовов COMовских интерфейсов из кода Windows такие случаи найдутся.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, 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).
PS. этот код убивает W2k3 Server, блокируя создание любых окон до завершения процесса. Помогает только _заранее_ открытая консоль + 'taskkill /IM test.exe /F'.