最近在学习 Win32编程,所以顺便将每日所学记录下来,一方面为了巩固学习的知识,另一方面也为同样在学习Win32开发的童鞋们提供一份参考。
本系列博文均根据学习《Windows核心编程》一书总结而来;
运行环境:
- 操作系统: Windows 10家庭版
- 编译器:Visual Studio 2019
内核对象
内核对象可以提供系统和应用程序使用来管理各种各样的资源;
什么是内核对象
每个内核对象只是内核分配的一个内存块,并且只能由内核访问。该内存块是一种数据结构,它的成员负责维护该对象的各种信息;
内核对象使用计数
内核对象由内核所拥有,而非进程所拥有。如果你的进程调用了一个创建内核对象的函数,然后进程终止,但是内核对象不一定会撤销;内核对象的存在时间可以比创建该对象的进程时间长;
进程内核对象句柄表
当一个进程被初始化时,系统要为它分配一个句柄表。该句柄表只用于内核对象不用于用户对象或GDI对象;
创建内核对象
当进程初次被初始化时,它的句柄表是空的。当进程中的线程调用创建内核对象函数的时候,内核就位该对象分配一个内存块,并对它初始化。这时,内核对象对进程的句柄表进行扫描,找到一个空项。内核对象找到空项上的结构并对它进行初始化。
关闭内核对象
无论怎样创建内核对象,都要向系统指明将调用CloseHandle来结束该对象的操作:
1 | BOOL CloseHandle(HANDLE hobj); |
该函数首先检查调用进程的句柄表,以确保传递给它的索引用于一个进程实际上无权访问的对象。如果该索引是有效的,那么系统就可以获得内核对象的数据结构的地址,并可确定该结构中的使用计数的数据成员。如果使用计数是0,该内核便从内存中撤销该内核对象。
如果将一个无效句柄传递给CloseHandle,将会出现两种情况,如果程序进程正常,CloseHandle返回FALSE;如果进程正在排除错误,系统将通知调试程序;
当进程终止运行时,操作系统能够确保该进程使用的任何资源或全部资源都被释放,这是保证的;
跨进程边界共享内核对象
在很多情况中,在不同进程中运行的线程需要共享内核对象:
- 文件映射对象使你能够在同一台机器上运行的两个进程之间共享数据块;
- 邮槽和指定的管道使得应用程序能够在联网的不同机器上运行的进程之间发送数据块;
- 互斥对象、信标和事件使得不同进程中的线程能够同步它们的连续运行。
对象句柄继承性
只有进程具有父子关系时,才能使用对象句柄的继承性。父进程可以使用一个或多个对象句柄,并且该父进程可以决定生成一个子进程,为紫禁城赋予父进程的内核对象访问权;
- 父进程创建内核对象时,必须指明,它希望对象的句柄是可继承的
- 父进程指定一个SECURITY_ATTRIBUTES结构体并进行初始化
- 将结构的地址传递给指定的函数;
当我们给bInheritHandle赋值为TRUE时,操作系统就创建该新子进程,但是不允许子进程立即开始执行它的代码。不过由于TRUE传递给了CreateProcess的bInheritHandle参数,因此系统要进行另一项操作,即它要遍历父进程的句柄表,对于它找到包含有效的可继承句柄的每个项目,系统会将该项目准确地拷贝到子进程的句柄表中。该项目拷贝到子进程的句柄表中的位置与父进程的句柄表中的位置完全相同;
除了拷贝句柄表意外,系统还要递增内核对象的使用计数,因为现在两个进程都在使用该对象