ImageVerifierCode 换一换
格式:DOCX , 页数:15 ,大小:27.93KB ,
资源ID:5258093      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/5258093.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(关于MFC 消息映射机制剖析.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

关于MFC 消息映射机制剖析.docx

1、关于MFC 消息映射机制剖析软采用了所谓的消息映射机制,来完成不同对象之间消息的传递,本文就MFC9.0源码进行分析,大致讲解MFC的消息映射机制。步入正题,在AfxWinMain() 函数中,当MFC框架初始化完成后,即 pThread-InitInstance() 执行完成,就开始进行消息循环,入口函数是pThread-Run():cppview plaincopy1. /Performspecificinitializations2. if(!pThread-InitInstance()/MFC初始化框架3. 4. if(pThread-m_pMainWnd!=NULL)5. 6. TR

2、ACE(traceAppMsg,0,Warning:Destroyingnon-NULLm_pMainWndn);7. pThread-m_pMainWnd-DestroyWindow();8. 9. nReturnCode=pThread-ExitInstance();10. gotoInitFailure;11. 12. nReturnCode=pThread-Run();/进入消息循环执行CWinApp: Run():cppview plaincopy1. /Mainrunningroutineuntilapplicationexits2. intCWinApp:Run()3. 4. i

3、f(m_pMainWnd=NULL&AfxOleGetUserCtrl()5. 6. /Notlaunched/Embeddingor/Automation,buthasnomainwindow!7. TRACE(traceAppMsg,0,Warning:m_pMainWndisNULLinCWinApp:Run-quittingapplication.n);8. AfxPostQuitMessage(0);9. 10. returnCWinThread:Run();11. 执行CWinThread:Run():cppview plaincopy1. /mainrunningroutineu

4、ntilthreadexits2. intCWinThread:Run()3. 4. ASSERT_VALID(this);5. _AFX_THREAD_STATE*pState=AfxGetThreadState();6. 7. /fortrackingtheidletimestate8. BOOLbIdle=TRUE;9. LONGlIdleCount=0;10. 11. /acquireanddispatchmessagesuntilaWM_QUITmessageisreceived.12. GetMessage:从系统获取消息,将消息从系统中移除,属于阻塞函数。当系统无消息时,GetM

5、essage会等待下一条消息。而函数PeekMesssge是以查看的方式从系统中获取消息,可以不将消息从系统中移除,是非阻塞函数;当系统无消息时,返回FALSE,继续执行后续代码 13. for(;)14. 15. /phase1:checktoseeifwecandoidlework16. while(bIdle&17. !:PeekMessage(&(pState-m_msgCur),NULL,NULL,NULL,PM_NOREMOVE)18. 19. /callOnIdlewhileinbIdlestate20. if(!OnIdle(lIdleCount+)21. bIdle=FALS

6、E;/assumenoidlestate22. 23. 24. /phase2:pumpmessageswhileavailable25. do26. 27. /pumpmessage,butquitonWM_QUIT28. if(!PumpMessage()29. returnExitInstance();30. 31. /resetnoidlestateafterpumpingnormalmessage32. /if(IsIdleMessage(&m_msgCur)33. if(IsIdleMessage(&(pState-m_msgCur)34. 35. bIdle=TRUE;36. l

7、IdleCount=0;37. 38. 39. while(:PeekMessage(&(pState-m_msgCur),NULL,NULL,NULL,PM_NOREMOVE);/查看消息队列中是否有消息40. 41. 在 do-while 循环中进行消息的路由,主要函数就是PumpMessage(),我们跟着进入这个函数看看做了什么:cppview plaincopy1. BOOLCWinThread:PumpMessage()2. 3. returnAfxInternalPumpMessage();4. 继续跟踪:cppview plaincopy1. BOOLAFXAPIAfxInte

8、rnalPumpMessage()2. 3. _AFX_THREAD_STATE*pState=AfxGetThreadState();4. 5. if(!:GetMessage(&(pState-m_msgCur),NULL,NULL,NULL)/从消息队列获取消息6. 7. #ifdef_DEBUG8. TRACE(traceAppMsg,1,CWinThread:PumpMessage-ReceivedWM_QUIT.n);9. pState-m_nDisablePumpCount+;/applicationmustdie10. #endif11. /Note:preventscalli

9、ngmessageloopthingsinExitInstance12. /willneverbedecremented13. returnFALSE;14. 15. 16. #ifdef_DEBUG17. if(pState-m_nDisablePumpCount!=0)18. 19. TRACE(traceAppMsg,0,Error:CWinThread:PumpMessagecalledwhennotpermitted.n);20. ASSERT(FALSE);21. 22. #endif23. 24. #ifdef_DEBUG25. _AfxTraceMsg(_T(PumpMessa

10、ge),&(pState-m_msgCur);26. #endif27. 28. /processthismessage29. 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. returnTRUE;36. 从上面的代码我们可以看到 MFC是通过GetMessage() 来获取消息,然后再看

11、下面这几句代码:cppview plaincopy1. if(pState-m_msgCur.message!=WM_KICKIDLE&!AfxPreTranslateMessage(&(pState-m_msgCur)2. 3. :TranslateMessage(&(pState-m_msgCur);4. :DispatchMessage(&(pState-m_msgCur);5. 也就是说当系统获取消息后,先调用AfxPreTranslateMessage() 这个看起来跟我们经常看到的PreTranslateMessage() 很像!我们来看看到底发生了什么:cppview plain

12、copy1. BOOL_cdeclAfxPreTranslateMessage(MSG*pMsg)2. 3. CWinThread*pThread=AfxGetThread();4. if(pThread)5. returnpThread-PreTranslateMessage(pMsg);6. else7. returnAfxInternalPreTranslateMessage(pMsg);8. 执行 pThread-PreTranslateMessage():cppview plaincopy1. BOOLCWinThread:PreTranslateMessage(MSG*pMsg)2

13、. 3. ASSERT_VALID(this);4. returnAfxInternalPreTranslateMessage(pMsg);5. 执行AfxInternalPreTranslateMessage():cppview plaincopy1. BOOLAfxInternalPreTranslateMessage(MSG*pMsg)2. 3. /ASSERT_VALID(this);4. 5. CWinThread*pThread=AfxGetThread();6. if(pThread)7. 8. /ifthisisathread-message,short-circuitthis

14、function9. if(pMsg-hwnd=NULL&pThread-DispatchThreadMessageEx(pMsg)10. returnTRUE;11. 12. 13. /walkfromtargettomainwindow14. CWnd*pMainWnd=AfxGetMainWnd();15. if(CWnd:WalkPreTranslateTree(pMainWnd-GetSafeHwnd(),pMsg)/注意这个函数16. returnTRUE;17. 18. /incaseofmodelessdialogs,lastchanceroutethroughmain19.

15、/windowsacceleratortable20. if(pMainWnd!=NULL)21. 22. CWnd*pWnd=CWnd:FromHandle(pMsg-hwnd);23. if(pWnd-GetTopLevelParent()!=pMainWnd)24. returnpMainWnd-PreTranslateMessage(pMsg);25. 26. 27. returnFALSE;/nospecialprocessing28. 执行 CWnd:WalkPreTranslateTree(pMainWnd-GetSafeHwnd(), pMsg)cppview plaincop

16、y1. BOOLPASCALCWnd:WalkPreTranslateTree(HWNDhWndStop,MSG*pMsg)2. 3. ASSERT(hWndStop=NULL|:IsWindow(hWndStop);4. ASSERT(pMsg!=NULL);5. 6. /walkfromthetargetwindowuptothehWndStopwindowchecking7. /ifanywindowwantstotranslatethismessage8. 9. for(HWNDhWnd=pMsg-hwnd;hWnd!=NULL;hWnd=:GetParent(hWnd)10. 11.

17、 CWnd*pWnd=CWnd:FromHandlePermanent(hWnd);12. if(pWnd!=NULL)13. 14. /targetwindowisaC+window15. if(pWnd-PreTranslateMessage(pMsg)16. returnTRUE;/trappedbytargetwindow(eg:accelerators)17. 18. 19. /gottohWndStopwindowwithoutinterest20. if(hWnd=hWndStop)21. break;22. 23. returnFALSE;/nospecialprocessin

18、g24. MFC在后台维护了一个句柄和C+对象指针的映射表,一旦有消息产生时,我们知道这个消息的结构体中包含了该消息所属窗口的句柄,那么通过这个句柄我们可以找到相对于的C+对象的指针,在for循环里面遍历当前窗口的所有父窗口,查找是否有消息重写,一旦有子类重写父类消息的,则通过当前消息所属窗口的句柄来调用 CWnd:FromHandlePermanent(hWnd) 函数,从而得到当前C+对象的指针,最后调用 PreTranslateMessage(),因为PreTranslateMessage()是虚函数,所以调用的是子类的PreTranslateMessage(),该函数可以自定义一部分消

19、息的处理方式。需要注意的是,PreTranslateMessage() 返回为 FALSE 时,说明没有发生消息的重写,则把消息直接给TranslateMessage() 和DispatchMessage() 进行处理,当返回是TRUE时,则去消息队列获取下一条消息。另外,SendMessage() 是直接发送给WindowProc进行处理(该函数是一个DispatchMessage() 中的一个回调函数,用于处理默认的一些系统消息),没有进入消息队列,所以不会被GetMessage() 抓取到,所以也就不会PreTranslateMessage() 抓到了,但是PostMessage() 是

20、进入消息队列的,是可以被GetMessage() 抓到的。所以从上面的代码跟踪可见,当我们需要重写一些系统消息时,比如给程序设置一些快捷键等,可以在PreTranslateMessage() 中进行操作,当然,不是PreTranslateMessage() 并不是可以重写所有消息,有一些消息也是无法处理的,这时可以交给WindowProc 进行处理,WindowProc () 也是虚函数。cppview plaincopy1. LRESULTCWnd:WindowProc(UINTmessage,WPARAMwParam,LPARAMlParam)2. 3. /OnWndMsgdoesmost

21、ofthework,exceptforDefWindowProccall4. LRESULTlResult=0;5. if(!OnWndMsg(message,wParam,lParam,&lResult)6. lResult=DefWindowProc(message,wParam,lParam);7. returnlResult;8. 消息的映射主要是通过 OnWndMsg() 进行处理,考虑到该函数代码很多,就不全贴了,我们分析其中一小段:cppview plaincopy1. for(/*pMessageMapalreadyinited*/;pMessageMap-pfnGetBase

22、Map!=NULL;2. pMessageMap=(*pMessageMap-pfnGetBaseMap)()3. 4. /Note:catchnotsocommonbutfatalmistake!5. /BEGIN_MESSAGE_MAP(CMyWnd,CMyWnd)6. ASSERT(pMessageMap!=(*pMessageMap-pfnGetBaseMap)();7. if(messagelpEntries,11. message,0,0)!=NULL)12. 13. pMsgCache-lpEntry=lpEntry;14. winMsgLock.Unlock();15. got

23、oLDispatch;16. 17. 18. else19. 20. /registeredwindowsmessage21. lpEntry=pMessageMap-lpEntries;22. while(lpEntry=AfxFindMessageEntry(lpEntry,0xC000,0,0)!=NULL)23. 24. UINT*pnID=(UINT*)(lpEntry-nSig);25. ASSERT(*pnID=0xC000|*pnID=0);26. /mustbesuccessfullyregistered27. if(*pnID=message)28. 29. pMsgCache-lpEntry=lpEntry;30. winMsgLock.Unlock();31. gotoLDispatchRegistered;32. 33. lpEntry+;/keeplookingpastthisone34. 35. 36. 在for循环里面有这样一个数据:AFX_MSGMAP*pMessageMap() ,它代表当前C+对象的消息映射表指针,那么这里的消息映射表到底是个什么样的数据结构,我们来一探究竟。我们打开

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1