在我的代码中,以下内容崩溃了在Windows 10 Professional上运行的应用程序。
this.ShowInTaskbar = true;
已在2台不同的机器上测试过。当我在try / catch块中包含上述代码行时,没有显示异常。当我订阅Appdomain.UnhandledException
事件时,也没有例外。
在事件查看器中Event 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
中的命令执行顺序如何,应用程序也不会崩溃。
答案 0 :(得分:5)
免责声明:大多数是非合同行为,因此不要权威地采取行动 - Windows和.NET Framework的不同版本和配置可能会对#&#有什么微小影响39;发生了。
您在任务栏中显示窗口。这需要重新创建窗口,这会导致调整大小。在resize事件处理程序中,您隐藏任务栏中的窗口。这需要重新创建窗口,这会导致调整大小。在resize事件处理程序中,您隐藏了任务栏中的窗口 - 但是这并没有重新创建窗口,因为“我在任务栏中显示了什么?”"字段实际上已经更新。然而,它在创建句柄时进入臭名昭着的访问Control.Handle"无限循环 - 这可以说是框架中的一个错误(有趣的是,如果表单被最小化或最大化,它会发生,但不会#34;正常大小")。 Control.Handle
调用Form.RecreateHandleCore
来调用Control.Handle
并且您已完成了操作:)
为什么不在所有机器上发生这种情况?因为调整大小并不总是必要的。这可能与任何数量的东西有关 - UI主题,字体大小,显示......但基本错误仍然存在 - 您将导致无限递归。它只是被跳过,因为你得到的事件少Resize
。
为什么你不能抓住这个例外?好吧,StackOverflowException
可能有点鬼鬼祟祟。您正处于安全关键代码的中间,可能在本机调用中,并且您获得了堆栈溢出。你究竟如何恢复?所有运行时都知道堆栈防护已被命中 - 据他所知,有人只是替换了你程序内存的一半。 OutOfMemoryException
非常相似 - 你不知道如何再次进入安全状态,所以唯一的选择是快速失败。
在WindowState
之前更改ShowInTaskbar
可以通过两种方式解决问题 - 一,它会改变调整大小处理程序的工作方式 - 这是代码中的错误,并且更改窗口状态可防止该代码(ShowInTaskbar = false
)来自运行。第二个是当窗体重新创建其句柄时Control.Handle
访问仅在窗口最小化或最大化时发生 - 这是框架部分。不用说,这非常脆弱 - 像这样的错误很难找到并修复。
那么,这样做的正确方法是什么?您希望在最小化时将窗口隐藏在任务栏中。只有在窗口状态曾经非最小化并且更改为Minimized时才会这样 - 所以你需要保持旧的窗口状态并检查它。
更好,不要惹恼ShowInTaskbar
。当你真正想要的是在它被最小化时隐藏窗口时,你似乎正在制造不必要的复杂事物! Show
和Hide
会做,不需要完全信任,也不会在Alt + Tab菜单中保留表单。 ShowInTaskbar
适用于具有以某种方式连接的多个窗口的应用程序 - 例如显示在不同表单顶部的模式对话框,具有相同z顺序的多窗口界面等。如果您只需要隐藏表单,请将其隐藏。无需继续创建和销毁所有窗口句柄:)我怀疑框架设计师给我们ShowInTaskbar
属性的唯一原因是为设计师提供了不错的支持 - 但你不应该真正改变它创建表单后;给定的表单显示在任务栏中,或者它不是。没理由在运行时更改它。