• 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);
    }

      

        

  • 相关阅读:
    [恢]hdu 2098
    [恢]hdu 2049
    [恢]hdu 2027
    [恢]hdu 2111
    [恢]hdu 1202
    [恢]hdu 2131
    Windows Phone 7 文件下载进度和速度显示
    深入WPF中的图像画刷(ImageBrush)之1——ImageBrush使用举例
    深入WPF中的图像画刷(ImageBrush)之2——ImageBrush的铺设方式
    textblock设置属性
  • 原文地址:https://www.cnblogs.com/1314NNNKKK/p/3474115.html
Copyright © 2020-2023  润新知