Windows 内核对象

来源:互联网 发布:淘宝主图文字规定 编辑:程序博客网 时间:2024/06/08 16:47


1.      内核对象(keneralobject )概念:操作系统用来管理文件、进程、线程等的内核数据结构,应用程序不能直接访问,必须通过handle来访问

2.      内核对象固定成员变量:每个内核对象至少有一个引用计数(用来决定是否释放内核对象,与com引用计数类似)和一个安全属性对象(用来决定访问权限等)成员变量。

3.      keneral object 与handle 区别: keneral object 是操作系统级别的,handle 是进程级别的,可以认为handle就是进程用来标识keneral object的,进程对handle的操作都是直接作用于keneral object。

4.      每个进程创建时,windows都会为进程初始话一个handletable,此handle table是windows用来隐藏内核对象实现的重要数据结构进程退出时候清理handle table。注意此handletable仅仅适用于内核对象,用户对象或者gdi对象不使用。handle table的 table项可以认为是这样一个数据结构

struct  hanleTableItem

{

      UINT uIndex; //一般值=hanle /4,此项至关重要,可以认为作用于handle有关的函数都是通过查找hanle table的这个值引用pKeneral指向的内核对象进行相应的操作,应用程序对handle的错误操作可能引起的一系列问题可能就是这项值引起的,下文将讲述

     void* pKeneral; //指向内核对象的指针

     DWORD dwAcsee;  //内核对象访问权限。参见下面网址:

http://msdn2.microsoft.com/en-us/library/ms686670.aspx

     BOOL BInheritance; //handle是否可以继承

}

当进程创建一个keneral object(如文件对象),windows查找创建进程的handle表的uIndex如果存在则返回表项的handle,否则就创建一个新的handle并且填充到handle table中。当进程结束清理handle table,如果keneral object引用计数变为0释放内核对象。

5.       调用CloseHanle并不是销毁内核对象而是减少引用计数。具体来说是windows根据handle 值/4查找handle table对应的uIndexhandle 项从handle table .中移除。引用计数为0时候销毁pKeneral指向的keneral object。

6.      上面提到的对handle的函数调用将导致的问题:如果调用CloseHanle函数后没有把相应的handle置为NULL(确保handle不再使用),后续如果程序创建一个handle刚好uIndex正好等于没有置为null的那个handle的uIndex,新的handle类型刚好跟没有置为null的那个handle的类型一样,这下悲剧了,以后对没有置为null的那个handle的操作正常进行,应用程序正常工作,但是程序状态将破坏,而且无法恢复。所以CloseHanle后handle 应该赋值为null。

7.      忘记调用CloseHanle:进程运行过程中可能会造成内存泄露,结束时候清理handle table,根据keneral object的引用计数(与com的)进行正确清理。这条规则适用于所有用户对象。可以用process explore 来查看内存泄漏。http://msdn.microsoft.com/msdnmag/issues/03/01/GDILeaks本文gdi 对象泄漏情况捕捉对项目资源泄漏可能有帮助。

8.        跨进程共享内核对象方法:

<1>使用句柄继承,主要用在父子进程当中。主要用到CreateEvent等创建内核对象的LPSECURITY_ATTRIBUTES参数和CreateProcess函数的  BOOL bInheritHandles参数。 在父子进程中传递handle值方法:命令行传递、ipc 通信机制、环境变量。

<2>使用命名内核对象:此方法最常用。如常用的mutex、file mapping

   使用命名对象的一个隐藏的坑:如果在我们的程序创建一个命名对象之前,当前系统已经跑起来的其他程序已经创建了一个相同名字的对象(即使不是相同类型的内核对象),可能引发问题。

HANDLE hMutex = CreateMutex(NULL. FALSE,"JeffObj");

HANDLE hSem = CreateSemaphore(NULL, 1, 1,"JeffObj"); // hSem为null

DWORD dwErrorCode = GetLastError();//dwErrorCode为E R R O R _I N VA L I D _ H A N D L E。

解决方案:为内核对象使用一个独一无二的命名对象。方法有:使用一个guid、使用专有空间命名(见windows核心编程第三章sington例子,应用程序sington可以参考)

<3>使用Du p l i c a t e H a n d l e.

 

参考资料:

1.      windows 核心编程第三章内核对象

2.      msdn关于CreateEvent的说明

3.      windows 图形编程第三章