无论怎样创建内核对象,都要向系统指明将通过调用C l o s e H a n d l e 来结束对该对象的操作:
BOOL CloseHandle(HANDLE hobj);
该函数首先检查调用进程的句柄表,以确保传递给它的索引(句柄)用于标识一个进程实际上无权访问的对象。如果该索引是有效的,那么系统就可 以获得内核对象的数据结构的地址,并可确定该结构中的使用计数的数据成员。如果使用计数是0 ,该内核便从内存中撤消该内核对象。
如果将一个无效句柄传递给C l o s e H a n d l e ,将会出现两种情况之一。如果进程运行正常,C l o s e H a n d l e 返回FA L S E ,而G e t L a s t E r r o r 则返回E R R O R _ I N VA L I D _ H A N D L E 。如果进程正在排除错误,系统将通知调试程序,以便能排除它的错误。
在C l o s e H a n d l e 返回之前,它会清除进程的句柄表中的项目,该句柄现在对你的进程已经无效,不应该试图使用它。无论内核对象是否已 经撤消,都会发生清除操作。当调用C l o s e H a n d l e 函数之后,将不再拥有对内核对象的访问权,不过,如果该对象的使用计数没有递减为 0 ,那么该对象尚未被撤消。这没有问题,它只是意味着一个或多个其他进程正在使用该对象。当其他进程停止使用该对象时(通过调用C l o s e H a n d l e ),该对象将被撤消。
假如忘记调用C l o s e H a n d l e 函数,那么会不会出现内存泄漏呢?答案是可能的,但是也不一定。在进程运行时,进程有可能泄漏资源(如 内核对象)。但是,当进程终止运行时,操作系统能够确保该进程使用的任何资源或全部资源均被释放,这是有保证的。对于内核对象来说,系统将 执行下列操作:当进程终止运行时,系统会自动扫描进程的句柄表。如果该表拥有任何无效项目(即在终止进程运行前没有关闭的对象),系统将关 闭这些对象句柄。如果这些对象中的任何对象的使用计数降为0 ,那么内核便撤消该对象。
因此,应用程序在运行时有可能泄漏内核对象,但是当进程终止运行时,系统将能确保所有内容均被正确地清除。另外,这个情况适用于所有对象、 资源和内存块,也就是说,当进程终止运行时,系统将保证进程不会留下任何对象。
共享跨越进程边界的内核对象的第二种方法是给对象命名。许多(虽然不是全部)内核对象都是可以命名的。例如,下面的所有函数都可以创建命名的内核对象:
HANDLE CreateMutex(
PSLCURITY_ATTRIBUTES psa,
BOOL bInitialOwner,
PCTSTR pszName);
HANDLE CreateEvent(
PSECURITY_ATTRIBUTES psa,
BOOL bManualReset,
BOOL bInitialState,
PCTSTR pszName);
HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTES psa,
LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszNarne);
HANDLE CreateWaitableTimer(
PSLCURITY_ATTRIBUTES psa,
BOOL bManualReset,
PCTSTR pszName);
HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName);
HANDLE CreateJobObject(
PSECURITY_ATTRIBUTES psa,
PCTSTR pszName);
所有这些函数都有一个共同的最后参数p s z N a m e 。当为该参数传递N U L L 时,就向系统指明了想创建一个未命名的(匿名)内核对象。当创建一个未命名的对象时,可以通过使用继承性(如上一节介绍的那样)或D u p l i c a t e H a n d l e (下一节将要介绍)共享跨越进程的对象。若要按名字共享对象,必须为对象赋予一个名字。
如果没有为p s z N a m e 参数传递M U L L ,应该传递一个以0 结尾的字符串名字的地址。该名字的长度最多可以达到M A X _ PAT H (定义为2 6 0 )个字符。但是,M i c r o s o f t 没有提供为内核对象赋予名字的指导原则。例如,如果试图创建一个称为“J e ff O b j ”的对象,那么不能保证系统中不存在一个名字为“J e ff O b j ”的对象。更为糟糕的是,所有这些对象都共享单个名空间。由于这个原因,对下面这个C r e a t e S e m a p h o r e 函数的调用将总是返回N U L L :