.NETでグローバルフック

.NET Frameworkでマウスとキーボードのグローバルフックができたのでメモ。
NETではほげほげな理由でグローバルフックはできないそうですが、例外的にマウスとキーボードの低水準フックだけはできるそうです。下のサイトではマウスのローカルフックのやり方が示されています。
How to set a Windows hook in Visual C# .NET


上の例からグローバルフックに変えるためにはSetWindowsHookExに与えるパラメータを少し変える必要があるみたいで、その変え方は以下のサイトにありました。そして、その理由はもう一つ下のサイトに。しかし、どうしてこの二つだけ例外的に扱われているのでしょうね。ちなみにこの方法によるフックはNT系でしか使えないようです。
Low-Level Global Hooks in .NET 2.0 - Srivatsn's Blog - Site Home - MSDN Blogs
What is the HINSTANCE passed to SetWindowsHookEx used for? - The Old New Thing - Site Home - MSDN Blogs


もう少し調べたらSetWindowsHookExをラップして使いやすくしているものが見つかりました。しかし、そのままだと動かなかったので、SetWindowsHookExに与えるパラメータを上のフックと同じようにGetModuleHandleを使ったらうまくいきました。
ぬるり。: グローバルフック・ザ・キーボード


試しに使ってみると以下のように非常に簡単に使えることがわかりました。Form1クラスと同じ名前空間に先ほどのクラスに突っ込むなりusingするなりしてコンパイルすると、このフォームがアクティブじゃなくなってもVisual Studioデバッグウィンドウに入力したキーコードが表示されます。

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();
  }

  private void Form1_Load(object sender, EventArgs e)
  {
    keyHook = new KeyboardHook();
    keyHook.KeyboardHooked += new KeyboardHookedEventHandler(keyHookProc);
  }

  private void keyHookProc(object sender, KeyboardHookedEventArgs e)
  {
    Debug.WriteLine(e.KeyCode.ToString("d"));
  }

  private static KeyboardHook keyHook;
}

delegateとかP/Invokeとかマーシャリングとかわからないことが多くて手間取りました。。