winston 发表于 2012-3-17 22:51:12

《Windows核心编程》学习笔记(12)– 获取线程,进程伪句柄

HANDLE GetCurrentProcess(); HANDLE GetCurrentThread();
这两个函数都返回到主调线程的进程或线程内核对象的一个伪句柄(pseudohandle )。它们不会在主调进程的句柄表中新建句柄。而且,调用这两个函数,不会影响进程或线程内核对象的使用计数。如果调用CloseHandle,将一个伪句柄作为参数传入,CloseHandle只是简单地忽略此调 用,并返回FALSE。在这种情况下,GetLastError将返回ERROR_INVALID_HANDLE。

将伪句柄转换为真正的句柄
    有时或许需要一个真正的线程句柄,而不是一个伪句柄。所谓“真正的句柄”,指的是能明确、无歧义地标识一个线程的句柄。来仔细分析下面的代码:
DWORD WINAPI ParentThread(PVOID pvParam) { HANDLE hThreadParent = GetCurrentThread(); CreateThread(NULL, 0, ChildThread, (PVOID) hThreadParent, 0, NULL); // Function continues... } DWORD WINAPI ChildThread(PVOID pvParam) { HANDLE hThreadParent = (HANDLE) pvParam; FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime; GetThreadTimes(hThreadParent, &ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime); // Function continues... }
能看出这个代码段的问题吗?其意图是让父线程向子线程传递一个可以标识父线程的句柄。但是,父线程传递的是一个伪句柄,而不是一个真正的句柄。子线程开始执行时,它把这个伪句柄传给GetThreadTimes函数,这将导致子线程得到的是它自己的CPU计时数据,而不是父线程的。之所以会发生这种情况,是因为线程的伪句柄是一个指向当前线程的句柄;换言之, 指向的是发出函数调用的那个线程。
   为了修正这段代码,必须将伪句柄转换为一个真正的句柄。DuplicateHandle函数可以执行这个转换:
BOOL DuplicateHandle( HANDLE hSourceProcess, HANDLE hSource, HANDLE hTargetProcess, PHANDLE phTarget, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
正常情况下,利用这个函数,你可以根据与进程A相关的一个内核对象句柄来创建一个新句柄,并让它同进程B相关。但是,我们可以采取一种特殊的方式来使用它,以纠正前面的那个代码段的错误。纠正过后的代码如下:
DWORD WINAPI ParentThread(PVOID pvParam) { HANDLE hThreadParent; DuplicateHandle( GetCurrentProcess(), // Handle of process that thread pseudohandle is relative to GetCurrentThread(), // 父伪句柄GetCurrentProcess(), // Handle of process that the new, real, thread handle is relative to &hThreadParent, // Will receive the new, real, handle identifying the parent thread 0, // Ignored due to DUPLICATE_SAME_ACCESS FALSE, // New thread handle is not inheritable DUPLICATE_SAME_ACCESS); // New thread handle has same access as pseudohandle
CreateThread(NULL, 0, ChildThread, (PVOID) hThreadParent, 0, NULL); // Function continues... }
DWORD WINAPI ChildThread(PVOID pvParam) { HANDLE hThreadParent = (HANDLE) pvParam; FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime; GetThreadTimes(hThreadParent, &ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime); CloseHandle(hThreadParent); // Function continues... }
现在,当父线程执行时,它会把标识父线程的有歧义的伪句柄转换为一个新的、真正的句柄,后者明确、无歧义地标识了父线程。然后,它将这个真正的句柄传给CreateThread。当子线程开始执行时,其pvParam参数就会包含这个真正的线程句柄。在调用任何函数时,只要传入这个句 柄,影响的就将是父线程,而非子线程。 因为DuplicateHandle递增了指定内核对象的使用计数,所以在用完复制的对象句柄后,有必要 把目标句柄传给CloseHandle,以递减对象的使用计数。前面的代码体现了这一点。调用 GetThreadTimes之后,子线程紧接着调用CloseHandle来递减父线程对象的使用计数。在这段代 码中,我假设子线程不会用这个句柄调用其他任何函数。如果还要在调用其他函数时传入父线程的句柄,那么只有在子线程完全不需要此句柄的时候,才能调用CloseHandle。
还要强调一点,DuplicateHandle函数同样可用于把进程的伪句柄转换为真正的进程句柄,如下所示: HANDLE hProcess; DuplicateHandle( GetCurrentProcess(), // Handle of process that the process pseudohandle is relative to GetCurrentProcess(), // Process' pseudohandle GetCurrentProcess(), &hProcess,0,FALSE,DUPLICATE_SAME_ACCESS)

页: [1]
查看完整版本: 《Windows核心编程》学习笔记(12)– 获取线程,进程伪句柄