BOOL CWnd::Create(LPCTSTR lpszClassName,LPCTSTR lpszWindowName, DWORD dwStyle,const RECT& rect,CWnd* pParentWnd, UINT nID,CCreateContext* pContext){ // can't use for desktop or pop-up windows (use CreateEx instead) ASSERT(pParentWnd != NULL); ASSERT((dwStyle & WS_POPUP) == 0); // 實際內部調用CreateEx進行視窗建立 return CreateEx(0, lpszClassName, lpszWindowName,dwStyle | WS_CHILD,rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top,pParentWnd->GetSafeHwnd(), (HMENU)(UINT_PTR)nID, (LPVOID)pContext);}BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,LPCTSTR lpszWindowName, DWORD dwStyle,int x, int y, int nWidth, int nHeight,HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam){ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) || AfxIsValidAtom(lpszClassName));ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));// 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;if (!PreCreateWindow(cs)) // 完成視窗類別註冊,PreCreateWindow為虛函數,可重載,修改視窗樣式{PostNcDestroy();return FALSE;}AfxHookWindowCreate(this); // 利用鉤子,註冊視窗函數,將類對應的視窗函數置為AfxWndProc // 建立視窗HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams); // ...}LRESULT AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam){// special message which identifies the window as using AfxWndProcif (nMsg == WM_QUERYAFXWNDPROC)return 1;// all other messages route through message mapCWnd* pWnd = CWnd::FromHandlePermanent(hWnd);ASSERT(pWnd != NULL);ASSERT(pWnd==NULL || pWnd->m_hWnd == hWnd);if (pWnd == NULL || pWnd->m_hWnd != hWnd)return ::DefWindowProc(hWnd, nMsg, wParam, lParam);return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam); // 調用對應的視窗處理函數}LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,WPARAM wParam = 0, LPARAM lParam = 0){ // ... lResult = pWnd->WindowProc(nMsg, wParam, lParam); // 調用對應的視窗處理函數 // ... }LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam){// OnWndMsg does most of the work, except for DefWindowProc callLRESULT lResult = 0;if (!OnWndMsg(message, wParam, lParam, &lResult)) // 調用類的OnWndMsg進行訊息處理lResult = DefWindowProc(message, wParam, lParam);return lResult;}BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult){LRESULT lResult = 0;union MessageMapFunctions mmf;mmf.pfn = 0;CInternalGlobalLock winMsgLock;// special case for commandsif (message == WM_COMMAND) // 在OnCommand中處理命令訊息{if (OnCommand(wParam, lParam)){lResult = 1;goto LReturnTrue;}return FALSE;}// special case for notifiesif (message == WM_NOTIFY) // 在OnNotify中處理通告訊息{NMHDR* pNMHDR = (NMHDR*)lParam;if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))goto LReturnTrue;return FALSE;} // ... AfxFindMessageEntry // 在AfxFindMessageEntry中處理普通訊息,尋找訊息映射表,直線回溯 // ...}CWnd::OnNotify 或 CWnd::OnCommand{ // ...// reflect notification to child window control // 將訊息反射回傳送子視窗,給子視窗自身一個處理的機會if (ReflectLastMsg(hWndCtrl, pResult))return TRUE; // eaten by child,若子視窗已處理過該訊息,直接返回,不需再找下去AFX_NOTIFY notify;notify.pResult = pResult;notify.pNMHDR = pNMHDR;return OnCmdMsg((UINT)nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, NULL);}
綜上所述,DispatchMessage將訊息指派到AfxWndProc中,AfxWndProc內部實際調用各個視窗類別的視窗函數,然後要麼直線回溯尋找訊息映射表處理訊息,要麼進入OnCommand或OnNotify進行處理,它們提供了一次將訊息反射回子視窗的處理機會,實際上同樣是尋找訊息映射表進行處理。