在MFC中,PreTranslateMessage是虛函式,是用來截獲訊息的。我們可以通過重載它來處理鍵盤和滑鼠訊息。在sdk中,這有所不同,我們必須在回調函式LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)中處理訊息。
它和PreTranslateMessage起的作用是類似的,只是MFC封裝的更好而已。
PreTranslateMessage是訊息在送給TranslateMessage函式之前被調用的,絕大多數本視窗的訊息都要通過這裡,比較常用,當你需要在MFC之前處理某些訊息時,常常要在這裡添加代碼.。
基本介紹
- 外文名:PreTranslateMessage
- 類別:函式
- 平台:windows
- cpu占用率:高
簡介
特徵
GetMessage在沒有訊息的時候等待訊息,cpu當然低
PeekMessage沒有訊息的時候立刻返回.
因為遊戲不能靠windows訊息驅動,所以要用PeekMessage();
BOOLCSearchuserDlg::PreTranslateMessage(MSG*pMsg)
if(pMsg->message==WM_KEYDOWN)//判斷是否有按鍵按下
switch(pMsg->wParam)
caseVK_DOWN://表示是方向鍵中的向下的鍵//addhandlecodehere
caseVK_UP://表示是方向鍵中的向上的鍵//addhandlecodehere
****************************************************************************************************************************************
MSGmsg;
if(::PeekMessage(&msg,NULL,0,0,PM_REMOVE))
::PostQuitMessage(-1);
if(!AfxGetApp()->PreTranslateMessage(&msg))
::TranslateMessage(&msg);
原理
PretranslateMessage的實現,不得不談到MFC訊息循環的實現。MFC通過CWinApp類中的Pumpmessage函式實現訊息循環,但是實際的訊息循環代碼位於CWinThread中,CWinApp只是從CWinThread繼承過來。其簡化後的代碼大概如下:
BOOLCWinThread::PumpMessage()
{
_AFX_THREAD_STATE*pState=AfxGetThreadState();
::GetMessage(&(pState->m_msgCur),NULL,NULL,NULL))
if(!AfxPreTranslateMessage(&(pState->m_msgCur)))
{
::TranslateMessage(&(pState->m_msgCur));
::DispatchMessage(&(pState->m_msgCur));
}
return TRUE;
}
從上可以看到,PumpMessage在實際的TranslateMessage和DispatchMessage發生之前會調用AfxPreTranslateMessage。
BOOLPASCALCWnd::WalkPreTranslateTree(HWNDhWndStop,MSG*pMsg)
{
ASSERT(hWndStop==NULL||::IsWindow(hWndStop));
ASSERT(pMsg!=NULL);
//walk from the target window up to the hWnd Stop window checking
//if any window wants to translate this message
for(HWNDhWnd=pMsg->hwnd;hWnd!=NULL;hWnd=::GetParent(hWnd))
{
CWnd*pWnd=CWnd::FromHandlePermanent(hWnd);
if(pWnd!=NULL)
{
//target window is a Cwindow
if(pWnd->PreTranslateMessage(pMsg))
return TRUE;//trappedbytargetwindow(eg:accelerators)
}
//gotto hWnd Stop window without interest
if(hWnd==hWndStop)
break;
}
return FALSE;//no specialprocessing
}
到這裡我們可以看到,代碼還是很直接的。從接受到訊息的視窗層層往上遍歷,並調用PretranslateMessage看是否返回TRUE,是則結束,否則繼續。
這裡有一個地方非常關鍵:CWnd*pWnd=CWnd::FromHandlePermanent(hWnd)這一句代碼從當前AfxModuleThreadState拿到Permanent句柄表,從而找到hWnd對應的CWnd
MFC中PreTranslateMessage是GetMessage(...)函式的下一級操作,即GetMessage(...)從訊息佇列中獲取訊息後,交由PreTranslateMessage()處理,若其返回FALSE則再交給TranslateMessage和DispatchMessage處理(進入WindowProc);
如果用SendMessage,則訊息直接交到WindowProc處理,所以GetMessage不會取得SendMessage的訊息,當然PreTranslateMessage也就不會被調用。 [Page]
如果用PostMessage,則訊息進入訊息佇列,由GetMessage取得,PreTranslateMessage就有機會進行處理。windows訊息處理機制是這樣的:
首先系統(也就是windows)把來自硬體(滑鼠,鍵盤等訊息)和來自應用程式的訊息 放到一個系統訊息佇列中去.而應用程式需要有自己的訊息佇列,也就是執行緒訊息佇列,每一個執行緒有自己的訊息佇列,對於多執行緒的應用程式就有和執行緒數目相等的執行緒訊息佇列.
windows訊息佇列把得到的訊息傳送到執行緒訊息佇列,執行緒訊息佇列每次取出一條訊息傳送到指定視窗,不斷循環直到程式退出.這個循環就是靠訊息環(while(GetMessage()) TranslateMessage();DispatchMessage();實現的.GetMessage()只是從執行緒訊息中取出一條訊息,TranslateMessage()把virtuekey訊息轉化成character訊息,如VK_F1會轉化成WM_HELP,而DispatchMessage則把取出的訊息傳送到目的視窗.如果收到WM_CLOSE訊息則結束循環,傳送postqiutmessage(0),處理WM_DESTROY銷毀視窗!
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}