2013-03-13 124 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