2013-03-13 69 views
1

我对两个应用程序之间的交互有点问题。处理被阻止的消息循环

你可以用代码复制的问题是这样的:

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)进程将挂起。

我的问题是,我要解决这个问题,而不能只固定在悬挂应用程序的代码。我可以把窗户踢进一个单独的线程,但这看起来很笨拙,有点脆弱。有谁知道使用本地调用或其他更直接的方法清除此问题的方法?

+0

真实的代码,这是执行以替代的Thread.Sleep,可能有一定的循环。尝试将Application.DoEvents添加到此循环中。 – 2013-03-13 18:50:55

+0

此代码不包含任何循环 - 发布的代码触发错误,并且Form1是在Visual Studio中的空白Windows窗体项目中创建的默认窗体。 – 2013-03-13 19:06:14

+0

表单*不应该*仍然有注册的句柄,因为'using'应该叫做'Dispose'。在睡眠之后是否有其他代码执行?或者一旦睡眠完成,程序是否会退出? – 2013-03-13 19:51:29

回答

1

与其说Sleep你可以使用一个可等待计时器(与CreateWaitableTimer函数创建),并继续运行一个消息循环(使用MsgWaitForMultipleObjects功能),直到计时器到期。

+0

我已经更新了我的帖子:“睡眠”电话只是一个快速重现问题的例子。在我的生产代码中,各种形式在任意时间显示为长时间运行的应用程序线程的一部分。消息队列与这些窗口关联。但是窗口的范围re:EnumWindows与它的范围re不同:SendMessage!这正是我想要处理的。 – 2013-03-13 21:21:13