1. 程式人生 > >MFC訊息對映機制的理解

MFC訊息對映機制的理解

當窗體,控制元件,點選標題欄等時,會產生訊息,然後發給訊息處理函式進行處理,而訊息與訊息對映表是一一對應的關係,這個關係就是訊息對映表,根據根據訊息通過訊息對映表來查詢對應的訊息處理函式,這就稱為訊息對映機制。
而Windows有自己的訊息佇列,通過訊息迴圈,採用GetMessage來獲取訊息,對於不呼叫加速鍵時就要派發訊息,讓目標視窗函式進行處理,訊息是通過視窗過程函式來處理的。

MFC中訊息分為:系統訊息和使用者自定義訊息。
系統訊息分為三類:
a.標準訊息:除了WM_COMMANd,以WM開頭的都是標準訊息。
b.命令訊息:WM_COMMAND,點選選單欄啊,工具欄之類產生的訊息
c.通知訊息:在b的基礎上進行的擴充套件,不過也是WM_COMMAND訊息,不過會帶對應控制元件的ID

使用者訊息:使用者自己定義的訊息,WM_USER +100

訊息的實現方式:
1.在.h中用DECLARE_MESSAGE_MAP()用這個巨集進行申明訊息對映,注意afx開頭的
2.在cpp,在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()實現訊息對映,也就是新增訊息處理函式。

PreTranslateMessage函式的理解:
是一個虛擬函式,可以通過函式過載來處理鍵盤,滑鼠等訊息,從GetMessage中獲得訊息,然後傳送給Pretranslate,而且傳送的訊息是沒有進行翻譯的,先進行過濾一下下,預處理。
該函式是表示在訊息處理(TranslateMessge()和DispatchMessage()等)前所作的操作。如果此函式返回為true,則不呼叫 translate和dispatch函式,返回false才會呼叫這兩個函式,才會翻譯和分發派送訊息,交由訊息處理函式(進入WindowProc)進行處理。只對通過訊息佇列的訊息處理才有用,而對sendMessage處理訊息沒有任何作用。
SendMessage是將訊息直接分發到對應的視窗去處理,交由訊息直接交到WindowProc處理直接處理。
PostMessage是進入訊息佇列的,傳送到後就會立馬返回,而SendMessage是訊息處理完畢才會返回。。。
在對訊息進行分發和派送。訊息的分發派送是從最頂層視窗開始的,依次傳遞給它的下一級視窗,如果想要某個編輯框控制元件在相應enter鍵時,如果在編輯框的上層有視窗,則視窗函式執行預設的OK訊息處理函式,所以,為了讓目標視窗執行這個enter,可以在編輯框控制元件之前的視窗,過載pretranslate函式,如果有enter時,則返回false。

BOOL CAutoCutDlg::PreTranslateMessage(MSG* pMsg) 
{
	if (WM_KEYDOWN==pMsg->message)
	{
		if ((VK_RETURN==pMsg->wParam) || (VK_SPACE==pMsg->wParam) || (VK_ESCAPE==pMsg->wParam))
		{
			return false;//
		}
	}
	return CDialog::PreTranslateMessage(pMsg);
}

對於WM_KEYDOWN訊息,即使添加了訊息處理函式OnkeyDown(),但因為先被pretranslate函式捕獲,所以會執行其中的內容 ,而後面自定義的訊息處理函式則不會被執行到了。(???待解釋)

GetSafeHwnd()

AfxGetApp():AfxGetApp( )這個函式可以得到當前引用的指標CWinApp*,通過這個指標可以訪問到這個程序中的物件
CTestApp theApp;(工程名為Test)
//Test.cpp檔案中
CTestApp theApp;(工程名為Test)
的語句。它是指向工程物件的一個指標,你可以用它方向Test工程的成員函式和變數。

是DLL程式的話,情況會稍有不同。你會發現在DLL中呼叫AfxGetApp這個函式會得到DLL的應用物件。原因出現在DLL的模組狀態上。應用程式在呼叫DLL時為了保證資源不出問題,往往會呼叫一句:

AFX_MANAGE_STATE(AfxGetStaticModuleState())
注意這是一個巨集。他的作用是切換模組的全域性變數範圍,即把應用程式的那些全域性變數拷貝切換到這個DLL的全域性變數拷貝,自然用AfxGetApp得到就是DLL裡面的這個APP了。如果向訪問應用程式的App物件,那麼只要把模組狀態切換回去就可以了,記著執行完後一定要把狀態再切換回來啊,否則就要出問題了。

好了,現在我們就在CConfig類中呼叫str吧!
//Config.cpp檔案
CTestApp *pApp=(CTestApp *)AfxGetApp( );
AfxMessageBox(pApp->str);

GetSafeHwnd()
  當我們想得到一個視窗物件(CWnd的派生物件)指標的控制代碼(HWND)時,最安全的方法是使用GetSafeHwnd()函式,你看有很多函式的引數要求HWND,它就可以派上用場了.
  HWND hwnd;
  CWnd* pWnd;
  pWnd=((CFrameWnd*)(AfxGetApp()->m_pMainWnd))->GetActiveView();
  hwnd=pWnd->GetDlgItem(IDC_EDIT2)->GetSafeHwnd();
  ::SetWindowText(hwnd,m_strResult);

參考:
1.https://blog.csdn.net/yiziweiyang/article/details/52470683
2.https://blog.csdn.net/yiziweiyang/article/details/52470683
3.https://blog.csdn.net/very_2/article/details/6535505
4.https://baike.so.com/doc/6744089-6958626.html