I set up a thread-specific window binding to track messages sent to WndProc. At first he worked. However, after I pressed Tab about 19 times to move the focus around the form, my hook callback is called nolonger. This caused concern about whether I pressed Tab quickly or slowly. Can anyone explain what is really happening?
Below is the code I wrote. I tested it on a 64-bit version of Windows 7.
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); /// <summary> /// The main entry point for the application. /// </summary> [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); } } }
source share