我有两段非常相似的代码,它们注册了全局钩子。
注册全局键盘钩子:
public class KeyboardHook : IDisposable
{
#region Events
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public delegate void HookEventHandler(object sender, KeyboardHookEventArgs e);
public event HookEventHandler KeyDown;
public event HookEventHandler KeyUp;
#endregion
#region Constants
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_SYSKEYDOWN = 0x0104;
private LowLevelKeyboardProc _proc = null;
private static IntPtr _hookID = IntPtr.Zero;
#endregion
#region Imports
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion
#region Constructor
public KeyboardHook()
{
_proc = new LowLevelKeyboardProc(HookCallback);
_hookID = SetHook(_proc);
}
#endregion
#region Methods
private IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
//if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))
{
int vkCode = Marshal.ReadInt32(lParam);
WinForms.Keys key = (WinForms.Keys)vkCode;
if (this.KeyDown != null)
this.KeyDown(this, new KeyboardHookEventArgs(vkCode));
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
#endregion
#region Destructor
public void Dispose()
{
UnhookWindowsHookEx(_hookID);
}
#endregion
}
注册全局shell挂钩:
public enum ShellEvents
{
HSHELL_WINDOWCREATED = 1,
HSHELL_WINDOWDESTROYED = 2,
HSHELL_ACTIVATESHELLWINDOW = 3,
HSHELL_WINDOWACTIVATED = 4,
HSHELL_GETMINRECT = 5,
HSHELL_REDRAW = 6,
HSHELL_TASKMAN = 7,
HSHELL_LANGUAGE = 8,
HSHELL_ACCESSIBILITYSTATE = 11
}
public class ShellHook
{
#region Events
private delegate IntPtr ShellProc(int nCode, IntPtr wParam, IntPtr lParam);
public delegate void HookEventHandler(object sender, ShellHookEventArgs e);
public event HookEventHandler WindowActivated;
#endregion
#region Constants
private const int WH_SHELL = 10;
private ShellProc _proc = null;
private static IntPtr _hookID = IntPtr.Zero;
#endregion
#region Imports
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
ShellProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
#endregion
#region Fields
#endregion
#region Constructor
public ShellHook()
{
_proc = new ShellProc(HookCallback);
_hookID = SetHook(_proc);
}
#endregion
#region Methods
private IntPtr SetHook(ShellProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_SHELL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam.Equals(ShellEvents.HSHELL_WINDOWACTIVATED))
{
string windowTitle = GetWindowTitle(wParam);
if (this.WindowActivated != null)
this.WindowActivated(this, new ShellHookEventArgs(windowTitle));
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private string GetWindowTitle(IntPtr hWnd)
{
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
if (GetWindowText(hWnd, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
#endregion
#region Destructor
public void Dispose()
{
UnhookWindowsHookEx(_hookID);
}
#endregion
}
由于某种原因,键盘钩子工作,但shell钩子失败(SetWindowsHookEx
返回0
并且永远不会回调)。
任何想法为什么?
答案 0 :(得分:2)
我想我会回答我自己的问题。来自pinvoke.net的引用解释了为什么......
但是,您无法在Microsoft .NET Framework中实现全局挂钩 除了低级别的钩子。要安装全局钩子,钩子必须有一个 本机动态链接库(DLL)导出将自己注入另一个 需要有效,一致的函数才能调用的进程。这个 需要DLL导出,.NET Framework不支持。管理 代码没有函数指针的一致值的概念 因为这些函数指针是构建的代理 动态。