标签:
4.1 编写第一个Windows应用程序
(1)进程的组成:(两个部分)
①进程也是一个内核对象(即进程内核对象),操作系统用它来管理进程,也是系统保存进程统计信息的地方。
②进程是一个地址空间,包含可执行文件或DLL模块的代码和数据,还包含动态内存分配,如线程堆栈或堆的分配。
(3)应用程序类型和相应的入口点函数
应用程序类型 |
C\C++入口点函数 |
嵌入可执行文件的 启动函数 |
链接器开关 |
处理ANSI字符(串)的GUI程序 |
_tWinMain(WinMain) |
WinMainCRTStartup |
/SUBSYSTEM:WINDOWS |
处理Unicode字符(串)的GUI程序 |
_tWinMain(wWinMain) |
wWinMainCRTStartup |
|
处理ANSI字符(串)的CUI程序 |
_tmain(Main) |
mainCRTStartup |
/SUBSYSTEM:CONSOLE |
处理Unicode字符(串)的CUI程序 |
_tmain(Wmain) |
wmainCRTStartup |
★两者界线是模糊的,即可以创建向控制台输出文字的GUI或能显示GUI的控制台应用程序。
(4)C/C++嵌入的启动函数
①C/C++应用程序中,进程启动过程wWinMainCRTStartup()→_tmainCRTStartup()→wWinMain()。由此可见操作系统并不调用我们写的入口点函数(如_tWinMain),而是调用C/C++运行期的启动函数(如wWinMainCRTStartup)。
②wWinMainCRTStartup的作用:——启动函数要进行一些额外的操作:
A、检索指向新进程的完整命令行的指针。
B、检索指向新进程的环境变量的指针。
C、对C/C + +运行期的全局变量进行初始化。如果包含了Stdlib.h 文件,代码就能访问这些变量。(如__environ、__argv等,见课本第69页,表4-2)
D、对C 运行期内存单元分配函数(malloc 和calloc)和其他低层输入/输出程序使用的堆进行初始化。这样就可以调用malloc和free之类的C库函数。
E、为所有全局和静态C++类对象调用构造函数。以确保已经声明的任何C++全局对象和静态对象能够在代码执行以前正确地创建。
F、调用我们写的入口函数(如wWinMain)等函数,该入口函数返回后,嵌入的启动函数会调用由_onexit添加的回调函数(调用顺序与添加顺序相反),然后清除全局对象和静态变量。
(4)如果链接器选项的“入口点”不设置的话(默认情况),C/C++程序入口点是被嵌入到可执行文件的WinMainCRTStartup启动函数(注意,不是WinMain)。如果设定入口点为我们指定的函数,这时不再嵌入那些启动函数。因此,所有的初始化和退出时清理全局变量的操作也得由我们自己来完成。(这对于纯API应用程序来说,有很好用的)
【OnExit程序】WinMainCRTStartup的执行流程
#include <tchar.h> #include <Windows.h> #include <strsafe.h> #define GRS_USEPRINTF() TCHAR pBuf[1024]={} //可变参数...与可变宏__VA_ARGS__ //宏定义中参数列表的最后一个参数为省略号(也就是三个点)。 //预定义宏__VA_ARGS__,当宏替换时,用来替换省略号所代表的字符串 #define GRS_PRINTF(...) \ StringCchPrintf(pBuf, 1024, __VA_ARGS__); WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), pBuf, lstrlen(pBuf), NULL, NULL); int fn1(void); int fn2(void); int fn3(void); int fn4(void); //注意以下创建的是GUI应用程序,但却使用控制台来输出! int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR pszCmdLine, int nShowCmd) { AllocConsole(); //为进程分配一个新的控制台(注意一个进程只可以拥用一个控制台的关联) GRS_USEPRINTF(); //因为WinMainCRTStartup函数会调用WinMain函数,但WinMain执行完毕后, //WinMainCRTStartup会继续调用由_onexit注册的回调函数且调用顺序与 //注册函数的顺序相反,所以当WinMain退出后,fn4、fn3、fn2、fn1会依次被调用。 //但注意,这4个函数只有在退出WinMain后才被调用。 _onexit(fn1); _onexit(fn2); _onexit(fn3); _onexit(fn4); GRS_PRINTF(_T("注意哦,我是第1个被输出的语句!\n")); GRS_PRINTF(_T("回调函数的注册顺序:fn1->fn2->fn3->fn4\n")); GRS_PRINTF(_T("回调函数的执行顺序:")); return 0; //注意,该函数退出后,仍会执行退出回调函数fnX等函数 } int fn1() { GRS_USEPRINTF(); GRS_PRINTF(_T("->fn1\n")); _tsystem(_T("PAUSE")); FreeConsole(); return 0; } int fn2() { GRS_USEPRINTF(); GRS_PRINTF(_T("->fn2")); return 0; } int fn3() { GRS_USEPRINTF(); GRS_PRINTF(_T("->fn3")); return 0; } int fn4() { GRS_USEPRINTF(); GRS_PRINTF(_T("fn4")); return 0; }
标签:
原文地址:http://www.cnblogs.com/5iedu/p/4655948.html