.NET TIPS

WindowsフォームでWindowsメッセージを直接処理するには?

デジタルアドバンテージ 遠藤 孝信
2006/06/30

 Windows OSでは、ユーザーからの入力や操作はすべてメッセージ(以下、Windowsメッセージ)として処理される。例えばマウス・カーソルが移動された場合には「WM_MOUSEMOVE」というIDのWindowsメッセージがウィンドウに送られるため、プログラムではユーザーによるマウス・カーソルの移動を知ることができる。

 しかし.NETのWindowsフォームでは、たいていの場合、直接Windowsメッセージをプログラムで処理する必要はなく、フォームのメンバであるWndProcメソッドが、受け取ったWindowsメッセージを.NETのイベントに置き換えてくれる*。WM_MOUSEMOVEメッセージがフォームに送られてきたら、フォームでMouseMoveイベントが発生するといった具合だ。実際この場合には、MouseMoveイベントのイベント・ハンドラを記述すれば、マウス移動時の処理を記述できる。

* 実際には、フォーム(Formクラス)の基本クラスであるControlクラスのWndProcメソッドでも、多くのWindowsメッセージが処理されている。

 だが、すべてのWindowsメッセージがWndProcメソッドでイベントに置き換えられるわけではない。このため少し特殊な処理をフォームに実装したい場合などでは、プログラムで直接Windowsメッセージを取得し処理しなければならないこともある。本稿ではそのようなケースでの処理について解説する。

WndProcメソッドのオーバーライド

 フォームに送られてくるWindowsメッセージを直接プログラムで処理したい場合には、Formクラス(System.Windows.Forms名前空間)のWndProcメソッドを自分のフォームでオーバーライドすればよい。

 Visual Studioを利用している場合、基本クラスのメソッドのオーバーライドは、コード画面でフォームのコードを開き、C#の場合には「override」、VBの場合には「Overrides」と入力すればオーバーライド可能なメソッドが一覧され、以下のようなメソッドを簡単にコード内に挿入できる。

protected override void WndProc(ref Message m) {
  base.WndProc(ref m);
}
Protected Overrides Sub WndProc(ByRef m As Message)
  MyBase.WndProc(m)
End Sub
フォームのWndProcメソッドをオーバーライドするメソッドのひな型(上:C#、下:VB)
Visual Studioを利用している場合、C#の場合には「override」、VBの場合には「Overrides」と入力すれば、このようなメソッドのひな型が自動挿入される。

 このメソッドはフォームにWindowsメッセージが送られるたびに呼び出される。また、メソッドのパラメータであるMessage構造体(System.Windows.Forms名前空間)のオブジェクトが、フォームに送られてきたWindowsメッセージを表している*

* 「m.Msg」の値を画面に表示するようにすれば、マウス・カーソルの移動時には512番(WM_MOUSEMOVEメッセージのIDの値。16進数では「200」)のメッセージが送られているのが分かるはずだ。

 このようにしてフォームでWndProcメソッドをオーバーライドすれば、実際にウィンドウに送られてきているすべてのWindowsメッセージをチェックできるため、.NETのイベントに対応していないWindowsメッセージの処理が可能だ。以下にその一例を示す。

[×]ボタンで閉じないウィンドウ

 ここでは、WM_NCHITTESTメッセージを処理する例を示す。このメッセージはすべてのマウス入力メッセージに先立って送られてくるメッセージで、このメッセージが送られてくると、フォームのWndProcメソッドはウィンドウ内のどの部分にマウス・カーソルがあるのかを返すことになっている(返す結果はMessageオブジェクトのResultプロパティにセットされる)。

 例えば、マウス・カーソルがウィンドウ右上隅にある[×]ボタン上にある場合には、WndProcメソッドでの処理の結果、Resultプロパティの値は「20」となる。そこで、WndProcメソッドを以下のような内容でオーバーライドして、Resultプロパティの値が「20」のときに限り、その値をマウス・カーソルがどこも指していない状態である「0」に置き換えれば、[×]ボタンをクリックしても閉じないフォームが出来上がる。

protected override void WndProc(ref Message m) {
  base.WndProc(ref m);
  if (m.Msg == 0x84) {            // 0x84 : WM_NCHITTEST
    if (m.Result == (IntPtr)20) { // 20   : HTCLOSE
      m.Result = (IntPtr)0;       // 0    : HTNOWHERE
    }
  }
}
Protected Overrides Sub WndProc(ByRef m As Message)
  MyBase.WndProc(m)
  If m.Msg = &H84 Then                   ' &H84 : WM_NCHITTEST
    If m.Result = CType(20, IntPtr) Then ' 20   : HTCLOSE
      m.Result = CType(0, IntPtr)        ' 0    : HTNOWHERE
    End If
  End If
End Sub
ウィンドウを[×]ボタンで閉じなくするWndProcメソッド(上:C#、下:VB)
このコードを試すには、Visual StudioでWindowsアプリケーションのプロジェクトを新規作成し、Form1.csを開いてForm1クラスのメンバとしてこのメソッドを追加すればよい。

 なお、このコード中で使用している3つの定数(16進数の「84」や「20」「0」)は、プラットフォームSDKに含まれるC/C++言語向けのヘッダ・ファイルであるWinUser.hで定義されているものだ*

* WinUser.hファイルはVisual Studio 2005 Professional Editionなどには含まれている。それ以外のエディションを使用している場合は、「Microsoft Download Center: Windows Server 2003 R2 Platform SDK Web Install」からプラットフォームSDK(PSDK-x86.exe)の[Microsoft Windows Core SDK]−[Build Environment]−[Build Environment (x86 32-bit)]をインストールすれば、インストールしたプラットフォームSDKのIncludeフォルダ内に配置されるはずだ。また、MSDNでは公開されていないが、Googleなどで検索すれば、実際にそのファイルの内容を公開しているサイトが見つかる。

 WinUser.hでは、これらの定数には上記コードのコメントにあるように、「WM_NCHITTEST」「HTCLOSE」「HTNOWHERE」という定数名が付けられている。Windowsメッセージを直接処理するコードを記述するには、プラットフォームSDKのヘルプやWinUser.hの内容をよく調べる必要がある。End of Article

カテゴリ:Windowsフォーム 処理対象:ウィンドウ
使用ライブラリ:Formクラス(System.Windows.Forms名前空間)
使用ライブラリ:Message構造体(System.Windows.Forms名前空間)

この記事と関連性の高い別の.NET TIPS
時間がかかる処理での「応答なし」を回避するには?
Windowsアプリケーションでキー処理が行われる順序は?
不要となった古いクラスやメソッドを残すには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」

TechTargetジャパン

Insider.NET フォーラム 新着記事

@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

RSSフィード

キャリアアップ

- PR -
@IT Sepcial

イベントカレンダー

PickUpイベント

- PR -
もっと見る
- PR -

お勧め求人情報

ホワイトペーパーTechTargetジャパン

@IT Sepcial
ソリューションFLASH