我有一個從命名管道讀取消息的線程。這是一個阻塞閱讀,這就是爲什麼它在自己的線程。當此線程讀取消息時,我希望它通知在主線程中運行的Windows窗體消息循環已準備好消息。我怎樣才能做到這一點?在win32中,我會做一個PostMessage,但是這個函數似乎不存在於.Net中(或者至少我找不到它)。發送或發佈消息到Windows窗體消息循環
回答
在WinForms中,您可以使用Control.BeginInvoke來實現此目的。一個例子:
public class SomethingReadyNotifier
{
private readonly Control synchronizer = new Control();
/// <summary>
/// Event raised when something is ready. The event is always raised in the
/// message loop of the thread where this object was created.
/// </summary>
public event EventHandler SomethingReady;
protected void OnSomethingReady()
{
SomethingReady?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Causes the SomethingReady event to be raised on the message loop of the
/// thread which created this object.
/// </summary>
/// <remarks>
/// Can safely be called from any thread. Always returns immediately without
/// waiting for the event to be handled.
/// </remarks>
public void NotifySomethingReady()
{
this.synchronizer.BeginInvoke(new Action(OnSomethingReady));
}
}
其不依賴於的WinForms上述的清潔器的變體是使用SynchronizationContext
。在主線程上調用SynchronizationContext.Current,然後將該引用傳遞給下面顯示的類的構造函數。
public class SomethingReadyNotifier
{
private readonly SynchronizationContext synchronizationContext;
/// <summary>
/// Create a new <see cref="SomethingReadyNotifier"/> instance.
/// </summary>
/// <param name="synchronizationContext">
/// The synchronization context that will be used to raise
/// <see cref="SomethingReady"/> events.
/// </param>
public SomethingReadyNotifier(SynchronizationContext synchronizationContext)
{
this.synchronizationContext = synchronizationContext;
}
/// <summary>
/// Event raised when something is ready. The event is always raised
/// by posting on the synchronization context provided to the constructor.
/// </summary>
public event EventHandler SomethingReady;
private void OnSomethingReady()
{
SomethingReady?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Causes the SomethingReady event to be raised.
/// </summary>
/// <remarks>
/// Can safely be called from any thread. Always returns immediately without
/// waiting for the event to be handled.
/// </remarks>
public void NotifySomethingReady()
{
this.synchronizationContext.Post(
state => OnSomethingReady(),
state: null);
}
}
PostMessage
(以及同樣SendMessage
)是Win32 API函數,因此不直接與.NET關聯。但是.NET使用P/Invoke調用可以很好地支持與Win32 API的交互。
因爲看起來你是做Win32編程.NET的新手,所以this MSDN Magazine article提供了一個關於該主題的可靠介紹。
The excellent pinvoke.net website詳細介紹瞭如何使用C#/ VB.NET中的許多API函數。 See this page爲PostMessage
具體。
標準的聲明如下:
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
但是作爲頁面顯示,這是明智的包裝這個功能,妥善處理的Win32錯誤:
void PostMessageSafe(HandleRef hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
bool returnValue = PostMessage(hWnd, msg, wParam, lParam);
if(!returnValue)
{
// An error occured
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
我不一定要使用PostMessage。沒有簡單的.Net方式來做我想做的事情? – 2009-09-30 13:11:15
簡短回答:No. – 2009-09-30 13:12:25
邁克是對的。您正在使用Windows消息循環,它基於Win32 API,因此需要P/Invoke。 – Noldorin 2009-09-30 13:14:47
你真正想要發佈一條消息到消息循環,或者你只是想更新窗體中的某個控件,顯示一個消息框等?如果是前者,則參考@諾多林的迴應。如果是後者,那麼您需要使用Control.Invoke()方法來將您的「閱讀」線程的調用編組到主UI線程。這是因爲控件只能通過它們創建的線程來更新。
這是.NET中非常標準的東西。請參閱這些MSDN文章,以獲得基本知識:
- Control.Invoke Method
- Control.InvokeRequired Property(參考第一個例子中的社區內容)
一旦你瞭解如何做到這一點,請參閱Peter Duniho's blog如何提高在規範技術上。
- 1. 發送消息或收到消息?
- 2. Windows:將消息發送到父窗口?
- 3. 發送Windows消息
- 4. 消息框發送Windows消息?
- 5. Windows消息循環
- 6. 發佈者只發送無限循環中的消息
- 7. 用Mono發送Windows消息
- 8. 發送Windows消息到Windows服務
- 9. 如何將Windows消息發送到非主窗體
- 10. 發送消息
- 11. 發送消息
- 12. 發送消息
- 13. 發送消息到Windows GUI線程
- 14. Azure每天發送錯誤消息或發生錯誤消息
- 15. PHP表單發佈不發送消息
- 16. Excel VBA窗體錯誤消息循環
- 17. iPhone App發送Facebook消息或發佈到朋友的牆壁
- 18. 發送消息到對象
- 19. 發送消息到Twitter
- 20. 發送消息到WM_PAINT
- 21. MSMQ發佈消息
- 22. 發送C2DM消息
- 23. 發送SOAP消息
- 24. Android消息發送
- 25. OMNET發送消息
- 26. 發送PCIe消息
- 27. 不發送消息
- 28. 發送SMS消息
- 29. Zabbix發送消息
- 30. GCDAsyncSocket發送消息
如圖所示,OnSomethingReady()方法中存在競爭條件。在檢查null之後但在引發事件之前,可能會將SomethingReady事件設置爲null。爲了避免這種情況,請按照這裏的建議:http://blogs.msdn。com/brada/archive/2005/01/14/353132.aspx – 2009-09-30 14:46:56
@wcoenen,原諒我,但我繼續解決問題。 – 2009-09-30 14:54:28