Chinaunix首页 | 论坛 | 博客
  • 博客访问: 390091
  • 博文数量: 165
  • 博客积分: 436
  • 博客等级: 下士
  • 技术积分: 887
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-10 02:49
文章分类

全部博文(165)

文章存档

2012年(95)

2011年(70)

分类:

2012-01-20 23:44:00

原文地址:20120120Windows内核对象 作者:windhawkgyang

终于开始看大牛Jeffrey的了,虽然这是部大部头,读起来肯定没那么容易,中间少不了死脑细胞,不过随着越来越多地写Windows程序,也越来越迫切地感觉到需要花上时间下功夫好好看下Windows编程的原理了。正好利用寒假集中的时间,开始这块“大骨头”。


春节前的前半周先学习了前三章,主要介绍了Windows编程的必备知识。
第一章介绍了windows的错误处理机制。windows函数利用不同的返回值区分执行成功和错误的不同类型,即windows有着相当“健全”的错误代码,这在写winsock函数时就可见一斑,比如socket()执行成功会返回可用handle值,失败则返回INVALID_SOCKET_VALUE。在VS中可以利用GetLastError()函数获得最近一次函数执行结果的代码,使用lookup工具可以查看该错误的详细文本描述。
第二章介绍了windows下的推荐使用的字符和字符处理函数。这里需要知道的是windows内部全部使用unicode编码字符。因为C中的ASC2编码使用单字节,最多编码255个字符,这对于英文来说足够了;但是对于其他语言,如汉语,日语等就显得不够了。为了实现windows系统的国际化,windows采用了双字节的unicode编码,最多可以支持65535个字符,已经可以涵盖基本上所有的语言体系,以此可以方便地实现程序的本地化。这里介绍了windows自身的几个字符处理函数,它们往往可以同时接受ASC2和Unicode编码参数,但是实际运行时ASC2编码要转换成Unicode编码再调用内部windows函数。简言之,windows实际直接操作的只能是unicode编码,使用其他编码都需要额外转换,不免降低了效率。
第三章主要介绍了windows使用的内核对象,这里我们重点来讨论一下她们。

一、windows内核对象的基本概念
1.所谓内核对象,实质就是由系统内核在内存中分配的一个内存块,这个内存块只能由内核分配,也只能由内核访问。常见的内核对象如:文件对象,时间对象,文件映射对象,互斥量对象,进程对象,线程对象等。
2.内核对象所对应的内存块是一个数据结构,这个结构中有多个属性字段。安全描述符(security descriptor, SD)和使用计数为所有对象都有的。
&&.使用计数用来表示当前有多少个进程在使用该进程对象,当使用计数变为0时,系统便释放该内核对象。
&&.安全描述符用来描述该内核对象的安全权限。因为内核对象的重要性,所有创建内核对象的API都要包含一个指向SD的指针参数,用来确定其对应的安全权限设置。默认可以使用NULL。
3.内核对象由windowsAPI创建,创建成功后会返回一个唯一的句柄值(handle)。每个进程都维护着一张内核对象的句柄表,里面记录了该对象的内存地址,安全权限和继承标志。函数返回的handle值右移2位便是该对象在进程句柄表中的索引号。所以,进程创建的内核对象是与进程相关的,这当然是处于系统健壮性和安全性的考量。因而一个进程创建的内核对象句柄是不能直接传递给另一个进程使用的,二者对应的是不同的内核对象句柄表。

二、跨进程边界共享内核对象
Micorsoft将句柄设计成进程相关的(process-relative),有时又需要多个进程共享一个内核对象。为此,windows提供了三种机制用来实现这个目的。

1.使用对象句柄继承
想法其实很简单:父进程创建一个可继承的内核对象,然后创建子进程,子进程自动将父进程中所有标志位可继承的内核对象拷贝到子进程内核对象句柄表中相应的位置,即保证句柄值和索引的对应关系不变。这样在子进程中直接使用句柄值也可以找到对应的内核对象记录。具体来说步骤就是:
1.1-父进程创建内核对象时,安全属性值中设置可继承标志
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = TRUE;
1.2-父进程创建子进程时,设置参数自动拷贝父进程中所有可继承内核对象
BOOL CreatProcess(
...
BOOL bInheritHandles,             //设为TRUE
...
)
1.3-子进程创建时就会遍历父进程的句柄表,检查每一个记录项,将所有标志可继承的记录项完整地复制到子进程的句柄表。在子进程的句柄表中,复制项的位置与它在父进程句柄表中的位置是完全一样的。如此一来,句柄值和索引值的对应在父进程和子进程中都同时成立。
1.4-子进程使用句柄时往往借助于命令行参数或者环境变量的形式从父进程得到句柄值
1.5-注意:
&-对象不能继承,继承的只能是对象的句柄
&-对象句柄继承只能用于父子进程之间,而且只在子进程创建时才有效

2.为对象命名
直接使用句柄的问题在于句柄与进程相关,直接对应着进程的句柄表中的索引。所以如果我们不适用句柄而是直接命名的话,就可以摆脱掉这种对应关系。直接为对象命名,会直接返回新进程可用的句柄值。如:
在进程A中:
HANDLE hMutexProcessA = CreatMutex(NULL, FALSE, TEXT("MyMutex");
这里第一个参数是安全属性,NULL默认是不可继承的,第三个参数是对象名
在进程B中:
HANDLE hMutexProcessB = CreatMutex(NULL, FALSE, TEXT("MyMutex");
此时系统会首先检查对象名“MyMutex”是否存在;若存在再检查对象类型。若要创建的对象类型同已存在的类型相同,则接着验证调用者是否拥有该对象的完全访问权限。若具有权限,则系统在B的句柄表中寻找一个空记录项将其初始化为现有的内核对象,返回B中对应索引的句柄值。这样进程B也可以使用该内核对象了。
注意:
&-为对象命名可以跳出父子进程的限制;
&-为对象命名只可以针对可以命名的内核对象,这类对象的创建函数往往具有一个"PCTSTR pszName"参数用来为对象命名;
&-windows并不检查对象名是否重复,所以需要创建、指定专门的命名空间以避免命名重复带来的诸多问题

3.复制对象句柄
这种情况需啊哟调用DuplicateHandle()函数进行内核对象的直接复制,同样,新进程的对象句柄值同源进程的句柄值是不同的。
阅读(795) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~