//1. 每个内核对象都只是一个内存块,他由操作系统分配,并只能由操作内核访问。这个内存块是一个数据结构,其成员维护着与对象有关的信息。 少数成员如:安全描述符和使用计数等是所有对象共有的。但其他大多数成员都是不同类型的对象特有的 //2. 为了增强操作系统的可靠性,内核对象句柄值是与进程相关的。所以,如果将句柄值传给另一个进程,那么另一个进程用此句柄值来进行调用时, 会发生失败,更糟糕的是,他们会根据该句柄在我们进程的句柄表的索引来引用一个可能完全不同类型的内核对象 //3. 内核对象的拥有者是操作系统内核,而非进程。内核对象的生命期可能会长于创建他的那个线程 操作系统通过内核对象的使用计数,来确定内核对象的销毁时间 //4. 内核对象可以用一个安全描述符来保护。安全描述符描述了谁拥有对象、谁被允许使用和访问对象。 用于创建内核对象的所有函数几乎都有一个指向 SECURITY_ATTRIBUTES 结构的指针作为参数,大多数情况下应传入 nullptr ,这样创建的 内核对象具有默认安全属性 //5. 一个进程在初始化时,系统将为其分配一个句柄表。这个句柄表仅供内核对象使用,一个进程初始化时候,其句柄表为空, 当进程调用创建内核对象的 API 时,内核扫描进程的句柄表,查找一个空白的记录项并对其进行初始化 //6. 创建内核对象的 API 调用失败,返回值可能是 NULL 也可能是 INVALID_HANDLE_VALUE //7. 在不需要使用内核对象的时候,记得使用 CloseHandle 来释放资源 //8. 跨进程使用内核对象的三种方法: A:使用对象句柄继承 (1):只有在进程之间具有父子关系时,才可以使用对象句柄继承。 (2):父进程若想子进程继承其某个对象句柄,必须使此对象句柄的安全属性中的 SECURITY_ATTRIBUTES::bInheritHandle 设为 true , 然后在调用 CreateProcess 中指定第五个参数为 true ,系统会遍历父进程的句柄表,将所有可继承的句柄都完全复制到子进程 的句柄表中,且复制后的位置是一样的,这就意味着:在父进程与子进程之间的句柄值是完全一样的。随后系统会递增相应内核对象的使用计数 (3):父进程通过命令行的形式或者其他方法将对应句柄值通知到子进程中,则子进程就可以正常使用继承的句柄了 进程可以通过 SetHandleInformation 来改变句柄的标志位,每个句柄目前有2个标志位: HANDLE_FLAG_INHERIT //指明可继承性 HANDLE_FLAG_PROTECT_FROM_CLOSE //指明不可关闭句柄, 调用 CloseHandle 将会出错 例: SetHandleInformation(hTem, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); //打开继承标志 SetHandleInformation(hTem, HANDLE_FLAG_INHERIT, 0); //关闭继承标志 进程可以通过 GetHandleInformation 来查询句柄的标志位 B:通过为对象命名(许多但不是全部内核对象都可以命名) (1):命名的名称长度为 260 (2):所有的内核对象都共享一个命名空间,即使其类型不同 (3):Create* Open* 系列函数都可以用于打开已有的句柄。 Create* 系列的函数在指定名称的内核对象不存在的情况下,还会进行创建 (4):为了防止内核对象重名,建议为每个名字添加一个GUID字符串 可以很方便的利用命名的内核对象来防止打开同一个应用的多个实例 C:利用 DuplicateHandle 来复制内核对象 BOOL WINAPI DuplicateHandle( __in HANDLE hSourceProcessHandle, //拥有参数2的进程句柄 __in HANDLE hSourceHandle, //希望被复制的句柄 __in HANDLE hTargetProcessHandle, //目标进程句柄,也就是将参数2指定句柄复制到此进程中 __deref_out LPHANDLE lpTargetHandle, //目标进程中,复制成功后的句柄值,此值是相对于参数3指定的进程的 __in DWORD dwDesiredAccess, __in BOOL bInheritHandle, __in DWORD dwOptions ); 此函数参考文档: //https://msdn.microsoft.com/en-us/library/ms724251(VS.85).aspx 注意:不要在除了参数3对应的进程外调用 CloseHandle 来关闭 参数4 对应的句柄