来自 MFC 对话框中使用的托管 C# 用户控件的未处理异常
Posted
技术标签:
【中文标题】来自 MFC 对话框中使用的托管 C# 用户控件的未处理异常【英文标题】:Unhandled Exceptions from Managed C# User Control used in MFC Dialog 【发布时间】:2009-07-27 02:02:37 【问题描述】:我们的核心应用程序是用 MFC C++ 构建的,但我们正在尝试在 .NET 中编写新代码,并在 .NET 中创建了一个用户控件,它将用于现有的 MFC 对话框。
但是,当用户控件抛出意外/未处理的异常时,它会导致 MFC 应用程序崩溃(非法操作样式),无法恢复。
我已经添加了
AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.UnhandledException += new UnhandledExceptionEventHandler(currentDomain_UnhandledException); Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
.NET 用户控件的构造函数,但它似乎没有捕捉到任何东西。
有没有办法在 MFC 中添加事件来处理这些?
快速谷歌没有返回任何有用的东西。
谢谢。
编辑:仍然无法以我想要的方式解决这个问题,看起来是 最好的 方法,尝试并抓住所有 .NET 代码,所以没有异常冒泡。
【问题讨论】:
检查我的编辑。我在每个事件处理程序中都使用它;你也可以。 您只需要尝试/捕捉 .NET 代码的最外层 - 事件处理程序和公共入口点。 哦,是的,这就是我必须做的,但它确实涵盖了所有 .NET 代码,无论是直接还是间接。 【参考方案1】:我不久前也问过同样的问题:Final managed exception handler in a mixed native/managed executable?
我发现托管的未处理异常事件仅在托管线程中运行时才会触发。托管的 WndProc 是奇迹发生的地方。
您有几个选择:您可以在 CWinApp 中放置一个低级覆盖并捕获 Exception^。这可能会产生意想不到的副作用。或者,您可以使用结构化异常处理 (SEH),这将使您能够破解 /all/ 未处理的异常。这不是一条容易的路。
【讨论】:
【参考方案2】:我认为您希望在 MFC 方面拥有未处理的异常处理程序:
AppDomain::CurrentDomain->UnhandledException += gcnew UnhandledExceptionEventHandler(&CurrentDomain_UnhandledException);
[Application.ThreadException 相同]
在 MSDN 论坛上查看类似的问题:Unhandled Exception in Mixed Mode application
【讨论】:
所提供的链接中的代码实际上不起作用,遗憾的是提供的示例也没有。编译 100%,但结果仍然相同 确实,这行不通。另外,为什么事件注册运行的上下文会对注册产生任何影响?您链接的线程接受了错误的答案,后来的回复证实了这个提问者的问题。【参考方案3】:当然,更好的想法是要么在 C# 代码中处理异常,要么找出导致它的原因并修复它,以便永远不会抛出异常。是什么阻止了这种情况?
在用户控件的每个事件处理程序中,放置一个 try/catch 块:
private void btnOk_Click(object sender, EventArgs e)
try
// real code here
catch (Exception ex)
LogException(ex);
// do whatever you must in order to shut down the control, maybe just
这是我使用的:
public static class UI
public static void PerformUIAction(Control form, Action action)
PerformUIAction(form, action, (string) null);
public static void PerformUIAction(
Control form, Action action, string message)
PerformUIAction(form, action, () => message);
public static void PerformUIAction(
Control form, Action action, Func<string> messageHandler)
var saveCursor = form.Cursor;
form.Cursor = Cursors.WaitCursor;
try
action();
catch (Exception ex)
MessageBox.Show(
messageHandler() ?? ex.Message, "Exception!",
MessageBoxButtons.OK, MessageBoxIcon.Error,
MessageBoxDefaultButton.Button1,
MessageBoxOptions.DefaultDesktopOnly);
Debug.WriteLine(ex.ToString(), "Exception");
throw;
finally
form.Cursor = saveCursor;
我这样称呼它:
private void _copyButton_Click(object sender, EventArgs e)
UI.PerformUIAction(
this, () =>
// Your code here
);
【讨论】:
例外情况是我们不知道它们什么时候来,也不知道为什么。所以这是不可能的。并且用户控件也有很多事件和方法。我已经针对可能的异常进行了编码,但这是我想要捕获的其他异常 似乎需要做很多工作,并且确实需要一个不需要我在需要捕获异常的每个地方都添加额外代码的解决方案(除了我可以预期的) 随你喜欢。但是请注意,您在打开的“”之后添加了三行代码,在结尾的“”之前添加了一行。如果您不介意一些简单的正则表达式,您可以使用搜索和替换来做到这一点。此外,您可能没有注意到;您可以在“your code here”块中访问“sender”和“e”。您包装的代码不会改变。 不要误会我的意思,它是一个很好的解决方案,但遗憾的是不适合我的问题。如果我可以发布更多代码,我会发布,但由于它与工作相关。 没问题。我没有生气。 :-) 我很想知道这种模式不适合什么情况,仅仅是因为多年来它适合很多情况。我首先将它与 .NET 1.1 一起使用,在该版本中,您必须为委托使用显式方法名称。 那太丑了! Lambda 解决了我自 2003 年以来遇到的所有问题!【参考方案4】:我将未处理的异常处理程序添加到 .NET 用户控件的构造函数中
我认为这行不通;我相信必须在调用 Application.Run 之前设置异常处理程序。您的应用中有任何 Application.Run 调用吗?
在初始化任何 .NET 控件之前,在 MFC 方面做这样的事情怎么样:
Application.SetUnhandledExceptionMode(System.Windows.Forms.UnhandledExceptionMode.CatchException);
Application.ThreadException += ...;
查看是否调用了 ThreadException 处理程序。
【讨论】:
有趣的想法,如果你尝试一下,请分享结果。 我应该让线程异常调用 .NET 事件还是 MFC 代码?对不起,这整个编程事情都是新手...... 在 MFC 方面有这个。您需要将 C++ 代码编译为 C++/CLI(托管 C++ 代码)。以上是关于来自 MFC 对话框中使用的托管 C# 用户控件的未处理异常的主要内容,如果未能解决你的问题,请参考以下文章
在 MFC 应用程序中托管 Windows 窗体 (C#) (VC++,VS6.0)