《Windows核心编程》笔记2 --- 内核对象二

续上......

内核对象如何在进程边界共享?
1.对象句柄的继承
    当进程具有父子关系,就能使用对象句柄的继承性。父进程有一个或多个对象句柄,并且父进程可以决定生成一个子进程,为子进程赋于父进程的内核对象的访问权。
    具体实现:
    在安全描述符中指定,如:
   
None.gif SECURITY_ATTRIGBUTES sa
None.gif    sa.nLength
= sizeof (sa);
None.gif    sa.lpSecuntyDescriptor
= null ;
None.gif    sa.bInherithandle
= TRUE;  // 指定子进程可以继承该父进程的内核对象。
None.gif
    HANDLE hMutex     =     CreateMutex(@sa,FALSE,NULL);
   
    然后,在进程中使用CreateProcess函数:
None.gif BOOL CreateProcess(
None.gif   PCTSTR pszApplicationName,
None.gif   PTSTR pszCommandLine,
None.gif   PSECURITY_ATTRIBUTES psaProcess,
None.gif   PSECURITY_ATTRIBUTES psaThread,
None.gif   BOOL bInheritHandles,
None.gif   DWORD fdwCreale,
None.gif   PVOIO pvEnvironment,
None.gif   PCTSTR pszCurDir,
None.gif   PSTARTUPINFO psiStartInfo,
None.gif   PPROCESS_INFORMATION ppiProcInfo);
为bInheritHandles指定TRUE,则告诉系统,子进程继承父进程的句柄表中的可继承句柄。

2.改变句柄标志:
    因为每个进程都会有个内核对象句柄表,指明该进程所拥有的句柄信息。那么,我们可以直接设置进程的句柄表,以获取某个内核对象的访问权。
    句柄表的样式:
索引内核对象内存块的指针访问屏蔽(标志位的D W O R D )标志(标志位的D W O R D )
10 x 0 0 0 0 0 0 0 0(无)(无)
20 x 0 0 0 0 0 0 0 0(无)(无)
30 x F 0 0 0 0 0 1 00 x ? ? ? ? ? ? ? ?0 x 0 0 0 0 0 0 0 1
    设置句柄标志的函数:
None.gif BOOL SetHandleInformation(
None.gif   HANDLE hObject,
None.gif   DWORD dwMask,
None.gif   DWORD dwFlags);
None.gif
可以看到,该函数拥有3 个参数。第一个参数h O b j e c t 用于标识一个有效的句柄。第二个参数d w M a s k 告诉该函数想要改变哪个或那几个标志。目前有两个标志与每个句柄相关联:
None.gif #define  HANDLE FLAG_INHERIT 0x00000001
None.gif
#define  HANDLE FLAG PROTECT FROM CLOSE 0x00000002
None.gif
比如,打开一个内核对象的继承标志,则可以这样:
SetHandleInformation(hobj, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
关闭该标志,则可以:
SetHandleInformation(hobj, HANDLE_FLAG_INHERIT, 0);

3.给内核对象命名
    创建许多内核对象可以进行命名,如:
   
None.gif HANDLE CreateMutex(
None.gif   PSLCURITY_ATTRIBUTES psa,
None.gif   BOOL bInitialOwner,
None.gif   PCTSTR pszName);
None.gif
None.gifHANDLE CreateEvent(
None.gif   PSECURITY_ATTRIBUTES psa,
None.gif   BOOL bManualReset,
None.gif   BOOL bInitialState,
None.gif   PCTSTR pszName);
None.gif
None.gifHANDLE CreateSemaphore(
None.gif   PSECURITY_ATTRIBUTES psa,
None.gif   LONG lInitialCount,
None.gif   LONG lMaximumCount,
None.gif   PCTSTR pszNarne);
None.gif
None.gifHANDLE CreateWaitableTimer(
None.gif   PSLCURITY_ATTRIBUTES psa,
None.gif   BOOL bManualReset,
None.gif   PCTSTR pszName);
None.gif
None.gifHANDLE CreateFileMapping(
None.gif   HANDLE hFile,
None.gif   PSECURITY_ATTRIBUTES psa,
None.gif   DWORD flProtect,
None.gif   DWORD dwMaximumSizeHigh,
None.gif   DWORD dwMaximumSizeLow,
None.gif   PCTSTR pszName);
None.gif

    如果创建时最后的参数设置NULL,则创建一个末名命的内核对象当创建一个未命名的对象时,可以通过使用继承性(如上一节介绍的那样)或D u p l i c a t e H a n d l e (下一节将要介绍)共享跨越进程的对象。若要按名字共享对象,必须为对象赋予一个名字
    实现:我们在ProcessA中创建一个内核对象:
    HANDLE hMutexPronessA = CreateMutex(NULL, FALSE, "JeffMutex");
    然后,在ProcessB中创建一个与ProcessA中同名的内核对象:
    HANDLE hMutexProcessB = CreateMutex(NULL, FALSE, "JeffMutex");
    下面,会发生什么情况?以下是书中所揭示的:
    当Process B 调用C r e a t e M u t e x 时,系统首先要查看是否已经存在一个名字为“J e ff M u t e x ”的内核对象。由于确实存在一个带有该名字的对象,因此内核要检查对象的类型。由于试图创建一个互斥对象,而名字为“J e ff M u t e x ”的对象也是个互斥对象,因此系统会执行一次安全检查,以确定调用者是否拥有对该对象的完整的访问权。如果拥有这种访问权,系统就在Process B 的句柄表中找出一个空项目,并对该项目进行初始化,使该项目指向现有的内核对象。如果该对象类型不匹配,或者调用者被拒绝访问,那么C r e a t e M u t e x 将运行失败(返回N U L L )。当Process B 对C r e a t e M u t e x 的调用取得成功时,它并不实际创建一个互斥对象。相反,Process B 只是被赋予一个与进程相关的句柄值,用于标识内核中现有的互斥对象。当然,由于Process B 的句柄表中的一个新项目要引用该对象,互斥对象的使用计数就会递增。在Process A和Process B 同时关闭它们的对象句柄之前,该对象是不会被撤消的。请注意,这两个进程中的句柄值很可能是不同的值。这是可以的。Process A 将使用它的句柄值,而Process B 则使用它自己的句柄值来操作一个互斥内核对象。

按名字共享对象的另一种方法是,进程不调用C r e a t e *函数,而是调用下面显示的O p e n *函数中的某一个,如:
None.gif HANDLE OpenMutex(
None.gif   DWORD dwDesiredAccess,
None.gif   BOOL bInheritHandle,
None.gif   PCTSTR pszName);
None.gif
None.gifHANDLE OpenEvent(
None.gif   DWORD dwDesiredAccess,
None.gif   BOOL bInheritHandle,
None.gif   PCTSTR pszName);
None.gif
None.gifHANDLE OpenSemaphore(
None.gif   DWORD dwDesiredAccess,
None.gif   BOOL bInheritHandle,
None.gif   PCTSTR pszName);
None.gif
None.gifHANDLE OpenWaitableTimer(
None.gif   DWORD dwDesiredAccess,
None.gif   BOOL bInheritHandle,
None.gif   PCTSTR pszName);
None.gif
None.gifHANDLE OpenFileMapping(
None.gif   DWORD dwDesiredAccess,
None.gif   BOOL bInheritHandle,
None.gif   PCTSTR pszName);
None.gif

调用Create*与调用Open*来创建打开内核对象有什么区别呢?
调用C r e a t e *函数与调用O p e n *函数之间的主要差别是,如果对象并不存在,那么C r e a t e *函数将创建该对象,而O p e n *函数则运行失败。

4.复制内核对象句柄:
    共享跨越进程边界的内核对象的最后一个方法是使用D u p l i c a t e H a n d l e 函数:
None.gif BOOL DuplicateHandle(
None.gif   HANDLE hSourceProcessHandle,
None.gif   HANDLE hSourceHandle,
None.gif   HANDLE hTargetProcessHandle,
None.gif   PHANDLE phTargetHandle,
None.gif   DWORD dwDesiredAccess,
None.gif   BOOL bInheritHandle,
None.gif   DWORD dwOptions);
None.gif

简单说来,该函数取出一个进程的句柄表中的项目,并将该项目拷贝到另一个进程的句柄表中。

二,进程

1.何为进程,进程有何特性?
    所谓进程,就是一个正在运行程序的实例。它由两部分组成:
    • 一个是操作系统用来管理进程的内核对象。
    • 另一个是地址空间,它包含所有可执行模块或D L L 模块的代码和数据。它还包含动态内存分配的空间。如线程堆栈和堆分配空间。

   注意,进程是不活泼的,即进程完成的操作,是需要靠进程中的线程来完成。每个进程都必须有一个线程,也可以有多个线程。线程负责执行包含在进程地址空间内的代码。所谓多线程,就是多个线程同时执行包含在地址空间内的代码。
    若要使线程执行进程内的代码,操作系统必须为线程分配CPU时间片。它是以一种循环的方式来提供时间片的,即给每个线程多少时间,时间完成之后,收回CPU,转交给另外的线程。
    创建一个进程,系统会自动为其进程创建一个主线程。然后,可利用该线程可以创建其它的线程,其正是多线程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值