国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
MFC淺析(7) CWnd類虛函數(shù)的調(diào)用時機(jī)、缺省實(shí)現(xiàn)
 
CWnd類虛函數(shù)的調(diào)用時機(jī)、缺省實(shí)現(xiàn)

1. Create
2. PreCreateWindow
3. PreSubclassWindow
4. PreTranslateMessage
5. WindowProc
6. OnCommand
7. OnNotify
8. OnChildNotify
9. DefWindowProc
10. DestroyWindow
11. PostNcDestroy

CWnd作為MFC中最基本的與窗口打交道的類,完成了大部分窗口管理任務(wù)。同時提供了很多虛擬函數(shù),這些虛擬函數(shù)在適當(dāng)?shù)牡胤教峁┝斯┡缮悈⑴c管理的接口。
一直以來,對這些虛擬函數(shù)的來龍去脈有所糊涂,無法明確的判斷他們在什么時候調(diào)用,又缺省完成了些什么。重載時哪些是要注意的...等等。
抽時間查看了MFC的原碼,想看其究竟。
總結(jié)如下:

1. Create
virtual BOOL Create( LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
調(diào)用時機(jī):
窗口建立時
作為主窗口,大多在InitInstance()中將直接或間接調(diào)用Create
作為子窗口,大多再父窗口建立后發(fā)出WM_CREATE消息,對其進(jìn)行處理時OnCreate()中調(diào)用。
功能:
控制建立細(xì)節(jié)
CWnd實(shí)現(xiàn):
 .......
 //注冊窗口類,調(diào)用API建立窗口
 // allow modification of several common create parameters
 CREATESTRUCT cs;
 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;
 //在此調(diào)用虛擬函數(shù)PreCreateWindow,允許在實(shí)際建立之前“篡改”建立參數(shù)。
 if (!PreCreateWindow(cs))
 {
  PostNcDestroy();
  return FALSE;
 }
 AfxHookWindowCreate(this);
 HWND hWnd = ::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 _DEBUG
 if (hWnd == NULL)
 {
  TRACE1("Warning: Window creation failed: GetLastError returns 0x%8.8X\n",
   GetLastError());
 }
#endif
 if (!AfxUnhookWindowCreate())
  PostNcDestroy();        // cleanup if CreateWindowEx fails too soon
 if (hWnd == NULL)
  return FALSE;
 ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
 return TRUE;
}
2. PreCreateWindow
調(diào)用時機(jī):
參見上段,在Create()中,設(shè)置好窗口建立數(shù)據(jù)cs后,在實(shí)際建立窗口之前,將cs“暴露”給派生類,允許派生類在此時改變窗口建立參數(shù)。
功能:
控制建立參數(shù) (在Create()中可以設(shè)置建立信息,但Create有時是框架結(jié)構(gòu)隱含調(diào)用的,故在PreCreateWindow時,再提供一個修訂窗口建立參數(shù)的機(jī)會)。
CWnd實(shí)現(xiàn):
BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs)
{
 //如果在派生類中用戶沒有定制類名,沒有制定窗口類名,使用MFC默認(rèn)注冊類
 if (cs.lpszClass == NULL)
 {
  // make sure the default window class is registered
  VERIFY(AfxDeferRegisterClass(AFX_WND_REG));
  // no WNDCLASS provided - use child window default
  ASSERT(cs.style & WS_CHILD);
  cs.lpszClass = _afxWnd;
 }
 return TRUE;
}
如果需要,使用自定的窗口類,應(yīng)該在派生類的PreCreateWindow中注冊,并得到并指定類名。
3. PreSubclassWindow
調(diào)用時機(jī):
建立窗口的同時將C++Wnd對象附著在窗口上
 CWnd::Create()中:
 ...
 AfxHookWindowCreate(this);
 HWND hWnd = ::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();
 ...
建立窗口時,系統(tǒng)建立WH_CBT(訓(xùn)練)鉤子(截獲窗口動作),在鉤子函數(shù)中完成CWnd對象對窗口的"包裹".
file://操作很多,主要有
   //pWndInit為傳入的參數(shù),應(yīng)該就是CWnd對象指針了
   //對象連接到窗口句柄
   pWndInit->Attach(hWnd);
   ...
   //調(diào)用虛擬函數(shù)PreSubclassWindow,給用戶一個定義相關(guān)操作的機(jī)會,例如,子控件的附著
   pWndInit->PreSubclassWindow();
   ...
   //設(shè)置消息處理函數(shù)等等。
   WNDPROC *pOldWndProc = pWndInit->GetSuperWndProcAddr();
   ...
   WNDPROC afxWndProc = AfxGetAfxWndProc();
   oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC,
     (DWORD)afxWndProc);
   ...
CWnd實(shí)現(xiàn):
CWnd類中,在此虛擬函數(shù)中沒有缺省動作。
4. PreTranslateMessage
調(diào)用時機(jī):
進(jìn)程的消息隊列處理循環(huán)中,在將窗口的消息分發(fā)到窗口的消息處理函數(shù)之前將調(diào)用CWinApp虛擬函數(shù)PreTranslateMessage,允許再窗口派生類中對即將發(fā)送的消息進(jìn)行處理。
而CWinApp::PreTranslateMessage將有可能調(diào)用到窗口的PreTranslateMessage。
先來看以下CWinThread::PumpMessage中對消息的分發(fā)過程
 ...
 ::GetMessage(&m_msgCur, NULL, NULL, NULL)
 ...
 //CWinThread的PreTranslateMessage虛擬函數(shù)被調(diào)用
 
 if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
 {
  ::TranslateMessage(&m_msgCur);
  ::DispatchMessage(&m_msgCur);
 }
BOOL CWinThread::PreTranslateMessage(MSG* pMsg)
{
 ....
 CWnd* pMainWnd = AfxGetMainWnd();
 //依此調(diào)用從命令發(fā)出窗口到主窗口間各級窗口的PreTranslateMessage();
 //參見下面的WalkPreTranslateTree原碼
 if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
  return TRUE;
 // in case of modeless dialogs, last chance route through main
 //   window's accelerator table
 if (pMainWnd != NULL)
 {
   CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
   if (pWnd->GetTopLevelParent() != pMainWnd)
   return pMainWnd->PreTranslateMessage(pMsg);
 }
 return FALSE;   // no special processing
}
BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
{
 ....
 //依次調(diào)用各級窗口的PreTranslateMessage
 for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
 {
  CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
  if (pWnd != NULL)
  {
   if (pWnd->PreTranslateMessage(pMsg))
    return TRUE; // trapped by target window (eg: accelerators)
  }
  // got to hWndStop window without interest
  if (hWnd == hWndStop)
   break;
 }
 return FALSE;       // no special processing
}

5. WindowProc
調(diào)用時機(jī):
窗口建立后,將進(jìn)入消息循環(huán)。在此期間,WindowPro被調(diào)用以處理各消息。
在窗口建立時,消息處理函數(shù)被制定,一般是AfxWndProc,其將調(diào)用AfxCallWndProc,而AfxCallWndProc最終將調(diào)用到虛擬函數(shù)WindowProc。
功能:
允許派生類在消息處理前,添加處理。
CWnd實(shí)現(xiàn):
LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
 
 LRESULT lResult = 0;
 file://主要是由OnWndMsg完成消息的分類,分解處理。
 if (!OnWndMsg(message, wParam, lParam, &lResult))
 file://剩余部分交由缺省命令處理函數(shù)處理。
  lResult = DefWindowProc(message, wParam, lParam);
 return lResult;
}
附:OnWndMsg流程
在OnWndMsg中,將根據(jù)消息的性質(zhì),歸類成命令消息、通知消息、普通消息
分別由OnCommand、OnNotify...處理

BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
 //如果是WM_COMMAND消息,由虛擬函數(shù)OnCommand處理,
 //WM_COMMAND由菜單、工具條等發(fā)出,表示特定的命令,與窗口消息由所不同。
 if (message == WM_COMMAND)
 {
  ....
  OnCommand(wParam, lParam))
  ....
 }
 //如果消息是WM_NOTIFY,即通知消息,由虛擬函數(shù)OnNotify處理,
 if (message == WM_NOTIFY)
 {
  .....
  OnNotify(wParam, lParam, &lResult))
  .....
 }
 
 //對特殊消息的處理:
 WM_ACTIVATE...
 WM_SETCURSOR...
 
 //普通消息
 .......
 //在類消息映射中查找消息對應(yīng)的消息處理函數(shù)。
 //參數(shù)轉(zhuǎn)換等等...
 .......
 //找到后,調(diào)用該函數(shù)。
 mmf.pfn = lpEntry->pfn;
 lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
 .......
}
6. OnCommand
調(diào)用時機(jī):
在OnWndMsg中,如果消息是WM_COMMAND,即命令消息,將調(diào)用OnCommand;
在OnCommand中可以對命令處理進(jìn)行操作。
CWnd實(shí)現(xiàn): file://參見對命令更新機(jī)制的分析
BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam)
{
  .....
  //試探性的調(diào)用OnCmdMsg(,,CN_UPDATE_COMMAND_UI..)看當(dāng)前命令項(xiàng)是否有效
  CTestCmdUI state;
  state.m_nID = nID;
  OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL);
  if(...)//命令有效時設(shè)置標(biāo)志為命令標(biāo)志:CN_COMMAND
  nCode = CN_COMMAND;
  ....
  //如果是子窗口的通知消息,則反射給子窗口 ????,若子窗口有相應(yīng)處理,則返回。若未處理,還是作為命令處理。
  //有一部分通知消息是通過WM_COMMAND發(fā)送的
 
  if(ReflectLastMsg(hWndCtrl))
   return TRUE;    // eaten by child
  //命令消息經(jīng)過整理后,調(diào)用虛擬函數(shù)OnCmdMsg !!!!!!
  return OnCmdMsg(nID, nCode, NULL, NULL);
}
對命令處理的具體流程,參見文章相關(guān)文章。

7. OnOnNotify
BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult)
調(diào)用時機(jī):
OnWndMsg中,若處理的消息是WM_NOTIFY,將調(diào)用OnNotify對該通知消息具體處理。
虛函數(shù)OnNotify提供了在派生類中管理通知消息的接口。
CWnd實(shí)現(xiàn): BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult) { ..... file://將通知消息反射到發(fā)出通知的窗口,由其處理,若該窗口未處理,在由OnCmdMSg處理。 if (ReflectLastMsg(hWndCtrl, pResult)) return TRUE; // eaten by child ..... file://交由OnCmdMsg處理。對應(yīng)的消息映射宏為 return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, NULL); }
關(guān)于消息反射:
控件通常將自己的變化情況以通知消息的形式告知父窗口。由父窗口響應(yīng)處理。
MFC的反射機(jī)制可將通知消息傳回到原窗口,在原窗口的消息映射體系中得到對事件的處理。這便于窗口功能的封裝。
若子窗口沒有對該通知的反射處理函數(shù),則該通知消息還是由父窗口處理。

在ReflectLastMsg中,將調(diào)用pWnd->SendChildNotifyLastMsg,(pWnd是指向子窗口的指針)
SendChildNotifyLastMsg中將調(diào)用虛擬函數(shù)OnChildNotify。
在子窗口的OnChildNotify中可以在接收到反射消息,處理之前添加處理。

8. OnChildNotify
BOOL CWnd::OnChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
調(diào)用時機(jī):
窗口向父窗口發(fā)出通知后,被反射回來時,將先調(diào)用OnChildNotify。
可以在此函數(shù)中監(jiān)測處理由父窗口傳來的通知消息。
CWnd實(shí)現(xiàn):
調(diào)用CWnd成員ReflectChildNotify
通知消息的處理實(shí)際上還是由原有消息、命令處理流程完成的。不同的是,他們的消息、命令數(shù)值被調(diào)整以區(qū)別窗口自己的消息、命令。
在類的消息映射項(xiàng)中,反射消息處理宏完成對應(yīng)的通知消息與處理函數(shù)的關(guān)聯(lián)。
BOOL CWnd::ReflectChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
 //針對返回的消息分類處理成特定消息格式
 switch (uMsg)
 {
 //普通消息
 //WM_HSCROLL,WM_VSCROLL:.........
 .....
  //轉(zhuǎn)換成反射消息號,由命令處理函數(shù)。(在消息映射中,反射消息的序號為WM_REFLECT_BASE+uMsg)
  return CWnd::OnWndMsg(WM_REFLECT_BASE+uMsg, wParam, lParam, pResult);
 //如果是WM_COMMAND
 case WM_COMMAND:
  {
   .....
   //直接交給窗口的OnCmdMsg,同時命令的序號被相應(yīng)改變,以與窗口自己收到的同樣命令相區(qū)別,并有不同的消息映射項(xiàng)。
   CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_COMMAND), NULL, NULL))
   .....
  }
 //如果是 WM_NOTIFY通知
 case WM_NOTIFY:
  {
   //.......
   //交由OnCmdMsg處理。更改命令序號。
   CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_NOTIFY), ?ify, NULL);
   .....
  }
  //顏色類
  if (uMsg >= WM_CTLCOLORMSGBOX && uMsg <= WM_CTLCOLORSTATIC)
  {
   ....
   CWnd::OnWndMsg(WM_REFLECT_BASE+WM_CTLCOLOR, 0, (LPARAM)&ctl, pResult);
   ....
  }
  ......
}
9. DefWindowProc
調(diào)用時機(jī):
WindowProc中消息經(jīng)由OnWndMsg后,未找到對應(yīng)的處理函數(shù),將交由DefWindowProc處理。
在DefWindowProc中,可以針對這些未處理的消息增加相應(yīng)操作。
CWnd實(shí)現(xiàn)
LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
 if (m_pfnSuper != NULL)
  return ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam);
 WNDPROC pfnWndProc;
 if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL)
  return ::DefWindowProc(m_hWnd, nMsg, wParam, lParam);
 else
  return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam);
}
10. DestroyWindow
先來看CWnd對DestroyWindow的實(shí)現(xiàn)。
BOOL CWnd::DestroyWindow()
{
  ....
  //銷毀窗口
  if (m_pCtrlSite == NULL)
   bResult = ::DestroyWindow(m_hWnd);
  else
   bResult = m_pCtrlSite->DestroyControl();
  ....
  //C++窗口對象與窗口脫離
  Detach();
}
在此實(shí)現(xiàn)中,調(diào)用API:BOOL DestroyWindow(HWND hWnd);
API的DestroyWindow將向窗口發(fā)送WM_DESTROY和WM_NCDESTROY消息,

調(diào)用時機(jī):
①.對于主窗口:(CFrameWnd)
當(dāng)窗口接收到關(guān)閉消息時,將調(diào)用DestroyWindow
關(guān)閉消息的發(fā)送:
在菜單上選擇退出,將給一個ID_APP_EXIT命令,該命令在CWinApp::OnAppExit中有缺省實(shí)現(xiàn):向主窗口發(fā)送WM_CLOSE;
另,按下窗口關(guān)閉鈕,將給窗口一個WM_CLOSE消息。
在WM_CLOSE的缺省處理OnClose()中
void CFrameWnd::OnClose()
{
 ....
 DestroyWindow();
 ....
}
②.對于其他窗口
主窗口銷毀時將調(diào)用::DestroyWindow,此API將向窗口發(fā)送WM_DESTROY和WM_NCDESTROY消息。
并自動完成完成子窗口的銷毀。
在MFC中,子窗口的DestroyWindow虛擬函數(shù)并未被調(diào)用,但需要的時候可以重載后自己調(diào)用??刂谱哟翱诘匿N毀。

11. PostNcDestroy
調(diào)用時機(jī):
窗口銷毀后,在WM_NCDESTROY的處理函數(shù)OnNcDestroy()中調(diào)用。
在PostNcDestroy中一般將完成C++的窗口對象的刪除等收尾工作。
CWnd實(shí)現(xiàn):
CFrameWnd實(shí)現(xiàn)
delete this;(刪除窗口對象)

本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/FMD/archive/2001/06/16/5529.aspx
 
(#)
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
子類化和超類化區(qū)別(轉(zhuǎn)自--眼見為實(shí)(2):介紹Windows的窗口、消息、子類化和超類化...
windows窗口的創(chuàng)建
Windows程序基本框架
《白手起家Win32SDK應(yīng)用程序》(完整版+目錄)
WM_NOTIFY與消息反射—耗費(fèi)我兩天時間才解決的問題
VC進(jìn)程間通信之消息傳遞PostMessge()或SendMessage()
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服