一般来说,我们都会使用GetCurrentProcess()或GetCurrentThread()函数来获取一个进程句柄或是线程句柄。但是值得注意的是函数返回的只是其内核对象的一个伪句柄。而在使用这个伪句柄的时候,有些情况会无法得到我们想要的效果。例如:

Code
1
DWORD WINAPI ParentThread(PVOID pvParam)
2

{
3
HANDLE hThreadParent = GetCurrentThread();
4
CreateThread(NULL,0,ChildThread,(PVOID) hThreadParent,0,NULL);
5

6
}
7
8
DWORD WINAPI ChildThread(PVOID pvParam)
9

{
10
HANDLE hThreadParent = (HANDLE)pvParam;
11
FILETIME ftCreationTime,ftExitTime,ftKernelTime,ftUserTime;
12
GetThreadTimes(hThreadParent,&ftCreationTime,&ftExitTime,&ftKernelTime,&ftUserTime);
13

14
}
15
16
父线程传递自己的句柄给子线程,子线程在线程处理函数中获取父线程的CPU使用时间。但是这个意图不能实现,原因就在于,传递的是一个父线程的伪句柄,导致获得是子线程自己的CPU使用时间。
伪句柄的定义:一个指向当前线程/进程的句柄。
上面的例子中,当前的线程是子线程,所以传递的伪句柄便是子线程的句柄。解决的方法,需要灵活使用DuplicateHandle函数,将一个伪句柄转换为真正的句柄。
1
BOOL DuplicateHandle(
2
HANDLE hSourceProcess,
3
HANDLE hSource,
4
HANDLE hTargetProcess,
5
PHANDLE phTarget,
6
DWORD dwDesiredAccess,
7
BOOL bInheritHandle,
8
DWORD dwOptions); DuplicateHandle函数本意是跨进程边界共享内核对象,复制对象的句柄。它的第一个与第三个参数必须是进程内核对象句柄;第二个参数可以是任意类型的内核对象句柄,但是不能与此函数的主调进程句柄相关;第四个参数就是复制得到的句柄地址,从类型上可以看出他是指向内核对象句柄的句柄;最后三个参数这里不赘述,对这个问题影响不大。

Code
1
DWORD WINAPI ParentThread(PVOID pvParam)
2

{
3
HANDLE hThreadParent();
4
5
DuplicateHandle(
6
GetCurrentProcess(),
7
GetCurrentThread(),
8
GetCurrentProcess(),
9
&hThreadParent,
10
0,FALSE,
11
DUPLICATE_SAME_ACCESS);
12
13
CreateThread(NULL,0,ChildThread,(PVOID)hThreadParent,0,NULL);
14

15
}
16
17
DWORD WINAPI ChildThread(PVOID pvParam)
18

{
19
HANDLE hThreadParent = (HANDLE)pvParam;
20
FILETIME ftCreationTime,ftExitTime,ftKernelTime,ftUserTime;
21
GetThreadTimes(hThreadParent,&ftCreationTime,&ftExitTime,&ftKernelTime,&ftUserTime);
22
CloseHandle(hThreadParent);
23

24
}因为DuplicateHandle递增了内核对象的使用计数,所以在复制的对象句柄用完后必须调用CloseHandle()函数,递减内核对象的使用技术。这里补充的是,CloseHandle()接受的句柄参数也必须是真正的句柄,如果传递的是伪句柄,则返回FALSE同时GetLastError()将返回ERROR_INVALID_HANDLE。