键盘钩子的实现

程序用一个系统范围的远程钩子来实现监视所有键盘输入的功能,且程序中的文本框属性为只读,这样可更好的观察键盘钩子(WH_KEYBOARD)是否正确的截获了WM_KEYUP或WM_KEYDOWN消息。

 

 

现在把键盘钩子当作远程钩子使用,即需要将钩子函数写入到DLL中去,且其实含有共享的数据段。因为系统中只有DLL程序是可以插入到其他进程的地址空间中去。命名所写的钩子函数Dll文件名为HookDll;

 

在HoolDll.h文件中声明需要导出的函数:
extern "C" _declspec(dllexport) BOOL InstallHook(HWND,UINT);
extern "C" _declspec(dllexport) VOID UninstallHook();

 

//其中__declspec (dllexport)是Windows扩展关键字的组合,表示DLL里的对象的存储类型关键字;extern "C"用于C++程序使用该函数时的函数声明的链接属性

 

HookDll.cpp文件:

 

 

//设置共享的数据段,并命名为"shared"

#pragma data_seg("shared")
extern "C" _declspec(dllexport) HWND hWnd=NULL;
extern "C" _declspec(dllexport) HHOOK hHook=NULL;
extern "C" _declspec(dllexport) UINT dwMessage=NULL;
extern "C" _declspec(dllexport) unsigned short szAscii[256]={0};
#pragma data_seg,

//告诉链接器"shared"数据段具有RWS属性(Read、Write和Shared),为共享属性

#pragma comment(linker,"/SECTION:shared,RWS")

 

 

HINSTANCE hInstance;

int WINAPI DllMain(HINSTANCE _hInstance,DWORD dwReason,PVOID pvReserved)
{
 hInstance=_hInstance;
 return TRUE;
}

 

//键盘钩子回调函数
LRESULT CALLBACK HookProc(int _dwCode,WPARAM _wParam,LPARAM _lParam)
{
 unsigned char lpKeyState[256];//申请256个字节的内存空间

 

 CallNextHookEx(hHook,_dwCode,_wParam,_lParam);;

 

 GetKeyboardState(lpKeyState);//可按照VK_xx虚拟码的顺序排列填写按键状态;

                              //但区分VK_LSHIFTVK_RSHIFT;而ToAscii函数检测的是VK_SHIFT,所以要对SHIFT按键进行处理

 

 short ax=GetKeyState(VK_SHIFT);//获取VK_SHIFT的状态

 lpKeyState[VK_SHIFT]=ax;

 

//ToAscii用法:(将虚拟码或扫描码转换为ASCII码)

int ToAscii(UINT dwVirtKey,UINT uScanCode,PBYTE lpKeyState,LPWORD lpBuffer,UINT uFlags) //其中uScanCode去高16位的LPARAM的值,来标志一次的记录HIWORD(LPARAM)

 

int t=ToAscii(_wParam,HIWORD(_lParam),lpKeyState,szAscii,0);   //对于每个击键动作,钩子回调函数会在按下和释放的时候被调用两次;但只需根据lParam的最高位

                                                               //标志来记录一次

szAscii[t]='/0';
 
PostMessage(hWnd,dwMessage,(WPARAM)szAscii,NULL);   //向主程序发送包含已转换为ASCII码的按键消息(WM_HOOK)

                                                   //此处有一点要注意:消息中包含的WPARAM类型的变量(szAscii)是一个地址;今后的操作要是对应的地址操作

                                                   //否则容易引起地址内存的未知错误

 }

     
 return 0;
}

 

//安装钩子
BOOL InstallHook(HWND _hWnd,UINT _dwMessage)
{
 hWnd=_hWnd;
 dwMessage=_dwMessage; //自定义的钩子消息

 HHOOK hHook=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)HookProc,hInstance,NULL);//设置键盘钩子(WH_KEYBOARD)
 if(hHook)
  return TRUE;
 else
  return FALSE;
}

//卸载钩子
VOID UninstallHook()
{
 UnhookWindowsHookEx(hHook);
}

 

 总结:

 

安装好了键盘钩子后,在写被监视的程序KeyHook.cpp:

 

 

 #define WM_HOOK WM_USER+100   //在自定义的消息WM_USER后定义自己使用的消息WM_HOOK;

 

 

#pragma comment(lib,"HOOKDLL.lib")

 

LRESULT CALLBACK DialogProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam);

 

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
 DialogBoxParam(hInstance,(LPCSTR)IDD_DLG,NULL,(DLGPROC)DialogProc,NULL);
 ExitProcess(NULL);
 return TRUE;
}

 

LRESULT CALLBACK DialogProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
{
 switch(message)
 {
 case WM_CLOSE:
  UninstallHook();//卸载钩子
  EndDialog(hDlg,NULL);
  break;

 case WM_INITDIALOG:
  if(!InstallHook(hDlg,WM_HOOK)){
   MessageBox(hDlg,"InstallHook-Failed",NULL,MB_OK);
   EndDialog(hDlg,NULL);
  }
  break;

 case WM_HOOK:                      //钩子消息发生时
  unsigned int *dwTemp;

  dwTemp=(unsigned int *)wParam;   //地址类型的强制性转换,把握两边的数据性质相同就行了
  if(*dwTemp==0x000d){            //若是ASCII码为回车符
   *dwTemp=0x0a0d;               //则转换为换行符
  }
  else
   dwTemp=(unsigned int *)wParam;

  SendDlgItemMessage(hDlg,IDC_EDIT,EM_REPLACESEL,0,(LPARAM)dwTemp);
  break;
 }
 return 0;
}

在这个钩子程序中最开始写了后引起了内存泄漏,经过纠结一段时间后才发现在钩子回调函数中PostMessage时,传的是地址。其他都好说。注意程序的调试与断点的设置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值