读书笔记
-----------------摘自《windows核心编程》
Unicode与ASCII
标准的ANSI C 字符串函数和它们的等价U n i c o d e 函数
char * strchr(const char *,int);
wchar_t * wcschr(const wchar_t *,wchar_t);
int strcmp(const char *,const char *);
int wcscmp(const wchar_t *,const wchar_t *);
char * strcpy(char *,const char *);
wchar_t * wcscpy(wchar_t *,const wchar_t *);
size_t strlen(const char *);
size_t wcslen(const wchar_t *);
字符串(literal string )前面的大写字母L ,用于告诉编译器该字符串应该作为U n i c o d e 字符串来编译。当编译器将字符串置于程序的数据部分中时,它在每个字符之间分散插入零字节。这种变更带来的问题是,现在只有当定义了_ U N I C O D E 时,程序才能成功地进行编译。我们需要另一个宏,以便有选择地在字符串的前面加上大写字母L 。这项工作由_ T E X T 宏来完成,_ T E X T 宏也在T C h a r. h 文件中做了定义。如果定义了_ U N I C O D E ,那么_ T E X T 定义为下面的形式:
#define _TEXT(x) L ## x
如果没有定义_ U N I C O D E ,_ T E X T 将定义为
#define _TEXT(x) x
第三章 内核对象:
每个内核对象只是内核分配的一个内存块,并且只能由该内核访问。该内存块是一种数据结构,它的成员负责维护该对象的各种信息。有些数据成员(如安全性描述符、使用计数等)在所有对象类型中是相同的,但大多数数据成员属于特定的对象类型。例如,进程对象有一个进程I D 、一个基 本优先级和一个退出代码,而文件对象则拥有一个字节位移、一个共享模式和一个打开模式。
内核对象由内核所拥有,而不是由进程所拥有。换句话说,如果你的进程调用了一个创建内核对象的函数,然后你的进程终止运行,那么内核对象不 一定被撤消。在大多数情况下,对象将被撤消,但是如果另一个进程正在使用你的进程创建的内核对象,那么该内核知道,在另一个进程停止使用该 对象前不要撤消该对象,必须记住的是,内核对象的存在时间可以比创建该对象的进程长。每个对象包含一个使用计数。如果内核对象的使用计数降为0 ,内核就撤消该对象。这样可以确保在没有进程引用该对象时系统中不保留任 何内核对象.
内核对象能够得到安全描述符的保护 默认安全性意味着对象的管理小组的任何成员和对象的创 建者都拥有对该对象的全部访问权,而其他所有人均无权访问该对象
进程的内核对象句柄表
当一个进程被初始化时,系统要为它分配一个句柄表
当进程初次被初始化时,它的句柄表是空的。然后,当进程中的线程调用创建内核对象的函数时,比如CreateFileMapping,内核 就为该对象分配一个内存块,并对它初始化。
这时,内核对进程的句柄表进行扫描,找出一个空项。
创建内核对象的函数
CreateThread
CreateFile
CreateFileMapping
CreateSemaphore
用于创建内核对象的所有函数均返回与进程相关的句柄,这些句柄可以被在相同进程中运行的任何或所有线程成功地加以使用。该句柄值实际上是放 入进程的句柄表中的索引,它用于标识内核对象的信息存放的位置,特别要注意的是,只有当调用CreateFile函数时,才能将该值与I N VA L I D _ H A N D L E _ VA L U E 进行比较
3.2.2 关闭内核对象
BOOL CloseHandle(HANDLE hobj);
该函数首先检查调用进程的句柄表,以确保传递给它的索引(句柄)用于标识一个进程实际上无权访问的对象。如果该索引是有效的,那么系统就可 以获得内核对象的数据结构的地址,并可确定该结构中的使用计数的数据成员。如果使用计数是0 ,该内核便从内存中撤消该内核对象。当调用C l o s e H a n d l e 函数之后,将不再拥有对内核对象的访问权,不过,如果该对象的使用计数没有递减为 0 ,那么该对象尚未被撤消。这没有问题,它只是意味着一个或多个其他进程正在使用该对象。当其他进程停止使用该对象时(通过调用C l o s e H a n d l e ),该对象将被撤消。
在进程运行时,进程有可能泄漏资源(如 内核对象)。但是,当进程终止运行时,操作系统能够确保该进程使用的任何资源或全部资源均被释放,这是有保证的。对于内核对象来说,系统将 执行下列操作:当进程终止运行时,系统会自动扫描进程的句柄表。如果该表拥有任何无效项目(即在终止进程运行前没有关闭的对象),系统将关 闭这些对象句柄。如果这些对象中的任何对象的使用计数降为0 ,那么内核便撤消该对象。
3.3 跨越进程边界共享内核对象
文件映射对象使你能够在同一台机器上运行的两个进程之间共享数据块。
邮箱和指定的管道使得应用程序能够在连网的不同机器上运行的进程之间发送数据块。
互斥对象、信标和事件使得不同进程中的线程能够同步它们的连续运行,
文件对象句柄的继承性
只有当进程具有父子关系时,才能使用对象句柄的继承性
父进程可以使用一个或多个内核对象句柄,并且该父进程可以决定生成一 个子进程,为子进程赋予对父进程的内核对象的访问权。若要使这种类型的继承性能够实现,父进程必须执行若干个操作步骤。
1)首先,当父进程创建内核对象时,必须向系统指明,它希望对象的句柄是个可继承的句柄。请记住,虽然内核对象句柄具有继承性,但是内核对象本 身不具备继承性.
2)系统为子进程创建一个新的和空的句柄表,就像它为任何新进程创建句柄表那样。不过,由于将T R U E 传递给 了C r e a t e P r o c e s s 的b I n h e r i t H a n d l e s 参数,因此系统要进行另一项操作,即它要遍历父进程的句柄表,对于它找到的 包含有效的可继承句柄的每个项目,系统会将该项目准确地拷贝到子进程的句柄表中。该项目拷贝到子进程的句柄表中的位置将与父进程的句柄表中 的位置完全相同。这个情况非常重要,因为它意味着在父进程与子进程中,标识内核对象所用的句柄值是相同的。
3)系统还要递增内核对象的使用计数,因为现在两个进程都使用该对象。如果要撤消内核对象,那么父进程和子进程必须调用 该对象上的C l o s e H a n d l e 函数,也可以终止进程的运行。子进程不必首先终止运行,但是父进程也不必首先终止运行。实际上,C r e a t e P r o c e s s 函数返回后,父进程可以立即关闭对象的句柄,而不影响子进程对该对象进行操作的能力。
应该知道,对象句柄的继承性只有在生成子进程的时候才能使用。如果父进程准备创建带有可继承句柄的新内核对象,那么已经在运行的子进程将无法继承这些新句柄。
子进程为了确定它期望的内核对象的句柄值,最常用的方法是将句柄值作为一个命令行参数传递给子进程,该子进程的初始化代码对命令行进行分析(通常通过调用s s c a n f 函数来进行分析),并取出句柄值。一旦子进程拥有该句柄值,它就具有对该对象的无限访问权。请注意,句柄继承权起作用的唯一原因是,父进程和子进程中的共享内核对象的句柄值是相同的,这就是为什么父进程能够将句柄值作为命令行参数来传递的原因。
改变句柄的标志
SetHandleInformation
GetHandleInformation
命名对象
CreateMutex
CreateEvent
CreateSemaphore
CreateWaitableTimer
CreateFileMapping
CreateJobObject
访问命名对象
OpenMutex
OpenEvent
OpenSemaphore
OpenWaitableTimer
OpenFileMapping
Openjob0bject
如果存在带有指定名字的内核对象,并且它是相同类型的对象,那么系统就要查看是否允许执行所需的访问。如果拥有该访问权,调用进程的句柄表就被更新,对象的使用计数被递增。
复制对象句柄
DuplicateHandle
该函数取出一个进程的句柄表中的项目,并将该项目拷贝到另一个进程的句柄表中
/************************************************/
`╰Witchつ ---2012年5月29日
http://blog.csdn.net/Witch_Soya
/************************************************/