2009-09-30 8 views
16

名前付きパイプからメッセージを読み取るスレッドがあります。これはブロッキング読み取りであり、その理由は独自のスレッドにあるからです。このスレッドがメッセージを読むとき、私はそれがメッセージが準備ができているメインスレッドで実行されているWindowsフォームのメッセージループに通知する必要があります。どうやってやるの? Win32ではPostMessageをやっていましたが、その機能は.Net(あるいは少なくとも私はそれを見つけることができませんでした)には存在していないようです。Windowsフォームのメッセージループにメッセージを送信または投稿します。

答えて

15

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)); 
    } 
} 

リサイズに依存しない上記のクリーナー変異体は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); 
     } 
    } 
+0

示されているように、OnSomethingReady()メソッドに競合条件があります。 SomethingReadyイベントは、nullのチェック後、イベントが発生する前にnullに設定できます。これを避けるには、http://blogs.msdnのアドバイスに従ってください。com/brada/archive/2005/01/14/353132.aspx –

+1

@ wcoenen、私を許してください。しかし、私は先に進み、問題を修正しました。 –

18

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関数の使い方の詳細。特にPostMessageの場合はSee this pageです。

標準宣言は以下の通りです:

[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()); 
    } 
}   
+0

必ずしもPostMessageを使用する必要はありません。私がしたいことをするためのプレーンなネット方法はありませんか? –

+0

短い答え:いいえ –

+0

マイクは正しいです。 Win32 APIに基づくWindowsメッセージループを使用しているため、P/Invokeが必要です。 – Noldorin

4

あなたは、実際に投稿したいと思っていますメッセージループへのメッセージ、または単にフォーム内の一部のコントロールを更新したい、メッセージボックスを表示したい、などですか?それが前者の場合は、@ Noldorinの応答を参照してください。後者の場合は、Control.Invoke()メソッドを使用して、呼び出しを「読み取り」スレッドからメインのUIスレッドにマーシャリングする必要があります。これは、コントロールが作成されたスレッドによってのみコントロールを更新できるためです。

これは.NETのかなり標準的なことです。あなたがこれを行う方法を理解すれば

(コミュニティコンテンツの最初の例を参照)

関連する問題