title: Thread hook procedure is no longer called after pressing Tab several times. Why?
body: <p>I installed a thread-specific windows hook to monitor messages sent to WndProc. It worked at first. However, after I pressed Tab about 19 times to move focus around a form, my hook callback is nolonger called. This happened regaless of whether I pressed Tab quickly or slowly. Can anybody explain what is really going on?</p>
  
  <p>Below is the code I wrote. I tested it on Windows 7 64 bit.</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Windows.Forms;
  using System.Runtime.InteropServices;
  
  namespace HookTest
  {
      static class Program
      {
          private const int WH_CALLWNDPROC = 4;
  
          private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
  
          private class MainForm : Form
          {
              private Button button1;
              private TextBox textBox1;
  
              public MainForm()
              {
                  this.button1 = new System.Windows.Forms.Button();
                  this.textBox1 = new System.Windows.Forms.TextBox();
                  this.SuspendLayout();
                  // 
                  // button1
                  // 
                  this.button1.Location = new System.Drawing.Point(12, 38);
                  this.button1.Name = "button1";
                  this.button1.Size = new System.Drawing.Size(75, 23);
                  this.button1.TabIndex = 0;
                  this.button1.Text = "Button 1";
                  this.button1.UseVisualStyleBackColor = true;
                  // 
                  // textBox1
                  // 
                  this.textBox1.Location = new System.Drawing.Point(12, 12);
                  this.textBox1.Name = "textBox1";
                  this.textBox1.Size = new System.Drawing.Size(100, 20);
                  this.textBox1.TabIndex = 1;
                  // 
                  // MainForm
                  // 
                  this.Controls.Add(this.textBox1);
                  this.Controls.Add(this.button1);
                  this.Name = "MainForm";
                  this.Text = "Main Form";
                  this.ResumeLayout(false);
                  this.PerformLayout();
              }
          }
  
          private static IntPtr hWndProcHook = IntPtr.Zero;
          private static int messageCount = 0;
  
          [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
          public static extern IntPtr GetModuleHandle(string lpModuleName);
  
          [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
          public static extern uint GetCurrentThreadId();
  
          [DllImport("User32.dll", CharSet = CharSet.Auto)]
          private static extern IntPtr SetWindowsHookEx(int idHook,
              HookProc lpfn, IntPtr hMod, uint dwThreadId);
  
          [DllImport("User32.dll", CharSet = CharSet.Auto)]
          [return: MarshalAs(UnmanagedType.Bool)]
          private static extern bool UnhookWindowsHookEx(IntPtr hhk);
  
          [DllImport("User32.dll", CharSet = CharSet.Auto)]
          private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
              IntPtr wParam, IntPtr lParam);
  
          /// &lt;summary&gt;
          /// The main entry point for the application.
          /// &lt;/summary&gt;
          [STAThread]
          static void Main()
          {
              Application.EnableVisualStyles();
              Application.SetCompatibleTextRenderingDefault(false);
              InstallHook();
              Application.Run(new MainForm());
              UninstallHook();
          }
  
          private static void InstallHook()
          {
              if (Program.hWndProcHook == IntPtr.Zero)
              {
                  Console.WriteLine("Hooking...");
  
                  Program.hWndProcHook = SetWindowsHookEx(
                      WH_CALLWNDPROC,
                      WndProcHookCallback,
                      GetModuleHandle(null),
                      GetCurrentThreadId());
  
                  if(Program.hWndProcHook != IntPtr.Zero)
                      Console.WriteLine("Hooked successfully.");
                  else
                      Console.WriteLine("Failed to hook.");
              }
          }
  
          private static void UninstallHook()
          {
              if (Program.hWndProcHook != IntPtr.Zero)
              {
                  Console.WriteLine("Unhooking...");
  
                  if (UnhookWindowsHookEx(Program.hWndProcHook))
                      Console.WriteLine("Unhooked successfully.");
                  else
                      Console.WriteLine("Failed to unhook.");
  
                  Program.hWndProcHook = IntPtr.Zero;
              }
          }
  
          private static IntPtr WndProcHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
          {
              Console.WriteLine("WndProcHookCallback {0}", Program.messageCount++);
  
              return CallNextHookEx(Program.hWndProcHook, nCode, wParam, lParam);
          }
      }
  }
  </code></pre>