处理阻塞的消息循环

时间:2013-03-13 18:28:52

标签: c# .net winforms winapi

我对两个应用程序之间的交互存在一些问题。

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

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

Thread.Sleep(120000);

使用此代码,当我们的应用程序运行代码的Thread.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)进程将挂起。

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

1 个答案:

答案 0 :(得分:1)

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