System.Windows.Forms.NativeWindowによる、メッセージ専用ウインドウの作成
サンプルコードNativeWindowMessageOnly.zip
NativeWindowクラスは、ウインドウ処理の基本となる処理をまとめたクラスで、ウインドウメッセージ(SendMessage,PostMessage)とウインドウプロシージャ(WndProc)の処理をカプセル化するための処理が集まっています。今回はこの機能を利用してメッセージ専用ウインドウを作成します。
メッセージ専用ウインドウとは、その名前の通りメッセージのみを扱うウインドウです。ウインドウサイズは0で画面に表示されません。ウインドウというとFormやButtonなどの画面の構成要素を想像しますが、表示しないウインドウも作成する事ができます。使用用途は、プロセス間通信に使用するWM_COPYDATAやウインドウメッセージのリフティングになります。また、アドインなど画面を持たないプログラム上でウインドウメッセージのリフティングをするさいの対象となるウインドウのために利用することもできます。
この場合にシンプルなウインドウ処理を実装しているNativeWindowクラスが基本クラスとなります。
メッセージ専用ウインドウ。ウインドウメッセージのリフティング処理で、現在のスレッドがIDLE(暇)になった場合に処理を実行します。コンストラクタでサイズ0でウインドウハンドルを作成し、Finalizeメソッドをオーバーライドしてウインドウハンドルを破棄しています。
Imports System.Runtime.InteropServicesPublic Class MessageOnlyWindow
Inherits NativeWindow
_
Private Shared Function PostMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean
End FunctionPublic Const WM_USER As UInteger = &H400
Public Const WM_IDLE As UInteger = WM_USER + 1Private Const WS_BORDER As Int32 = &H800000
Public Sub New()
MyBase.New()
Dim cp As New CreateParams
cp.X = 0
cp.Y = 0
cp.Height = 0
cp.Width = 0cp.Style = WS_BORDER
Me.CreateHandle(cp)
End Sub
Protected Overrides Sub Finalize()
Me.DestroyHandle()
End Sub
Public Sub PostIdleMessage()
PostMessage(Me.Handle, WM_IDLE, IntPtr.Zero, IntPtr.Zero)
End SubProtected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_IDLE Then
Debug.Print("IDLEメッセージを受信しました。")
Exit Sub
End IfMyBase.WndProc(m)
End Sub
End Class
検証用のコードです。処理の先頭でIDLEメッセージをメッセージ専用ウインドウに対してPostMessageしていますが、処理が行われるのはSleep処理のあとの5秒後であることを確認します。(5秒間は現在のスレッドはSleepするため)
Public Class Form1Private _messageOnlyWindow As New MessageOnlyWindow
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
_messageOnlyWindow.PostIdleMessage()
System.Threading.Thread.Sleep(5 * 1000)
End Sub
End Class
5秒後にイミディエイトウインドウに以下のように出力されます。
IDLEメッセージを受信しました。
今回はウインドウメッセージがメッセージキューの末尾に入ること、現在のスレッドが終了するまでメッセージキューが処理されないことを確認するために処理の先頭でIDLEメッセージを送信していますが、ウインドウメッセージのリフティング処理では通常は処理の末尾でPostMessageを行います。ある処理で画面操作を行った場合に内部的に様々なメッセージが画面の部品に対してPostMessageされている可能性があるためです。先頭でPostMessageしてしまうと、処理が終わるまでに様々なメッセージがメッセージキューに入る場合があります。
gsf_zero1さんもNativeWindowについて記事を書かれてたので紹介します。1年も前にすでに記載されてました!
[C#] .NET クラスライブラリ探訪-016 (System.Windows.Forms.NativeWindow) (WndProcオーバーライド, メッセージ)
http://d.hatena.ne.jp/gsf_zero1/20080903/p1