C ++ / CLI:捕获所有(.NET / Win32 / CRT)异常

时间:2011-07-08 17:56:00

标签: .net exception-handling c++-cli

我知道这是不赞成的,但我在这里没有选择。我正在开发一个C ++ / CLI应用程序,它有一个我无法追踪的错误 - 主要是因为它绕过我当前的崩溃处理程序:

AppDomain::CurrentDomain->UnhandledException += gcnew UnhandledExceptionEventHandler(&LogAndExit);
Application::ThreadException += gcnew ThreadExceptionEventHandler(&LogAndExit);
Application::SetUnhandledExceptionMode(UnhandledExceptionMode::CatchException);
try 
{ 
    Application::Run(gcnew frmMain()); 
} 
catch (Exception^ ex) 
{ 
    LogAndExit(ex); 
} 
catch (...) 
{ 
    LogAndExit(); 
}

我认为标准.NET崩溃处理。 MSDN报告称,某些CRT异常会破坏托管堆栈并以静默方式中止应用程序。

我一直在阅读_set_invalid_parameter_handler,但即使我收到LNK2001错误,它似乎也不能与/ clr:pure一起使用。我是对的,还是我只是PEBKAC了它并错过了一个lib文件?

5 个答案:

答案 0 :(得分:4)

你能以/clr模式运行吗?如果你可以试试这个:

#include <exception>

然后:

try
{
    try
    {
        Application::Run(gcnew frmMain()); 
    }
    catch(const exception& ex)
    {
        throw gcnew System::Exception(gcnew System::String(ex.what()));
    }
} 
catch (Exception^ ex) 
{ 
    LogAndExit(ex); 
} 
catch (...) 
{ 
    LogAndExit(); 
}

需要注意的另一件事:如果您的应用程序是多线程的,那么您只会从正在运行frmMain()的线程中捕获异常。因此,在这种情况下,无法完成整个应用程序的全部工作!

答案 1 :(得分:1)

首先,这不适用于表单。

  

在使用Windows窗体的应用程序中,未处理的异常   主应用程序线程导致   Application.ThreadException事件发生   被提高。如果处理此事件,   默认行为是   未处理的异常不会终止   申请,虽然   申请是留在未知的   州。在那种情况下,   UnhandledException事件不是   提高。可以更改此行为   通过使用应用程序配置   文件,或使用   Application.SetUnhandledExceptionMode   将模式更改为的方法   UnhandledExceptionMode.ThrowException   在ThreadException事件之前   处理程序被连接起来。这适用   仅限主应用程序线程。   引发了UnhandledException事件   抛出未处理的异常   其他线程。

其次,可能存在非托管异常(不是 System::Exception 类型。)

try { Application::Run(gcnew frmMain()); } 
catch (Exception^ ex) { LogAndExit(ex); }
catch (...) { LogAndExit(new Exception("Some Unmanage exception"));

msdn- How to catch exceptions in Visual C++

答案 2 :(得分:1)

我建议您尝试__try / __except

__try 
{ 
  Application::Run(gcnew frmMain()); 
} 
__except(EXCEPTION_EXECUTE_HANDLER) 
{ 
  LogAndExit(new Exception("Some Unmanage exception")); 
}

MSDN文档:

http://msdn.microsoft.com/en-us/library/s58ftw19(v=vs.80).aspx

如果您想变得非常棘手,可以尝试双重包装:

__try 
{ 
  try {
    Application::Run(gcnew frmMain()); 
  } 
  catch(SEHException^ e)
  {
    LogAndExit(new Exception("Some Unmanage exception")); 
  }
  catch(...) //Leave this out if you're /clr:pure
  {
    LogAndExit(new Exception("Some Unmanage exception")); 
  }
} 
__except(EXCEPTION_EXECUTE_HANDLER) 
{ 
  LogAndExit(new Exception("Some Unmanage exception")); 
}

结构化异常通常包含在SEHException中。

您还需要考虑到您实际上可能正在捕获异常,但是LogAndExit方法中的某些内容会导致抛出辅助异常,这实际上是程序的结束。尝试删除你的LogAndExit函数,看看是否可以使崩溃发生,而不是使用标准的中止消息和/或将你的LogAndExit代码包装在另一个隐藏任何异常的try / catch中。

作为一个为C ++ / CLI投入大量时间的人,我可以同情你的困境。希望这个解决方案有所帮助。

有关C ++ / CLI异常处理的其他MSDN文档:

如何:定义和安装全局异常处理程序 http://msdn.microsoft.com/en-us/library/171ezxzc.aspx

/ clr下的异常处理 http://msdn.microsoft.com/en-us/library/633chdda.aspx

答案 3 :(得分:0)

有几种类型的异常处理。您发布的内容仅处理托管例外。

C ++代码也可能抛出非托管异常(特别是来自标准库)。此外,非托管代码可能会抛出Win32异常。

Start here并阅读结构化异常处理(Win32异常)。 C ++异常和托管异常是基于SEH构建的,因此如果您在流程中每个线程的顶点处理SEH,您将受到保护。

答案 4 :(得分:0)

并非每次崩溃都是例外,至少不会立即发生。一个狂野的指针完全有可能踩踏.NET内部数据结构,以至于当抛出异常时,托管处理程序无法正常运行。

尝试使用本机处理程序。 Visual C ++提供了__try / __except,但是您需要确保处理程序位于程序中每个线程的调用堆栈上,并且仍然可以对异常进行未处理(例如CreateThread)用指针指向非法指令)。要处理所有边缘情况,您应该使用SetUnhandledExceptionFilter

请注意,对于/clr:pure,所有代码都依赖于CLR,因此会因运行时损坏而失败。即使是原生处理程序也可能依赖于已损坏的状态,尽管它们不如基于MSIL的处理程序脆弱。为了实现强大的错误处理,您确实需要在流程外部运行代码。