内核对象

来源:互联网 发布:淘宝美国代购 编辑:程序博客网 时间:2024/04/30 06:12

内核对象包括符号对象,事件对象,文件对象,文件映射对象,I/O完成端口对象,作业对象,信箱对象,互斥对象,管道对象,进程对象,信标对象,线程对象和等待计算器对象等。

每个内核对象只是一个内存块,只能由该内核访问。该内存是一个数据结构,其成员负责维护该对象的各种信息。有些是所有内核对象都有的,比如安全标识符,使用计数;有些是特有的,比如进程对象有一个进程ID,一个基本优先级和一个退出代码,而一个文件对象则拥有一个字节位移,一个共享模式和一个打开模式。

Windows编程中使用句柄来标识内核对象,并提供一些方法来对内核对象进行操作。为了使操作系统变得更加健壮,这些句柄值是与进程密切相关的。因此,如果将该句柄值传递给另一个进程中的一个线程(使用某种形式的进程间的通信)那么这另一个进程使用你的进程的句柄值所作的调用就会失败。

1.1使用计数

用于记录使用该内核对象的进程数。

内核对象建立时,其使用计数置为1,另一个进程访问该对象时,计数增加1。调用CloseHandle时,计数减一。

当进程终止运行时,系统会自动扫描进程的句柄表。如果该表拥有任何无效项目(即在终止进程运行前没有关闭的对象),系统将关闭这些对象句柄。如果这些对象中的任何对象的使用计数降为0,那么内核便撤消该对象。
      应用程序在运行时有可能泄漏内核对象,但是当进程终止运行时,系统将能确保所有内容均被正确地清除。另外,这个情况适用于所有对象、资源和内存块,也就是说,当进程终止运行时,系统将保证进程不会留下任何对象。 

     调用CreateThread可使系统创建一个线程内核对象。该对象的初始使用计数是2(在线程停止运行和从CreateThread返回的句柄关闭之前,线程内核对象不会被撤销)。

1.2安全性

通常用于服务器端编程,不去深究。

数据结构

typedef struct _SECURITY_ATTRIBUTES
{
   DWORD nLength,
   LPVOID lpSecurityDescriptor;
   BOOL bInherttHandle;
} SECURITY_ATTRIBUTES;

初始化

  SECURITY_ATTRIBUTES sa;
   sa.nLength = sizeof(sa);       //Used for versioning
   sa.lpSecuntyDescriptor = pSD,  //Address of an initialized SD
   sa.bInheritHandle = FALSE;     //Discussed later
   HANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE,
      &sa, PAGE_REAOWRITE, 0, 1024, "MyFileMapping");
 

2进程的内核对象句柄表

进程初始化时,系统为进程创建一个句柄表,该句柄表只能用于内核对象。

3 - 1 显示了进程的句柄表的样子。可以看到,它只是个数据结构的数组。每个结构都包含一个指向内核对象的指针、一个访问屏蔽和一些标志。

3-1 进程的句柄结构

索引

内核对象内存块的指针

访问屏蔽(标志位的D W O R D

标志(标志位的D W O R D

1

0 x ? ? ? ? ? ? ? ?

0 x ? ? ? ? ? ? ? ?

0 x ? ? ? ? ? ? ? ?

2

0 x ? ? ? ? ? ? ? ?

0 x ? ? ? ? ? ? ? ?

0 x ? ? ? ? ? ? ? ?

...

...

...

...

 

2.1创建内核对象

进程初始化后,创建如表3—1的内存块。指针为该内核对象在内存中的地址,访问屏蔽置为全部访问权。

用于创建内核对象的函数返回的句柄实际上就是表3-1的句柄结构的索引。注意,句柄的含义并没有记入文档资料,并且可能随时变更。实际上在Windows 2000 中,返回的值用于标识放入进程的句柄表 的该对象的字节数,而不是索引号本身。

每当调用一个一个以内核对象句柄为参数的函数时,从内部来说,该函数要访问进程的内核对象句柄表,获取要生成的内核对象的地址,然后生成该对象的数据结构。

如果传递了一个无效索引(句柄),该函数便返回失败,而G e t L a s t E r r o r 则返回6E R R O R _ I N VA L I D _ H A N D L E )。由 于句柄值实际上是放入进程句柄表的索引,因此这些句柄是与进程相关的,并且不能由其他进程成功地使用。

如果调用一个函数以便创建内核对象,但是调用失败了,那么返回的句柄值通常是0N U L L )。发生这种情况是因为系统的内存非常短缺,或者 遇到了安全方面的问题。不过有少数函数在运行失败时返回的句柄值是-1 I N VA L I D _ H A N D L E _ VA L U E )。例如,如果C r e a t e F i l e未能打开指定的文件,那么它将返回I N VA L I D _ H A N D L E _ VA L U E ,而不是返回N U L L 。当查看创建内核对象的函数返回值 时,必须格外小心。特别要注意的是,只有当调用C r e a t e F i l e 函数时,才能将该值与I N VA L I D _ H A N D L E _ VA L U E 进行比较

2.2关闭内核对象

 

BOOL CloseHandle(HANDLE hobj);

在进程运行时,进程有可能泄漏资源(如 内核对象)。但是,当进程终止运行时,操作系统能够确保该进程使用的任何资源或全部资源均被释放,这是有保证的。对于内核对象来说,系统将 执行下列操作:当进程终止运行时,系统会自动扫描进程的句柄表。如果该表拥有任何无效项目(即在终止进程运行前没有关闭的对象),系统将关 闭这些对象句柄。如果这些对象中的任何对象的使用计数降为0 ,那么内核便撤消该对象。

因此,应用程序在运行时有可能泄漏内核对象,但是当进程终止运行时,系统将能确保所有内容均被正确地清除。另外,这个情况适用于所有对象、 资源和内存块,也就是说,当进程终止运行时,系统将保证进程不会留下任何对象。

3跨进程共享内核对象

3.1继承性

创建能继承的句柄,父进程必须指定一个S E C U R I T Y _ AT T R I B U T E S 结构并对它进行初始化,然后将该结构的地址传递给特定的C r e a t e 函数。下面的代码用于创建一个互斥对象,并将一个可继承的句柄返回给它:

   SECURITY_ATTRIBUTES sa;

   sa.nLength = sizeof(sa);

   sa.lpSecuntyDescriptor = NULL;

   //Make the returned handle inheritable.

   sa.bInheritHandle =- TRUE;

   HANDLE hMutex = CreateMutex(&sa, FALSE, NULL);

该代码对一个S E C U R I T Y _ AT T R I B U T E S 结构进行初始化,指明该对象应该使用默认安全性(在Windows 98 中该安全性被忽略)来创 建,并且返回的句柄应该是可继承的。 

使用对象句柄继承性时要执行的下一个步骤是让父进程生成子进程。

BOOL CreateProcess(

   PCTSTR pszApplicationName,

   PTSTR pszCommandLine,

   PSECURITY_ATTRIBUTES psaProcess,

   PSECURITY_ATTRIBUTES psaThread,

   BOOL bInheritHandles,//若该参数为true子进程就可以继承父进程的可继承句柄值。

   DWORD fdwCreale,

   PVOIO pvEnvironment,

   PCTSTR pszCurDir,

   PSTARTUPINFO psiStartInfo,

   PPROCESS_INFORMATION ppiProcInfo);

对象句柄的继承性只有在生成子进程的时候才能使用。如果父进程准备创建带有可继承句柄的新内核对象,.

那么已经在运行的子进程将无法继承这些新句柄。

3.2命名对象

创建内核对象的函数的最后一个参数pszName为对象的名字。若要按名字共享对象,必须为对象赋予一个名字。

注:所有这些对象都共享单个名空间。

调用C r e a t e *函数与调用O p e n *函数之间的主要差别是,如果对象并不存在,那么C r e a t e *函数将创建该对象,

O p e n *函数则运行失败。

 

 
 

原创粉丝点击