一般來說,我們都會使用GetCurrentProcess()或GetCurrentThread()函數來擷取一個進程控制代碼或是線程控制代碼。但是值得注意的是函數返回的只是其核心對象的一個偽控制代碼。而在使用這個偽控制代碼的時候,有些情況會無法得到我們想要的效果。例如:Code
1DWORD WINAPI ParentThread(PVOID pvParam)
2{
3 HANDLE hThreadParent = GetCurrentThread();
4 CreateThread(NULL,0,ChildThread,(PVOID) hThreadParent,0,NULL);
5
6}
7
8DWORD 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函數,將一個偽控制代碼轉換為真正的控制代碼。1BOOL DuplicateHandle(
2 HANDLE hSourceProcess,
3 HANDLE hSource,
4 HANDLE hTargetProcess,
5 PHANDLE phTarget,
6 DWORD dwDesiredAccess,
7 BOOL bInheritHandle,
8 DWORD dwOptions);
DuplicateHandle函數本意是跨進程邊界共用核心對象,複製對象的控制代碼。它的第一個與第三個參數必須是進程核心物件控點;第二個參數可以是任意類型的核心物件控點,但是不能與此函數的主調進程控制代碼相關;第四個參數就是複製得到的控制代碼地址,從類型上可以看出他是指向核心物件控點的控制代碼;最後三個參數這裡不贅述,對這個問題影響不大。Code
1DWORD 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
17DWORD 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。