C# 正在消失的FormClosing/FormClosed事件

C# 正在消失的FormClosing/FormClosed事件,c#,.net,winforms,winapi,events,C#,.net,Winforms,Winapi,Events,下面的代码片段可能看起来很奇怪,但它是一种非常简单的方法,可以重现与不同应用程序的复杂交互问题 示例应用程序有两个窗体,两个窗体都注册FormClosing和FormClosing事件,只是在那里执行Debug.WriteLine 主要功能包括: [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false

下面的代码片段可能看起来很奇怪,但它是一种非常简单的方法,可以重现与不同应用程序的复杂交互问题

示例应用程序有两个窗体,两个窗体都注册FormClosing和FormClosing事件,只是在那里执行Debug.WriteLine

主要功能包括:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Form2 form2 = new Form2();
    form2.Show();
    Application.Run(new Form1());
}
当我关闭Form2时,我收到了预期的事件。当我关闭Form1时,应用程序将退出,Form2也将关闭。但是:表2的事件没有发生

我推翻了Form2的WndProc。当我关闭Form2时,我收到

15.10.2012 10:25:04 WndProc - WM_CLOSE
15.10.2012 10:25:04 OnClosing
15.10.2012 10:25:04 Form2_FormClosing
15.10.2012 10:25:04 OnClosed
15.10.2012 10:25:04 Form2_FormClosed
...
15.10.2012 10:25:04 WndProc - WM_DESTROY
...
15.10.2012 10:25:04 WndProc - WM_NCDESTROY
当我关闭Form1时,Form2不会收到WM_关闭。但是收到了WM_DESTROY和WM_NCDESTROY

编辑: 获得这种奇怪行为的另一种方式如下: 该项目有三个表单,表单1和表单2各有一个按钮用于打开下一个表单。在form2的按钮单击事件中,执行以下操作:

Form3 frm3 = new Form3();
frm3.Parent = null;
frm3.Show(null);
同样,如上所述注册事件处理程序。关闭form2时,应用程序保持运行(form1仍显示),但form3也会关闭,并且没有收到WM_CLOSE事件。注意,我已经将表单的父级和所有者都设置为null


出现这种奇怪行为的原因是什么?

WM\u CLOSE
消息被发送以具有取消关闭的选项。请参见此流程图:

所以,不管怎样,当窗口即将被破坏时,在这个消息中并没有必要。这是故意的行为。关闭应用程序的主窗体时,将调用
application.ThreadExit
方法。它被描述为:

退出当前线程上的消息循环并关闭当前线程上的所有窗口 线

如果您希望所有打开的表单都接收到
WM_CLOSE
消息,则需要使用
应用程序。请退出

通知所有消息泵它们必须终止,然后关闭 处理消息后的所有应用程序窗口

因此,只需订阅
Form1\u FormClosing
事件,并通知所有打开的窗口关闭:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    Application.Exit();
}

WM_CLOSE
消息被发送以具有取消关闭的选项。请参见此流程图:

所以,不管怎样,当窗口即将被破坏时,在这个消息中并没有必要。这是故意的行为。关闭应用程序的主窗体时,将调用
application.ThreadExit
方法。它被描述为:

退出当前线程上的消息循环并关闭当前线程上的所有窗口 线

如果您希望所有打开的表单都接收到
WM_CLOSE
消息,则需要使用
应用程序。请退出

通知所有消息泵它们必须终止,然后关闭 处理消息后的所有应用程序窗口

因此,只需订阅
Form1\u FormClosing
事件,并通知所有打开的窗口关闭:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    Application.Exit();
}

谢谢你的解释。现在我明白了为什么我们不能在这个例子中得到信息。但是我们首先发现问题的设置要复杂得多。第三方定义了C++接口。我们在混合模式(非托管/托管)dll中实现它。当ThirdParty调用StartUp方法时,我们会创建一个用于通信的窗口(并将桌面设置为其所有者)。当第三方关闭加载系统的窗口时,我们的窗口也会消失——没有事件。但我们的系统保持加载状态(即,它们不卸载应用程序域)。现在,我们必须找出还有哪些其他方法可以在不获取事件的情况下关闭窗口。您可以覆盖
Form2
上的
WndProc
,并通过调用
close()
方法处理
WM\u DESTROY
消息。它将处理表单及其资源。感谢您的精彩解释。现在我明白了为什么我们不能在这个例子中得到信息。但是我们首先发现问题的设置要复杂得多。第三方定义了C++接口。我们在混合模式(非托管/托管)dll中实现它。当ThirdParty调用StartUp方法时,我们会创建一个用于通信的窗口(并将桌面设置为其所有者)。当第三方关闭加载系统的窗口时,我们的窗口也会消失——没有事件。但我们的系统保持加载状态(即,它们不卸载应用程序域)。现在,我们必须找出还有哪些其他方法可以在不获取事件的情况下关闭窗口。您可以覆盖
Form2
上的
WndProc
,并通过调用
close()
方法处理
WM\u DESTROY
消息。它将处理表单及其资源。