C# 处理阻塞的消息循环

C# 处理阻塞的消息循环,c#,.net,winforms,winapi,C#,.net,Winforms,Winapi,我对两个应用程序之间的交互有点问题 您可以使用如下代码复制此问题: using (Form1 frm = new Form1()) { frm.ShowDialog(); } Thread.Sleep(120000); 使用此代码,当应用程序运行代码的线程.Sleep部分时,一个我们不控制的单独应用程序将冻结。事实上,我们对发生的事情有一个很好的了解,因为之前我们一直是这个bug的接收端:另一个应用程序有一个来自本机EnumWindows方法的回调,它不会使用IsWindowVisi

我对两个应用程序之间的交互有点问题

您可以使用如下代码复制此问题:

using (Form1 frm = new Form1())
{
    frm.ShowDialog();
}

Thread.Sleep(120000);
使用此代码,当应用程序运行代码的
线程.Sleep
部分时,一个我们不控制的单独应用程序将冻结。事实上,我们对发生的事情有一个很好的了解,因为之前我们一直是这个bug的接收端:另一个应用程序有一个来自本机
EnumWindows
方法的回调,它不会使用IsWindowVisible本机方法检查窗口是否可见。然后,当它调用
GetWindowText
或其他函数时,它会挂起

这种挂起的原因是它试图与我们的(现在关闭的)窗口对话,该窗口仍然注册了一个句柄,但不响应发送到其队列的消息,因此调用者只是无限期地坐在那里(直到我们的Thread.Sleep之后窗口完全关闭)

下面是我们必须处理的“不可触及”应用程序的一些示例代码:

public bool RunTest()
{
    return NativeMethods.EnumWindows(new NativeMethods.EnumWindowsProc(EnumWindowsCallback), IntPtr.Zero);
}

private bool EnumWindowsCallback(IntPtr windowHandle, IntPtr parameter)
{
    NativeMethods.SendMessage(windowHandle, 0x000E, IntPtr.Zero, IntPtr.Zero);
    return true;
}
如果运行第一个代码,请关闭它打开的窗口,然后在单独的进程中运行第二个代码块,则第二个(EnumWindows)进程将挂起


我的问题是,我必须处理这个问题,不能只修复挂起的应用程序中的代码。我可以把窗户踢成一条单独的线,但这看起来很笨拙,而且有点脆弱。有人知道使用本机调用或任何其他更直接的方法解决此问题的方法吗?

您可以使用可等待计时器(使用
CreateWaitableTimer
函数创建)并继续运行消息循环(使用
MsgWaitForMultipleObjects
函数),而不是调用
Sleep
直到计时器过期。

您可以使用可等待计时器(使用
CreateWaitableTimer
函数创建)并继续运行消息循环(使用
MsgWaitForMultipleObjects
函数)而不是调用
Sleep
直到计时器过期。

您的真实代码,它将代替线程执行。Sleep,可能有一些循环。尝试将Application.DoEvents添加到此循环中。此代码不包含任何循环-发布的代码会触发错误,Form1是在Visual Studio中的空Windows窗体项目中创建的默认窗体。该窗体不应仍然注册句柄,因为
using
应调用
Dispose
。在那次睡眠之后还有其他代码执行吗?还是在睡眠结束后程序退出?这完全是正常的,也是预期的结果。对于像这样写得不好的程序,只有一个很好的解决方法:卸载它们。@Jim Mischel-不应该是对的,但是操作系统在窗体被销毁之后一直保持着窗体的句柄,因此出现了问题。操作系统只在窗体所属线程终止时清理句柄。您的实际代码(而不是执行thread.Sleep)可能有一些循环。尝试将Application.DoEvents添加到此循环中。此代码不包含任何循环-发布的代码会触发错误,Form1是在Visual Studio中的空Windows窗体项目中创建的默认窗体。该窗体不应仍然注册句柄,因为
using
应调用
Dispose
。在那次睡眠之后还有其他代码执行吗?还是在睡眠结束后程序退出?这完全是正常的,也是预期的结果。对于像这样写得不好的程序,只有一个很好的解决方法:卸载它们。@Jim Mischel-不应该是对的,但是操作系统在窗体被销毁之后一直保持着窗体的句柄,因此出现了问题。操作系统只在窗体所属线程终止时清理句柄。我更新了一点我的帖子:
Sleep
调用只是一个快速重现问题的示例。在我的产品代码中,各种形式在任意时间显示为长时间运行的应用程序线程的一部分。消息队列与这些窗口相关联。但是窗口re:EnumWindows的作用域不同于其作用域re:SendMessage!这就是我试图解决的问题。我更新了一点我的帖子:
Sleep
调用只是一个很快重现这个问题的例子。在我的产品代码中,各种形式在任意时间显示为长时间运行的应用程序线程的一部分。消息队列与这些窗口相关联。但是窗口re:EnumWindows的作用域不同于其作用域re:SendMessage!这就是我正在努力解决的问题。