Можно ли предотвратить создание отчетов об ошибках Microsoft для одного приложения?
У нас есть неуправляемое приложение C++, которое использует сторонние API для чтения файлов САПР. На некоторых поврежденных файлах САПР происходит сбой сторонней библиотеки, которая отключает наш EXE-файл. Из-за этого наше основное приложение представляет собой отдельный EXE-файл, и таким образом на него не влияет сбой. Как бы то ни было, мы получаем раздражающие диалоги отчетов об ошибках Microsoft.
Я не хочу отключать всю систему отчетов об ошибках Microsoft. Есть ли способ отключить создание отчетов об ошибках для одного приложения, чтобы в случае его сбоя происходило тихое завершение без всплывающих диалогов об ошибках?
5 ответов
Да, ты можешь кое-что сделать. Вызовите SetUnhandledExceptionFilter() в вашем методе main() для регистрации обратного вызова. Он будет вызван, когда никто не пожелает обработать исключение, как раз перед тем, как появится диалоговое окно Microsoft WER.
На самом деле выполнение чего-либо в этом обратном вызове чревато проблемами. Программа умерла с неизменно чем-то неприятным, как исключение AccessViolation. Который часто споткнулся из-за коррупции в куче. Попытка сделать что-то вроде отображения окна сообщения, чтобы сообщить пользователю, проблематична, когда куча тостов. Deadlock всегда скрывается за углом, готовый просто заблокировать программу без какой-либо диагностики.
Единственное, что можно сделать безопасно - это иметь вспомогательный процесс, который защищает ваш основной процесс. Проснись, сигнализируя именованное событие в вашем обратном вызове. Дайте ему информацию об исключении, которая ему нужна, с отображенным в память файлом. Помощник может делать практически все, что хочет, когда видит событие. В том числе показ сообщения, взятие минидампа. И прекращение основного процесса.
Именно так работает помощник Microsoft WerFault.
Ответ Ханса Пассанта о SetUnhandledExceptionFilter находится на правильном пути. Он также делает некоторые хорошие замечания о невозможности сделать слишком много в обратном вызове, потому что различные части процесса могут находиться в нестабильном состоянии.
Однако, из-за того, как описана проблема, не похоже, что вы хотите что-то делать, кроме как сказать системе не выводить обычный диалог сбоя. В этом случае это легко и должно быть безопасно независимо от того, на какие части процесса мог повлиять сбой.
Сделайте функцию примерно такой:
LONG WINAPI UnhandledExceptionCallback(PEXCEPTION_POINTERS pExceptPtrs)
{
if (IsDebuggerPresent())
// Allow normal crash handling, which means the debugger will take over.
return EXCEPTION_CONTINUE_SEARCH;
else
// Say we've handled it, so that the standard crash dialog is inhibited.
return EXCEPTION_EXECUTE_HANDLER;
}
И где-то в вашей программе (возможно, как можно раньше) установите обратный вызов:
SetUnhandledExceptionFilter(UnhandledExceptionCallback);
Это должно делать то, что вы хотите - позволить любым сбоям этой конкретной программы молча умирать.
Однако есть еще кое-что, что следует отметить по этому поводу: всякий раз, когда вы добавляете сторонние компоненты (DLL, OCX и т. Д.), Существует риск того, что один из них также может вызвать SetUnhandledExceptionFilter и, таким образом, заменить ваш обратный вызов своим собственным. Однажды я столкнулся с элементом управления ActiveX, который устанавливал свой собственный обратный вызов при создании экземпляра. И что еще хуже, он не смог восстановить первоначальный обратный вызов, когда он был уничтожен. Это казалось ошибкой в их коде, но, несмотря на это, мне пришлось предпринять дополнительные шаги, чтобы гарантировать, что мой желаемый обратный вызов был восстановлен, по крайней мере, тогда, когда это должно было произойти после того, как их управление было отключено. Так что, если вы обнаружите, что это иногда не работает для вас, даже если вы знаете, что правильно установили обратный вызов, вы можете столкнуться с чем-то похожим.
В Vista и выше функция API WerAddExcludedApplication может использоваться для исключения указанного исполняемого файла приложения из отчетов об ошибках. Насколько я знаю, в XP и других старых версиях ОС подобного варианта нет.
Однако, поскольку WER будет активировать только необработанные исключения приложения, вы сможете подавить его, добавив обработчик исключений "catch-all" в ваш EXE-файл. Посмотрите векторную обработку исключений для некоторых идей о том, как этого добиться.
Обратите внимание, что подавление всех необработанных исключений, как правило, является плохой идеей (и, например, приведет к тому, что ваше приложение не пройдет сертификацию Windows Logo), поэтому вам не следует использовать эту технику без разбора...
Я оказался именно в такой ситуации при разработке приложения для Delphi. Я обнаружил, что мне нужно две вещи, чтобы надежно подавить диалоговое окно "приложение перестало работать".
призвание SetErrorMode(SEM_NOGPFAULTERRORBOX);
подавляет диалоговое окно "приложение перестало работать". Но тогда обработчик исключений Delphi отображает окно сообщения с сообщением об ошибке во время выполнения.
Чтобы подавить обработчик исключений Delphi, я вызываю SetUnhandledExceptionFilter
с пользовательским обработчиком, который завершает процесс, вызывая Halt
,
Таким образом, скелет для клиентского приложения Delphi, выполняющего код, склонный к сбоям, становится:
function HaltOnException(const ExceptionInfo: TExceptionPointers): Longint; stdcall;
begin
Halt;
Result := 1; // Suppress compiler warning
end;
begin
SetErrorMode(SEM_NOGPFAULTERRORBOX);
SetUnhandledExceptionFilter(@HaltOnException);
try
DoSomethingThatMightCrash;
except
on E: Exception do
TellServerWeFailed(E.Message);
end;
end.
Я не совсем уверен, но, возможно, SetErrorMode
или же SetThreadErrorMode
у тебя будет работать?