HOOK函数(一)——进程内HOOK

  什么是HOOK呢?其实很简单,HOOK就是对Windows消息进行拦截检查处理的一个函数。在Windows的消息机制中,当用户产生消息时,应用程序通过调用GetMessage函数取出消息,然后把消息放入到消息队列,再使用消息调度函数DispatchMessage函数讲消息调度给系统,Windows系统会调用创建窗口类时制定的窗口过程中进行次消息的处理。而HOOK函数的话,就可以对此消息进行拦截。经过此HOOK函数的处理后,再决定是屏蔽掉此消息,还是继续往下传递。至于为什么叫“钩子”,可能就是因为它可以像钩子一样把消息给钩住。话说四川话里面的“钩子”却是屁股的意思...哈哈,四川的同学读钩子肯定多了几份趣味

  钩子函数的实现分为以下步骤:

  1 安装钩子函数

  安装钩子函数是通过函数SetWindowHookEx来实现的:

  

HHOOK WINAPI SetWindowsHookExW(__in int idHook,  __in HOOKPROC lpfn,__in_opt HINSTANCE hmod,  __in DWORD dwThreadId);

  此函数的第一个参数idHook指定将要安装的钩子过程的类型,如果我们安装键盘钩子,则设为WH_KEYBOARD,鼠标钩子则设为WH_MOUSElpfn指向了相应的钩子函数,如果dwThreadId为0,或者指定了一个其他进程创建的线程之标识符,则lpfn必须指向一个位于某动态链接库中的钩子函数。如果为进程外钩子,hMod指向的是钩子函数所在的DLL的句柄,如果为进程内钩子,则设为NULLdwThreadId指定与钩子过程相关的线程表示,为0表示与所有线程相关。函数成功返回所安装的钩子函数的句柄,否则返回NULL。PS:最后安装的钩子函数总是排在钩子链的最前面。

  

  2 添加全局变量

HHOOK g_hMouse = NULL;

HHOOK g_hKeyboard = NULL;

HWND g_hWnd = NULL;

     全局句柄g_hMouse、g_hKeyboard分别代表我们所要安装的鼠标钩子和键盘钩子过程的句柄,g_hWnd用来保存当前的窗口句柄。

  3 声明钩子函数

  如果想要监视鼠标消息,需要定义相应的鼠标钩子过程。同样,要监视键盘消息,也需要定义相应的键盘钩子过程。该钩子函数的形式必须如下:

LRESULT CALLBACK  HookProc(int nCode, WPARAM wParam, LPARAM lParam);

  在当前钩子函数中处理完信息后,如果想把信息继续传递给下一个钩子函数,可以调用CallNextHookEx函数来实现:

LRESULT

WINAPI CallNextHookEx( __in_opt HHOOK hhk,   __in int nCode, __in WPARAM wParam,  __in LPARAM lParam

  CallNextHookEx函数的第一个参数是钩子的句柄,就是我们调用SetWindowHookEx函数返回的句柄,其他几个参数和HookProc中是一样的。

  4 卸载钩子函数

  当我们不需要再使用钩子函数的时候,可以将其卸载,调用函数:

  

BOOL WINAPI UnhookWindowsHookEx(  __in HHOOK hhk);

  函数的唯一参数便为钩子函数的句柄。

  说一千道一万,不如一个程序来的实在。下面便是一个实现进程内钩子函数的MFC例子。步骤如下:

  1 新建一个名字CInnerHookDlg的MFC工程。

  2 在CInnerHookDlgDlg.cpp中添加钩子的全局变量和当前句柄

  

HHOOK g_hMouse = NULL;

HHOOK g_hKeyboard = NULL;

HWND g_hWnd = NULL;

  3 然后再分别实现键盘和鼠标钩子函数,我们在键盘钩子函数中显示出当前按下去的键盘。而在鼠标钩子函数中,当我们双击右键时候,会显示出对话框。

//鼠标钩子函数

LRESULT CALLBACK MouseProc( int nCode, WPARAM wParam, LPARAM lParam )

{

...

}

    





//键盘钩子函数

LRESULT CALLBACK KeyBoardProc( int nCode, WPARAM wParam, LPARAM lParam )

{

...

}

  4 在CCInnerHookDlgDlg的OnInitDialog()中设置钩子,添加如下代码

  

//设置鼠标钩子

    g_hMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, NULL,GetCurrentThreadId());



    //设置键盘钩子

    g_hKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyBoardProc, NULL, GetCurrentThreadId());

    

    //获取当前句柄

    g_hWnd = m_hWnd;

  5 最后在CCInnerHookDlgDlg的OnSysCommand()中卸载钩子,添加如下代码:

UnhookWindowsHookEx(g_hMouse);

    UnhookWindowsHookEx(g_hKeyboard);

  下面是所有的代码啦!

// CInnerHookDlgDlg.cpp : 实现文件

//



#include "stdafx.h"

#include "CInnerHookDlg.h"

#include "CInnerHookDlgDlg.h"



#ifdef _DEBUG

#define new DEBUG_NEW

#endif



HHOOK g_hMouse = NULL;

HHOOK g_hKeyboard = NULL;

HWND g_hWnd = NULL;





// 用于应用程序“关于”菜单项的 CAboutDlg 对话框



class CAboutDlg : public CDialog

{

public:

    CAboutDlg();



// 对话框数据

    enum { IDD = IDD_ABOUTBOX };



    protected:

    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持



// 实现

protected:

    DECLARE_MESSAGE_MAP()

};



CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)

{

}



void CAboutDlg::DoDataExchange(CDataExchange* pDX)

{

    CDialog::DoDataExchange(pDX);

}



BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)

END_MESSAGE_MAP()





// CCInnerHookDlgDlg 对话框

CCInnerHookDlgDlg::CCInnerHookDlgDlg(CWnd* pParent /*=NULL*/)

    : CDialog(CCInnerHookDlgDlg::IDD, pParent)

{

    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}



void CCInnerHookDlgDlg::DoDataExchange(CDataExchange* pDX)

{

    CDialog::DoDataExchange(pDX);

}



BEGIN_MESSAGE_MAP(CCInnerHookDlgDlg, CDialog)

    ON_WM_SYSCOMMAND()

    ON_WM_PAINT()

    ON_WM_QUERYDRAGICON()

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()



//鼠标钩子函数

LRESULT CALLBACK MouseProc( int nCode, WPARAM wParam, LPARAM lParam )

{

    LPMOUSEHOOKSTRUCT pMouseHook = (MOUSEHOOKSTRUCT*)(lParam);



    if (nCode >= 0)

    {

        //双击右键弹出当前窗口的窗口名

        if (wParam == WM_RBUTTONDBLCLK)

        {

            HWND hWnd = pMouseHook->hwnd;  //鼠标所在的窗口

            HWND hParent;



            //获取顶层窗口

            while(hWnd != NULL)

            {

                hParent = GetParent(hWnd);

                if (hParent == NULL)

                    break;

                hWnd = hParent;

            }



            if (hWnd != NULL)

            {

                //得到窗口名

                TCHAR strDlgName[MAX_PATH] = {0};

                GetWindowText(hWnd,strDlgName, MAX_PATH);

                AfxMessageBox( strDlgName );

            }

        }

    }



    return CallNextHookEx(g_hMouse,nCode, wParam, lParam);

}



//键盘钩子函数

LRESULT CALLBACK KeyBoardProc( int nCode, WPARAM wParam, LPARAM lParam )

{

    LRESULT lReturnValue;

    lReturnValue = CallNextHookEx(g_hKeyboard, nCode, wParam, lParam);



    //键盘按键是否已经松动

    if ( (lParam & 0x80000000) && (HC_ACTION == nCode))

    {

        char c = (char) lParam;

        CString strText(_T("按下了键"));

        strText += c;

        AfxMessageBox(strText);  //显示当前的按键

    }



    //如果按下F4,则退出程序

    if (wParam == VK_F4)

    {

        SendMessage(g_hWnd, WM_CLOSE,0,0);  

    }



    return lReturnValue;

}





// CCInnerHookDlgDlg 消息处理程序



BOOL CCInnerHookDlgDlg::OnInitDialog()

{

    CDialog::OnInitDialog();



    // 将“关于...”菜单项添加到系统菜单中。



    // IDM_ABOUTBOX 必须在系统命令范围内。

    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

    ASSERT(IDM_ABOUTBOX < 0xF000);



    CMenu* pSysMenu = GetSystemMenu(FALSE);

    if (pSysMenu != NULL)

    {

        CString strAboutMenu;

        strAboutMenu.LoadString(IDS_ABOUTBOX);

        if (!strAboutMenu.IsEmpty())

        {

            pSysMenu->AppendMenu(MF_SEPARATOR);

            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

        }

    }



    // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动

    //  执行此操作

    SetIcon(m_hIcon, TRUE);            // 设置大图标

    SetIcon(m_hIcon, FALSE);        // 设置小图标



    // TODO: 在此添加额外的初始化代码



    //设置鼠标钩子

    g_hMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, NULL,GetCurrentThreadId());



    //设置键盘钩子

    g_hKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyBoardProc, NULL, GetCurrentThreadId());

    

    //获取当前句柄

    g_hWnd = m_hWnd;



    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE

}

void CCInnerHookDlgDlg::OnSysCommand(UINT nID, LPARAM lParam)

{

    if ((nID & 0xFFF0) == IDM_ABOUTBOX)

    {

        CAboutDlg dlgAbout;

        dlgAbout.DoModal();

    }

    else

    {

        CDialog::OnSysCommand(nID, lParam);

    }



    UnhookWindowsHookEx(g_hMouse); UnhookWindowsHookEx(g_hKeyboard); }



// 如果向对话框添加最小化按钮,则需要下面的代码

//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,

//  这将由框架自动完成。



void CCInnerHookDlgDlg::OnPaint()

{

    if (IsIconic())

    {

        CPaintDC dc(this); // 用于绘制的设备上下文



        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);



        // 使图标在工作区矩形中居中

        int cxIcon = GetSystemMetrics(SM_CXICON);

        int cyIcon = GetSystemMetrics(SM_CYICON);

        CRect rect;

        GetClientRect(&rect);

        int x = (rect.Width() - cxIcon + 1) / 2;

        int y = (rect.Height() - cyIcon + 1) / 2;



        // 绘制图标

        dc.DrawIcon(x, y, m_hIcon);

    }

    else

    {

        CDialog::OnPaint();

    }

}



//当用户拖动最小化窗口时系统调用此函数取得光标

//显示。

HCURSOR CCInnerHookDlgDlg::OnQueryDragIcon()

{

    return static_cast<HCURSOR>(m_hIcon);

}

 

  

 

 

 

    

 

你可能感兴趣的:(OO)