C'è una correzione da fare nella classe TestHook. L'oggetto delegate va impostato come membro della classe, altrimenti può portare ad un eccezione di Callback dopo l'esecuzione del Garbage Collector

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Windows.Forms;

namespace TestHook
{
public delegate long KeyboardCallbackDelegation(int code, Int32 wParam, IntPtr lParam);
private KeyboardCallbackDelegation keyCallbackDeleg = new KeyboardCallbackDelegation(KeyboardCallback);

public struct KBDLLHOOKSTRUCT{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
class Hook
{
[DllImport("user32")]
public static extern short GetAsyncKeyState(int vKey);

[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, KeyboardCallbackDelegation lpfn, IntPtr hInstance, int threadId);

//Import for UnhookWindowsHookEx.
//Call this function to uninstall the hook.
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);

//Import for CallNextHookEx.
//Use this function to pass the hook information to next hook procedure in chain.
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode,Int32 wParam, IntPtr lParam);

//Low-Level Keyboard Constants
private const int HC_ACTION = 0x0;
private const int LLKHF_EXTENDED = 0x1;
private const int LLKHF_INJECTED = 0x10;
private const int LLKHF_ALTDOWN = 0x20;
private const int LLKHF_UP = 0x80;

// Virtual Keys
public const int VK_TAB = 0x9;
public const int VK_CONTROL = 0x11;
public const int VK_ESCAPE = 0x1B;
public const int VK_DELETE = 0x2E;

private const int WH_KEYBOARD_LL = 13;

public int keyboardHandle;

public KeyboardHook keyboardHook;

public Hook(KeyboardHook keyboardHook)
{
this.keyboardHook = keyboardHook;
}

public bool isHooked(ref KBDLLHOOKSTRUCT HookStruct) {
if (keyboardHook == null)
{
return false;
}
if (HookStruct.vkCode == VK_ESCAPE && GetAsyncKeyState(VK_CONTROL)==VK_CONTROL) {
return keyboardHook.BlockControlEscape();
}
if (HookStruct.vkCode == VK_TAB && (HookStruct.flags== LLKHF_ALTDOWN))
{
return keyboardHook.BlockAtlTab();
}
if (HookStruct.vkCode == VK_ESCAPE && (HookStruct.flags == LLKHF_ALTDOWN))
{
return keyboardHook.BlockAltEscape();
}
return false;
}
public long KeyboardCallback(int code, Int32 wParam, IntPtr lParam)
{


//KBDLLHOOKSTRUCT Hookstruct = new KBDLLHOOKSTRUCT();
if (code == HC_ACTION) {
//CopyMemory(Hookstruct, lParam.ToInt32(), 5);
KBDLLHOOKSTRUCT Hookstruct = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
if (isHooked(ref Hookstruct)) {
return 1;
}
}
return CallNextHookEx(keyboardHandle, code, wParam, lParam);
}
public void HookKeyboard() {
keyboardHandle = SetWindowsHookEx(WH_KEYBOARD_LL, keyCallbackDeleg, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly ().GetModules()[0]), 0);
if (keyboardHandle != 0)
{
MessageBox.Show("Keyboard hooked");
}
else {
MessageBox.Show("Keyboard hooked failed");
}
}
public void UnookKeyboard() {
if (keyboardHandle != 0) {
UnhookWindowsHookEx(keyboardHandle);
}
}
}
}