消息钩子与定时器(VC_Win32)

目录

消息钩子
定时器

(本章节中例子都是用 VS2005 编译调试的)


消息钩子

[概述][相关函数][编写消息钩子]

概述

钩子过程

操作系统在传递消息时,将我们感兴趣的消息先传递给HOOK过程,在此函数中进行检查,然后在决定是否放行该消息,就好像逃犯在逃亡时可能会经过许多段路段,为了抓住他,警察要在某些地方设置检查站,以便检查过往的车辆和行人,我们可以把车辆和行人看做是消息,检查站就好像是HOOK过程,如果在摸个检查站发现了这个逃犯,就会把他抓起来,这样就相当于阻止了逃犯的逃亡过程,让他无法在继续逃亡下去了,这个道理和钩子过程是一样的,操作系统将我们感兴趣的消息都交给钩子过程,后者实际就是一个函数,在此函数中进行判断,如果是我们希望屏蔽的消息,那么就直接处理掉,不然它继续向下传递.如果我们不感兴趣的消息,就直接放弃对它们的处理,这就好像对于那些不是逃犯的行人和车辆一样,警察会让他们继续前进

钩子链

SetWindowsHookEx函数作用是安装一个应用程序定义的钩子过程,并将其放到钩子链中,为了让读者更好的理解钩子的概念,让我们在看看前面所举的逃犯的例子.警察在抓捕逃犯时,可以再多个地方设置检查站,逐一对车辆和行人进行排查,同样地,应用程序也可以在多个地方安装钩子函数,对我们感兴趣的多个消息逐一进行排查,这样多个钩子过程就形成了钩子链,要注意的是,最后安装的钩子过程总是排列在该链的前面

消息钩子分类

  • 进程内钩子  勾取本进程消息
  • 全局钩子     勾取所有消息

 

相关函数

显示相关函数

[设置消息钩子][消息钩子回调函数][移除消息钩子]

设置消息钩子 SetWindowsHookEx

函数原型

HHOOK SetWindowsHookEx(
int idHook, // hook type
HOOKPROC lpfn, // hook procedure
HINSTANCE hMod, // handle to application instance
DWORD dwThreadId // thread identifier
);

参数说明

  • idHook

    指定要安装的钩子过程的类型

    • WH_CALLWNDPROC    安装一个钩子过程,在操作系统将消息发送到目标窗口处理过程之前,对该消息进行监视
    • WH_CALLWNDPROCRET 安装一个钩子过程,它对被目标窗口处理过了的消息进行监视
    • WH_CBT         安装一个钩子过程,接受对CBT应用程序有用的消息
    • WH_DEBUG         安装一个钩子过程,以便对其他钩子过程调试
    • WH_FOREGROUNDIDLE  安装一个钩子过程,该钩子过程当应用程序的前提线程即将进入空闲状态时被调用,它有助于在空闲时间内执行低优先级的任务
    • WH_GETMESSAGE     安装一个钩子过程对发送到消息队列的消息进行监视
    • WH_JOURNALPLAYBACK 安装一个钩子过程,对此前由WH_JORNALRECORD钩子过程记录的消息进行发送
    • WH_JOURNALRECORD   安装一个钩子过程,对发送到系统消息队列的输入消息进行记录
    • WH_KEYBOARD      安装一个钩子过程,对键盘按键消息进行监视
    • WH_KEYBOARD_LL      安装一个钩子过程,只能在Windows NT中安装,用来对底层的键盘输入事件进行监视
    • WH_MOUSE        安装一个钩子过程,对鼠标消息进行监视
    • WH_MOUSE_LL       安装一个钩子过程,只能在Windows NT中安装,用来对底层的鼠标输入事件进行监视
    • WH_MSGFILTER      安装一个钩子过程,以监视由对话框,消息框,菜单条,或滚动条中输入事件引发的消息
    • WH_SHELL            安装一个钩子过程,以接受外壳应用程序有用的通知
    • WH_SYSMSGFILTER   安装一个钩子过程,以监视对话框,消息框,菜单条,或滚动条中输入事件引发的消息,该钩子过程对系统中所有应用程序的这里消息都进行监视

    对应的回调函数也就是钩子函数的处理过程的形式在MSDN查阅

    如果钩子函数返回非零值,表示已经对当前消息进行了处理,这样系统就不会在将这个消息传递给目标窗口过程,因此,如果钩子过程对于当前消息进行处理,则返回一个非零值,以避免系统再次将此消息传递给目标窗口过程;否则建议调用CallNextHookEx含返回该函数的返回值,以便其他安装了此消息类型钩子过程的应用程序捕获相应的通知

  • lpfn

    指向相应的钩子过程,如果dwThreadId参数为0,或者指定了一个其他进程创建的线程标识符,那么参数lpfn必须指向一个位于动态链接库中的钩子过程.否则,参数lpfn可以指向当前进程相关的代码中定义的一个钩子过程

  • hMod

    指定lpfn指向的钩子过程所在的DLL的句柄,如果参数dwThreadId指定的线程由当前进程穿件,并且相应的钩子过程定义与当前进程相关的代码中,那么必须将参数hMod设置为NULL(全局钩子,此参数必须指向DLL句柄)

  • dwThreadId

    指定与钩子过程相关的线程标识,如果值为0,那么按照的钩子过程将与桌面上运行的所有线程都有关(安装的钩子过程可以与某个特定线程相关,也可以和所有线程相关,取决于这个参数的取值)

返回值

如果成功返回的值是钩子过程的句柄,如果函数失败返回的是NULL

钩子回调函数原型 CallNextHookEx

函数原型

LRESULT CallNextHookEx(
HHOOK hhk, // handle to current hook
int nCode, // hook code passed to hook procedure
WPARAM wParam, // value passed to hook procedure
LPARAM lParam // value passed to hook procedure
);

参数说明

  • hhk:  指定当前钩子过程句柄
  • nCode,wParam,lParam:  后三个参数是钩子过程回调函数的三个参数

返回值

这个值是在钩子链中的下个钩子函数的返回值

取消消息钩子函数 UnhookWindowsHookEx

函数原型

BOOL UnhookWindowsHookEx(
  HHOOK hhk   // handle to hook procedure
);

参数说明

  • hhk:   要被移除的消息钩子

 

编写消息钩子

流程图:

  • 进程钩子

  • 全局钩子

代码样例:

进程钩子

程序源码:

View Code
#include<windows.h>
#include<string.h>

HHOOK g_hKeyboard=NULL;
HHOOK g_hMouse=NULL;

LRESULT CALLBACK MouseProc(
  int nCode,      // hook code
  WPARAM wParam,  // message identifier
  LPARAM lParam   // mouse coordinates
)
{
    return 1;
}

LRESULT CALLBACK KeyboardProc(
  int code,       // hook code
  WPARAM wParam,  // virtual-key code
  LPARAM lParam   // keystroke-message information
)
{
    //当按下回车键时候取消消息钩子
    if(VK_RETURN==wParam)
    {
        UnhookWindowsHookEx(g_hKeyboard);
        UnhookWindowsHookEx(g_hMouse);
        MessageBox(NULL,"取消消息钩子","消息",MB_OK);
    }
    return 1;
}

LRESULT CALLBACK textprom(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);


int WINAPI WinMain(  HINSTANCE hInstance,  // handle to current instance
  HINSTANCE hPrevInstance,  // handle to previous instance
  LPSTR lpCmdLine,      // pointer to command line
  int nCmdShow          // show state of window
  )
{
    WNDCLASS wndclass;
    MSG msg;

    wndclass.cbClsExtra=0;
    wndclass.cbWndExtra=0;
    wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);
    wndclass.hInstance=hInstance;
    wndclass.lpfnWndProc=textprom;
    wndclass.lpszClassName="text";
    wndclass.lpszMenuName=NULL;
    wndclass.style=CS_HREDRAW | CS_VREDRAW;

    if(!RegisterClass(&wndclass))
    {
        MessageBox(NULL,"create windows error!","error",MB_OK | MB_ICONSTOP);
    }

    HWND hwnd=CreateWindow("text","hellow world",WS_DLGFRAME | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT,
        400,250,NULL,NULL,hInstance,NULL);

    ShowWindow(hwnd,nCmdShow);
    UpdateWindow(hwnd);

    //设置鼠标和键盘消息钩子
    g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());
    g_hKeyboard=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,NULL,GetCurrentThreadId());
    
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK textprom(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;

    switch(uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        ;
    }
    return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

运行结果:

全局钩子

动态链接库源码:

View Code
// .h 头文件 -----------------------------------------------------
#ifndef DLL_API
#define DLL_API _declspec(dllimport)
#endif
#include"windows.h"

HHOOK g_hMouse=NULL;
HHOOK g_hKeyboard=NULL;

DLL_API void SetHook();
LRESULT CALLBACK MouseProc(int nCode,WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK KeyboardProc(int code,WPARAM wParam,LPARAM lParam);


// .cpp 源程序 ---------------------------------------------------
#define DLL_API _declspec(dllexport)
#include"dllHook.h"

LRESULT CALLBACK MouseProc(
  int nCode,      // hook code
  WPARAM wParam,  // message identifier
  LPARAM lParam   // mouse coordinates
)
{
    return 1;
}

LRESULT CALLBACK KeyboardProc(
  int code,       // hook code
  WPARAM wParam,  // virtual-key code
  LPARAM lParam   // keystroke-message information
)
{
    if(VK_RETURN==wParam)
    {
        UnhookWindowsHookEx(g_hMouse);
        UnhookWindowsHookEx(g_hKeyboard);
        MessageBox(NULL,"取消消息钩子","消息",MB_OK);
    }
    return 1;
}

void SetHook()
{
    g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("dllHook.dll"),0);
    g_hKeyboard=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,GetModuleHandle("dllHook.dll"),0);
}

程序源码: 

View Code
#include<windows.h>
//加载动态连接库头文件
#include"../dllHook/dllHook.h"
//加载动态连接库的引入库(LIB)
#pragma comment(lib, "../debug/dllHook.lib")


LRESULT CALLBACK textprom(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);


int WINAPI WinMain(  HINSTANCE hInstance,  // handle to current instance
  HINSTANCE hPrevInstance,  // handle to previous instance
  LPSTR lpCmdLine,      // pointer to command line
  int nCmdShow          // show state of window
  )
{
    WNDCLASS wndclass;
    MSG msg;

    wndclass.cbClsExtra=0;
    wndclass.cbWndExtra=0;
    wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);
    wndclass.hInstance=hInstance;
    wndclass.lpfnWndProc=textprom;
    wndclass.lpszClassName="text";
    wndclass.lpszMenuName=NULL;
    wndclass.style=CS_HREDRAW | CS_VREDRAW;

    if(!RegisterClass(&wndclass))
    {
        MessageBox(NULL,"create windows error!","error",MB_OK | MB_ICONSTOP);
    }

    HWND hwnd=CreateWindow("text","hellow world",WS_DLGFRAME | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT,
        400,250,NULL,NULL,hInstance,NULL);

    ShowWindow(hwnd,nCmdShow);
    UpdateWindow(hwnd);
    
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK textprom(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;

    switch(uMsg)
    {
    case WM_LBUTTONDOWN:
        //设置消息钩子
        SetHook();
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        ;
    }
    return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

运行结果(回车钱所有鼠标事件和键盘事件都将被屏蔽)


定时器

[相关函数][编写定时器]

相关函数

显示相关函数

[建立定时器][删除定时器]

建立新定时器 SetTimer

函数原型:

UINT SetTimer(
HWND hWnd, 
UINT nIDEvent, 
UINT uElapse, 
TIMERPROC lpTimerFunc ); 

参数说明:

  • hWnd:      指定定时器的关联窗口
  • nIDEvent:   指定了不为零的定时器标识符.
  • nElapse:     指定了定时值;以毫秒为单位.
  • lpfnTimer:   指定了应用程序提供的TimerProc回调函数的地址,该函数被用于处理WM_TIMER消息.如果这个参数为NULL,则WM_TIMER消息被放入应用程序的消息队列并由CWnd对象来处理.

返回值

如果函数成功,则返回新定时器的标识符.应用程序可以将这个值传递给KillTimer成员函数以销毁定时器.如果成功,则返回非零值;否则返回0

说明:

  • 所属类    CWnd
  • 相对事件   WM_TIMER
  • 这个函数设置一个系统定时器.指定了一个定时值,每当发生超时,则系统就向设置定时器的应用程序的消息队列发送一个WM_TIMER消息,或者将消息传递给应用程序定义的TimerProc回调函数.lpfnTimer回调函数不需要被命名为TimerProc,但是它必须按照如下方式定义:
    void CALLBACK EXPORT TimerProc(
      HWND hWnd, // 调用SetTimer的窗口的句柄
      UINT nMsg, // WM_TIMER 
      UINT nIDEvent // 定时器标识
      DWORD dwTime // 系统时间 
    );
    定时器是有限的全局资源;因此对于应用程序来说,检查SetTimer返回的值以确定定时器是否可用是很重要的

消除已存在定时器

函数原型

BOOL KillTimer( int nIDEvent );

参数说明

  • nIDEvent:   传递给SetTimer的定时器事件值

返回值

指定了函数的结果.如果事件已经被销毁,则返回值为非零值.如果KillTimer成员函数不能找到指定的定时器事件,则返回0

说明 

  • 所属类 CWnd
  • 销毁以前调用SetTimer创建的用nIDEvent标识的定时器事件.任何与此定时器有关的未处理的WM_TIMER消息都从消息队列中清除

 

编写定时器

流程图:

代码样例:

程序源码:

View Code
#include"windows.h"
#include<cstdlib>
#include<iostream>
using namespace std;

VOID CALLBACK TimerProc(HWND hwnd,UINT msg ,UINT_PTR dwEvent,DWORD dwTime);

void main()
{
    MSG msg;

    //建立定时器
    UINT TimerID = SetTimer(NULL,1,1000,(TIMERPROC)TimerProc);

    //消息循环
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    system("pause");
}

VOID CALLBACK TimerProc(HWND hwnd,UINT msg ,UINT_PTR dwEvent,DWORD dwTime)
{
    cout<<"定时器消息回调函数调用成功"<<endl;
    
    //关闭定时器
    if(KillTimer(NULL,dwEvent))
        PostQuitMessage(0);
}

运行结果:

posted @ 2012-11-14 18:21  kzangv  阅读(2408)  评论(0编辑  收藏  举报
top