全局键盘钩子有时会失效的问题!

nostopping 2010-06-14 11:03:19
如题:
有一C++写的DLL,用于实现全局键盘钩子,在C#程序中对其进行调用,安装的时候没有问题并且钩子可以正常使用,但过一段时间之后,钩子就可能失去作用了。郁闷中,下面是部分代码:

DLL钩子代码如下:C/C++ code
#include ...

//share global variable during different process
#pragma data_seg ("sharedsec")
static HHOOK g_HookPart=NULL;
#pragma data_seg ()
#pragma comment(linker, "/SECTION:sharedsec,RWS")


void Log_Message(TCHAR *fmt,...); //save log


LRESULT CALLBACK KeyHandler(int code, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT *Key = (KBDLLHOOKSTRUCT *)lParam;
if (code == HC_ACTION)
{

Log_Message(_T("Flag: %X\t Key Scancode: %X\t Vkcode: %X"), Key->flags, Key->scanCode ,Key->vkCode);

if (0xab == Key->scanCode)
{
//do something
return 1;
}
}

return CallNextHookEx(g_HookPart, code, wParam, lParam);
}

bool InstallHook()
{

g_HookPart = SetWindowsHookEx(WH_KEYBOARD_LL, KeyHandler,::GetModuleHandle (NULL),0);

if (g_HookPart)
return true;
else
return false;
}

bool UninstallHook()
{
if (UnhookWindowsHookEx(g_HookPart))
return true;
else
return false;
}

void Log_Message(TCHAR *fmt,...)
{

/******Set log file path and log file name*******/
TCHAR CurrentDir[256];
TCHAR LogFile[256];
TCHAR *EndChar = NULL;

memset(CurrentDir, 0, sizeof(CurrentDir));
memset(LogFile, 0, sizeof(LogFile));

//Get Current process's full path
if (::GetModuleFileName(::GetModuleHandle(NULL), CurrentDir, sizeof(CurrentDir)) == 0)
{
//Log_Message(_T("Get service path fail"), true);
return;
}

//Get current process's directory
EndChar = strrchr(CurrentDir, _T('\\'));
if (EndChar)
EndChar[1] = 0;

int copied = 0;
strcpy_s(LogFile, sizeof(LogFile) / sizeof (TCHAR), CurrentDir);
_tcscat_s(LogFile, _T("VolHandler.log"));
/************************************/


FILE *fp = NULL;
TCHAR DateTime[25];
TCHAR Time[10];

_tstrdate_s(DateTime);
_tstrtime_s(Time);
_tcscat_s(DateTime, _T("&&"));
_tcscat_s(DateTime, Time);

if (!strcmp(_T(""), fmt))
{
if (_tfopen_s(&fp, LogFile, _T("w")))
{
return;
}
}
else
{
if (_tfopen_s(&fp, LogFile, _T("a")))
{
return;
}

fprintf(fp, _T("%s: "),DateTime);
}

va_list ap; /* points to each unnamed arg in turn */
TCHAR *p, *sval;
int ival;

va_start(ap, fmt); /* make ap point to 1st unnamed arg */

for (p = fmt; *p; p++)
{
if (*p != '%')
{
fprintf(fp, _T("%c"), *p);
continue;
}

switch (*++p)
{
case 'd':
ival = va_arg(ap, int);
fprintf(fp, _T("%d"), ival);
break;
case 's':
for (sval = va_arg(ap, char *); *sval; sval++)
fprintf(fp, _T("%c"), *sval);
break;
case 'x':
ival = va_arg(ap, int);
fprintf(fp, _T("%x"), ival);
break;
case 'X':
ival = va_arg(ap, int);
fprintf(fp, _T("%X"), ival);
break;
default:
fprintf(fp, _T("%c"), *p);
break;
}
}

va_end(ap); /* clean up when done */

fprintf(fp, _T("\n"));

fflush(fp);
fclose(fp);
}


在C#中调用时,先导入引用:
C# code[DllImport("KeyboardHook.dll")]
public static extern bool InstallHook();


然后在窗口初始化的时候调用InstallHook安装钩子。

请各位大侠帮忙看下可能会是什么原因?
非常感谢!
...全文
3056 14 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
qilixue 2011-07-10
  • 打赏
  • 举报
回复
如果设成0,或者1,是啥效果?
qilixue 2011-07-10
  • 打赏
  • 举报
回复
楼主,请教!我在注册表了没找到LowLevelHooksTimeout,自己设了,但好像对钩子函数没有任何影响。请问怎么设?如果我在钩子里加个MessageBox,停到那,系统会把它自动关闭终止吗?
nostopping 2010-06-19
  • 打赏
  • 举报
回复
问题解决啦!
原来真是和钩子处理函数的执行时间有关,看到3楼的回复之后,我只查看了我自己机器上的
LowLevelHooksTimeout值(还以为是系统默认的呢),但没有看所在测试机的注册表值,现在在测试机的注册表中加入此项并设置其值为5000后,钩子再也不会失效了。

唉,我都在怀疑事件对象了,呵呵。


谢谢各位的热心回复,祝大家都工作顺利!

[Quote=引用 3 楼 zgl7903 的回复:]
低级Hook需要在一个限定时间内处理完毕,否则系统驱动会自动调下一个hook链 看MSDN上的详细说明

The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value in the following registr……
[/Quote]
cnzdgs 2010-06-19
  • 打赏
  • 举报
回复
是执行SetEvent之后失效吗?事件触发后,等待这两个事件的程序会执行什么样的操作?是否会导致调用SetWindowsHookEx的线程暂停相应消息?WH_KEYBOARD_LL钩子要借助消息来回调,如果该线程没有相应消息则LowLevelKeyboardProc不会被调用。
xiezonglin 2010-06-18
  • 打赏
  • 举报
回复
是不是被别的程序把你的钩子抢了?
定时注册钩子看看?
stonewater 2010-06-18
  • 打赏
  • 举报
回复
你用的win7 会不会跟系统有关
nostopping 2010-06-18
  • 打赏
  • 举报
回复
谢谢各位大侠!

小弟现在更新一下验证状况:
1. 用C#加载全局钩子,钩子失效时钩子所在的DLL并没有被卸载(因为无法删除此DLL文件,提示DLL正被使用);
2. 在C#中,使用LoadLibrary + Marshal类安装钩子也会出现钩子失效的现象;
3. 使用MFC加载钩子DLL,也会出现钩子失效的现象;

NOTE: 如果在钩子处理函数中单纯的记录按键消息则不会出现钩子失效的情况。但我需要在钩子中设置事件对象,然后在另外的一个EXE中开了几个线程分别用WaitForSingleObject等待事件对象有信号,然后再做相应动作。钩子DLL的代码如下:

#include "afxwin.h"
#include <tlhelp32.h>
#include "atlstr.h"
#include <windows.h>
#include <string>

//share global variable during different process
#pragma data_seg ("shared")
static HHOOK g_HookPart=NULL;
#pragma data_seg ()
#pragma comment(linker, "/SECTION:shared,RWS")

using namespace std;

HANDLE hEvent1 = NULL; //Event object handle to Inc processbar
HANDLE hEvent2 = NULL; //Event object handle to Dec processbar

bool InitEvent(void)
{
// set SECURITY_DESCRIPTOR
SECURITY_DESCRIPTOR secutityDese;
::InitializeSecurityDescriptor(&secutityDese, SECURITY_DESCRIPTOR_REVISION);
::SetSecurityDescriptorDacl(&secutityDese,TRUE,NULL,FALSE);

SECURITY_ATTRIBUTES securityAttr;

// set SECURITY_ATTRIBUTES
securityAttr.nLength = sizeof SECURITY_ATTRIBUTES;
securityAttr.bInheritHandle = FALSE;
securityAttr.lpSecurityDescriptor = &secutityDese;

hEvent1 = ::CreateEvent(&securityAttr, FALSE, FALSE, TEXT("Global\\{EVENT1}"));
hEvent2 = ::CreateEvent(&securityAttr, FALSE, FALSE, TEXT("Global\\{EVENT2}"));

if (!hEvent1 || !hEvent2)
return false;

//set Event Object to Nonsignal status
::ResetEvent (hEvent1);
::ResetEvent (hEvent2);

return true;
}

LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT *Key = (KBDLLHOOKSTRUCT *)lParam;
if (code == HC_ACTION)
{
if (0x30 == Key->scanCode)
{
SetEvent(hEvent1);

return 1;
}

if (0x2E == Key->scanCode)
{
SetEvent(hEvent2);

return 1;
}
}

return CallNextHookEx(g_HookPart, code, wParam, lParam);
}

bool InstallHook()
{
g_HookPart = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc,::GetModuleHandle (NULL),0);

if (g_HookPart)
{
if (!InitEvent())
return false;
}
else
return false;

return true;
}
swlilike 2010-06-18
  • 打赏
  • 举报
回复
接分~~~~~~~~~~~~接分~~~~~~~~~~~~接分~~~~~~~~~~~~
cnzdgs 2010-06-17
  • 打赏
  • 举报
回复
前面提的几点都试过了吗?有没有新的发现?
如果用VC写一个EXE来加载这个DLL是否会出问题?
nostopping 2010-06-17
  • 打赏
  • 举报
回复
不能沉呀,大家帮帮我吧!
nostopping 2010-06-15
  • 打赏
  • 举报
回复
谢谢楼上的指点!
我看了下我的注册表(WIN7),LowLevelHooksTimeout的默认值是5000,也就是5秒的时间。
我的钩子处理函数是不可能用那么久时间的,里面就有两步动作:

LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT *Key = (KBDLLHOOKSTRUCT *)lParam;
if (code == HC_ACTION)
{
Log_Message(_T("Flag: %X\t Key Scancode: %X\t Vkcode: %X"), Key->flags, Key->scanCode ,Key->vkCode);

if ((0x01 & Key->flags) && (0x80 & Key->flags)) //extended key release
{
if (0xAB == Key->scanCode)
{
::SetEvent(hEventObj_OK_Signal);
return 1;
}
}

if (0x30 == Key->scanCode)
{
SetEvent(hEventObjVolInc);

return 1;
}

if (0x2E == Key->scanCode)
{
SetEvent(hEventObjVolDec);

return 1;
}
}

return CallNextHookEx(g_HookPart, code, wParam, lParam);
}



另外,我的钩子失效的情况是:钩子没一旦没反应之后,再按什么键钩子都抓不到消息了。除非重新启动程序。
zgl7903 2010-06-15
  • 打赏
  • 举报
回复
低级Hook需要在一个限定时间内处理完毕,否则系统驱动会自动调下一个hook链 看MSDN上的详细说明

The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value in the following registry key:
HKEY_CURRENT_USER\Control Panel\Desktop
The value is in milliseconds. If the hook procedure does not return during this interval, the system will pass the message to the next hook.

http://msdn.microsoft.com/en-us/library/ms644985(v=VS.85).aspx
nostopping 2010-06-15
  • 打赏
  • 举报
回复
感谢楼上的建议!
我先尝试下用LoadLibrary加载DLL,应该跟Log_Message函数没关系,因为我上版的DLL没有此函数,但也出现了此种情况。
另外,我在钩子处理函数中有设置信号量的动作,可能和这个有关么?
cnzdgs 2010-06-15
  • 打赏
  • 举报
回复
SetWindowsHookEx的第3参数要给DLL的HMODULE,而GetModuleHandle(NULL)得到的是EXE的HMODULE,可以在DllMain中把HMODULE保存到全局变量来使用。不过对于WH_KEYBOARD_LL,由于不需要注入到其它进程,这个参数可能是被忽略的。
建议你先把Log_Message注释掉,确认一下问题是否与该函数有关。
另外,不清楚C#中DllImport加载DLL会在什么时候卸载,可以自己调用一下LoadLibrary,以防DLL被卸载。

15,473

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧