MFC中如何改装SDK的WinMain函数
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 }