gpt4 book ai didi

c# - 为什么 ShowInTaskbar 会毫无异常(exception)地使我的应用程序崩溃?

转载 作者:太空宇宙 更新时间:2023-11-03 19:49:11 24 4
gpt4 key购买 nike

在我的代码中,以下代码会使在 Windows 10 专业版上运行的应用程序崩溃。

this.ShowInTaskbar = true;

这已经在 2 台不同的机器上进行了测试。当我在 try/catch block 中包含上述代码行时,没有显示异常。当我订阅 Appdomain.UnhandledException 事件时也不异常(exception)。

事件查看器中有一个应用程序错误,事件 ID 1000 指出 System.Windows.Forms.ni.dll 中发生了错误,但我没有别的可以理解。

在 Windows 10 Professional 上运行的开发机器上也无法重现此问题。

除了 NotifyIcon 之外,表单没有其他控件。经过实验,我发现问题出在以下代码行:

private void onFormResize(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized) this.ShowInTaskbar = false;
}

private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
try
{
this.ShowInTaskbar = true;
this.WindowState = FormWindowState.Normal;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

如果我先更改 WindowState,然后在任务栏上显示表单,那么一切正常。此外,如果我从 OnFormResize 中删除代码,应用程序也不会崩溃,无论 notifyIcon1_MouseDoubleClick 中的命令执行顺序如何。

最佳答案

免责声明:其中大部分是非契约(Contract)行为,所以不要把它当作权威 - Windows 和 .NET Framework 的不同版本和配置可能会对正在发生的事情产生微小的影响。

您在任务栏中显示窗口。这需要重新创建窗口,这会导致调整大小。在调整大小事件处理程序中,您将窗口隐藏在任务栏中。这需要重新创建窗口,这会导致调整大小。在调整大小事件处理程序中,您将窗口隐藏在任务栏中 - 但不会重新创建窗口,因为“我是否显示在任务栏中?”字段实际上已经更新。然而,它进入了臭名昭著的“在创建句柄时访问 Control.Handle”无限循环——这可以说是框架中的一个错误(有趣的是,如果表单被最小化或最大化,但不是“正常大小”,就会发生这种情况)。 Control.Handle 调用 Form.RecreateHandleCore,后者调用 Control.Handle,您就完成了 :)

为什么这不会发生在所有机器上?因为调整大小并不总是必要的。这可能与许多事情有关——UI 主题、字体大小、显示……但基本错误仍然存​​在——你导致了无限递归。它只是被跳过了,因为你少了一个 Resize 事件。

为什么不能捕获异常?好吧,StackOverflowException 这种方式可能有点偷偷摸摸。您正处于安全关键代码的中间,可能在 native 调用中,并且出现堆栈溢出。你具体是怎么恢复的?运行时所知道的只是堆栈保护已被击中——就其所知,有人刚刚替换了你程序的一半内存。 OutOfMemoryException 非常相似 - 您不知道如何再次进入安全状态,所以唯一的选择就是快速失败。

ShowInTaskbar 之前更改 WindowState 可以通过两种方式解决问题 - 第一,它会更改调整大小处理程序的工作方式 - 这是代码中的错误,并且更改窗口状态阻止该代码 (ShowInTaskbar = false) 运行。第二个是当窗体重新创建其句柄时 Control.Handle 访问仅在窗口最小化或最大化时发生 - 这是框架部分。不用说,这是非常脆弱的 - 像这样的错误很难找到和修复。

那么,这样做的正确方法是什么?您想在窗口最小化时从任务栏中隐藏该窗口。那只是当窗口状态以前是非最小化的,变成最小化的时候——所以你需要保持旧的窗口状态并检查它。

更好的是,不要乱用 ShowInTaskbar。看起来你让事情变得不必要的复杂,而你真正想要的只是在窗口最小化时隐藏它! ShowHide 都可以,不需要完全信任,并且不会将表单保留在 Alt+Tab 菜单中。 ShowInTaskbar 适用于具有多个以某种方式连接的窗口的应用程序 - 例如显示在不同窗体之上的模态对话框,具有相同 z 顺序的多窗口界面等。如果您只需要隐藏窗体,请将其隐藏。无需继续创建和销毁所有窗口句柄 :) 我怀疑框架设计者为我们提供 ShowInTaskbar 属性的唯一原因是在设计者中提供体面的支持 - 但你不应该真正改变它在创建表单之后;给定的表单要么显示在任务栏中,要么不显示。没有理由在运行时更改它。

关于c# - 为什么 ShowInTaskbar 会毫无异常(exception)地使我的应用程序崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41823588/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com