关于MFC 消息映射机制剖析 下载本文

内容发布更新时间 : 2024/5/14 17:52:30星期一 下面是文章的全部内容请认真阅读。

软采用了所谓的消息映射机制,来完成不同对象之间消息的传递,本文就MFC9.0源码进行分析,大致讲解MFC的消息映射机制。

步入正题,在AfxWinMain() 函数中,当MFC框架初始化完成后,即 pThread->InitInstance() 执行完成,就开始进行消息循环,入口函数是pThread->Run():

[cpp] view plaincopy

1. // Perform specific initializations

2. if (!pThread->InitInstance())// MFC初始化框架 3. {

4. if (pThread->m_pMainWnd != NULL) 5. {

6. TRACE(traceAppMsg, 0, \);

7. pThread->m_pMainWnd->DestroyWindow(); 8. }

9. nReturnCode = pThread->ExitInstance(); 10. goto InitFailure; 11. }

12. nReturnCode = pThread->Run();// 进入消息循环

执行CWinApp:: Run():

[cpp] view plaincopy

1. // Main running routine until application exits 2. int CWinApp::Run() 3. {

4. if (m_pMainWnd == NULL && AfxOleGetUserCtrl()) 5. {

6. // Not launched /Embedding or /Automation, but has no main window! 7. TRACE(traceAppMsg, 0, \ quitting application.\\n\); 8. AfxPostQuitMessage(0); 9. }

10. return CWinThread::Run(); 11. }

执行CWinThread::Run():

[cpp] view plaincopy

1. // main running routine until thread exits 2. int CWinThread::Run() 3. {

4. ASSERT_VALID(this);

5. _AFX_THREAD_STATE* pState = AfxGetThreadState(); 6.

7. // for tracking the idle time state 8. BOOL bIdle = TRUE; 9. LONG lIdleCount = 0; 10.

11. // acquire and dispatch messages until a WM_QUIT message is received. 12. GetMessage:从系统获取消息,将消息从系统中移除,属于阻塞函数。当系统无消

息时,GetMessage会等待下一条消息。而函数PeekMesssge是以查看的方式从系统中获取消息,可以不将消息从系统中移除,是非阻塞函数;当系统无消息时,返回FALSE,继续执行后续代码

13. for (;;) 14. {

15. // phase1: check to see if we can do idle work 16. while (bIdle &&

17. !::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOV

E)) 18. {

19. // call OnIdle while in bIdle state 20. if (!OnIdle(lIdleCount++))

21. bIdle = FALSE; // assume \ 22. } 23.

24. // phase2: pump messages while available 25. do 26. {

27. // pump message, but quit on WM_QUIT 28. if (!PumpMessage()) 29. return ExitInstance(); 30.

31. // reset \ 32. //if (IsIdleMessage(&m_msgCur))

33. if (IsIdleMessage(&(pState->m_msgCur))) 34. {

35. bIdle = TRUE; 36. lIdleCount = 0; 37. } 38.

39. } while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOR

EMOVE)); //查看消息队列中是否有消息

40. } 41. }

在 do-while 循环中进行消息的路由,主要函数就是 PumpMessage(),我们跟着进入这个函数看看做了什么:

[cpp] view plaincopy

1. BOOL CWinThread::PumpMessage() 2. {

3. return AfxInternalPumpMessage(); 4. }

继续跟踪:

[cpp] view plaincopy

1. BOOL AFXAPI AfxInternalPumpMessage() 2. {

3. _AFX_THREAD_STATE *pState = AfxGetThreadState(); 4.

5. if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))// 从消息队列获

取消息 6. {

7. #ifdef _DEBUG

8. TRACE(traceAppMsg, 1, \

\);

9. pState->m_nDisablePumpCount++; // application must die 10. #endif

11. // Note: prevents calling message loop things in 'ExitInstance' 12. // will never be decremented 13. return FALSE; 14. } 15.

16. #ifdef _DEBUG

17. if (pState->m_nDisablePumpCount != 0) 18. {

19. TRACE(traceAppMsg, 0, \

permitted.\\n\); 20. ASSERT(FALSE); 21. }

22. #endif 23.

24. #ifdef _DEBUG

25. _AfxTraceMsg(_T(\), &(pState->m_msgCur)); 26. #endif 27.

28. // process this message 29.

30. if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&

(pState->m_msgCur))) 31. {

32. ::TranslateMessage(&(pState->m_msgCur)); 33. ::DispatchMessage(&(pState->m_msgCur)); 34. }

35. return TRUE; 36. }

从上面的代码我们可以看到 MFC是通过 GetMessage() 来获取消息,然后再看下面这几句代码:

[cpp] view plaincopy

1. if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pSt

ate->m_msgCur))) 2. {

3. ::TranslateMessage(&(pState->m_msgCur)); 4. ::DispatchMessage(&(pState->m_msgCur)); 5. }

也就是说当系统获取消息后,先调用 AfxPreTranslateMessage() 这个看起来跟我们经常看到的PreTranslateMessage() 很像!我们来看看到底发生了什么:

[cpp] view plaincopy

1. BOOL __cdecl AfxPreTranslateMessage(MSG* pMsg) 2. {

3. CWinThread *pThread = AfxGetThread(); 4. if( pThread )

5. return pThread->PreTranslateMessage( pMsg ); 6. else

7. return AfxInternalPreTranslateMessage( pMsg ); 8. }

执行 pThread->PreTranslateMessage():

[cpp] view plaincopy

1. BOOL CWinThread::PreTranslateMessage(MSG* pMsg) 2. {

3. ASSERT_VALID(this);

4. return AfxInternalPreTranslateMessage( pMsg ); 5. }

执行AfxInternalPreTranslateMessage():

[cpp] view plaincopy

1. BOOL AfxInternalPreTranslateMessage(MSG* pMsg) 2. {

3. // ASSERT_VALID(this); 4.

5. CWinThread *pThread = AfxGetThread(); 6. if( pThread ) 7. {

8. // if this is a thread-message, short-circuit this function 9. if (pMsg->hwnd == NULL && pThread->DispatchThreadMessageEx(pMsg)) 10. return TRUE; 11. } 12.

13. // walk from target to main window 14. CWnd* pMainWnd = AfxGetMainWnd();

15. if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))// 注意这个

函数

16. return TRUE; 17.

18. // in case of modeless dialogs, last chance route through main 19. // window's accelerator table 20. if (pMainWnd != NULL) 21. {

22. CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd); 23. if (pWnd->GetTopLevelParent() != pMainWnd) 24. return pMainWnd->PreTranslateMessage(pMsg); 25. } 26.

27. return FALSE; // no special processing 28. }