Windows核心编程读书笔记4——线程(4)当前线程句柄与伪句柄

来源:互联网 发布:ps软件使用说明 编辑:程序博客网 时间:2024/06/06 02:20

在windows编程中,有时候我们会遇到需要传入作用对象句柄的函数,如GetThreadTimes(HANDLE hThread, ...)函数,允许我们获得句柄指定线程的运行时间。如果我们需要本线程的运行时间,那么只需要简单调用函数

GetCurrentThread()函数即可,其会返回当前线程的“伪”句柄。类似的,我们也有函数可以获得当前进程的句柄。

HANDLE GetCurrentThread();  //获得当前线程伪句柄HANDLE GetCurrentProcess(); //获取当前进程伪句柄

伪句柄与真实句柄

注意,之前我们说的通过GetCurrentThread与GetCurrentProcess函数获取的句柄,都是伪句柄。众所周知,每个进程都会有一个句柄表,来保存当前进程获取的内核对象句柄及其他信息。当进程获取一个内核对象时,操作系统会自动将该对象信息插入当前进程的句柄表,并返回类似于索引的句柄。因此每个内核对象的句柄在不同的进程中基本是不一样的。

但当我们调用GetCurrentThread()与GetCurrentProcess()时,其总是会返回值0xfffffffe(-2),0xffffffff(-1)。这就是所谓的伪句柄,它们并不反映真实的句柄表信息,仅用来作用于当前线程\进程本身。关于伪句柄,有以下几点要注意:

1、伪句柄仅限作用于当前线程\进程。超出了当前线程\进程便没有任何意义。

DWORD WINAPI childThread(PVOID pvParam){    HANDLE hThread = (HANDLE)pvParam;    ...    GetThreadTimes(hThread, ...);}int _tmain(int argc, _TCHAR* argv[]){    ...    HANDLE hThread = GetCurrentThread();    CreateThread(nullptr, 0, childThread, (PVOID)hThread, 0, nullptr);...    return 0;}

上面代码本意是通过子线程来获取主线程的运行时间,但由于传递的是伪句柄0xfffffffe(-2),因此在子线程中,其实会获取子线程的运行时间而非主线程。

2、伪句柄不用调用CloseHandle函数关闭

因为伪句柄不是真正的句柄,因此不需要CloseHandle来关闭。(即使调用了也没有任何影响,CloseHandle会返回errorcode ERROR_INVALID_HANDLE)。

伪句柄转换为真实句柄

像上面这种情况,有时候我们需要获取线程或进程的真实句柄,那么我们可以利用函数DuplicateHandle来获取。

BOOL WINAPI DuplicateHandle(  _In_   HANDLE hSourceProcessHandle,  _In_   HANDLE hSourceHandle,  _In_   HANDLE hTargetProcessHandle,  _Out_  LPHANDLE lpTargetHandle,  _In_   DWORD dwDesiredAccess,  _In_   BOOL bInheritHandle,  _In_   DWORD dwOptions);

该函数常用来从进程A中来复制一份内核对象句柄并使B进程可用。但我们可以灵活运用一下。我们可以将上面代码修改为

DWORD WINAPI childThread(PVOID pvParam){    HANDLE hThreadParent = (HANDLE)pvParam;    ...    GetThreadTimes(hThreadParent, ...);    CloseHandle(hThreadParent);  // 由于DuplicateHandle会增加句柄计数,因此不要忘记CloseHandle}int _tmain(int argc, _TCHAR* argv[]){    ...    HANDLE hThreadParent = nullptr;    // 通过DuplicateHandle获得线程的真实句柄。    DuplicateHandle(        GetCurrentProcess(),        GetCurrentThread(),        GetCurrentProcess(),        hThreadParent,        0,        FALSE,        DUPLICATE_SAME_ACCESS);    CreateThread(nullptr, 0, childThread, (PVOID)hThreadParent, 0, nullptr);...;    return 0;}
需要注意的是,通过DuplicateHandle获取的真实句柄,需要CloseHandle进行关闭。同理,我们也可以获取进程的真实句柄。


0 0
原创粉丝点击