伪句柄
一、什么是伪句柄
在使用很多函数的时候,我们都需要获得一个对象的句柄,而某些函数返回的是伪句柄。伪句柄本身不会打开内核对象的句柄表,因此内核对象的使用计数就不会增加。它本身就只指向调用它的主调进程或线程。会因为调用者的不同而改变,比如:调用者A使用一个伪句柄,这个句柄指向调用者A,而调用者A将该句柄传递给调用者X,则这个句柄就指向调用者X。我们可以通过调试的方式查看伪句柄,可以得知,进程的伪句柄总是0xffffffff,而线程的伪句柄总是0xfffffffe。
通过使用DuplicateHandle这个强大的函数,可以将伪句柄转换为真正的句柄。
顺便说说DuplicateHandle这个函数。该函数不仅仅可以使伪句柄转换为真正的句柄,还可以创建一个内核对象句柄的副本,并因此更改副本的某些属性,达到保护内核对象的目的。也可以将一个进程的内核对象句柄复制到另外一个进程的内核对象句柄表中。关于该函数更多的信息,可以参见《Windows via C/C++》。
二、为什么使用伪句柄
MICROSOFT为什么这样处理,其实真正的目的可能是:在本身进程和线程中,对句柄没有必要进行权限的限制,而在把句柄交由别的进程或别的线程操作时可能就不怎么放心,一般要加上权限限制,这样就可以减少意外情况的发生。
至于伪句柄和真实句柄之间的转换和权限限制,可以参考DumplicateHandle函数。
xiejl补充:
有时需要一个真正的线程句柄, 而不是一个伪句柄. 所谓"真正的句柄"指的是能明确/无歧义的标识一个线程的句柄.
void Ctst_pseudo_handleDlg::OnBnClickedOk() { HANDLE hThreadParent = GetCurrentThread(); m_pThreadParent = AfxBeginThread(ParentThread, this); } UINT Ctst_pseudo_handleDlg::ParentThread(PVOID pvParam) { HANDLE hThreadParent; DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hThreadParent, 0,FALSE, DUPLICATE_SAME_ACCESS); AfxBeginThread(ChildThread, (PVOID) hThreadParent); return 0; } UINT Ctst_pseudo_handleDlg::ChildThread(PVOID pvParam) { HANDLE hThreadParent = (HANDLE)pvParam; FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime; GetThreadTimes(hThreadParent, &ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime); return 0; }
现在, 当父线程执行时, 它会把标识父线程的有歧义的伪句柄转换为一个新的,真正的句柄, 后者明确,无歧义的标识了父线程. 然后,它将这个真正的句柄传给AfxBeginThread,当子线程开始执行时, 其pvParam参数就会包含这个真正的线程句柄. 在调用任何函数时, 只要传入这个句柄, 影响的将是父进程,而非子进程.
因为DuplicateHandle递增了指定内核对象的使用计数, 所以在用完复制的对象句柄后, 有必要把目标句柄进行CloseHandle操作,以递减对象的使用计数. 如果还要在调用其他函数时传入此复制的句柄,那么请在最后再关闭到此句柄.
还要强调一点, DuplicateHandle函数可用于把进程的伪句柄转换为真正的进程句柄,如下:
HANDLE hProcess; DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &hProcess, 0, FALSE, DUPLICATE_SAME_ACCESS);
by xiejl---from <windows via C/C++>