码迷,mamicode.com
首页 > 系统相关 > 详细

第4章 进程(1)

时间:2015-07-18 02:03:31      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:

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;
}

 

第4章 进程(1)

标签:

原文地址:http://www.cnblogs.com/5iedu/p/4655948.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!