Инсталирах специфична за нишка кука за Windows, за да наблюдавам съобщенията, изпратени до WndProc. Отначало проработи. Въпреки това, след като натиснах Tab около 19 пъти, за да преместя фокуса около формуляр, моето обратно извикване на кука вече не се извиква. Това се случи независимо от това дали натиснах Tab бързо или бавно. Може ли някой да обясни какво всъщност се случва?
По-долу е кодът, който написах. Тествах го на Windows 7 64 bit.
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);
}
}
}