1.一般将进程定义成一个正在运行的程序的一个实例,由以下两部分构成:

  • 一个内核对象,操作系统用它来管理进程,内核对象也是系统保存进程统计信息的地方。
  • 一个地址空间,其中包含所有可执行文件或DLL模块的代码和数据。此外它还包含动态内存分配,比如线程堆栈和堆的分配。

2.进程要做任何事情,都必须让一个线程在它的上下文中运行。该线程负责执行进程地址空间包含的代码。

3.每个线程都有它自己的一组CPU寄存器和它自己的堆栈。对于所有要运行的线程,操作系统会轮流为每一个线程调度一些CPU时间,它会采取轮询的方式为每个线程都分配时间片,从而营造出所有线程都在并发运行的假象。

4.用户运行应用程序时,操作系统的加载程序会检查可执行文件映像的文件头,并获取这个子系统。如果此值表明是一个CUI程序,加载程序会自动确保有一个可用的文本控制台窗口(从命令提示符启动),或者创建一个新窗口(从windows资源管理器启动)。如果此值表明是一个GUI程序,加载器只是加载这个程序。一旦程序开始运行,操作系统就不再关心应用程序的界面是什么类型。

5.Windows应用程序必须有一个入口点函数,应用程序开始运行时,这个函数会被调用。操作系统实际并不调用我们所写的入口点函数。相反,它会调用由C/C++运行库实现并在链接时使用-entry:命令行选项来设置的一个C/C++运行时启动函数。该函数将初始化C/C++运行库,使我们能调用malloc和free之类的函数。它还确保了在我们的代码开始执行之前,我们声明的任何全局和静态C++对象都被正确地构造。

6.在链接可执行文件时,将根据链接器开关 /SUBSYSTEM:WINDOWS或者 /SUBSYSTEM:CONSOLE以及UNICODE和ANSI来选择正确地C/C++运行库启动函数。

7.一旦链接器开关/SUBSYSTEM被移除,链接器会检查代码中的函数(WinMain,main...)是四个中的哪一个来推算。

8.所有C/C++运行库启动函数所做的事情基本都一样,区别在于它们要处理的是ANSI还是UNICODE字符串。以及在初始化C运行库之后,它们调用的是哪一个入口点函数。这些启动函数的用途简单总结如下。

  • 获取指向新进程的完整命令行的一个指针
  • 获取指向新进程的环境变量的一个指针
  • 初始化C/C++运行库的全局变量。如果包含了StdLib.h,我们的代码就可以访问这些变量。
  • 初始化C运行库内存分配函数(malloc和calloc)和其他底层I/O例程使用的堆(heap)。
  • 调用所有全局和静态C++类对象的构造函数。

9.完成上述所有的初始化工作之后,C/C++启动函数就会调用应用程序的入口点函数。

// 如果我们写了_tWinMain & 定义了_UNICODE
GetStartupInfo(&StartupInfo);
int nMainRetVal = wWinMain((HINSTANCE)&__ImageBase, NULL, pszCommandLineUnicode,
(StartupInfo.dwFlags & STARTF_USESHOWWINDOW) ? StartupInfo.wShowWindow : SW_SHOWDEFAULT);
// 如果我们写了_tWinMain & 没有定义_UNICODE
GetStartupInfo(&StartupInfo);
int nMainRetVal = WinMain((HINSTANCE)&__ImageBase, NULL, pszCommandLineAnsi,
(StartupInfo.dwFlags & STARTF_USESHOWWINDOW) ? StartupInfo.wShowWindow : SW_SHOWDEFAULT);

注意,__ImageBase是一个链接器定义的伪变量,表明可执行文件被映射到应用程序内存中的什么位置。

// 如果我们写了_tmain & 定义了_UNICODE
int nMainRetval = wmain(argc, argv, envp);
// 如果我们写了_tmain & 没有定义_UNICODE
int nMainRetval = main(argc, argv, envp);

注意,用VS向导生成应用程序时,CUI应用程序的入口中没有定义第三个参数(环境变量块),如果需要访问进程的环境变量,只需将上述调用换成下面这一行:

int _tmain(int argc, TCHAR* argv[], TCHAR* env[])

这个env参数指向一个数组,数组中包含所有环境变量及其值,两者用等号(=)分隔。

10.入口点函数返回后,启动函数将调用C运行库函数exit,向其传递返回值(nMainRetVal)。exit函数执行以下任务。

  • 调用_onexit函数调用所注册的任何一个函数
  • 调用所有全局和静态C++类对象的析构函数。
  • 在DEBUG生成中,如果设置了_CRTDBG_LEAK_CHECK_DF标志,就通过调用_CrtDumpMemoryLeaks函数来生成内存泄漏报告。
  • 调用操作系统的ExitProcess函数,向其传入nMainRetVal。这会导致操作系统“杀死”我们的进程,并设置它的退出代码。

11.加载到进程地址空间的每一个可执行文件或DLL文件都被赋予了一个独一无二的实例句柄。可执行文件的实例被当作WinMain函数的第一个参数hInstanceExe传入。

12.事实上,HMOUDLE和HINSTANCE完全是一回事。之所以有两种数据类型,是由于在16位Windows中,HMOUDLE和HINSTANCE表示不同类型的数据。

13.WinMain的hInstanceExe参数的实际值是一个内存基地址,系统将可执行文件的映像加载到进程地址空间中的这个位置。具体加载到哪一个基地址,是由连接器决定的。不同的链接器使用不同的默认基地址。可以使用GetModuleHandle函数来返回一个句柄/基地址。

14.C/C++运行库启动代码总是向WinMain的hPrevInstance参数传递NULL。该参数用于16位Windows系统。VS在向导生成的C++ GUI项目中利用UNREFERENCED_PARAMETER宏来消除这种警告。

15.C运行库的启动代码开始执行一个GUI应用程序的时候,会调用Windows函数GetCommandLine来获取进程的完整命令行,忽略可执行文件的名称,然后将指向命令行剩余部分的一个指针传给WinMain的pszCmdLine参数。

16.GetCommandLine函数返回一个缓冲区指针,缓冲区中包含完整的命令行(包括已执行的文件的完整路径名),而且这个函数返回的总是同一个缓冲区的地址,所以最好不要向其中写入数据。

17.每个进程都有一个与它关联的环境块,这是在进程地址空间内分配的一块内存,其中包含字符串和下面相似:

注意空格是有意义的。

18.用户登录Windows时,系统会创建外壳(shell)进程,并将一组环境字符串与其关联。系统通过检查注册表中的两个注册表项来获得初始的环境字符串。

  • 第一个注册表项包含应用于系统的所有环境变量的列表:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment

  • 第二个注册表项包含应用于当前登录用户的所有环境变量的列表:

    HKEY_CURRENT_USER\Environment

19.通常子进程会继承(不共享同一个环境块)一组环境变量,这些环境变量和父进程的环境变量相同,不过,父进程可以控制哪些环境变量允许子进程继承。

20.每个进程都关联了一组标志,作用时让系统知道进程如何响应严重错误,包括磁盘介质错误、未处理的异常、文件查找错误以及数据对齐错误等。进程可以调用SetErrorMode(UINT fuErrorMode)函数来告诉系统如何处理这些错误。

默认情况下,子进程会继承父进程的错误模式标志,例如一个进程已经打开了一个错误标志,并生成了一个子进程,则子进程也会打开这个标志。不过子进程并不知道这一点。父进程可以阻止子进程继承其错误模式。

21.系统跟踪记录着进程的当前驱动器和目录,但没有记录每个驱动器的当前目录,操作系统通过进程的环境字符串来提供多个驱动器的当前目录。例如:

=C:C:\Utility\Bin

=D:=D:\Program Files

如果变量没有找到,系统就假定指定驱动器的当前目录是它的根目录。

Windows Internals 笔记——进程的更多相关文章

  1. Windows Internals 笔记——进程的权限

    1.大多数用户都用一个管理员账户来登录Windows,在Vista之前,这样的登录会创建一个安全令牌.每当有代码试图使用一个受保护的安全资源时,操作系统就会出示这个令牌.从包括Windows资源管理器 ...

  2. Windows Internals 笔记——终止进程

    1.进程可以通过以下四种方式终止: 主线程的入口点函数返回(强烈推荐的方式) 进程中的一个线程调用ExitProcess函数(避免这种方式) 另一个进程中的线程调用TerminateProcess函数 ...

  3. Windows Internals 笔记——关联性

    1.默认情况下,Windows Vista在给线程分配处理器时,使用软关联.意思是如果其他因素都一样,系统将使线程在上一次运行的处理器上运行.让线程始终在同一个处理器上运行有助于重用仍在处理器高速缓存 ...

  4. Windows Internals 笔记——线程优先级

    1.每个线程都被赋予0(最低)~31(最高)的优先级数.当系统确定给哪个线程分配CPU时,它会首先查看优先级为31的线程,并以循环的方式进行调度.如果有优先级为31的线程可供调度,那么系统就会将CPU ...

  5. Windows Internals 笔记——线程调度

    1.线程内核对象中的CONTEXT反应了线程上一次执行时CPU寄存器的状态.大约每隔20ms,Windows都会查看所有当前存在的线程内核对象.Windows在可调度的线程内核对象中选择一个,并将上次 ...

  6. Windows Internals 笔记——线程

    1.进程有两个组成部分,一个进程内核对象和一个地址空间.线程也有两个组成部分: 一个是线程的内核对象,操作系统用它管理线程.系统还用内核对象来存放线程统计信息的地方. 一个线程栈,用于维护线程执行时所 ...

  7. Windows Internals 笔记——作业

    1.Windows提供了一个作业内核对象,它允许我们将进程组合在一起并创建一个“沙箱”来限制进程能够做什么.创建只包含一个进程的作业同样非常有用,因为这样可以对进程施加平时不能施加的限制. 2.如果进 ...

  8. Windows Internals 笔记——CreateProcess

    1.一个线程调用CreateProcess时,系统将创建一个进程内核对象,其初始使用计数为1.然后系统为新进程的主线程创建一个线程内核对象(使其计数为1). 2.CreateProcess在进程完全初 ...

  9. Windows Internals 笔记——内核对象

    1.每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核访问.这个内存块是一个数据结构,其成员维护着与对象相关的信息. 2.调用一个会创建内核对象的函数后,函数会返回一个句柄,它标 ...

随机推荐

  1. 一、Mysql安装

    一.官网下载:https://dev.mysql.com/downloads/mysql/ 二.解压下载好的压缩包,本人存放的位置如下: 如下图解压后的文件目录,因版本的差异.一开始解压后的文件夹下可 ...

  2. BZOJ 2243 染色

    树链剖分+区间染色 因为是一颗树不是森林,所以应该用树剖就行,但是LCT好像也能写.. 直接用线段树维护树上的节点,注意pushdown还有询问的时候要考虑区间相交的地方,也就是左孩子右边和有孩子的左 ...

  3. 【BZOJ5492】[HNOI2019]校园旅行(bfs)

    [HNOI2019]校园旅行(bfs) 题面 洛谷 题解 首先考虑暴力做法怎么做. 把所有可行的二元组全部丢进队列里,每次两个点分别向两侧拓展一个同色点,然后更新可行的情况. 这样子的复杂度是\(O( ...

  4. flex布局应用

    flex介绍  http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html 了解了flex布局之后,发现其功能非常强大. 当指定一个div dis ...

  5. 2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 J Beautiful Numbers (数位dp)

    题目链接:https://ac.nowcoder.com/acm/contest/163/J 题目大意:给定一个数N,求区间[1,N]中满足可以整除它各个数位之和的数的个数.(1 ≤ N ≤ 1012 ...

  6. jieba 库的使用和好玩的词云

    jieba库的使用: (1)  jieba库是一款优秀的 Python 第三方中文分词库,jieba 支持三种分词模式:精确模式.全模式和搜索引擎模式,下面是三种模式的特点. 精确模式:试图将语句最精 ...

  7. Java Properties 类读配置文件保持顺序

    前几天,公司项目中有一个需求是读取配置文件的,而且最好能够保证加载到内存中的顺序能够和配置文件中的顺序一致,但是,如果使用 jdk 中提供的 Properties 类的话,读取配置文件后,加载到内存中 ...

  8. 2018-2019-2《Java程序设计》结对编程项目-四则运算 第一周 阶段性总结

    码云链接 https://gitee.com/A5320/pair_programming_code 需求分析 实现一个命令行程序,要求: 1.自动生成小学四则运算题目(加.减.乘.除) 2.支持整数 ...

  9. WPF布局的应用

    一 写在开头1.1 本文内容本文主要内容是使用WPF来实现几个简单的界面. 二 登录窗口小例子2.1 实现代码XAML代码: <Window x:Class="LoginDialog. ...

  10. 第十三节: EF的三种模式(三) 之 来自数据库的CodeFirst模式

    一. 简介 [来自数据库的Code First模式]实质上并不是CodeFirst模式,而是DBFirst模式的轻量级版本,在该模式中取消了edmx模型和T4模板,直接生成了EF上下文和相应的类,该模 ...