我正在设置键盘的全局钩子。当我将键盘输入提供给其他应用程序时,应用程序不会收到输入并挂起。当控制台停止时,应用程序将恢复,键盘输入将一起发布。
DLL源:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
#define DLLEXPORT __declspec(dllexport)
DLLEXPORT bool installhook();
DLLEXPORT void unhook();
DLLEXPORT string TestLoaded();
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam );
static HHOOK kb_hook;
string test = "not loaded";
HINSTANCE hDLL;
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if(code == HC_ACTION) // if there is an incoming action and a key was pressed
{
switch(wParam)
{
case VK_SPACE:
printf("Space was pressed\n"); //tried without this also
MessageBoxA(NULL, "Hi", "Space", MB_OK);
break;
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
test = "loaded";
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hDLL = hModule;
break;
}
printf("test str = %s \n", test.c_str());
return TRUE;
}
bool installhook()
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hDLL, NULL);
if(!kb_hook)
{
return false;
}
return true;
}
void unhook()
{
if(kb_hook)
{
UnhookWindowsHookEx(kb_hook);
}
}
string TestLoaded()
{
return test;
}
控制台应用来源:
#include <iostream>
#include <Windows.h>
#include <string>
#define DLLIMPORT __declspec(dllimport)
using namespace std;
DLLIMPORT void unhook();
DLLIMPORT bool installhook();
DLLIMPORT string TestLoaded();
int main()
{
cout << TestLoaded() <<endl;
installhook();
for(int i = 1; i<=10 ; i++)
{
//Do some keyboard activities in this 10 secs
Sleep(1000);
cout << i<<endl;
}
unhook();
cin.get();
return 1;
}
我的怀疑是,由于dll将被加载到进程自己的地址空间中的每个进程中,并且控制台不会出现在其他应用程序中,因此它将失效并崩溃。所以我删除了控制台输出并替换为messagebox。然后也没什么区别。
可能是什么问题?
更新
我尝试在尝试全局之前对特定线程执行本地挂钩。但是我在setwindowshookex得到Parameter is incorrect
错误87
。以下是更新后的代码:
DLL:
bool installhook(DWORD ThreadId) //exporting this function
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, ThreadId); //tried with the dll module's handle also instead of NULL
if(!kb_hook)
{
printf("SetWindowsHookEx failed : %d\n", GetLastError());
return false;
}
return true;
}
控制台应用程序源:
DWORD myThread()
{
cout<< "Thread started\n";
char str[250];
cin>>str;
return 0;
}
int main()
{
cout << TestLoaded() <<endl;
DWORD myThreadID;
HANDLE myHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)myThread, NULL, 0, &myThreadID);
installhook(myThreadID);
for(int i = 0; i<100 ; i++)
{
Sleep(100);
if(i%10 == 0)
{
cout << i<<endl;
}
}
unhook();
}
答案 0 :(得分:2)
尝试使用WH_KEYBOARD_LL。即使没有dll在你的进程中声明钩子函数,你也可以设置全局钩子。另外,您应该使用PKBDLLHOOKSTRUCT struct
检测空间动作LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if ( code == HC_ACTION )
{
switch ( wParam )
{
case WM_KEYDOWN:
{
// Get hook struct
PKBDLLHOOKSTRUCT p = ( PKBDLLHOOKSTRUCT ) lParam;
if ( p->vkCode == VK_SPACE)
{
MessageBoxA( NULL, "Hi", "Space", MB_OK );
}
}
break;
}
}
return CallNextHookEx( NULL, code, wParam, lParam );
}
....
// Somewhere in code
kb_hook = SetWindowsHookEx( WH_KEYBOARD_LL, KeyboardProc, NULL, NULL );
答案 1 :(得分:0)
我有同样的问题,使用QT,GUI会被阻止(按计划),但每当它重新上线时,它都会处理我的键盘和鼠标点击。
我不确定这是否是处理它的最有效方法,但为了解决这个问题,我分别处理了所有键盘和鼠标事件。如果某项任务正在进行中,我会忽略关键事件。
否则我猜它只是排队等待它的'转!
答案 2 :(得分:0)
感谢答案和评论中的所有输入。
我发现了实际问题。我犯的错误是尝试使用没有任何消息队列的控制台窗口。
如果我理解正确,控制台窗口由conhost.exe托管,他们没有任何消息泵。只有当安装它的应用程序有一个消息队列时,钩子才能正常工作(应该通过这种方式探索更多关于它的原因)。请参阅下文了解如何使其发挥作用
如果您没有向控制台应用程序发布任何消息:
使用以下命令替换控制台应用程序主要中的for循环:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
如果您要向控制台应用程序发布任何消息:
使用CreateWindowEx
创建一个窗口,还有一个仅限消息窗口的选项。您必须创建一个类并分配一个CALLBACK过程。阅读here了解更多详情。创建它并将句柄传递给钩子dll和postmessage到句柄。使用循环获取消息并调度它(如上所述)。然后,您可以使用CALLBACK窗口进程处理从钩子dll发布虚拟窗口的所有消息。
<强>参考文献:强>
Why must SetWindowsHookEx be used with a windows message queue