《windows核心编程》里提到了“伪句柄”一词,故名思议,它并不是真的句柄,有时候不会达到你想要的效果。边看代码,边解释
代码如下:
// 伪句柄.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> #include <process.h> #include <windows.h> #include <string> using namespace std; DWORD WINAPI ParentThread(PVOID pvParam); //声明线程函数 DWORD WINAPI ChildThread(PVOID pvParam); int _tmain(int argc, _TCHAR* argv[]) { cout<<"输入任意字符,启动线程......."<<endl; system("pause"); PVOID pvParam = NULL; //启动线程父线程 HANDLE hThreadP = (HANDLE)_beginthreadex(NULL,0,(unsigned (__stdcall *)(void *))ParentThread,pvParam,0,0); Sleep(5000); if(CloseHandle(hThreadP)) { cout<<"成功关闭句柄hThreadP"<<endl; } system("pause"); return 0; } DWORD WINAPI ParentThread(PVOID pvParam) { HANDLE hThreadParent; //定义一个句柄,用于保存父线程的内核句柄 /*DuplicateHandle(GetCurrentProcess(), //创建父进程句柄的副本,保存于 hThreadParent中 GetCurrentThread(), GetCurrentProcess(), &hThreadParent, 0, FALSE, DUPLICATE_SAME_ACCESS);*/ hThreadParent = GetCurrentThread(); //启动子线程,在其中输出 父线程的相关时间参数(创建时间,销毁时间等) HANDLE hThreadC = (HANDLE)_beginthreadex(NULL,0,(unsigned (_stdcall*)( void*))ChildThread,(PVOID)hThreadParent,0,0); for(int i = 0;i<1000;++i) for(int j=0; j<1000; ++j) for(int z=0;z<1000;++z) { int num = 1000*1000; } Sleep(1000); //等待1秒 if(CloseHandle(hThreadC)) { cout<<"成功关闭句柄hThreadC"<<endl; } return 0; } DWORD WINAPI ChildThread(PVOID pvParam) { HANDLE hThreadParent = (HANDLE)pvParam; FILETIME ftCreationTime,ftExitTime,ftKernelTime,ftUserTime; Sleep(5000);//等待5秒,确定在父线程销毁的时候,调用GetThreadTimes函数,否则,ExitTime永远为0 //获取父线程的时间参数 // GetThreadTimes(hThreadParent,&ftCreationTime,&ftExitTime,&ftKernelTime,&ftUserTime); if(CloseHandle(hThreadParent)) { cout<<"成功关闭句柄hThreadParent"<<endl; } SYSTEMTIME systime1,systime2,systime3; //定义系统时间结构 FileTimeToSystemTime(&ftCreationTime, &systime1);//将文件时间 转换为 系统时间 FileTimeToSystemTime(&ftExitTime, &systime2); FileTimeToSystemTime(&ftUserTime, &systime3); cout<<"ParentThread的创建时间:"<<endl; cout<<systime1.wMinute<<"分,"<<systime1.wSecond<<"秒,"<<systime1.wMilliseconds<<"微妙。"<<endl; cout<<"ParentThread的结束时间:"<<endl; cout<<systime2.wMinute<<"分,"<<systime2.wSecond<<"秒。"<<systime2.wMilliseconds<<"微妙。"<<endl; cout<<"ParentThread的用户代码执行时间:"<<endl; cout<<systime3.wMinute<<"分,"<<systime3.wSecond<<"秒。"<<systime3.wMilliseconds<<"微妙。"<<endl; return 0; }
这段代码的意图,是要在 ChildThread 这个线程函数里获得其父线程的一些时间参数(例如:创建时间,结束时间,执行用户代码所需要的时间等等) ,因此,在父线程里,通过 GetCurrentThread() 函数,获得当前线程的句柄,并作为子线程函数的参数传递
代码是这句:HANDLE hThreadC = (HANDLE)_beginthreadex(NULL,0,(unsigned (_stdcall*)( void*))ChildThread,(PVOID)hThreadParent,0,0);
然后在子线程里,接收 父线程的句柄,用GetThreadTimes(hThreadParent,&ftCreationTime,&ftExitTime,&ftKernelTime,&ftUserTime)
获得相应的时间参数。但是输出结果并不是我们想要的 父线程的时间参数,而是子线程的时间参数,因为我们传递的是一个 “伪句柄”,而线程的伪句柄是一个指向当前线程的句柄;换言之,指向的是发出函数调用的那个线程!
要想获得真句柄,很简单,只需要用我们 注释的代码,换掉 GetCurrentThread() ,正确代码如下:
// 伪句柄.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> #include <process.h> #include <windows.h> #include <string> using namespace std; DWORD WINAPI ParentThread(PVOID pvParam); //声明线程函数 DWORD WINAPI ChildThread(PVOID pvParam); int _tmain(int argc, _TCHAR* argv[]) { cout<<"输入任意字符,启动线程......."<<endl; system("pause"); PVOID pvParam = NULL; //启动线程父线程 HANDLE hThreadP = (HANDLE)_beginthreadex(NULL,0,(unsigned (__stdcall *)(void *))ParentThread,pvParam,0,0); Sleep(5000); if(CloseHandle(hThreadP)) { cout<<"成功关闭句柄hThreadP"<<endl; } system("pause"); return 0; } DWORD WINAPI ParentThread(PVOID pvParam) { HANDLE hThreadParent; //定义一个句柄,用于保存父线程的内核句柄 DuplicateHandle(GetCurrentProcess(), //创建父进程句柄的副本,保存于 hThreadParent中 GetCurrentThread(), GetCurrentProcess(), &hThreadParent, 0, FALSE, DUPLICATE_SAME_ACCESS); //hThreadParent = GetCurrentThread(); //启动子线程,在其中输出 父线程的相关时间参数(创建时间,销毁时间等) HANDLE hThreadC = (HANDLE)_beginthreadex(NULL,0,(unsigned (_stdcall*)( void*))ChildThread,(PVOID)hThreadParent,0,0); for(int i = 0;i<1000;++i) for(int j=0; j<1000; ++j) for(int z=0;z<1000;++z) { int num = 1000*1000; } Sleep(1000); //等待1秒 if(CloseHandle(hThreadC)) { cout<<"成功关闭句柄hThreadC"<<endl; } return 0; } DWORD WINAPI ChildThread(PVOID pvParam) { HANDLE hThreadParent = (HANDLE)pvParam; FILETIME ftCreationTime,ftExitTime,ftKernelTime,ftUserTime; Sleep(5000);//等待5秒,确定在父线程销毁的时候,调用GetThreadTimes函数,否则,ExitTime永远为0 //获取父线程的时间参数 // GetThreadTimes(hThreadParent,&ftCreationTime,&ftExitTime,&ftKernelTime,&ftUserTime); if(CloseHandle(hThreadParent)) { cout<<"成功关闭句柄hThreadParent"<<endl; } SYSTEMTIME systime1,systime2,systime3; //定义系统时间结构 FileTimeToSystemTime(&ftCreationTime, &systime1);//将文件时间 转换为 系统时间 FileTimeToSystemTime(&ftExitTime, &systime2); FileTimeToSystemTime(&ftUserTime, &systime3); cout<<"ParentThread的创建时间:"<<endl; cout<<systime1.wMinute<<"分,"<<systime1.wSecond<<"秒,"<<systime1.wMilliseconds<<"微妙。"<<endl; cout<<"ParentThread的结束时间:"<<endl; cout<<systime2.wMinute<<"分,"<<systime2.wSecond<<"秒。"<<systime2.wMilliseconds<<"微妙。"<<endl; cout<<"ParentThread的用户代码执行时间:"<<endl; cout<<systime3.wMinute<<"分,"<<systime3.wSecond<<"秒。"<<systime3.wMilliseconds<<"微妙。"<<endl; return 0; }
DuplicateHandle()函数获得一个进程表中的记录项,在另一个进程的句柄表中创建这个记录项的副本。