訊息鉤子與定時器(VC_Win32)
訊息鉤子
概述
鉤子過程
作業系統在傳遞訊息時,將我們感興趣的訊息先傳遞給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
- 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: 要被移除的訊息鉤子
編寫訊息鉤子
流程圖:
- 程序鉤子
- 全域性鉤子
程式碼樣例:
程序鉤子
程式原始碼:
#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);
}
執行結果:
全域性鉤子
動態連結庫原始碼:
// .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);
}
程式原始碼:
#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,但是它必須按照如下方式定義:
定時器是有限的全域性資源;因此對於應用程式來說,檢查SetTimer返回的值以確定定時器是否可用是很重要的void CALLBACK EXPORT TimerProc( HWND hWnd, // 呼叫SetTimer的視窗的控制代碼 UINT nMsg, // WM_TIMER UINT nIDEvent // 定時器標識 DWORD dwTime // 系統時間 );
消除已存在定時器
函式原型
BOOL KillTimer( int nIDEvent );
引數說明
- nIDEvent: 傳遞給SetTimer的定時器事件值
返回值
指定了函式的結果.如果事件已經被銷燬,則返回值為非零值.如果KillTimer成員函式不能找到指定的定時器事件,則返回0
說明
- 所屬類 CWnd
- 銷燬以前呼叫SetTimer建立的用nIDEvent標識的定時器事件.任何與此定時器有關的未處理的WM_TIMER訊息都從訊息佇列中清除
編寫定時器
流程圖:
程式碼樣例:
程式原始碼:
#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);
}
執行結果:
相關推薦
訊息鉤子與定時器(VC_Win32)
訊息鉤子 [概述][相關函式][編寫訊息鉤子] 概述 鉤子過程 作業系統在傳遞訊息時,將我們感興趣的訊息先傳遞給HOOK過程,在此函式中進行檢查,然後在決定是否放行該訊息,就好像逃犯在逃亡時可能會經過許多段路段,為了抓住他,警察要在某些地方設定檢查站,以便檢查過往的車輛和行
MySQL5-函數/存儲過程與定時器、觸發器
名稱 狀態 訪問 safe 安全問題 ant comm gnu led 目錄 一、函數/存儲過程 二、定時器 三、觸發器 四、函數語句學習 一、函數/存儲過程 1、函數與存儲過程 (1) function與procedure的區別:一個有返回值,一個沒有,僅此而已。
MySQL觸發器與定時器的介紹和錯誤處理
MySQL觸發器與定時器的介紹和錯誤處理方法 最近在做一個東南亞的海外專案,整個專案的技術架構是由我負責,由於專案比較龐大,涉及三種語言,資料關係比較複雜,用的觸發器、定時器比較多。借這個新型大專案,也重溫了了很久沒有接觸的觸發器(TRIGGER)、定時器(EVENT),本文也是回憶結合
從零開始的全棧工程師——js篇2.14(表單與定時器)
一、表單 Form input select textarea type=”radio/checkbox/password/button/text/submit/reset/” 表單的事件 onchange 當表單內容被修改時觸發的事件 onfocus 獲取
STC51微控制器中斷與定時器配置參考
*外中斷INT0--------void intsvr0(void) interrupt 0 using 1 *定時/計數器T0-----void timer0(void) interrupt 1 using 1 *外中斷INT1--------void intsvr0(void)
利用隨機數與定時器做一個簡單的偽隨機抓鬮遊戲
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *
iOS -- GCD之延遲與定時器
我們開發常用的定時器有三種:NSTimer,CADisplyLink,CGD 本文詳細說一下CGD的延遲與定時器方法。文章最後,也會說說GCD與前兩個的區別。 直接上程式碼,首先是延遲的程式碼: 其中的delayInSeconds就是延遲的時間,執行之後,輸出臺會在2s之後,列
高效能網路程式設計6--reactor反應堆與定時器管理
反應堆開發模型被絕大多數高效能伺服器所選擇,上一篇所介紹的IO多路複用是它的實現基礎。定時觸發功能通常是伺服器必備元件,反應堆模型往往還不得不將定時器的管理囊括在內。本篇將介紹反應堆模型的特點和用法。首先我們要談談,網路程式設計界為什麼需要反應堆?有了IO複用,有了epoll
JavaScript時鐘與定時器
1.時鐘 例子:時鐘 <!doctype html><html><head><meta charset="utf-8"><title>clock</title><script type="text/javascript"&
react生命週期API(3.0)及生命週期與定時器的用法;
react的定時器的呼叫必須採用元件生命週期函式去呼叫: 有關元件的生命週期,見菜鳥教程: http://www.runoob.com/react/react-component-life-cycle
AJAX教程系列五:非同步資料獲取與定時器
window.onload = function() { var oBtn = document.getElementById('btn'); oBtn.onclick = function() { /*ajax({ url : 'getN
timer和ScheduledExecutorService延時器與定時器的使用
直接上程式碼: Timer timer = new Timer(); int interval = 10; //時間間隔 ,毫秒 timer.schedule(new TimerTask(){ public void run(){ //邏輯處理程式碼
mysql下儲存過程與定時器
一年前,第一次接觸資料庫的時候。發現專案上的一個表很神奇。當用戶提交資料的時候,狀態為0(表示未執行)。過了一陣子狀態為1(表示正在執行),又過一陣子狀態為2(表示執行成功)或者3(表示執行失敗)。 第一次接觸程式設計的小白感覺很神奇。因為神奇,就會以為特別複
Linux訊號實踐(5) --時間與定時器
三種不同精度的睡眠1.sleep#include <unistd.h> unsigned int sleep(unsigned int seconds);RETURN VALUE Zer
定時器與TATE應用
pre reg .cn err 開始 main 定時 .com spa 1 #include <reg51.h> 2 #include <stdio.h> 3 #define uchar unsigned char 4 sbit le
GCD dispatch_source基本使用,創建GCD定時器與NSTimer的區別
pre 任務調度 cnblogs class -s ping log glob ... 可以使用GCD創建定時器 創建定時器: dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PR
JavaScript定時器 setTimeout與setInterval 淺析
throttle tin 並不是 tint 導致 語句 運行 應用 超過 一、 前情提要 1)JavaScript 是運行在單線程的執行環境中的 2)由瀏覽器安排事件的執行順序 二、setTimeout 使用場景: 設定代碼在未來的某個時間執行,而執行的時機是不
node中定時器, process.nextTick(), setImediate()的區別與聯系
con ron 十分 入隊 interval 延遲 聯系 一個 實現類 1.定時器 setTimeout()和setInterval()與瀏覽器中的API是一致的,定時器的問題在於,他並非精確的(在容忍範圍內)。盡管事件循環十分快,但是如果某一次循環占用的時間較多,那麽
並發編程 - 線程 - 1.互斥鎖/2.GIL解釋器鎖/3.死鎖與遞歸鎖/4.信號量/5.Event事件/6.定時器
級別 src 總結 alex post strip CQ bsp 回收機制 1.互斥鎖: 原理:將並行變成串行 精髓:局部串行,只針對共享數據修改 保護不同的數據就應該用不用的鎖 1 from threading import Thread
定時器與在console中打印內容
IT char brush console asd true alert 內容 什麽 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8">