找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4192|回复: 0

《Windows核心编程》学习笔记(12)– 获取线程,进程伪句柄

[复制链接]
发表于 2012-3-17 22:51:12 | 显示全部楼层 |阅读模式

HANDLE GetCurrentProcess();

HANDLE GetCurrentThread();


这两个函数都返回到主调线程的进程或线程内核对象的一个伪句柄(pseudohandle )。它们不会在主调进程的句柄表中新建句柄。而且,调用这两个函数,不会影响进程或线程内核对象的使用计数。如果调用CloseHandle,将一个伪句柄作为参数传入,CloseHandle只是简单地忽略此调 用,并返回FALSE。在这种情况下,GetLastError将返回ERROR_INVALID_HANDLE。



将伪句柄转换为真正的句柄

    有时或许需要一个真正的线程句柄,而不是一个伪句柄。所谓“真正的句柄”,指的是能明确、无歧义地标识一个线程的句柄。来仔细分析下面的代码:


DWORD WINAPI ParentThread(PVOID pvParam) {

HANDLE hThreadParent = GetCurrentThread();

CreateThread(NULL, 0, ChildThread, (PVOID) hThreadParent, 0, NULL);

// Function continues...

}

DWORD WINAPI ChildThread(PVOID pvParam) {

HANDLE hThreadParent = (HANDLE) pvParam;

FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime;

GetThreadTimes(hThreadParent,

&ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime);

// Function continues...

}


  能看出这个代码段的问题吗?其意图是让父线程向子线程传递一个可以标识父线程的句柄。但是,父线程传递的是一个伪句柄,

而不是一个真正的句柄。子线程开始执行时,它把这个伪句柄传给GetThreadTimes函数,这将导致子线程得到的是它自己的CPU

计时数据,而不是父线程的。之所以会发生这种情况,是因为线程的伪句柄是一个指向当前线程的句柄;换言之,

指向的是发出函数调用的那个线程。


     为了修正这段代码,必须将伪句柄转换为一个真正的句柄。DuplicateHandle函数可以执行这个转换:


BOOL DuplicateHandle(

HANDLE hSourceProcess,

HANDLE hSource,

HANDLE hTargetProcess,

PHANDLE phTarget,

DWORD dwDesiredAccess,

BOOL bInheritHandle,

DWORD dwOptions);


正常情况下,利用这个函数,你可以根据与进程A相关的一个内核对象句柄来创建一个新句柄,并让它同进程B相关。但是,我们可以采取一种特殊的方式来使用它,以纠正前面的那个代码段的错误。纠正过后的代码如下:


DWORD WINAPI ParentThread(PVOID pvParam) {

HANDLE hThreadParent;

DuplicateHandle(

GetCurrentProcess(), // Handle of process that thread pseudohandle is relative to

GetCurrentThread(), // 父伪句柄

GetCurrentProcess(), // Handle of process that the new, real, thread handle is relative to

&hThreadParent, // Will receive the new, real, handle identifying the parent thread

0, // Ignored due to DUPLICATE_SAME_ACCESS

FALSE, // New thread handle is not inheritable

DUPLICATE_SAME_ACCESS); // New thread handle has same access as pseudohandle


CreateThread(NULL, 0, ChildThread, (PVOID) hThreadParent, 0, NULL);

// Function continues...

}


DWORD WINAPI ChildThread(PVOID pvParam) {

HANDLE hThreadParent = (HANDLE) pvParam;

FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime;

GetThreadTimes(hThreadParent, &ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime);

CloseHandle(hThreadParent);

// Function continues...

}


现在,当父线程执行时,它会把标识父线程的有歧义的伪句柄转换为一个新的、真正的句柄,后者明确、无歧义地标识了父线程。然后,它将这个真正的句柄传给CreateThread。当子线程开始执行时,其pvParam参数就会包含这个真正的线程句柄。在调用任何函数时,只要传入这个句 柄,影响的就将是父线程,而非子线程。 因为DuplicateHandle递增了指定内核对象的使用计数,所以在用完复制的对象句柄后,有必要 把目标句柄传给CloseHandle,

以递减对象的使用计数。前面的代码体现了这一点。调用 GetThreadTimes之后,子线程紧接着调用CloseHandle来递减父线程对象的使用计数。在这段代 码中,我假设子线程不会用这个句柄调用其他任何函数。如果还要在调用其他函数时传入父线程的句柄,那么只有在子线程完全不需要此句柄的时候,才能调用CloseHandle。


还要强调一点,DuplicateHandle函数同样可用于把进程的伪句柄转换为真正的进程句柄,如下所示:

HANDLE hProcess;

DuplicateHandle(

GetCurrentProcess(), // Handle of process that the process pseudohandle is relative to

GetCurrentProcess(), // Process' pseudohandle

GetCurrentProcess(),

&hProcess,

0,

FALSE,

DUPLICATE_SAME_ACCESS

)



您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-4-29 13:28 , Processed in 0.011920 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表