1.在TCHAR.H文件中定义了一个宏:
#define _tWinMain WinMain
这样MFC源代码在编译的时候,_tWinMain就会被替换为WinMain(),这样操作系统就可以调用了。
2.在APPMODUL.CPP文件中,定义了_tWinMain(),在_tWinMain()中 return AfxWinMain();
1 extern "C" int WINAPI 2 _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 3 LPTSTR lpCmdLine, int nCmdShow) 4 { 5 // call shared/exported WinMain 6 return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); 7 }
3.在WINMAIN.CPP中定义了 AfxWinMain函数,
在里面调用pApp->InitApplication()
pApp->InitInstance()
pThread->Run();
1 int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 2 LPTSTR lpCmdLine, int nCmdShow) 3 { 4 ASSERT(hPrevInstance == NULL); 5 6 int nReturnCode = -1; 7 CWinThread* pThread = AfxGetThread(); 8 CWinApp* pApp = AfxGetApp(); 9 10 // AFX internal initialization 11 if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)) 12 goto InitFailure; 13 14 // App global initializations (rare) 15 if (pApp != NULL && !pApp->InitApplication()) 16 goto InitFailure; 17 18 // Perform specific initializations 19 if (!pThread->InitInstance()) 20 { 21 if (pThread->m_pMainWnd != NULL) 22 { 23 TRACE0("Warning: Destroying non-NULL m_pMainWnd\n"); 24 pThread->m_pMainWnd->DestroyWindow(); 25 } 26 nReturnCode = pThread->ExitInstance(); 27 goto InitFailure; 28 } 29 nReturnCode = pThread->Run(); 30 31 InitFailure: 32 #ifdef _DEBUG 33 // Check for missing AfxLockTempMap calls 34 if (AfxGetModuleThreadState()->m_nTempMapLock != 0) 35 { 36 TRACE1("Warning: Temp map lock count non-zero (%ld).\n", 37 AfxGetModuleThreadState()->m_nTempMapLock); 38 } 39 AfxLockTempMaps(); 40 AfxUnlockTempMaps(-1); 41 #endif 42 43 AfxWinTerm(); 44 return nReturnCode; 45 }
稍加整理之后可以理解为
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { CWinThread* pThread = AfxGetThread(); CWinApp* pApp = AfxGetApp(); AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow); pApp->InitApplication(); pThread->InitInstance(); nReturnCode = pThread->Run(); return nReturnCode; }
4.在APPINIT.CPP中查看AfxWinInit()
1 BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance, 2 LPTSTR lpCmdLine, int nCmdShow) 3 { 4 ASSERT(hPrevInstance == NULL); 5 6 // handle critical errors and avoid Windows message boxes 7 SetErrorMode(SetErrorMode(0) | 8 SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); 9 10 // set resource handles 11 AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); 12 pModuleState->m_hCurrentInstanceHandle = hInstance; 13 pModuleState->m_hCurrentResourceHandle = hInstance; 14 15 // fill in the initial state for the application 16 CWinApp* pApp = AfxGetApp(); 17 if (pApp != NULL) 18 { 19 // Windows specific initialization (not done if no CWinApp) 20 pApp->m_hInstance = hInstance; 21 pApp->m_hPrevInstance = hPrevInstance; 22 pApp->m_lpCmdLine = lpCmdLine; 23 pApp->m_nCmdShow = nCmdShow; 24 pApp->SetCurrentHandles(); 25 } 26 27 // initialize thread specific data (for main thread) 28 if (!afxContextIsDLL) 29 AfxInitThread(); 30 31 return TRUE; 32 }
在AfxWinInit中主要是做了一些初始化工作,以及使用AfxInitThread() hook一些消息 我目前还不明确
5.AfxWinInit之后 执行pApp->InitApplication() APPCORE.CPP
6.接着执行 pApp->InitInstance() 在CWinApp中可以看到
BOOL CWinApp::InitInstance() { return TRUE; }
这是一个需要我们在派送类里面进行重写的函数,利用它来显示窗口 也就是CFrameWnd类的派生类 简单的写法如下
BOOL CMyWinApp::InitInstance() { m_pMainWnd = new CMyFrameWnd(); m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; }
其中CMyFrame是我自己写的CFrameWnd的派送类
MFC生成的是这样的
1 BOOL CGraphApp::InitInstance() 2 { 3 // Standard initialization 4 // If you are not using these features and wish to reduce the size 5 // of your final executable, you should remove from the following 6 // the specific initialization routines you do not need. 7 8 #ifdef _AFXDLL 9 Enable3dControls(); // Call this when using MFC in a shared DLL 10 #else 11 Enable3dControlsStatic(); // Call this when linking to MFC statically 12 #endif 13 14 LoadStdProfileSettings(); // Load standard INI file options (including MRU) 15 16 // Register the application‘s document templates. Document templates 17 // serve as the connection between documents, frame windows and views. 18 19 CMultiDocTemplate* pDocTemplate; 20 pDocTemplate = new CMultiDocTemplate( 21 IDR_GRAPHTYPE, 22 RUNTIME_CLASS(CGraphDoc), 23 RUNTIME_CLASS(CChildFrame), // custom MDI child frame 24 RUNTIME_CLASS(CGraphView)); 25 AddDocTemplate(pDocTemplate); 26 27 pDocTemplate = new CMultiDocTemplate( 28 IDR_NEWTYPE, 29 RUNTIME_CLASS(CNewDoc), 30 RUNTIME_CLASS(CMDIChildWnd), // use directly ! because CChildFrame::OnCreateClient be overrided for Graph Doc Type 31 RUNTIME_CLASS(CEditView)); 32 AddDocTemplate(pDocTemplate); 33 34 // create main MDI Frame window 35 CMainFrame* pMainFrame = new CMainFrame; 36 if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) 37 return FALSE; 38 m_pMainWnd = pMainFrame; 39 40 // Enable drag/drop open 41 m_pMainWnd->DragAcceptFiles(); 42 43 // Enable DDE Execute open 44 EnableShellOpen(); 45 RegisterShellFileTypes(TRUE); 46 47 // Parse command line for standard shell commands, DDE, file open 48 CCommandLineInfo cmdInfo; 49 ParseCommandLine(cmdInfo); 50 51 // Dispatch commands specified on the command line 52 if (!ProcessShellCommand(cmdInfo)) 53 return FALSE; 54 55 // The main window has been initialized, so show and update it. 56 pMainFrame->ShowWindow(m_nCmdShow); 57 pMainFrame->UpdateWindow(); 58 59 return TRUE; 60 }
7.在InitInstance()中创建了一个CMyFrameWnd对象,故要先调用CMyFrameWnd的构造函数,因为CMyFrameWnd的基类是CFrameWnd,所以先调用CFrameWnd的构造函数
被定义在WINFRM.CPP,可以继续追踪到CWnd类,CCmdTarget类,CObject类,但是都没有发现有关窗口创建的函数被调用。其实是利用
pMainFrame->LoadFrame(IDR_MAINFRAME) 完成的
8.CFrameWnd::LoadFrame()函数定义在WINFRM.CPP中
1 BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, 2 CWnd* pParentWnd, CCreateContext* pContext) 3 { 4 // only do this once 5 ASSERT_VALID_IDR(nIDResource); 6 ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource); 7 8 m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE) 9 10 CString strFullString; 11 if (strFullString.LoadString(nIDResource)) 12 AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string 13 14 VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); 15 16 // attempt to create the window 17 LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource); 18 LPCTSTR lpszTitle = m_strTitle; 19 if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault, 20 pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext)) 21 { 22 return FALSE; // will self destruct on failure normally 23 } 24 25 // save the default menu handle 26 ASSERT(m_hWnd != NULL); 27 m_hMenuDefault = ::GetMenu(m_hWnd); 28 29 // load accelerator resource 30 LoadAccelTable(MAKEINTRESOURCE(nIDResource)); 31 32 if (pContext == NULL) // send initial update 33 SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE); 34 35 return TRUE; 36 }
可以看到在LoadFrame中主要做了2件事,第一,注册窗口。第二,创建窗口
先来看注册窗口 AfxDeferRegisterClass() 在
AFXIMPL.H中
#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)
AfxEnDeferRegisterClass() 定义在WINCORE.CPP 中
1 BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister) 2 { 3 // mask off all classes that are already registered 4 AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); 5 fToRegister &= ~pModuleState->m_fRegisteredClasses; 6 if (fToRegister == 0) 7 return TRUE; 8 9 LONG fRegisteredClasses = 0; 10 11 // common initialization 12 WNDCLASS wndcls; 13 memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults 14 wndcls.lpfnWndProc = DefWindowProc; 15 wndcls.hInstance = AfxGetInstanceHandle(); 16 wndcls.hCursor = afxData.hcurArrow; 17 18 INITCOMMONCONTROLSEX init; 19 init.dwSize = sizeof(init); 20 21 // work to register classes as specified by fToRegister, populate fRegisteredClasses as we go 22 if (fToRegister & AFX_WND_REG) 23 { 24 // Child windows - no brush, no icon, safest default class styles 25 wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; 26 wndcls.lpszClassName = _afxWnd; 27 if (AfxRegisterClass(&wndcls)) 28 fRegisteredClasses |= AFX_WND_REG; 29 } 30 if (fToRegister & AFX_WNDOLECONTROL_REG) 31 { 32 // OLE Control windows - use parent DC for speed 33 wndcls.style |= CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; 34 wndcls.lpszClassName = _afxWndOleControl; 35 if (AfxRegisterClass(&wndcls)) 36 fRegisteredClasses |= AFX_WNDOLECONTROL_REG; 37 } 38 if (fToRegister & AFX_WNDCONTROLBAR_REG) 39 { 40 // Control bar windows 41 wndcls.style = 0; // control bars don‘t handle double click 42 wndcls.lpszClassName = _afxWndControlBar; 43 wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 44 if (AfxRegisterClass(&wndcls)) 45 fRegisteredClasses |= AFX_WNDCONTROLBAR_REG; 46 } 47 if (fToRegister & AFX_WNDMDIFRAME_REG) 48 { 49 // MDI Frame window (also used for splitter window) 50 wndcls.style = CS_DBLCLKS; 51 wndcls.hbrBackground = NULL; 52 if (_AfxRegisterWithIcon(&wndcls, _afxWndMDIFrame, AFX_IDI_STD_MDIFRAME)) 53 fRegisteredClasses |= AFX_WNDMDIFRAME_REG; 54 } 55 if (fToRegister & AFX_WNDFRAMEORVIEW_REG) 56 { 57 // SDI Frame or MDI Child windows or views - normal colors 58 wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; 59 wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); 60 if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME)) 61 fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG; 62 } 63 if (fToRegister & AFX_WNDCOMMCTLS_REG) 64 { 65 // this flag is compatible with the old InitCommonControls() API 66 init.dwICC = ICC_WIN95_CLASSES; 67 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WIN95CTLS_MASK); 68 fToRegister &= ~AFX_WIN95CTLS_MASK; 69 } 70 if (fToRegister & AFX_WNDCOMMCTL_UPDOWN_REG) 71 { 72 init.dwICC = ICC_UPDOWN_CLASS; 73 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_UPDOWN_REG); 74 } 75 if (fToRegister & AFX_WNDCOMMCTL_TREEVIEW_REG) 76 { 77 init.dwICC = ICC_TREEVIEW_CLASSES; 78 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TREEVIEW_REG); 79 } 80 if (fToRegister & AFX_WNDCOMMCTL_TAB_REG) 81 { 82 init.dwICC = ICC_TAB_CLASSES; 83 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TAB_REG); 84 } 85 if (fToRegister & AFX_WNDCOMMCTL_PROGRESS_REG) 86 { 87 init.dwICC = ICC_PROGRESS_CLASS; 88 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_PROGRESS_REG); 89 } 90 if (fToRegister & AFX_WNDCOMMCTL_LISTVIEW_REG) 91 { 92 init.dwICC = ICC_LISTVIEW_CLASSES; 93 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_LISTVIEW_REG); 94 } 95 if (fToRegister & AFX_WNDCOMMCTL_HOTKEY_REG) 96 { 97 init.dwICC = ICC_HOTKEY_CLASS; 98 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_HOTKEY_REG); 99 } 100 if (fToRegister & AFX_WNDCOMMCTL_BAR_REG) 101 { 102 init.dwICC = ICC_BAR_CLASSES; 103 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_BAR_REG); 104 } 105 if (fToRegister & AFX_WNDCOMMCTL_ANIMATE_REG) 106 { 107 init.dwICC = ICC_ANIMATE_CLASS; 108 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ANIMATE_REG); 109 } 110 if (fToRegister & AFX_WNDCOMMCTL_INTERNET_REG) 111 { 112 init.dwICC = ICC_INTERNET_CLASSES; 113 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_INTERNET_REG); 114 } 115 if (fToRegister & AFX_WNDCOMMCTL_COOL_REG) 116 { 117 init.dwICC = ICC_COOL_CLASSES; 118 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_COOL_REG); 119 } 120 if (fToRegister & AFX_WNDCOMMCTL_USEREX_REG) 121 { 122 init.dwICC = ICC_USEREX_CLASSES; 123 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_USEREX_REG); 124 } 125 if (fToRegister & AFX_WNDCOMMCTL_DATE_REG) 126 { 127 init.dwICC = ICC_DATE_CLASSES; 128 fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_DATE_REG); 129 } 130 131 // save new state of registered controls 132 pModuleState->m_fRegisteredClasses |= fRegisteredClasses; 133 134 // special case for all common controls registered, turn on AFX_WNDCOMMCTLS_REG 135 if ((pModuleState->m_fRegisteredClasses & AFX_WIN95CTLS_MASK) == AFX_WIN95CTLS_MASK) 136 { 137 pModuleState->m_fRegisteredClasses |= AFX_WNDCOMMCTLS_REG; 138 fRegisteredClasses |= AFX_WNDCOMMCTLS_REG; 139 } 140 141 // must have registered at least as mamy classes as requested 142 return (fToRegister & fRegisteredClasses) == fToRegister; 143 }
可以看到MFC预先定义了很多窗口类,调用AfxRegisterClass()函数进行注册
1 BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass) 2 { 3 WNDCLASS wndcls; 4 if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName, 5 &wndcls)) 6 { 7 // class already registered 8 return TRUE; 9 } 10 11 if (!::RegisterClass(lpWndClass)) 12 { 13 TRACE1("Can‘t register window class named %s\n", 14 lpWndClass->lpszClassName); 15 return FALSE; 16 } 17 18 if (afxContextIsDLL) 19 { 20 AfxLockGlobals(CRIT_REGCLASSLIST); 21 TRY 22 { 23 // class registered successfully, add to registered list 24 AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); 25 LPTSTR lpszUnregisterList = pModuleState->m_szUnregisterList; 26 // the buffer is of fixed size -- ensure that it does not overflow 27 ASSERT(lstrlen(lpszUnregisterList) + 1 + 28 lstrlen(lpWndClass->lpszClassName) + 1 < 29 _countof(pModuleState->m_szUnregisterList)); 30 // append classname + newline to m_szUnregisterList 31 lstrcat(lpszUnregisterList, lpWndClass->lpszClassName); 32 TCHAR szTemp[2]; 33 szTemp[0] = ‘\n‘; 34 szTemp[1] = ‘\0‘; 35 lstrcat(lpszUnregisterList, szTemp); 36 } 37 CATCH_ALL(e) 38 { 39 AfxUnlockGlobals(CRIT_REGCLASSLIST); 40 THROW_LAST(); 41 // Note: DELETE_EXCEPTION not required. 42 } 43 END_CATCH_ALL 44 AfxUnlockGlobals(CRIT_REGCLASSLIST); 45 } 46 47 return TRUE; 48 }
最终调用了SDK中的RegisterClass()
接着回到窗口的创建中,这是在CFrameWnd::LoadFrame()中调用Create()函数创建的,因为派生类没有改写Create() 所以还是调用了CFrameWnd::Create()
BOOL CFrameWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext) { HMENU hMenu = NULL; if (lpszMenuName != NULL) { // load in a menu that will get destroyed when window gets destroyed HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU); if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL) { TRACE0("Warning: failed to load menu for CFrameWnd.\n"); PostNcDestroy(); // perhaps delete the C++ object return FALSE; } } m_strTitle = lpszWindowName; // save title for later if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)) { TRACE0("Warning: failed to create CFrameWnd.\n"); if (hMenu != NULL) DestroyMenu(hMenu); return FALSE; } return TRUE; }
在CFrameWnd::Create()中又调用了CreateEx(),因为CFrameWnd没有改写,所以调用CWnd::CreateEx() WINCORE.CPP
1 BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, 2 LPCTSTR lpszWindowName, DWORD dwStyle, 3 int x, int y, int nWidth, int nHeight, 4 HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam) 5 { 6 // allow modification of several common create parameters 7 CREATESTRUCT cs; 8 cs.dwExStyle = dwExStyle; 9 cs.lpszClass = lpszClassName; 10 cs.lpszName = lpszWindowName; 11 cs.style = dwStyle; 12 cs.x = x; 13 cs.y = y; 14 cs.cx = nWidth; 15 cs.cy = nHeight; 16 cs.hwndParent = hWndParent; 17 cs.hMenu = nIDorHMenu; 18 cs.hInstance = AfxGetInstanceHandle(); 19 cs.lpCreateParams = lpParam; 20 21 if (!PreCreateWindow(cs)) 22 { 23 PostNcDestroy(); 24 return FALSE; 25 } 26 27 AfxHookWindowCreate(this); 28 HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, 29 cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, 30 cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams); 31 32 #ifdef _DEBUG 33 if (hWnd == NULL) 34 { 35 TRACE1("Warning: Window creation failed: GetLastError returns 0x%8.8X\n", 36 GetLastError()); 37 } 38 #endif 39 40 if (!AfxUnhookWindowCreate()) 41 PostNcDestroy(); // cleanup if CreateWindowEx fails too soon 42 43 if (hWnd == NULL) 44 return FALSE; 45 ASSERT(hWnd == m_hWnd); // should have been set in send msg hook 46 return TRUE; 47 }
关于PreCreateWindow()依据多态性 先调用派生类,接着是CMDIFrameWnd,然后是CFrameWnd的PreCreateWindow函数 在WINFRM.CPP中如下:
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) { if (cs.lpszClass == NULL) { VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background } if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4) cs.style |= FWS_PREFIXTITLE; if (afxData.bWin4) cs.dwExStyle |= WS_EX_CLIENTEDGE; return TRUE; }
9.接着回到p->InitInstance()中来 showWindow(),UpdataWindow()
10.接着是p-> Run(),派送类没改写的Run()的话 调用CWinApp::Run()
1 int CWinApp::Run() 2 { 3 if (m_pMainWnd == NULL && AfxOleGetUserCtrl()) 4 { 5 // Not launched /Embedding or /Automation, but has no main window! 6 TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application.\n"); 7 AfxPostQuitMessage(0); 8 } 9 return CWinThread::Run(); 10 }
而CWinThread::Run()定义如下
1 int CWinThread::Run() 2 { 3 ASSERT_VALID(this); 4 5 // for tracking the idle time state 6 BOOL bIdle = TRUE; 7 LONG lIdleCount = 0; 8 9 // acquire and dispatch messages until a WM_QUIT message is received. 10 for (;;) 11 { 12 // phase1: check to see if we can do idle work 13 while (bIdle && 14 !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)) 15 { 16 // call OnIdle while in bIdle state 17 if (!OnIdle(lIdleCount++)) 18 bIdle = FALSE; // assume "no idle" state 19 } 20 21 // phase2: pump messages while available 22 do 23 { 24 // pump message, but quit on WM_QUIT 25 if (!PumpMessage()) 26 return ExitInstance(); 27 28 // reset "no idle" state after pumping "normal" message 29 if (IsIdleMessage(&m_msgCur)) 30 { 31 bIdle = TRUE; 32 lIdleCount = 0; 33 } 34 35 } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); 36 } 37 38 ASSERT(FALSE); // not reachable 39 }
而CWinThread::PumMessage()
1 BOOL CWinThread::PumpMessage() 2 { 3 ASSERT_VALID(this); 4 5 if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)) 6 { 7 #ifdef _DEBUG 8 if (afxTraceFlags & traceAppMsg) 9 TRACE0("CWinThread::PumpMessage - Received WM_QUIT.\n"); 10 m_nDisablePumpCount++; // application must die 11 // Note: prevents calling message loop things in ‘ExitInstance‘ 12 // will never be decremented 13 #endif 14 return FALSE; 15 } 16 17 #ifdef _DEBUG 18 if (m_nDisablePumpCount != 0) 19 { 20 TRACE0("Error: CWinThread::PumpMessage called when not permitted.\n"); 21 ASSERT(FALSE); 22 } 23 #endif 24 25 #ifdef _DEBUG 26 if (afxTraceFlags & traceAppMsg) 27 _AfxTraceMsg(_T("PumpMessage"), &m_msgCur); 28 #endif 29 30 // process this message 31 32 if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur)) 33 { 34 ::TranslateMessage(&m_msgCur); 35 ::DispatchMessage(&m_msgCur); 36 } 37 return TRUE; 38 }