构造全局对象: theApp
应用程序对象(Applicate Object)的产生,内存于是获得配置,初值也设立,也调用了CWinApp的构造函数。
于是: CWinApp::m_pCurrentWinApp = this(this的动态指针类型是CMyWinApp,即:CWinApp::m_pCurrentWinApp = &theApp)。
theApp 配置完成之后,WinMain 登场。但我们并未撰写 WinMain程序代码。其实这是 MFC 早已准备好并由链接器直接加到应用程序代码中的。
代码如下:
extern "C"
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
int nReturnCode = -1;
CWinApp *pApp = AfxGetApp();
if ( !AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
if (!pApp->InitApplcation())
goto InitFailure;
if (!pApp->InitInstance())
{
if (pApp->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pApp->m_pMainWnd->DestroyWindow();
}
nReturnCode = pApp->ExitInstance();
goto InitFailure;
}
nReturnCode = pApp->Run();
AfxWinTerm();
return nReturnCode;
}
稍加整理,重点是调用了如下几个函数:
AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
pApp->InitApplcation()
pApp->InitInstance()
pApp->Run()
下面我们着手分析这四个函数在调用中,都具体做了那些操作。
AFX 应用程序内部初始化操作
AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
|
AfxInitThread()
MFC 为内部管理而做一些设置
pApp->InitApplcation()
注册窗口类,设置窗口样式,创建窗口 ,窗口显示与更新
pApp->InitInstance()
BOOL CMyWinApp::InitInstance()
{
m_pMainWnd = new CMyFrameWnd; // 创建一个框架窗口,将调用 CMyFrameWnd 类的构造函数
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpDateWindow();
}
CMyFrameWnd::CMyFrameWnd()
{
Create(...) // Create 函数是个虚函数。但 CMyFrameWnd 并没有重写他,所以这里调用的是其父类CFrameWnd的Create函数
...
}
BOOL CFrameWnd::Create(...)
{
CreateEx(...) // CreateEx 是类 CWnd 的一个成员函数
}
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)
{
CREATESTRUCT cs; // 这里我们将设置窗口产生时样式,cs用于保存窗口样式的名个参数
...
PreCreateWindow(cs) // 在这里注册窗口类。注意,cs.lpszClass 用于保存,是注册后的窗口类的名字
::CreateWindowEx(cs.?, cs.?...) // 创建窗口
}
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT &cs)
{
if (cs.lpszClass = NULL)
{
AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG);
cs.lpszClass = _afxWndFrameOrView;
}
}
#define AfxDeferRegisterClass(fClass) \
((afxRegisteredClasses & fClass) ? TRUE : AfxEndDeferRegisterClass(fClass))
这个宏表示,如果已经注册了fClass 这种窗口, MFC 什么都不做;否则就调用 AfxEndDefRegisterClass(fClass) 来注册窗口类
之后将调用
BOOL AFXAPI AfxEndDeferRegisterClass(short fClass)
{
... // 在这里,将根据给出的fClass 注册窗口类
}
// 我们发现,当 fClass = AFX_WNDFRAMEORVIEW_REG 时,其窗口类的类名就为 _afxWndFrameOrView
窗口显示与更新
当创建窗口的操作完成之后,我们再看回InitInstance 这个函数
BOOL CMyWinApp::InitInstance()
{
m_pMainWnd = new CMyFrameWnd; // 创建一个框架窗口,将调用 CMyFrameWnd 类的构造函数
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpDateWindow();
}
可以看到,程序在这里完成了窗口的显示和更新操作
消息循环
pApp->Run();
相当于调用:
CMyWinApp::Run()
后又调用
CWinThread::Run
do
{
::GetMessage(&msg,...);
PreTranslateMessage(&msg);
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}while (::PeekMessage(...));
之后,对于消息的处理将交由 窗口函数DefWindowProc来处理。
但 MFC 在这里又做了一些手脚,将消息送往了同是回调函数的::AfxWndProc,在AfxWndProc对消息进行处理
下面是消息的传递过程:
LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
CWnd *pWnd = CWnd::FromHandlePerManent(hWnd);
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); // WindowProc 是类 CWnd 的一个函数,其子类并没有重写
...
return lResult;
LRESUTL CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lPararm)
{
LRESULT lResult = 0;
if (!OnWndMsg(message, wParam, lParam, &lResult))
lResult = DefWindowProc(message, wParam, lParam);
return lResult;
}
在 CWnd::WindowProc中调用了OnWndMsg,而当程序进入CWnd::OnWndMsg时,程序会对消息进行分类
如是标准消息,直线上溯
如是命令消息,拐弯上溯
如是通知消息,那又是另一种处理方式
因这里内容太多,我就不详细说明了
而如果没有找到消息的处理函数,将由 CWnd::DefWindowProc 来处理。
而在 CWnd::DefWindowProc 中,将由全局函数 DefWindowProc 来进行处理