Windows程序的生成顺序
Windows窗口的生命周期
初始化操作
- 从WinMain函数开始,注册窗口;
- 创建窗口;
- 调用CreateWindow,为程序建立了一个窗口,作为程序的屏幕
舞台。CreateWindow产生窗口之后会送出WM_CREATE消息给窗口函数,后者
于是可以在此时做些初始化操作(例如配置内存、打开文件、设置窗口初始数据等)。
- 调用CreateWindow,为程序建立了一个窗口,作为程序的屏幕
- 显示刷新窗口
ShowWindow (hwnd, iCmdShow) ; //显示窗口
UpdateWindow (hwnd) ; //刷新窗口
用户交互操作
GetMessage函数用于从消息队列中获取消息,DispatchMessage函数(在Windows USER模块的帮助下)则是将消息分派到相应的窗口函数进行处理。这是Windows编程中常见的一种机制,用于处理用户界面的交互和事件。
WM_QUIT是特定的消息类型,当接收到这个消息时,GetMessage会返回0并结束while循环,进而结束整个程序。
下图为Windows处理用户交互信息的过程:
关闭窗口
使用者按下系统菜单中的Close命令 -> 系统送出WM_CLOSE消息 -> DefWindowProc处理调用DestroyWindow -> Destroy Window送出WM_DESTROY消息 -> 程序对WM_DESTROY的标准反应是调用PostQuitMessage送出WM_QUIT消息 -> 消息循环中的GetMessage取得,如步骤2,结束消息循环.
MFC程序的生成顺序
通过Windows SDK程序可以得出程序运行的最重要的两部分为WinMain(初始化操作)、WinProcedure(处理信息)
MFC中类的派生关系:CObject->CCmdTarget->CWinThread->CWinApp
准备阶段1
MFC程序中WinMain函数的作用被CWinApp类取代了,它所负责的全部初始化工作和对消息解释及分派都有 CWinApp类的内部函数来完成,但是WinMain仍然存在,并且扮演着驾驭CWinApp的角色。CWinApp中几个最重要的函数如下:
virtual BOOL InitApplication();
virtual BOOL InitInstance();
virtual int Run();
在SDK程序设计中至关重要的主窗口句柄(就是那个hwnd,几乎程序所有有关窗口的操作都必须用到该句柄,它为Windows定位所要输出的信息 的目的窗口),它被存储在CWinThread中名为m_MainWnd的成员变量中,而CWinThread是CWinApp的父类。
准备阶段2
WndProc窗口函数与WinMain一样被变形后由单独生成的类进行了替代,替代它的是名为CFrameWnd的类,该类一般因程序不同而被继承为不同的模样,比较有代表性的一般形态如下:
class CMyFrameWnd : public CFrameWnd
{
public:CMyFrameWND();afx_msg void OnPaint();afx_msg boid OnAbout();DECLARE_MESSAGE_MAP();
};
程序构建及运行
- 1、设置全局对象
大量的CWinApp之中的成员变量由于theApp的诞生而进行了配置或被赋初值,因此我们完全可以说theApp这个Application object是整个程序的引爆器。 - 2、the App配置完成之后,应有WinMain函数处理
在…\Microsoft Visual Studio\VC98\MFC\SRC目录下可以找到一个名为WinMain.cpp的文件其中体现WinMain主要工作的代码为:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)
{...CWinApp* pApp = AfxGetApp();// AFX internal initializationif (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))goto InitFailure;if (pApp != NULL && !pApp->InitApplication())goto InitFailure;// Perform specific initializationsif (!pThread->InitInstance()){...};nReturnCode = pThread->Run();}
重点为AfxWinInit函数调用、pApp->InitInstance(); nReturnCode=pApp->run();
- 首先是AfxWinInit,它隐藏在APPINIT.CPP中,重要代码如下:
BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)
{ ...CWinApp* pApp = AfxGetApp();if (pApp != NULL){// Windows specific initialization (not done if no CWinApp)pApp->m_hInstance = hInstance;pApp->m_hPrevInstance = hPrevInstance;pApp->m_lpCmdLine = lpCmdLine;pApp->m_nCmdShow = nCmdShow;pApp->SetCurrentHandles();}}
- pApp->InitInstance,CWinApp类中此函数是虚函数,由于程序改写了该函数,所以现在等于调用我们自己的InitInstance,我们的程序也将从这里开始自己主窗口的生命。生成的一个简单程序的这一段代码如下:
BOOL CTestApp::InitInstance()
{... CMainFrame* pMainFrame = new CMainFrame;//调用了CMainFrame的构造函数...if (!ProcessShellCommand(cmdInfo))return FALSE;m_pMainWnd->ShowWindow(SW_SHOW); //这两行与SDK程序m_pMainWnd->UpdateWindow(); //极为相似
}
- CWinApp::Run事实上指向CWinThread::Run,它位于THRDCORE.CPP中,代码如下:
int CWinThread::Run()
{while (bIdle &&!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)){// call OnIdle while in bIdle stateif (!OnIdle(lIdleCount++))bIdle = FALSE; // assume "no idle" state}// phase2: pump messages while availabledo{// pump message, but quit on WM_QUITif (!PumpMessage())return ExitInstance();// reset "no idle" state after pumping "normal" messageif (IsIdleMessage(&m_msgCur)){bIdle = TRUE;lIdleCount = 0;}} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));}ASSERT(FALSE); // not reachable
}
PumpMessage代码如下:
BOOL CWinThread::PumpMessage()
{ASSERT_VALID(this);if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)){return FALSE;}// process this messageif (m_msgCur.message != WM_KICKIDLE&& !PreTranslateMessage(&m_msgCur)){::TranslateMessage(&m_msgCur);//SDK相似代码::DispatchMessage(&m_msgCur);}return TRUE;
}
MFC程序死亡调用顺序与Win32程序大同小异。
文章主要参考:
http://blog.chinaunix.net/uid-21169302-id-446230.html