一 Win32窗口程序创建过程
#include <Windows.h> //消息处理回调函数 LRESULT CALLBACK MessageWindowProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { switch (msg) { case WM_CLOSE: PostQuitMessage(0); //发送一条WM_QUIT给系统,入口函数中,while一旦接受到该消息,就马上退出程序 break ; } return DefWindowProc(hwnd,msg,wParam,lParam); //调用默认的消息处理函数 } INT WINAPI WinMain(HINSTANCE hInstance,HINSTANCE pInstance,LPSTR cmdLine,int nShow ) { //1 设计窗体类 //2 注册窗体类 //3 创建窗体 //4 显示窗体 //5 更新窗体 //设计窗体类 WNDCLASSEX wndclass; wndclass.cbClsExtra = 0; //不需要窗口额外的存储空间 wndclass.cbSize = sizeof(WNDCLASSEX); //结构体大小 wndclass.cbWndExtra = 0; //不需要为窗口准备额外的存储空间 wndclass.hbrBackground = NULL; //不需要有背景,不需要有任何东西 wndclass.hCursor =LoadCursor(NULL,IDC_ARROW) ; //第一个参数 wndclass.hIcon = NULL; //exe程序在文件夹中显示的图标 wndclass.hIconSm = NULL; //程序运行后的窗口图标 wndclass.hInstance = hInstance; //代表当前程序的实例,程序启动后,系统自动赋值了 wndclass.lpfnWndProc = MessageWindowProc; //消息相应回调函数 wndclass.lpszClassName = L"MyWinForm"; //窗口ID,使用UNICODE环境,注意创建窗口的时候所填写的必须跟这里保持一模一样 wndclass.lpszMenuName = NULL; //Menu wndclass.style = CS_VREDRAW|CS_HREDRAW; //样式 //注册窗体类 ATOM atom = RegisterClassEx(&wndclass); //注册类 if (!atom){ return 0; } //创建窗体 HWND hwnd = CreateWindowEx(NULL, L"MyWinForm", L"我的应用程序", WS_OVERLAPPEDWINDOW, 100, 100, 800, 600, NULL, NULL, hInstance, NULL); //位置,大小,没有父窗口,没有菜单,程序实例,没有额外参数 //显示窗体 ShowWindow(hwnd,SW_SHOW); //更新窗体 UpdateWindow(hwnd); // 通过死循环,让程序不退出 MSG msg; while (true) { if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)){ //如果拿到一条消息,这条消息是从所有地方获取所有消息,PM_REMOVE不要给任何过滤,抓到消息后,把该消息从消息顶端移除掉 //获取消息后开始处理消息,如果是退出消息 从回调函数获取消息 if (msg.message == WM_QUIT){ break; } TranslateMessage(&msg); //如果不是退出消息就转换该消息 DispatchMessage(&msg); //把该消息派发给消息处理函数 } } return 0; }
二 MFC中的WinMain在哪儿?
MFC中不能直接看到WinMain函数,因为它被封装在 x:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc\appmodul.cpp ] 中,_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, int nCmdShow) _tWinMain是一个在 tchar.h中定义的宏: #define _tWinMain WinMain,它在编译的时候直接被替换成了WinMain文本了。
如何执行到WinMain的?在生成的项目中,解决方案资源管理器中,有一个以工程名字命名的头文件,在头文件中声明了一个全局变量 extern xxxxApp theApp; 其中一个带App的类(类名是项目名称XXXX与APP的组合),双击带有App后缀的类,可以在该文件中看到 theApp的定义,它代表了该应用程序。注: extern int theApp; //声明theApp而非定义,这时候它还没有内容的,也没有分配空间,它放在类外,表示一个全局的变量 如果赋值则表示定义 ,注意 theApp在类视图双击打开后的cpp文件中被定义,此时它成了一个有血有肉的具体对象了。由于它是全局的(保存在全局数据区域),程序一开始就先于WinMain函数执行执行初始化工作。由于它是一个全局对象,需要系统调用它的构造函数去分配空间。
由于xxxxApp类继承了CWinApp类;CWinApp在一个单文档应用程序中的子类有且仅有一个,而theApp又是xxxxApp类的一个唯一对象,因此theApp就代表了应用程序本身。一个子类的构造一个对象的时候,需要先调用父类的构造器,先构造父类对象,如果当前子类还有个爷爷类,则要先构造爷爷,完成后构造父类对象,最后才构造自身。
CWinApp 有一个构造函数explicit CWinApp( LPCTSTR lpszAppName = NULL); 基类如果有带参数构造器的,派生类应该去调用父类带参构造函器,在这里派生类xxxxApp的构造函数没有带参数,但如何显示的去传递值也能构造父类,原因就在于CWinApp的构造函数有一个缺省NULL;因此在构造的时候不用传递一个值也可以。
_tWinMain()返回 return AfxWinMain(hInstance,pInstance,cmdLine,nShow); AfxWinMain()定义在WINMAN.CPP文件中,AfxWinMain函数内包括一个CWinApp *pApp=AfxGetApp();获取到theApp;theApp什么时候被传入的?它在CWinApp的构造器中由 pThreadState->m_pCurrentWinThread = this; 传入,具体打开 appcore.cpp中CWinApp中可以看到。获取到了theApp对象后,通过调用它的InitApplication()app内部管理函数,接着调用,InitInstance()等一系列函数完成设计,注册(WINCORE.CPP中的AfxEndDeferRegisterClass()实现),AfxEndDeferRegisterClass()里面预定义了多个窗口类,并在InitInstance的时候完成。
创建窗口通过 class CMainFrame : public CFrameWnd 这个类来实现。它是以框架窗口,View类形成客户区。具体CMainFrame中 先于Create之前调用PreCreateWindow(WINFRM.CPP中PreCreateWindow())检查是否注册,没有注册则重新注册.如果注册了,开始首先调用(WINCORE.CPP中的CreateEx)Create();
CWnd显示,更新,通过调用(THRDCORE.CPP)CWinThread::Run() CWinThread::PumpMessage()实现消息循环。
DOC与View实现显示\逻辑分开. App.InitInstance(DOC+VIEW+CMainFrame)组装在一起了。