Windows操作系统版本
MicrosoftWindows NT(Network Termination),其主要特征如下:
纯32位构架
支持虚拟内存
支持多线程:抢占式的多线程系统
支持多处理器
DLL(动态链接库)指一组可调用的子例程,合起来被链接成一个二进制文件,使用这些子例程的应用程序可以动态地加载此二进制文件。例如Msvcrt.dll(C运行库)和Kernel32.dll(一个Windows API子系统库)。Windows的用户模式组件和应用程序大量使用了DLL。DLL比静态库的优势在于,应用程序可以共享DLL,Windows保证在内存中只有一份DLL代码,供所有引用该DLL的应用程序共享。
大多数典型的Windows程序产生的函数调用来源于上面三个动态链接库。
DLL与静态库的区别
C语言运行时库属于静态库,生成的应用程序会将CRT中的C库函数的机器代码链接到程序代码中,成为程序的二进制代码主体的一部分。而Windows函数的代码位于程序之外的DLL中。
在运行Windows程序时,它通过一个被称作“动态链接”的进程与Windows相接。虽说动态链接是在执行时期才发生“链接”,但在LINK时期,链接器需先为调用者(应用程序本身)准备一些适当的信息,才能在执行时顺利“跳”到DLL中执行。所以当链接Windows程序以产生一个可执行文件时,必须链接由编译环境提供的专门的“导入库(importlibrary)”。这些导入库包含了动态链接库的名称和所有Windows函数调用的引用信息。链接程序使用该信息在.EXE文件中构建一个表,当加载程序时,Windows使用它将调用转换为Windows函数。
保护模式
80x86CPU可在实模式、保护模式、虚拟86模式3种模式下运转。MS-DOS就是实模式的运行环境,实模式的寻址方式是“段基址+段偏移”,其设计思想是解决在16位字长(数据总线宽度)的机器里怎么提供20位地址(地址总线宽度)的问题,实模式下允许的最大寻址空间为 = 1MB,CPU一次可处理的数据空间大小为 =64KB,所以段的默认大小为64KB。所以指令寻址的地址就是内存中实际的物理地址。在实模式下,所有的段都是可读可写。
Windows操作系统运行在保护模式下,物理寻址空间 = = 4G。Win32的平坦内存模式使每个进程拥有赋予它自己的虚拟空间,大小为4G(0x00000000 ~ 0xFFFFFFFF)。其中一个2GB(0x00000000 ~ 0x7FFFFFFF)是应用程序内存部分(用户内存),另一个2GB(0x80000000 ~ 0xFFFFFFFF)是共享的内核部分(内核内存,受保护),在用户模式下不能访问。
80386分了四种特权级别:Ring0 ~ Ring3
Windows操作系统只用了两种级别:Ring0和Ring3
Windows操作系统内核运行在Ring0级,应用程序运行在Ring3级,Win32子系统(如Kernel32.dll、User32.dll、Gdi32.dll)也是运行在Ring3级,以提供与应用程序的接口。
进程、程序、线程
程序是指一个静态的指令集合。
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
理解:进程是Windows系统的基本构造块。进程有很多种解释,但最重要的一点是它是一段独立的虚拟内存地址空间(容器)。这个地址空间可以用来运行程序,为了保证每个程序都在自己的地址空间里运行,系统为每个进程都创建了地址空间,系统可以将代码模块加载到进程的地址空间中,但是为了真正地让程序运行起来,一个进程中必须至少让一个线程运行起来。
线程是最基本的代码执行单元。在任一给定时刻,系统中的每个处理器只运行一个线程,也就是说,一个处理器只运行一小段代码,,这段代码可以是一段用户程序,也可以是一段操作系统代码。线程的意义在于:Windows系统不必一直运行一段代码直至结束,而是能在任意时刻中断正在运行的线程,并切换至另一个线程。这一过程是Windows系统实现并行操作的关键技术。
Windows支持两种类型的应用程序:GUI程序和CUI程序。用Microsoft Visual Studio来创建一个应用程序时,集成开发环境会设置各种链接器开关,使链接器将子系统的正确类型嵌入最终生成的可执行文件(executable)中。对于CUI程序,这个链接器开关是/SUBSYSTEM:CONSOLE,对于GUI程序,则是/SUBSYSTEM:WINDOWS。用户运行应用程序时,操作系统的加载程序(loader)会检查执行文件映像的文件头,并获取这个子系统值。
实际上操作系统并不调用我们所写的入口点函数,而是调用由C/C++运行库实现并在链接时使用-entry:命令行选项来设置的一个C/C++运行时启动函数。该函数将初始化C/C++运行库,使我们能调用malloc和free之类的函数。它还确保了在我们的代码开始执行之前,我们声明的任何全局和静态C++对象都被正确地构造。
将当前窗口程序的链接器选项改为/SUBSYSTEM:CONSOLE,链接器会寻找main或wmain函数,并根据情况分别选择mainCRTStartup或wmainCRTStartup函数。如果没有找到,链接器会返回一个“unresolved external symbol”(无法解析的外部符号)错误。
推荐技巧:我们完全可以从自己的项目中移除/SUBSYSTEM链接器开关。一旦这样做,链接器就会自动判断应该将应用程序设为哪一个子系统。链接时,链接器会检查代码中包括4个函数中的哪一个(WinMain、wWinMain,main或wmain),并据此推算可执行文件应该是哪个子系统,以及应该在可执行文件中嵌入哪个C/C++启动函数。