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

在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进行关闭。同理,我们也可以获取进程的真实句柄。


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值