【发布时间】:2011-04-28 17:55:26
【问题描述】:
每当用户按下窗口中的某些键时,我的应用程序应该执行一些操作。
使用WH_KEYBOARD_LL 选项调用SetWindowsHookEx 似乎是实现此目的的标准方法。但是,在我的情况下,某些事情显然是错误的,并且没有触发回调。
我的调试控制台应用程序的主要方法:
static void Main(string[] args)
{
IntPtr moduleHandle = GetCurrentModuleHandle();
IntPtr hookHandle = IntPtr.Zero;
try
{
User32.HookProc hook = (nCode, wParam, lParam) =>
{
// code is never called :-(
if (nCode >= 0)
{
Console.WriteLine("{0}, {1}", wParam.ToInt32(), lParam.ToInt32());
}
return User32.CallNextHookEx(hookHandle, nCode, wParam, lParam);
};
hookHandle = User32.SetWindowsHookEx(User32.WH_KEYBOARD_LL, hook, moduleHandle, 0);
Console.ReadLine(); //
}
finally
{
if (hoodHandle != IntPtr.Zero)
{
var unhooked = User32.UnhookWindowsHookEx(hookHandle);
Console.WriteLine(unhooked); // true
hookHandle = IntPtr.Zero;
}
}
}
GetCurrentModuleHandle 方法:
private static IntPtr GetCurrentModuleHandle()
{
using (var currentProcess = Process.GetCurrentProcess())
using (var mainModule = currentProcess.MainModule)
{
var moduleName = mainModule.ModuleName;
return Kernel32.GetModuleHandle(moduleName);
}
}
从user32.dll 和kernel32.dll 导入:
public static class User32
{
public const int WH_KEYBOARD_LL = 13;
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
}
public static class Kernel32
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
}
你知道我的问题是什么吗?
【问题讨论】:
-
你有没有试过让你的 HookProc 成为一个真正的函数,也许是匿名函数声明的一些东西弄乱了它。只是在黑暗中开枪......
-
@Coding Gorilla:我试过了。没有帮助:-(
-
Jakub,我要做的第一件事就是在这里摆脱匿名方法。然后,检查包含该方法的类的持久性 - 当您的托管委托被删除并且仍然从非托管代码调用时会发生奇怪的事情。
-
@Jakub:您的 GetModuleHandle() 是否返回有效的模块句柄?
GetModuleHandle的 MSDN 文档表明,如果您将NULL传递给lpModuleName,它将默认使用调用进程。也许你可以试一试,看看你是否能得到更好的结果。 (更多在黑暗中拍摄=)) -
这是一个控制台应用程序吗?如果是这样,我认为这可以解释 Cyril Gupta 的回答。
标签: c# winapi setwindowshookex