Windows для профессионалов

       

Приостановка и возобновление процессов


В Windows понятия "приостановка" и "возобновление" неприменимы к процессам, так как они не участвуют в распределении процессорного времени. Однако меня не раз спрашивали, как одним махом приостановить все потоки определенного процесса. Это можно сделать из другого процесса, причем он должен быть отладчиком и, в частности, вызывать функции вроде WaitForDebugEvent и ContinueDebugEvent.

Других способов приостановки всех потоков процесса в Windows нет: программа, выполняющая такую операцию, может "потерять" новые потоки. Система должна как-то приостанавливать в этот период не только все существующие, но и вновь создаваемые потоки. Microsoft предпочла встроить эту функциональность в системный механизм отладки.

Вам, конечно, не удастся написать идеальную функцию SuspendProcess, но вполне по силам добиться eё удовлетворительной работы во многих ситуациях. Вот мой вариант функции SuspendProcess.

VOID SuspendProcess(DWORD dwProcessID, BOOL tSuspend)
{

// получаем список потоков в системе
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwProcessID),

if (hSnapshot != INVALID_HANDLE_VALUE) {

// просматриваем список потоков
THREADENTRY32 te = { sizeof(te) };

BOOL fOk = Thread32First(hSnapshot, &te);

for (, fOk, fOk = Thread32Next(hSnapshot, &te))
{

// относится ли данный поток к нужному процессу
if (te.th320wnerProcessID == dwProcessID)
{

// пытаемся получить описатель потока по его идентификатору
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te th32ThreadID);

if (hThread != NULL)
{

// приоcтанавливаем или возобновляем поток
if (fSuspend)
SuspendTh read(hThread);
else
ResumeThread(hThread);

}

CloseHandle(hThread);

}
}

CloseHandle(hSnapsnot);
}
}

Для перечисления списка потоков я использую ToolHelp функции (они рассматривались в главе 4). Определив потоки нужною процесса, я вызываю OpenThread.

HANDLE OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadID);

Это новая функция, которая появилась в Windows 2000.
Она находит объект ядра "поток" по идентификатору, указанному в dwTbreadJD, увеличивает его счетчик пользователей на 1 и возвращает описатель объекта. Получив описатель, я могу передать его в SuspendThread (или ResumeThread). OpenThread имеется только в Windows 2000, поэтому моя функция SuspendProcess не будет работать ни в Windows 95/98, ни в Windows NT 4 0.

Вероятно, Вы уже догадались, почему SuspendProcess будет срабатывать не во всех случаях: при перечислении могут создаваться новые и уничтожаться существующие потоки. После вызова CreateToolhelp32Snapshot в процессе может появиться новый поток, который моя функция уже не увидит, а значит, и не приостановит Впоследствии, когда я попытаюсь возобновить потоки, вновь вызвав SuspendProcess, она возобновит поток, который собственно и не приостанавливался. Но может быть еще хуже - при перечислении текущий поток уничтожается и создастся новый с тем же идентификатором. Тогда моя функция приостановит неизвестно какой поток (и даже непонятно в каком процессе).

Конечно, все эти ситуации крайне маловероятны, и, если Вы точно представляе те, что делает интересующий Вас процесс, никаких проблем не будет. В общем, используйте мою функцию на свой страх и риск.


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