Перехват исключений для входа в приложение C++ CLI
Я пытаюсь перехватить все исключения в приложении C++/CLI, чтобы я мог их регистрировать и записывать (включая трассировку стека). Пока у меня есть код, который выглядел многообещающе:
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Enabling Windows XP visual effects before any controls are created
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Create the main window and run it
try
{
Application::Run(gcnew MainForm());
}
catch( System::Exception^ e )
{
String^ message = gcnew String("");
System::Exception^ exceptionRecursor = e;
message = "ERROR: Uncaught exception encountered!\n\n";
while( exceptionRecursor )
{
message += exceptionRecursor->Source+"\n\t";
message += exceptionRecursor->Message+"\n\t";
message += exceptionRecursor->StackTrace+"\n\n";
exceptionRecursor = exceptionRecursor->InnerException;
}
MessageBox::Show(message);
}
return 0;
}
... но вместо того, чтобы отключить диалоговое окно с моими исправленными ошибками, я получаю кое-что еще:
An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll
Additional information: Exception has been thrown by the target of an invocation.
Это потому что Run
команда пытается как-то разобраться с исключением? Нужно ли обрабатывать вещи внутри MainForm
где-то?... или есть какой-то другой (лучший) способ сделать это.
На мгновение забыв об источнике ошибки (я нахожусь в середине цикла разработки и все еще отлаживаю), было бы неплохо иметь возможность перехватывать эти ошибки и производить аккуратную небольшую трассировку стека, которая может оставаться в коде вплоть до развертывания и дайте пользователям знать, когда что-то идет не так. В конце концов я бы обернул сообщение об ошибке во что-то, что можно было бы сообщить через Интернет.
2 ответа
Я нашел решение (используя Application:: ThreadException):
// Creates a class to throw the error.
public:
ref class ErrorHandler: public System::Windows::Forms::Form
{
// Inserts the code to create a form with a button.
// Programs the button to throw an exception when clicked.
private:
void button1_Click( Object^ /*sender*/, System::EventArgs^ /*e*/ )
{
throw gcnew ArgumentException( "The parameter was invalid" );
}
public:
static void Main()
{
// Creates an instance of the methods that will handle the exception.
CustomExceptionHandler ^ eh = gcnew CustomExceptionHandler;
// Adds the event handler to to the event.
Application::ThreadException += gcnew ThreadExceptionEventHandler( eh, &Form1::CustomExceptionHandler::OnThreadException );
// Runs the application.
Application::Run( gcnew ErrorHandler );
}
};
// Creates a class to handle the exception event.
internal:
ref class CustomExceptionHandler
{
// Handles the exception event.
public:
void OnThreadException( Object^ /*sender*/, ThreadExceptionEventArgs^ t )
{
System::Windows::Forms::DialogResult result = ::DialogResult::Cancel;
try
{
result = this->ShowThreadExceptionDialog( t->Exception );
}
catch ( Exception^ )
{
try
{
MessageBox::Show( "Fatal Error", "Fatal Error", MessageBoxButtons::AbortRetryIgnore, MessageBoxIcon::Stop );
}
finally
{
Application::Exit();
}
}
// Exits the program when the user clicks Abort.
if ( result == ::DialogResult::Abort )
{
Application::Exit();
}
}
// Creates the error message and displays it.
private:
System::Windows::Forms::DialogResult ShowThreadExceptionDialog( Exception^ e )
{
String^ errorMsg = "An error occurred please contact the adminstrator with the following information:\n\n";
errorMsg = String::Concat( errorMsg, e->Message, "\n\nStack Trace:\n", e->StackTrace );
return MessageBox::Show( errorMsg, "Application Error", MessageBoxButtons::AbortRetryIgnore, MessageBoxIcon::Stop );
}
};
Если отражение происходит в другом потоке, оболочка не сможет его отловить.