2008年1月16日水曜日

マウスの位置を取得し続ける(C#) その4

前回前々回の記事を見ていない人は先にそちらを。


前回までで、ローカルフックを用いてマウスの位置を取得し続けることはできました。

しかし、ローカルフックでは、そのプログラムが動いているスレッド上でしかマウスの
位置が取得できません。
(前回の場合、スレッド上で動いているのは"Form1"のみなので、
 "Form1"上の位置は取得できます。)

そこで、前回のソースを少し改変して、グローバルフックで取得できるようにします。

グローバル(Low-Level)フックを用いて、マウスメッセージを取得するためには、
フックタイプとして以下の値が必要になります。

/*** Form1.cs ***/
private const int WH_MOUSE_LL = 14;
"GetModuleHandle"メソッドをDLLインポートします。

/*** HookMethods.cs ***/
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(String lpModuleName);

"SetMouseHook"メソッドを以下のように変更します。

/*** Form1.cs ***/
private void SetMouseHook(HookMethods.HookProcedureDelegate proc)
{
using(Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
{
hHook = HookMethods.SetWindowsHookEx(WH_MOUSE_LL, proc, HookMethods.GetModuleHandle(module.ModuleName), 0);
}

if (hHook == IntPtr.Zero)
{
MessageBox.Show("SetWindowsHookEx Failed.");
}
}

実行します。



"Form1"以外でも、マウスの位置を取得できました。

上記のソースコードについて解説します。

"GetModuleHandle"メソッドは、呼び出し側プロセスのアドレス空間に
マップされているモジュールのハンドルを返します。
モジュール名の指定は、1つ目の引数"lpModuleName"に指定します。
"SetWindowsHookEx"メソッドの3つ目の引数"hInstance"は、
フックプロシージャを保持しているモジュールのハンドルを指定する必要が
あります。
"GetModuleHandle"が返すハンドルを"SetWindowsHookEx"の
3つ目の引数として与えることで、モジュールを指定します。

usingステートメント
using( オブジェクトの生成 )
{
処理
}

usingステートメントを用いると、using{ }ブロックから制御が離れた時に、
( )内で生成されたオブジェクトのDispose呼び出しが自動的に行われます。

usingステートメントはアンマネージリソースに対して効果を発揮します。

アンマネージリソース
C#を使っていると、オブジェクトに対してメモリ管理を意識することはありません。
これは、自動メモリ管理機能「ガベージコレクタ」が管理してくれているからです。
しかし、一部のオブジェクトはメモリを解放するタイミングを意識して
プログラムしなければなりません。
このオブジェクトをアンマネージリソースと言います。
ファイルやウィンドウ、データベース接続などがその対象です。


今回の場合、"ProcessModule"がアンマネージリソースであるため、
usingステートメントが使用されています。
(モジュールは、".dll"や".exe"などの実行ファイルだから。)


これで、どの位置にあるマウスでも、その位置を取得し続けることができました。

ただ、本当は位置だけではなく、他の情報も取得できます。
(例えば、マウスクリックとか)

0 件のコメント: