DLL中的KeyboardHookProc在python中调用时无效果
我一直在尝试用C语言写一个DLL。
安装钩子时设置了键盘处理函数。每次从Python调用 InstallHook()
和 UninstallHook()
函数时,结果总是返回0,我猜这可能是因为我的回调函数 KeyboardProc
没有正常工作。
下面是我写的DLL的C代码:
#include "stdafx.h"
#include <windows.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "ourdll.h"
//#pragma comment(linker, "/SECTION:.SHARED,RWS")
//#pragma data_seg(".SHARED")
HHOOK hKeyboardHook = 0;
int keypresses = 0;
HMODULE hInstance = 0;
//#pragma data_seg()
BOOL WINAPI DllMain (HANDLE hModule, DWORD dwFunction, LPVOID lpNot)
{
hInstance = hModule; //Edit
return TRUE;
}
LRESULT CALLBACK KeyboardProc(int hookCode, WPARAM vKeyCode, LPARAM flags)
{
if(hookCode < 0)
{
return CallNextHookEx(hKeyboardHook, hookCode, vKeyCode, flags);
}
keypresses++;;
return CallNextHookEx(hKeyboardHook, hookCode, vKeyCode, flags);
}
__declspec(dllexport) void InstallHook(void)
{
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hInstance, 0);
}
__declspec(dllexport) int UninstallHook(void)
{
UnhookWindowsHookEx(hKeyboardHook);
hKeyboardHook = 0;
return keypresses;
}
使用这个DLL的Python代码如下:
>>> from ctypes import *
>>> dll = CDLL('C:\...\OurDLL.dll')
>>> dll.InstallHook()
[在这里输入一些内容]
>>> result = dll.UninstallHook()
>>> result
0
补充一下,我还尝试过 LowLevelKeyboardHook
。我知道这个低级钩子是全局的,可以捕捉到所有的按键,但这导致我的 dll.InstallHook()
的Python代码在返回0之前卡了一两秒。
我对C语言不是很精通,所以任何帮助都非常感谢。谢谢。
1 个回答
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, 0);
SetWindowsHookEx 这个函数需要一个 hModule 参数 - 你需要在 DllMain 中保存这个 hModule,然后在这里传递它。(如果线程 ID 是你自己的线程,你可以传 NULL。)
不过,有一个例外,就是 _LL 类型的钩子;这些钩子不需要 hModule 参数,因为它们不会注入到目标进程中 - 这就是为什么你使用 KEYBOARD_LL 时代码能“成功”的原因。
至于为什么使用 KEYBOARD_LL 时可能会出现阻塞,LowLevelKeyboardHookProc 的文档提到,安装钩子的线程(也就是调用 SetWindowsHookEx 的线程)必须有一个消息循环,而你在 Python 代码中可能没有这个循环。
调试小贴士:看起来 SetWindowsHookEx 应该返回 NULL(同时 GetLastError() 会返回一个合适的错误代码);在开发代码时,使用 assert、printf 或 OutputDebugString 等方法来检查这些返回值是个好主意,这样可以确保你的假设是正确的,并给你一些线索,帮助你找出问题出在哪里。
顺便提一下,使用 KEYBOARD 和 KEYBOARD_LL 时还有一点需要注意:KEYBOARD 钩子会被加载到目标进程中 - 但前提是它们的位数要相同 - 所以一个 32 位的钩子只能看到其他 32 位进程按下的键。另一方面,KEYBOARD_LL 是在你自己的进程中被调用的,所以你可以看到所有的按键 - 而且不需要处理共享段(不过据我所知,它的效率也比 KEYBOARD 钩子低)。