Hook 簡單的實例--攔截鼠標和鍵盤消息(一)

Hook(鉤子)就是對Windows系統的一些消息或是API函數進行攔截和監控的處理平臺,讓能夠根據程序員的設置獲取其感興趣的信息。程序員

這裏主要是介紹一下Hook攔截鼠標消息和鍵盤消息。app

下面是CALLBACK Proc 回調函數 和 CallNextHookEx函數less

LRESULT CALLBACK HookProc
(
  int nCode, //指定是否須要處理該消息 
WPARAM wParam, 
LPARAM lParam //包含該消息的附加消息 ,
);
這個回調函數的名字能夠隨你取,但形式可必定要知足以上要求,其實鉤子的回調函數和Windows的差很少一個德行。看看鉤子函數的返回值,如果返回非0值,表示咱們已經本身處理了該消息,則消息就不被傳遞到目標窗口過程。
看看LRESULT CallNextHookEx
(HHOOK hhk;
int nCode;
WPARAM wParam;
ide

LPARAM lParam;)這個函數把鉤子信息傳遞給下一個鉤子函數,也就是能夠理解成把車輛放行到下一個檢查站,這個能夠根據本身的須要進行調用。如果咱們只設定了一個鉤子函數,那麼咱們假設把鉤子消息用CallNextHookEx傳給下個鉤子函數,由於不存在因此就傳遞迴了目標窗口函數。函數

先建立一個MFC  BaseDialog 工程佈局


XXXDlg.cpp代碼this

// MbHookDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MbHook.h"
#include "MbHookDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMbHookDlg dialog




CMbHookDlg::CMbHookDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CMbHookDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMbHookDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMbHookDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()


//////////////////////////////////////////////////////////
//Hook的過程函數
HHOOK hook;
HWND hWnd;


LRESULT CALLBACK MessageBoxProc(
	INT nCode,WPARAM wParam,LPARAM lParam
	)
{
	if(nCode<0)
	return CallNextHookEx(hook,nCode,wParam,lParam);

	if (wParam == VK_F3)//當按「F3」鍵時卸載Hook
	{
		EndDialog(hWnd,NULL);//關閉窗口
		UnhookWindowsHookEx(hook);//卸載HOOk函數
	}else
	{
		return 1;
	}

	
}






// CMbHookDlg message handlers

BOOL CMbHookDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here

	hWnd= m_hWnd;

	hook=SetWindowsHookEx(//WH_MOUSE//設置鼠標鉤子
		WH_KEYBOARD//設置鍵盤鉤子
		,MessageBoxProc,NULL,GetCurrentThreadId());





	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMbHookDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CMbHookDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

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

		// Center icon in client rectangle
		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;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CMbHookDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

SetWindowsHook() 安裝Hook:

HHOOK SetWindowsHookEx(spa

int idHook, // 鉤子的類型,即它處理的消息類型
HOOKPROC lpfn, // 鉤子子程的地址 指針。若是dwThreadId參數爲0
// 或是一個由別的進程建立的線程的標識,
// lpfn必須指向DLL中的鉤子子程。
// 除此之外,lpfn能夠指向當前進程的一段鉤子子程代碼。
//  鉤子函數的入口地址,當鉤子鉤到任何消息後便調用這個函數。
HINSTANCE hMod, //  應用程序實例的句柄。標識包含lpfn所指的子程的
DLL。
// 若是dwThreadId 標識當前進程建立的一個線程,
// 並且子程代碼位於當前進程,hMod必須爲NULL。
// 能夠很簡單的設定其爲本 應用程序的實例句柄。
DWORD dwThreadId // 與安裝的鉤子子程相關聯的線程的 標識符
// 若是爲0,鉤子子程與全部的線程關聯,即爲 全局鉤子
);
idHook參數能夠是如下的選擇:

每一種類型的Hook可使 應用程序可以監視不一樣類型的 系統消息處理機制。下面描述全部能夠利用的Hook類型。
一、 WH_CALLWNDPROCWH_CALLWNDPROCRET Hooks
WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks使你能夠監視發送到窗口過程的消息。系統在消息發送到接收窗口過程以前調用WH_CALLWNDPROC Hook子程,而且在窗口過程處理完消息以後調用WH_CALLWNDPROCRET Hook子程。
WH_CALLWNDPROCRET Hook傳遞 指針到CWPRETSTRUCT結構,再傳遞到Hook子程。
CWPRETSTRUCT結構包含了來自處理消息的窗口過程的返回值,一樣也包括了與這個消息關聯的消息參數。
二、 WH_CBT Hook
在如下事件以前,系統都會調用WH_CBT Hook子程,這些事件包括:
1)激活,創建,銷燬,最小化,最大化,移動,改變尺寸等窗口事件;
2)完成系統指令;
3)來自系統消息隊列中的移動鼠標, 鍵盤事件;
4)設置 輸入焦點事件;
5)同步系統消息隊列事件。
Hook子程的返回值肯定系統是否容許或者防止這些操做中的一個。
三、 WH_DEBUG Hook
系統調用系統中與其餘Hook關聯的Hook子程以前,系統會調用WH_DEBUG Hook子程。你可使用這個Hook來決定是否容許 系統調用與其餘Hook關聯的Hook子程。
四、 WH_FOREGROUNDIDLE Hook
應用程序的前臺 線程處於空閒狀態時,可使用WH_FOREGROUNDIDLE Hook執行低優先級的任務。當 應用程序的前臺 線程大概要變成空閒狀態時,系統就會調用WH_FOREGROUNDIDLE Hook子程。
五、 WH_GETMESSAGE Hook
應用程序使用WH_GETMESSAGE Hook來監視從GetMessage or PeekMessage函數返回的消息。你可使用WH_GETMESSAGE Hook去監視鼠標和 鍵盤輸入,以及其餘發送到 消息隊列中的消息。
六、 WH_JOURNALPLAYBACK Hook
WH_JOURNALPLAYBACK Hook使 應用程序能夠插入消息到系統消息隊列。可使用這個Hook回放經過使用WH_JOURNALRECORD Hook記錄下來的連續的鼠標和 鍵盤事件。只要WH_JOURNALPLAYBACK Hook已經安裝,正常的鼠標和 鍵盤事件就是無效的。
WH_JOURNALPLAYBACK Hook是全局Hook,它不能象線程特定Hook同樣使用。
WH_JOURNALPLAYBACK Hook返回超時值,這個值告訴系統在處理來自回放Hook當前消息以前須要等待多長時間(毫秒)。這就使Hook能夠控制實時事件的回放。
WH_JOURNALPLAYBACK是system-wide local hooks,它們不會被注射到任何行程位址空間。
七、 WH_JOURNALRECORD Hook
WH_JOURNALRECORD Hook用來監視和記錄輸入事件。典型的,可使用這個Hook記錄連續的鼠標和 鍵盤事件,而後經過使用WH_JOURNALPLAYBACK Hook來回放。
WH_JOURNALRECORD Hook是全局Hook,它不能象線程特定Hook同樣使用。
WH_JOURNALRECORD是system-wide local hooks,它們不會被注射到任何行程位址空間。
八、 WH_KEYBOARD Hook
應用程序中,WH_KEYBOARD Hook用來監視WM_KEYDOWN and WM_KEYUP消息,這些消息經過GetMessage or PeekMessage function返回。可使用這個Hook來監視輸入到 消息隊列中的 鍵盤消息。
九、 WH_KEYBOARD_LL Hook
WH_KEYBOARD_LL Hook監視輸入到線程 消息隊列中的 鍵盤消息。
十、 WH_MOUSE Hook
WH_MOUSE Hook監視從GetMessage 或者 PeekMessage 函數返回的鼠標消息。使用這個Hook監視輸入到 消息隊列中的鼠標消息。
十一、 WH_MOUSE_LL Hook
WH_MOUSE_LL Hook監視輸入到線程 消息隊列中的鼠標消息。
十二、 WH_MSGFILTER 和  WH_SYSMSGFILTER Hooks
WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使咱們能夠監視 菜單,滾動條, 消息框,對話框消息而且發現用戶使用ALT+TAB or ALT+ESC 組合鍵切換窗口。WH_MSGFILTER Hook只能監視傳遞到 菜單,滾動條, 消息框的消息,以及傳遞到經過安裝了Hook子程的 應用程序創建的對話框的消息。WH_SYSMSGFILTER Hook監視全部 應用程序消息。
WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使咱們能夠在模式循環期間過濾消息,這等價於在主 消息循環中過濾消息。
經過調用CallMsgFilter function能夠直接的調用WH_MSGFILTER Hook。經過使用這個函數, 應用程序可以在模式循環期間使用相同的代碼去過濾消息,如同在主 消息循環裏同樣。
1三、 WH_SHELL Hook
外殼 應用程序可使用WH_SHELL Hook去接收重要的通知。當外殼 應用程序是激活的而且當頂層窗口創建或者銷燬時, 系統調用WH_SHELL Hook子程。
WH_SHELL 共有5鍾狀況:
1)只要有個top-level、unowned 窗口被產生、起做用、或是被摧毀;
2)當Taskbar須要重畫某個按鈕;
3)當系統須要顯示關於Taskbar的一個程序的最小化形式;
4)當現在的 鍵盤佈局狀態改變;
5)當使用者按Ctrl+Esc去執行Task Manager(或相同級別的程序)。
按照慣例,外殼 應用程序都不接收WH_SHELL消息。因此,在 應用程序可以接收WH_SHELL消息以前,應用程序必須調用SystemParametersInfo function註冊它本身。
也就是說,若是你的App沒有調用以下代碼註冊本身以前,那麼它永遠也不會響應你的ShellProc:
//MINIMIZEDMETRICS mm = {sizeof(MINIMIZEDMETRICS), 0,0, ARW_HIDE};
MINIMIZEDMETRICS mm = {sizeof(MINIMIZEDMETRICS), 0,0, 0, ARW_HIDE};
SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS) , &mm, 0);



版權聲明:本文爲博主原創文章,未經博主容許不得轉載。線程

相關文章
相關標籤/搜索