低级键盘钩子屏蔽Win键、Alt+Tab键的响应

如果你是基于Windows操作系统做系统集成的,你可能希望你的最终产品独占系统资源。你希望规范用户行为,比如你不希望用户通过按Ctrl+Alt+Del终止某个进程,或者按下Win键弹出开始菜单,或者按下Alt+Tab组合键切换到别的应用程序。笔者已有相关一篇文章《Win2K/NT下屏蔽Ctrl+Alt+Del的响应》,介绍了如何通过GINA编程接口屏蔽Ctrl+Alt+Del的响应。作为续篇,本文将继续介绍屏蔽Win键和Alt+Tab组合键的方法。

由于这些按键的响应是系统级的,我们不可能简单地通过某个程序来控制它们。因此,我们需要使用微软提供的另外一种编程接口——钩子(Hook)。大家可能已经对钩子很了解了(网上有很多介绍钩子技术和应用的文章)。简单来说,钩子是一种通过替换系统提供的标准接口来截获特定的事件(消息),最终达到改变或增强系统默认行为目的的技术。我们现在的任务,就是要在用户按下Win键或Alt+Tab组合键、但系统还没有响应之前截获它们,然后改变系统的默认行为。很显然,我们要做一个全局钩子(钩子函数放在独立的DLL中实现),而且是个低级键盘钩子(Low Level Keyboard  hook)。

第一步,钩子DLL的实现。我们首先要定义一个全局数据区(记住这是一个全局钩子),如下(放在cpp文件的上头):
#pragma data_seg("mydata")
HHOOK      glhHook      = NULL;            // 安装的鼠标钩子句柄
HINSTANCE  glhInstance  = NULL;       // DLL实例句柄
#pragma data_seg()
然后在.def文件中声明这个数据区,如下:
SECTIONS
    mydata READ WRITE SHARED
当这个DLL被某个进程载入时,程序从WinMain进入,此时我们需要把模块句柄保存下来,如下:
glhInstance = (HINSTANCE) hModule;
接下去,我们就要定义两个导出函数,以及钩子的处理函数。我们重点看一下这个钩子处理函数(另外两个导出函数比较简单,只是通过调用SetWindowsHookEx和UnhookWindowsHookEx实现安装/卸载钩子函数;只需注意SetWindowsHookEx第一个参数为WH_KEYBOARD_LL,第四个参数为0)。
// 低级键盘钩子处理函数
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    BOOL fEatKeystroke = FALSE;
    PKBDLLHOOKSTRUCT p = NULL;

    if (nCode == HC_ACTION)
    {
        p = (PKBDLLHOOKSTRUCT) lParam;
        switch (wParam)
        {
            case WM_KEYDOWN:
            case WM_SYSKEYDOWN:
                        case WM_KEYUP:    
            case WM_SYSKEYUP:
        fEatKeystroke = (p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN) ||  // 屏蔽Win
        // 屏蔽Alt+Tab
        ((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0)) ||
        // 屏蔽Alt+Esc
        ((p->vkCode == VK_ESCAPE) && ((p->flags & LLKHF_ALTDOWN) != 0)) ||
        // 屏蔽Ctrl+Esc
        ((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) & 0x8000) != 0));
        break;
            default:
                break;
      }
    }

  return (fEatKeystroke ? TRUE : CallNextHookEx(glhHook,nCode,wParam,lParam));
}
大家可以看到,当程序发现按下的是Win键或者Alt+Tab组合键,就不再调用CallNextHookEx函数将这个消息传递下去。以此,我们做到了屏蔽这些按键的响应。

第二步,钩子DLL的测试程序。在VC中创建一个基于对话框的应用程序。通过调用LoadLibrary("KeyMask.dll")载入钩子DLL,通过GetProcAddress(m_hDll,"StartKeyMask")和GetProcAddress(m_hDll,"StopKeyMask")导入两个安装/卸载钩子的函数。在主对话框上定义两个按钮分别调用这两个函数,如下:
UI hook.jpg
当按下“Start_Hook”按钮,我们的钩子函数就起作用了。试一下Win键,或者Alt+Tab组合键,没反应了吧?!“Stop_Hook”按钮可以解除这个钩子。

讲到这,大家可能觉得钩子其实也是很容易的东西。是的,钩子容易使用,而且功能强大。但是,笔者建议,如果不是十分必要,请尽量少用钩子。因为钩子在实现强大功能的同时,可能也会严重降低你系统的性能。有时候是得不偿失的!

附源码:

//===============================================

// KeyMask.h

//===============================================

#ifdef KEYMASK_EXPORTS
#define KEYMASK_API __declspec(dllexport)
#else
#define KEYMASK_API __declspec(dllimport)
#endif

// This class is exported from the KeyMask.dll
class KEYMASK_API CKeyMask {
public:
 CKeyMask(void);
 // TODO: add your methods here.
};

extern KEYMASK_API int nKeyMask;

KEYMASK_API int fnKeyMask(void);

//=================================================

// KeyMask.cpp

//=================================================

#include "stdafx.h"
#include "KeyMask.h"

#pragma data_seg("mydata")
HHOOK      glhHook      = NULL;       // °²×°µÄÊó±ê¹³×Ó¾ä±ú
HINSTANCE  glhInstance  = NULL;       // DLLʵÀý¾ä±ú
#pragma data_seg()

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
 glhInstance = (HINSTANCE) hModule;

    switch (ul_reason_for_call)
 {
  case DLL_PROCESS_ATTACH:
  case DLL_THREAD_ATTACH:
  case DLL_THREAD_DETACH:
  case DLL_PROCESS_DETACH:
   break;
    }
    return TRUE;
}


// This is an example of an exported variable
KEYMASK_API int nKeyMask=0;

// This is an example of an exported function.
KEYMASK_API int fnKeyMask(void)
{
 return 42;
}

// This is the constructor of a class that has been exported.
// see KeyMask.h for the class definition
CKeyMask::CKeyMask()
{
 return;
}



// µÍ¼¶¼üÅ̹³×Ó´¦Àíº¯Êý
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
 BOOL fEatKeystroke = FALSE;
 PKBDLLHOOKSTRUCT p = NULL;

 if (nCode == HC_ACTION)
 {
  p = (PKBDLLHOOKSTRUCT) lParam;
  switch (wParam)
  {
   case WM_KEYDOWN:
    // Backdoor to user information
    if (p->vkCode == VK_F8)
    {
     ::MessageBox(NULL,"Let's make things better and better!/n","HQ Tech",MB_OK);
     break;
    }
   case WM_SYSKEYDOWN:
            case WM_KEYUP:   
   case WM_SYSKEYUP:
    fEatKeystroke = (p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN) ||  // ÆÁ±ÎWin
        // ÆÁ±ÎAlt+Tab
        ((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0)) ||
        // ÆÁ±ÎAlt+Esc
        ((p->vkCode == VK_ESCAPE) && ((p->flags & LLKHF_ALTDOWN) != 0)) ||
        // ÆÁ±ÎCtrl+Esc
        ((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) & 0x8000) != 0));
    break;
   default:
    break;
      }
 }

  return (fEatKeystroke ? TRUE : CallNextHookEx(glhHook,nCode,wParam,lParam));
}

void _stdcall StartKeyMask()
{
 // °²×°¹³×Ó
 glhHook = SetWindowsHookEx(WH_KEYBOARD_LL,LowLevelKeyboardProc,glhInstance,0);
}

void _stdcall StopKeyMask()
{
 // жÔع³×Ó
 if (glhHook!=NULL)
  UnhookWindowsHookEx(glhHook);
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值