Win32基础知识

Win32指的是针对32位处理器设计的Windows操作系统。
事实上,在Windows下运行的程序最终都是通过调用API函数来完成工作的,因此,可以把Win32 API看成是最底层的服务。通常所说的SDK编程就是直接调用API函数进行编程
应用程序的类型:

  • 基于图形用户界面GUI的窗口应用程序,这是大家常见的Windows应用程序;
  • 基于控制台用户界面CUI的应用程序,即“MS-DOS”界面的应用程序。
    控制台应用程序不需要创建自己的窗口,其输入输出方式也很简单。
    在API函数前加::符号,表示这是一个全局函数,以与C++类的成员函数相区分。
  1. Windows的多任务实现
    windows是多任务操作系统,在同一时间里系统内可能会有多个活动的进程。在CPU的支持下,每个进程都被给予它自己的私有地址空间。当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,属于其他进程的内存被屏蔽了,不能够被这个线程访问。
  2. 虚拟内存
    在保护模式下,80386处理器的所有32根地址线都可供寻址,处理器寻址的范围为2^32,即32位Windows系统可寻址4GB的地址空间。Windows为每个进程分配4GB的地址空间主要依靠CPU的支持,CPU在保护模式下支持虚拟存储,它可以帮助操作系统将磁盘空间当做内存空间使用。各进程的地址空间被分成了2GB的系统空间和2GB的用户空间。系统空间部分在所有进程中是共享的。
  3. 内核模式和用户模式
    为了阻止应用程序访问或者修改关键的系统数据(即2GB系统空间内的数据),Windows使用了两种访问模式:内核模式和用户模式。用户程序的代码在用户模式下运行,系统程序的代码在内核模式下运行。
    当应用程序调用一个系统函数的时候,用户的应用程序会从用户模式切换到内核模式去执行。
  4. 内核对象
    内核对象是系统提供的用户模式下代码与内核模式下代码进行交互的基本接口。软件开发人员会经常的创建、打开和操作内核对象。对于每一个内核对象,Windows都提供了在其上操作的API函数,这些API函数使应用程序有机会读或写系统数据,但这一切都是在系统的监视下进行的。
    一个内核对象是一块内核分配的内存,它只能被运行在内核模式下的代码访问。内核对象记录的数据在整个系统中只有一份,所以它们也称为系统资源。内核对象中的数据包含了此对象的状态信息。
  5. 对象句柄
    内核对象的数据结构仅能够从内核模式访问,所以直接在内存中定位这些数据结构对应用程序来说是不可能的,应用程序必须使用API函数访问内核对象。调用函数创建内核对象时,函数会返回标识此内核对象的句柄。可以想象此句柄是一个能够被该进程中任何线程使用的一个不透明的值,许多API函数需要以它作为参数,以便系统知道要操作哪一个内核对象。
  6. 进程的创建
    进程是一个正在运行的程序的实例。进程是不活泼的,一个进程要完成任何事情,它必须有一个运行在它的地址空间的线程,此线程负责执行该进程地址空间的代码。对一个不包含任何线程的进程来说,系统会自动销毁此进程和它的地址空间。
    线程是进程内执行代码的独立实体,没有它,进程中的程序代码是不可能执行的。
  7. 应用程序的启动过程

应用程序必须有一个入口函数,它在程序开始运行时被调用。如果是控制台应用程序,入口函数为main。操作系统事实上并不是真的调用main函数,而是去调用C/C++运行期启动函数,此函数会初始化C/C++运行期库。

应用程序的启动过程就是进程的创建过程,操作系统通过调用CreateProcess函数来创建新的进程。当一个线程调用CreateProcess函数时,系统会创建一个进程内核对象,其使用计数被初始化为1。此进程内核对象不是进程本身,仅仅是一个系统用来管理这个进程的小的数据结构。

系统然后会为新的进程创建一个虚拟地址空间,加载应用程序运行时所需要的代码和数据。系统接着会为新进程创建一个主线程,这个主线程通过执行C/C++运行期启动代码开始运行,C/C++运行期启动代码又会调用main函数。如果系统能够成功创建新的进程和进程的主线程,CreateProcess函数会返回TRUE,否则返回FALSE。

系统在创建新的进程时会为新进程指定一个STARTUPINFO类型的变量,这个结构包含了父进程传递给子进程的一些显示信息。一个进程可以调用GetStartupInfo函数来取得父进程创建自己时使用的STARTUPINFO结构。事实上,Windows系统就是通过调用这个函数来取得当前进程的创建信息,以便对新进程中主窗口的属性设置默认值。

CreateProcess函数创建一个新的进程和该进程的主线程。新的进程会在父进程的安全上下文中运行指定的可执行文件。
指针类型的变量名都以lp为前缀,它是long pointer的缩写。Windows开发者将这种命名变量的方法称为匈牙利表示法。如b表示BOOL,sz表示string zero(以0结尾的字符串)等。

  1. 多线程

系统中的每个进程都至少有一个线程,这个线程从入口地址main处开始执行,直到return语句返回,主线程结束,该进程也就从内存中卸载了。

主线程在运行过程中还可以创建新的线程,即所谓的多线程。在同一进程中运行不同的线程的好处是这些线程可以共享进程的资源,如全局变量,句柄等。当然各个线程也可以有自己的私有堆栈用于保护私有数据。

进程中同时可以有多个线程在执行,为了使它们能够同时执行,操作系统为每个线程轮流分配CPU时间片。为了充分利用CPU,一般情况下,应用程序使用主线程接受用户的输入,显示运行结果,而创建新的线程(辅助线程)来处理长时间的操作,比如读写文件,访问网络等。这样即便在程序忙于繁重的工作时也可以由专门的线程响应用户命令。

每个线程必须拥有一个进入点函数,线程从这个进入点开始运行。主线程的进入点是函数main,如果想在进程中创建一个辅助线程,则必须为该辅助线程指定一个进入点函数,这个函数称为线程函数。

创建新线程的函数是CreateThread,由这个函数创建的线程将在调用者的虚拟地址空间内执行。此函数执行成功后,将返回新建线程的线程句柄。使用完句柄后调用CloseHandle函数关闭句柄,如果不关闭的话,使用计数的值永远不会是0,系统将永远不会撤销它占用的内存,这就会造成内存泄漏(除非该进程结束了)

线程内核对象就是一个包含了线程状态信息的数据结构。每一次对CreateThread函数的成功调用,系统都会在内部为新的线程分配一个内核对象。系统提供的管理线程的函数其实就是依靠访问线程内核对象来实现管理的。

结束线程的最好方法是让线程函数自然返回。即当函数执行到return语句返回时,Windows将终止线程的执行。

每个线程都要被赋予一个优先级号,取值为0(最低)到31(最高)。只要优先级高的线程处于可调度状态,Windows是不允许优先级相对低的线程占用CPU的。

你可能感兴趣的:(Win32基础知识)