Windows

       

Преобразование псевдоописателя в настоящий описатель


Иногда бывает нужно выяснить настоящий, а не псевдоописатель потока. Под "насто ящим" я подразумеваю описатель, который однозначно идентифицирует уникальный поток Вдумайтесь в такой фрагмент кода:

DWORD WINAPI ParentThread(PVOID pvParam)
{
HANDLE hThreadParent = GetCurrentThread();
CreateThread(NULL, 0, ChildThread, (PVOID) hThreadParent, 0, MULL);

// далее следует какой-то код
}

DWORD WINAPI ChildThread(PVOID pvParam)
{
HANDLE hThreadParent = (HANDLE) pvParam;

FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime;

GetTh readTimes(hThreadParent, &ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime);

// далее следует какой-ro код.
}

Вы заметили, чго здесь не все ладно. Идея была в том, чтобы родительский поток передавал дочернему свой описатель. Но он передает псевдо-, а не настоящий описа тель Начиная выполнение, дочерний поток передает этот псевдоописатель функции GetThreadTimes, и она вследствие этого возвращает временные показатели своего — а вовсе не родительского потока. Происходит так потому, что псевдоописатель яв ляется описателем текущего потока, т e. того, который вызывает эту функцию.

Чтобы исправить приведенный выше фрагмент кода, превратим псевдоописатель в настоящий через функцию DuplicateHandle (о ней я рассказывал в главе 3):

BOOL DuplicateHandle( HANDLE hSourceProcess, HANDLE hSource, HANDLE hTargetProcess, PHANDLE phTarget, DWORD fdwAccess, BOOL bInhentHandle, DWORD fdwOpfions),

Обычно она используется для создания нового "процессо-зависимого» описателя из описателя объекта ядра, значепие которого увязано с другим процессом. А мы вос пользуемся DuplicateHandle не совсем по назначению и скорректируем с ее помощью наш фрагмент кода так

DWORD WINAPI ParentThread(PVOID pvParam)
{
HANDLE hThreadParent;

DuplicateHandle(
GetCurrentProcebs(), // описатель процесса, к которому относится псевдоописатель потока,
GetCurrentThread(), // псевдоописатель родительского потока;
GetCurrentProcess(), // описатель процесса, к которому относится новый, настоящий описатель потока




&hThreadParent, // даст новый настоящий описатель идентифицирующий родительский поток;
0, // игнорируется из-за DUPLICATE_SAME_ACCESS FALSE, новый описатель потока ненаследуемый, DUPLICATE_SAME_ACCESS); // новому описателю потока присваиваются те же атрибуты защиты, что и псевдоописателю

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

// далее следует какой-то код
}

DWORD WINAPI ChildThread(PVOID pvParam)
{

HANDLE hThreadParent = (HANDLE) pvParam;

FILETIME ftCreaUonTime, ftExitTime, ftKernelTime, ftUserTime;

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

CloseHandle(hThreadParent);

// далее следует какой-то код..
}

Тeпeрь родительский поток преобразует свой "двусмысленный» псевдоописатель в настоящий описатель, однозначно определяющий родительский поток, и передает его в CreateThread Когда дочерний поток начинает выполнение, его параметр pvParam содержит настоящий описатель потока. В итоге вызов какой-либо функции с этим описателем влияет не на дочерний, а на родительский поток

Поскольку DuplicateHandle увеличивает счетчик пользователей указанного объек та ядра, то, закончив работу с продублированным описателем объекта, очень важно не забыть уменьшить счетчик Сразу после обращения к GetThreadTimes дочерний поток вызывает CloseHandle, уменьшая тем самым счетчик пользователей объекта "ро дительский поток" на 1 В этом фрагменте кода я исходил из того, что дочерний по ток не вызывает других функций с передачей этого описателя Если же ему надо выз вать какие-то функции с передачей описателя родительского потока, то, естествен но, к CloseHandle следует обращаться только после тоoro, как необходимость в этом описателе у дочернего потока отпадет

Надо заметить, что DuphcateHandle позволяет преобразовать и псевдоописатель процесса. Вот как это сделать

HANDLE hProcess;

DuplicateHandle(
GetCurrentProcess(), // описатель процесса, к которому относится псевдоописатель,
GetCurrentProcess(), // псевдоописатель процесса
GetCurrentProcess(), // описатель процесса, к которому относится новый, настоящий описатель;
&hProcess, // дает новый, настоящий описатель идентифицирующий процесс,
0, // игнорируется из-за DUPLICATE_SAME_ACCESS,
FALSE, // новый описатель процесса ненаследуемый,
DUPLICATE_SAME_ACCESS); // новому описателю процесса присваиваются

// те же атрибуты защиты, что и псевдоописателю


Содержание раздела