您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > MFC浅析(7)CWnd类虚函数的调用时机缺省实现
MFC浅析(7)CWnd类虚函数的调用时机、缺省实现1.Create2.PreCreateWindow3.PreSubclassWindow4.PreTranslateMessage5.WindowProc6.OnCommand7.OnNotify8.OnChildNotify9.DefWindowProc10.DestroyWindow11.PostNcDestroyCWnd作为MFC中最基本的与窗口打交道的类,完成了大部分窗口管理任务。同时提供了很多虚拟函数,这些虚拟函数在适当的地方提供了供派生类参与管理的接口。一直以来,对这些虚拟函数的来龙去脉有所糊涂,无法明确的判断他们在什么时候调用,又缺省完成了些什么。重载时哪些是要注意的...等等。抽时间查看了MFC的原码,想看其究竟。总结如下:1.CreatevirtualBOOLCreate(LPCTSTRlpszClassName,LPCTSTRlpszWindowName,DWORDdwStyle,constRECT&rect,CWnd*pParentWnd,UINTnID,CCreateContext*pContext=NULL);调用时机:窗口建立时作为主窗口,大多在InitInstance()中将直接或间接调用Create作为子窗口,大多再父窗口建立后发出WM_CREATE消息,对其进行处理时OnCreate()中调用。功能:控制建立细节CWnd实现:.......//注册窗口类,调用API建立窗口//allowmodificationofseveralcommoncreateparametersCREATESTRUCTcs;cs.dwExStyle=dwExStyle;cs.lpszClass=lpszClassName;cs.lpszName=lpszWindowName;cs.style=dwStyle;cs.x=x;cs.y=y;cs.cx=nWidth;cs.cy=nHeight;cs.hwndParent=hWndParent;cs.hMenu=nIDorHMenu;cs.hInstance=AfxGetInstanceHandle();cs.lpCreateParams=lpParam;//在此调用虚拟函数PreCreateWindow,允许在实际建立之前“篡改”建立参数。if(!PreCreateWindow(cs)){PostNcDestroy();returnFALSE;}AfxHookWindowCreate(this);HWNDhWnd=::CreateWindowEx(cs.dwExStyle,cs.lpszClass,cs.lpszName,cs.style,cs.x,cs.y,cs.cx,cs.cy,cs.hwndParent,cs.hMenu,cs.hInstance,cs.lpCreateParams);#ifdef_DEBUGif(hWnd==NULL){TRACE1(Warning:Windowcreationfailed:GetLastErrorreturns0x%8.8X/n,GetLastError());}#endifif(!AfxUnhookWindowCreate())PostNcDestroy();//cleanupifCreateWindowExfailstoosoonif(hWnd==NULL)returnFALSE;ASSERT(hWnd==m_hWnd);//shouldhavebeensetinsendmsghookreturnTRUE;}2.PreCreateWindow调用时机:参见上段,在Create()中,设置好窗口建立数据cs后,在实际建立窗口之前,将cs“暴露”给派生类,允许派生类在此时改变窗口建立参数。功能:控制建立参数(在Create()中可以设置建立信息,但Create有时是框架结构隐含调用的,故在PreCreateWindow时,再提供一个修订窗口建立参数的机会)。CWnd实现:BOOLCWnd::PreCreateWindow(CREATESTRUCT&cs){//如果在派生类中用户没有定制类名,没有制定窗口类名,使用MFC默认注册类if(cs.lpszClass==NULL){//makesurethedefaultwindowclassisregisteredVERIFY(AfxDeferRegisterClass(AFX_WND_REG));//noWNDCLASSprovided-usechildwindowdefaultASSERT(cs.style&WS_CHILD);cs.lpszClass=_afxWnd;}returnTRUE;}如果需要,使用自定的窗口类,应该在派生类的PreCreateWindow中注册,并得到并指定类名。3.PreSubclassWindow调用时机:建立窗口的同时将C++Wnd对象附着在窗口上CWnd::Create()中:...AfxHookWindowCreate(this);HWNDhWnd=::CreateWindowEx(cs.dwExStyle,cs.lpszClass,cs.lpszName,cs.style,cs.x,cs.y,cs.cx,cs.cy,cs.hwndParent,cs.hMenu,cs.hInstance,cs.lpCreateParams);AfxUnhookWindowCreate();...建立窗口时,系统建立WH_CBT(训练)钩子(截获窗口动作),在钩子函数中完成CWnd对象对窗口的包裹.file://操作很多,主要有//pWndInit为传入的参数,应该就是CWnd对象指针了//对象连接到窗口句柄pWndInit-Attach(hWnd);...//调用虚拟函数PreSubclassWindow,给用户一个定义相关操作的机会,例如,子控件的附着pWndInit-PreSubclassWindow();...//设置消息处理函数等等。WNDPROC*pOldWndProc=pWndInit-GetSuperWndProcAddr();...WNDPROCafxWndProc=AfxGetAfxWndProc();oldWndProc=(WNDPROC)SetWindowLong(hWnd,GWL_WNDPROC,(DWORD)afxWndProc);...CWnd实现:CWnd类中,在此虚拟函数中没有缺省动作。4.PreTranslateMessage调用时机:进程的消息队列处理循环中,在将窗口的消息分发到窗口的消息处理函数之前将调用CWinApp虚拟函数PreTranslateMessage,允许再窗口派生类中对即将发送的消息进行处理。而CWinApp::PreTranslateMessage将有可能调用到窗口的PreTranslateMessage。先来看以下CWinThread::PumpMessage中对消息的分发过程...::GetMessage(&m_msgCur,NULL,NULL,NULL)...//CWinThread的PreTranslateMessage虚拟函数被调用if(m_msgCur.message!=WM_KICKIDLE&&!PreTranslateMessage(&m_msgCur)){::TranslateMessage(&m_msgCur);::DispatchMessage(&m_msgCur);}BOOLCWinThread::PreTranslateMessage(MSG*pMsg){....CWnd*pMainWnd=AfxGetMainWnd();//依此调用从命令发出窗口到主窗口间各级窗口的PreTranslateMessage();//参见下面的WalkPreTranslateTree原码if(CWnd::WalkPreTranslateTree(pMainWnd-GetSafeHwnd(),pMsg))returnTRUE;//incaseofmodelessdialogs,lastchanceroutethroughmain//window'sacceleratortableif(pMainWnd!=NULL){CWnd*pWnd=CWnd::FromHandle(pMsg-hwnd);if(pWnd-GetTopLevelParent()!=pMainWnd)returnpMainWnd-PreTranslateMessage(pMsg);}returnFALSE;//nospecialprocessing}BOOLPASCALCWnd::WalkPreTranslateTree(HWNDhWndStop,MSG*pMsg){....//依次调用各级窗口的PreTranslateMessagefor(HWNDhWnd=pMsg-hwnd;hWnd!=NULL;hWnd=::GetParent(hWnd)){CWnd*pWnd=CWnd::FromHandlePermanent(hWnd);if(pWnd!=NULL){if(pWnd-PreTranslateMessage(pMsg))returnTRUE;//trappedbytargetwindow(eg:accelerators)}//gottohWndStopwindowwithoutinterestif(hWnd==hWndStop)break;}returnFALSE;//nospecialprocessing}5.WindowProc调用时机:窗口建立后,将进入消息循环。在此期间,WindowPro被调用以处理各消息。在窗口建立时,消息处理函数被制定,一般是AfxWndProc,其将调用AfxCallWndProc,而AfxCallWndProc最终将调用到虚拟函数WindowProc。功能:允许派生类在消息处理前,添加处理。CWnd实现:LRESULTCWnd::WindowProc(UINTmessage,WPARAMwParam,LPARAMlParam){LRESULTlResult=0;file://主要是由OnWndMsg完成消息的分类,分解处理。if(!OnWndMsg(message,wParam,lParam,&lResult))file://剩余部分交由缺省命令处理函数处理。lResult=DefWindowProc(message,wParam,lParam);returnlResult;}附:OnWndMsg流程在OnWndMsg中,将根据消息的性质,归类成命令消息、通知消息、普通消息分别由OnCommand、OnNotify...处理BOOLCWnd::OnWndMsg(UINTmessage,WPARAMwParam,LPARAMlParam,LRESULT*pResult){//如果是WM_COMMAND消息,由虚拟函数OnCommand处理,//WM_COMMAND由菜单、工具条等发出,表示特定的命令,与窗口消息由所不同。if(message==WM_COMMAND){....OnCommand(wParam,lParam))....}//如果消息是WM_NOTIFY,即通知消息,由虚拟函数OnNotify处理,if(message==WM_NOTIFY){.....OnNotify(wParam,lParam,&lResult)).....}//对特殊消息的处理:WM_ACTIVATE...WM_SETCURSOR...//普通消息.......//在类消息映射中查找消息对应的消息处理函数。//参数转换等等..........//找到后,调用该函数。mmf.pfn=lpEntry-pfn;lResult=(this-*mmf.pfn_lwl)(wParam,lParam);.......}6.OnCommand
本文标题:MFC浅析(7)CWnd类虚函数的调用时机缺省实现
链接地址:https://www.777doc.com/doc-2888503 .html