35

我们的单元测试会触发子进程,有时这些子进程会崩溃。当发生这种情况时,会弹出一个Windows错误报告对话框,该进程将一直保持活动状态,直到手动解除。这当然可以防止单元测试终止。

如何避免这种情况?


以下是Win7中的一个对话框示例,其中包含常用设置:

替换文本

如果我禁用Ae调试注册表项,JIT调试选项消失:

替换文本

如果我禁用检查解决方案(这是我似乎可以通过控制面板控制的唯一一件事),它看起来像这样,但仍然会出现,并且仍然会阻止程序停止运行,直到用户按下某个按钮。WerAddExcluded应用程序记录也有这种效果。

替换文本

2
  • 1
    您如何调用WerAddExcludedApplication? 评论 2010年8月31日18:08
  • @Eric恐怕我已经删除了我的extern声明,pinvoke.net上也没有。所以我不能确切地说出我上次是怎么称呼它的。不过,这似乎是在转移注意力;它似乎只禁用发送报告bit,而不是整个崩溃对话框。 评论 2010年8月31日18:26

3个答案

重置为默认值
57

jdehaan和Eric Brown的答案摘要,以及这个问题(另请参阅这个问题):

注意:。这些解决方案也可能影响其他错误报告,例如加载DLL或打开文件失败。

选项1:全局禁用

在整个用户帐户或计算机上全局工作,这既有好处也有缺点。

设置[HKLM|HKCU]\Software\Microsoft\Windows\Windows错误报告\DontShowUI至1。更多信息:WER设置.

选项2:禁用应用程序

需要修改崩溃程序,文档中描述为最佳实践,不适用于库函数。

呼叫设置错误模式:SetErrorMode(设置错误模式(0)|SEM_NOGPFAULTERRORBOX);(或与SEM辅助参数). 更多信息:禁用程序崩溃对话框(解释了奇怪的通话安排)。

选项2a:禁用功能:

需要修改崩溃程序,需要Windows 7/2008 R2(仅限桌面应用程序)或更高版本,在文档中描述为首选设置错误模式,适用于线程安全库函数。

呼叫并重置设置线程错误模式:

DWORD旧线程错误模式=0;设置线程错误模式(SEM_FAILCRITICALERRORS和旧线程错误模式);设置线程错误模式(z_OldThreadErrorMode,NULL);

更多信息:没有多少可用的?

选项3:指定处理程序

需要修改崩溃程序。

使用设置UnhandledExceptionFilter设置您自己的结构化异常处理程序,该异常处理程序只需退出,可能会报告,也可能会尝试清理。

选项4:作为异常捕获

需要修改崩溃程序。对于。仅限NET应用程序。

将所有代码包装到全局try/catch块中。指定处理进程损坏状态异常属性也可能是安全关键属性关于捕获异常的方法。更多信息:处理损坏状态异常

注释:这可能无法捕获由托管调试助手; 如果是这样,则还需要在应用程序中禁用这些功能。

选项5:停止报告过程

在整个用户帐户上全局工作,但只在控制的持续时间内工作。

在Windows错误报告进程出现时立即终止该进程:

var-werKiller=新线程(()=>{while(真){foreach(Process.GetProcessesByName(“WerFault”)中的var proc)程序。Kill();线程。睡眠(3000);}});werKiller。IsBackground=真;werKiller。开始();

但这仍然不是完全防弹的,因为控制台应用程序可能会通过不同的错误消息崩溃,而错误消息显然是由名为NtRaiseHard错误:

替换文本

4
  • SetErrorMode()是否也会影响C++中线程产生的关键错误(如访问冲突)? 评论 2011年3月11日16:06
  • @恐怕我现在不记得了。我认为只要你的程序不使用SetUnhandledExceptionFilter并在那里显示自己的消息,它就会这样做。 评论 2011年3月11日17:31
  • 特别是当您被旧框架(例如VCL6)锁定时SetErrorMode(设置错误模式(0)|SEM_NOGPFAULTERRORBOX);效果最好@你让我度过了一天:-)
    – 
    评论 2015年7月2日9:55
  • “找不到入口点”和“系统错误”(“您的计算机中缺少…dll”)对话框似乎被抑制reg add HKLM\SYSTEM\CurrentControlSet\Control\Windows/v错误模式/t reg_DWORD/f/d 2。它们不受DontShowUI注册表设置的影响。 评论 2017年12月20日23:33
5

唯一的解决方案是在非常高的级别捕获所有异常(对于每个线程)并正确终止应用程序(或执行另一个操作)。

这是防止异常逃离应用程序并激活WER的唯一方法。

添加:

如果异常是您不希望发生的情况,您可以使用断言不抛出(NUnit)或其他单元测试框架中的类似代码,以封装触发子进程的代码。这样,您也可以将其放入单元测试报告中。在我看来,这是我能想到的最干净的解决方案。

添加2:正如下面的评论所示,我错了:你不能总是捕捉异步异常,这取决于环境允许的情况。英寸。NET阻止了一些异常被捕获,是什么使我的想法在这种情况下毫无价值。。。

对于。NET:存在涉及AppDomains使用的复杂解决方案,导致卸载AppDomain,而不是整个应用程序崩溃。太糟糕了。。。

http://www.bluebytesoftware.com/blog/PermaLink,指南,223970c3-e1cc-4b09-9d61-99e8c5fae470.aspx

http://www.develop.com/media/pdfs/developments_archive/AppDomains.pdf


编辑:

我终于明白了。NET 4.0您可以添加处理进程损坏状态异常属性。运行时。包含try/catch块的方法的ExceptionServices。这真的奏效了!也许不推荐,但很有效。

使用系统;使用系统。反思;使用系统。运行时。InteropServices;使用系统。运行时。例外服务;命名空间异常捕获{公共类测试{public void StackOverflow(){StackOverflow();}public void CustomException(){throw new Exception();}公共不安全void AccessViolation(){字节b=*(字节*)(8762765876);}}课程计划{[HandleProcessCorruptedStateExceptions]static void Main(字符串[]参数){测试测试=新测试();尝试{//测试。StackOverflow();测试。访问违规();//测试。自定义异常();}抓住{慰问。WriteLine(“捕获”);}慰问。WriteLine(“程序结束”);}}      }
12
  • 1
    我想这在大多数情况下都会起作用,但StackOverflowException和AccessViolationException是不可匹配的呢? 评论 2010年8月24日23:05
  • 即使是这些例外情况也应该是可捕捉的。在C++中,这可能意味着使用异步异常(/环境影响评价例如,MSVC++编译器的标志,请参见msdn.microsoft.com/en-us/library/1deeycx5.aspx). 变得如此技术化,问题不再是语言不可知论。英寸。NET,您可以捕获这些异常,而无需进行调整。
    – 杰哈恩
    评论 2010年8月24日23:22
  • 1
    @杰哈恩我很确定不能英寸。净利润。对C++不太确定。我试图保持不可知论,但似乎你的建议取决于语言细节。。。 评论 2010年8月24日23:49
  • @romkyns,哎哟。。。在很古老的过去,它起了作用。NET,现在不再是了。我理解背后的“技术原因”,但有时你只是反复出现,无法控制它们可能会变得有多深。我开始讨厌了。NET关于此。。。谢谢你的消息,我真的直到现在才知道!
    – 杰哈恩
    评论 2010年8月25日5:36
  • 1
    我在这里找到了另一个非常有趣的文档:development.com/media/pdfs/developments_archive/AppDomains.pdf有趣的是,我没有意识到自此之后行为发生了彻底的改变。NET 2.0。。。
    – 杰哈恩
    评论 2010年8月25日9:50

尝试设置

HKCU\Software\Microsoft\Windows\Windows错误报告\DontShowUI

至1。(您也可以在HKLM中设置相同的密钥,但需要管理员权限才能完成此操作。)

这将阻止WER显示任何UI。

你的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策.

不是你想要的答案吗?浏览已标记的其他问题问你自己的问题.