TranslateMessage ,GetMessage, DispatchMessage分析
TranslateMessage(&msg);
TranslateMessage是用來把快捷鍵消息轉換為字符消息,并將轉換后的新消息投遞到調用線程的消息隊列中。
由于Windows對所有鍵盤編碼都是采用虛擬鍵的定義,這樣當按鍵按下時,并不得字符消息,需要鍵盤映射轉換為字符的消息。字符消息被投遞到調用線程的消息隊列中,當下一次調用GetMessage函數時被取出。
LONG DispatchMessage(CONST MSG*lpmsg);
函數功能:該函數分發一個消息給窗口程序,即把消息推送到afxwndproc,最后流向pwnd->windowproc,而DispatchMessage是在cwinapp::run 調用pumpmessage,而pumpmessage又調用DispatchMessage。通常消息從GetMessage函數獲得或者TranslateMessage函數傳遞的。消息被分發到回調函數(過程函數),作用是消息傳遞給操作系統,然后操作系統去調用我們的回調函數,也就是說我們在窗體的過程函數中處理消息
在mfc2.5時代(九幾年代),所有窗口類共享同一個窗口函數(即afxwndproc)。
但現在使用的是鉤子技術(即hook),所以要關聯hook章節一起看。
hook操作是在每一個cwnd派生類之對象產生之際發生。
所以DispatchMessage把消息推送到hook技術中的afxwndproc.
?
HOOK(鉤子,掛鉤)是一種實現Windows平臺下類似于中斷的機制。HOOK機制允許應用程序攔截并處理Windows消息或指定事件,當指定的消息發出后,HOOK程序就可以在消息到達目標窗口之前將其捕獲,從而得到對消息的控制權,進而可以對該消息進行處理或修改,加入我們所需的功能。
定義鉤子函數
鉤子函數是一種特殊的回調函數。鉤子監視的特定事件發生后,系統會調用鉤子函數進行處理。不同事件的鉤子函數的形式是各不相同的。下面以鼠標鉤子函數舉例說明鉤子函數的原型:
LRESULT CALLBACK HookProc(int nCode ,WPARAM wParam,LPARAM lParam)
參數wParam和 lParam包含所鉤消息的信息,比如鼠標位置、狀態,鍵盤按鍵等。
安裝鉤子
在程序初始化的時候,調用函數SetWindowsHookEx安裝鉤子。其函數原型為:
HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId )
參數idHook表示鉤子類型,它是和鉤子函數類型一一對應的。比如,WH_KEYBOARD表示安裝的是鍵盤鉤子,WH_MOUSE表示是鼠標鉤子等等。
卸載鉤子
當不再使用鉤子時,必須及時卸載。簡單地調用函數:
BOOL UnhookWindowsHookEx( HHOOK hhk)即可。
PeekMessage和GetMessage函數的主要區別有:
GetMessage的主要功能是從消息隊列中“取出”消息,消息被取出以后,就從消息隊列中將其刪除;而PeekMessage的主要功能是“窺視”消息,如果有消息,就返回true,否則返回false。也可以使用PeekMessage從消息隊列中取出消息,這要用到它的一個參數(UINT wRemoveMsg),如果設置為PM_REMOVE,消息則被取出并從消息隊列中刪除;如果設置為PM_NOREMOVE,消息就不會從消息隊列中取出。
如果GetMessage從消息隊列中取不到消息,則線程就會被操作系統掛起,等到OS重新調度該線程時,兩者的性質不同:使用GetMessage線程仍會被掛起,使用PeekMessage線程會得到CPU的控制權,運行一段時間。
GetMessage每次都會等待消息,直到取到消息才返回;而PeekMessage只是查詢消息隊列,沒有消息就立即返回,從返回值判斷是否取到了消息
PeekMessage是一個具有線程異步行為的函數,不管消息隊列中是否有消息,函數都會立即返回。而GetMessage則是一個具有線程同步行為的函數,如果消息隊列中沒有消息的話,函數就會一直等待,直到消息隊列中至少有一條消息時才返回。
另外:PumpMessage起到消息泵的作用,其原理就是使用GetMessage或PeekMessage函數從消息隊列中逐個讀取消息,然后進行必要處理之后再發送出去。我們可以使用PumpMessage默認處理過程,當然也可以自己修改消息處理的方式。通常我們在我們自己設計窗口時也會自己設計消息循環方式。即PumpMessage函數會調用GetMessage、TranslateMessage、DispatchMessage
一般wm_xx消息
?
wm_command
?/*********************
1.windows消息循環
if (GetMessage(&msg, NULL, 0, 0)) {
? ?TranslateMessage(&msg); //消息轉化
? ?DispatchMessage(&msg); ?//消息派遣. ?把TranslateMessage轉換的消息發送到窗口的消息處理函數,此函數在窗口注冊時已經指定
? }
執行過程:
消息循環調用GetMessage()從消息隊列中查找消息進行處理,如果消息隊列為空,程序將停止執行并等待(程序阻塞)。
事件發生時導致一個消息加入到消息隊列(例如系統注冊了一個鼠標點擊事件),GetMessage()將返回一個正值,這表明有消息需要被處理,并且消息已經填充到傳入的MSG參數中;當傳入WM_QUIT消息時返回0;如果返回值為負表明發生了錯誤。
取出消息(在Msg變量中)并將其傳遞給TranslateMessage()函數,這個函數做一些額外的處理:將虛擬鍵值信息轉換為字符信息。這一步實際上是可選的,但有些地方需要用到這一步。
DispatchMessage()函數將消息分發到消息的目標窗口,并且查找目標窗口過程函數,給窗口過程函數傳遞窗口句柄、消息、wParam、lParam等參數然后調用該函數。
在窗口過程函數中,檢查消息和其他參數,你可以用它來實現你想要的操作。如果不想處理某些特殊的消息,你應該總是調用DefWindowProc()函數,系統將按按默認的方式處理這些消息(通常認為是不做任何操作)。
一旦一個消息處理完成,窗口過程函數返回,DispatchMessage()函數返回,繼續循環處理下一個消息。
2. 函數定義
2.1GetMessage
BOOL WINAPI GetMessage(
?_Out_ ? ? LPMSG lpMsg,
?_In_opt_ ?HWND hWnd,
?_In_ ? ? ?UINT wMsgFilterMin,
?_In_ ? ? ?UINT wMsgFilterMax
);
GetMessage 函數的作用是從當前線程的消息隊列里獲取一個消息并填入 MSG 結構 中。
該函數只能獲取調用線程的消息,不能獲得其他線程的消息。成功獲取消息后,線程將從消息隊列中刪除該消息。
使用 GetMessage 函數,如果消息隊列為空,函數會一直等待直到有消息到來才有返回值。
2.2 TranslateMessage
//BOOL TranslateMessage(CONST MSG *lpMsg);
1
參數:lpMsg
指向一個含有用GetMessage或PeekMessage函數從調用線程的消息隊列中取得消息信息的MSG結構的指針
函數功能描述:
將虛擬鍵消息轉換為字符消息。字符消息被送到調用線程的消息隊列中,在下一次線程調用函數GetMessage或PeekMessage時被讀出。
TranslateMessage函數不修改由參數lpMsg指向的消息。
2.3 DispatchMessage
函數原型:LONG DispatchMessage(CONST MSG*lpmsg);
1
參數:
lpmsg:指向含有消息的MSG結構的指針。
返回值:
返回值是窗口程序返回的值。盡管返回值的含義依賴于被調度的消息,但返回值通常被忽略。
備注:
MSG結構必須包含有效的消息值。如果參數lpmsg指向一個WM_TIMER消息,并且WM_TIMER消息的參數IParam不為NULL,則調用IPa1ram指向的函數,而不是調用窗口程序。
3. 程序實例
如果處理時間大于定時器時間,按照處理時間循環。
如果處理時間小于定時器時間,按照定時器時間。
#pragma comment(lib,"user32")
#include <stdio.h>
#include <time.h>
#include <sys/timeb.h>
#include <windows.h>
char datestr[16];
char timestr[16];
char mss[4];
void log(char *s) {
?struct tm *now;
?struct timeb tb;
?ftime(&tb);
?now = localtime(&tb.time);
?sprintf(datestr, "%04d-%02d-%02d", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday);
?sprintf(timestr, "%02d:%02d:%02d", now->tm_hour, now->tm_min, now->tm_sec);
?sprintf(mss, "%03d", tb.millitm);
?printf("%s %s.%s %s", datestr, timestr, mss, s);
}
VOID CALLBACK myTimerProc1(
?HWND hwnd, // handle of window for timer messages
?UINT uMsg, // WM_TIMER message ************
?UINT idEvent, // timer identifier
?DWORD dwTime // current system time)
?{
?log("In myTimerProc1\n");
}
VOID CALLBACK myTimerProc2(
?HWND hwnd, // handle of window for timer messages
?UINT uMsg, // WM_TIMER message
?UINT idEvent, // timer identifier
?DWORD dwTime // current system time)?
?{
?log("In myTimerProc2\n");
}
int main()?
{
?MSG msg;
?SetTimer(NULL, 0, 4000, myTimerProc1);
?SetTimer(NULL, 1, 2000, myTimerProc2);
?for (int i = 0; i<20; i++)?
?{
? Sleep(1000);
? log("In main\n");
? if (GetMessage(&msg, NULL, 0, 0))?
? {
? ?TranslateMessage(&msg); //消息處理
? ?DispatchMessage(&msg); ?//消息派遣. ?把TranslateMessage轉換的消息發送到窗口的消息處理函數,此函數在窗口注冊時已經指定
?}
?}
? return 0;
}
?
總結
以上是生活随笔為你收集整理的TranslateMessage ,GetMessage, DispatchMessage分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: input 框 去掉下面的提示文字、提示
- 下一篇: 《 第一本Docker书 》读书笔记 -