第4章 进程(1)

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;
}
时间: 2024-08-07 08:37:26

第4章 进程(1)的相关文章

《Unix环境高级编程》读书笔记 第7章-进程环境

1. main函数 int main( int argc, char *argv[] ); argc是命令行参数的数目,包括程序名在内 argv是指向参数的各个指针所构成的数组,即指针数组 当内核执行C程序时(使用exec函数),在调用main前先调用一个特殊的启动例程.可执行程序文件将此启动例程指定为程序的起始地址——这是由连接器设置的,而连接器则是由C编译器调用.启动例程从内核取得命令行参数和环境变量值,然后按上述方式调用main函数做好安排. 2. 进程终止 有8种方式使进程终止,其中5种

APUE学习笔记:第九章 进程关系

9.1 引言 本章将更详尽地说明进程组以及POSIX.1引入的会话的概念.还将介绍登陆shell(登录时所调用的)和所有从登陆shell启动的进程之间的关系. 9.1 终端登陆 系统管理员创建通常名为/etc/ttys的文件,其中每个终端设备都有一行,每一行说明设备名传递给getty程序的参数.当系统自举时,内核创建进程ID为1的进程,依旧是init进程.init进程使系统进入多用户状态.init进程读文件/etc/ttys,对每一个允许登陆的终端设备,init调用一次fork,所生成的子进程则

APUE学习笔记:第七章 进程环境

7.1 引言 本章将学习:当执行程序时,其main函数是如何被调用的:命令行参数是如何传送给执行程序的:典型的存储器布局是什么样式:如何分配另外的存储空间:进程如何使用环境变量:各种不同的进程终止方式等:另外还将说明longjmp和setjmp函数以及它们与栈的交互作用:还将介绍研究进程的资源限制 7.2 main函数 C程序总是从main函数开始执行.当内核执行C程序时,在调用main前先调用一个特殊的启动例程.可执行程序文件将此启动例程指定为程序的起始地址——这是由连接编辑器设置的,而连接编

Android学习笔记—第五章 进程与线程

第五章 进程与线程 进程:一个应用程序就是一个进程 (1)进程的优先级: Foreground Process 前台进程 a. 当前用户正在操作的Activity所在的进程 b. 绑定了当前用户操作的Activity的service所在的进程 c. 通过调用了startForeground()方法提升优先级的service所在的进程 d. 正在调用onCreate().onStart().onDestory()方法的service所在的进程 e. 正在调用onReceiver()方法的Broad

第十三章 进程、线程类的实现

                                        第十三章   进程.线程类的实现         多线程是指在一个进程内可以同时运行多个任务,每个任务由一个单独的线程来完成.线程是进程运行的基本单位,一个进程中可以同时运行多个线程.如果程序被设置为多线程方式,可以提高程序运行的效率和处理速度. 多个线程共用一个进程的资源:进程的调度.切换是在10ms的"时钟滴答"定时中断程序里进行.如果一个线程获得CPU,那么在下一个Tick到来前:是不可能被切换出去的

Linux内核分析——第三章 进程管理

第三章 进程管理 3.1 进程 1.进程就是处于执行期的程序:进程就是正在执行的程序代码的实时结果:进程是处于执行期的程序以及相关的资源的总称:进程包括代码段和其他资源. 线程:是在进程中活动的对象. 2.执行线程,简称线程,是在进程中活动的对象.每个线程都拥有一个独立的程序计数器.进程栈和一组进程寄存器. 3.内核调度的对象是线程,而不是进程.Linux对线程并不特别区分,视其为特殊的进程 4.在现代操作系统中,进程提供两种虚拟机制:虚拟处理器和虚拟内存.在线程之间可以共享虚拟内存,但每个都拥

Windows核心编程之核心总结(第四章 进程(一))(2018.6.8)

学习目标 第四章进程的学习可谓是任重而道远,虽然不难,但知识量很多,也比较零散,需要多总结,脑海里才有进程的框架.所以,我把本章分为几个小节来讲完.我还是一如既往的添加辅助性内容,希望对于小白有所帮助.而比我流弊的大有人在,大神们可以跳过辅助性内容.本小节的学习目标如下:1.C/C++程序编译过程2.C/C++命令行参数的使用3.什么是进程4.Windows的入口点函数5.进程实例句柄(可执行文件实例句柄或者DLL文件实例句柄) C/C++程序编译过程 C/C++的编译.链接过程要把我们编写的一

Unix编程第7章 进程环境

准备雄心勃勃的看完APUE,但是总感觉看着看着就像进入一本字典,很多地方都是介绍函数的用法的,但是给出例子远不及函数介绍的多.而且这本书还是个大部头呢.第7章的讲的进程环境,进程是程序设计中一个比较重要的概念,知道倒是知道它的大概意思,但是其实还是有很多的细节其实都没有深究,这章呢APUE就带着我们逛了一下如下的几个主题(尼玛,学C语言的话,学那点语法其实不是很重要,反而经常把时间浪费在语法的蹩脚处): 1.程序执行的时候main函数是如何被调用的 2.命令行参数是如何传递给新程序的: 3.典型

第11章 进程与多线程

Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. “同时”执行是人的感觉,在线程之间实际上轮换执行. 二.Jav

第4章 进程(4)

4.5.8 ProcessInfo示例程序 (1)自定义函数 函数名称 功能 GetProcessIntegrityLevel 1.获取进程完整性级别和代码策略:分别在GetTokenInformation中 TokenIntegrityLevel及TokenMandatoryPolicy 2.获取资源完整性级别及资源策略:调用API—GetSecurityInfo传入LABEL_SECURITY_INFORMATION,然后从SACL中获取 GetProcessElevation 1.获取令牌