winapi-process-list/

А тем временем я все продолжаю ностальгировать по сишечке и WinAPI . Сегодня совместными усилиями мы вспомним, как на WinAPI получить список запущенных процессов, а также динамических библиотек, используемых этими процессами.

Для этого нам понадобятся следующие процедуры и структуры.

CreateToolhelp32Snapshot ( dwFlags , dwProcessId ) ;

CreateToolhelp32Snapshot создает снапшот запущенных процессов, модулей, нитей и так далее. Аргумент dwFlags определяет, снапшот чего именно мы хотим получить. Некоторые возможные значения — TH32CS_SNAPPROCESS, TH32CS_SNAPMODULE, TH32CS_SNAPTHREAD. Параметр dwProcessId задает идентификатор процесса, для которого создается снапшот. Может быть ненужным и устанавливаться в ноль в зависимости от dwFlags. В случае успеха процедура возвращает хэндл снапшота, который должен быть потом закрыт с помощью уже знакомой нам процедуры CloseHandle . В случае ошибки возвращается значение INVALID_HANDLE_VALUE, а подробности поможет узнать GetLastError.

Process32First ( hSnapshot , & peProcessEntry ) ;

Process32First принимает хэндл, полученный от CreateToolhelp32Snapshot, вызванной с dwFlags = TH32CS_SNAPPROCESS, а также указатель на структуру PROCESSENTRY32 . Перед вызовом процедуры поле dwSize этой структуры должно быть установлено в sizeof ( PROCESSENTRY32 ) . В случае успеха возвращается TRUE, а в peProcessEntry записывается информация о первом процессе. В случае ошибки возвращается FALSE, а подробности поможет узнать GetLastError.

Process32Next ( hSnapshot , & peProcessEntry ) ;

Процедура Process32Next работает полностью аналогично Process32First, но служит для получения второго и последующих процессов.

Еще мы воспользуемся процедурами Module32First и Module32Next , а также структурой MODULEENTRY32 . Семантика у этих процедур полностью аналогична Process32First и Process32Next, только служат они для перечисления модулей в заданном процессе (CreateToolhelp32Snapshot с параметром dwFlags, равным TH32CS_SNAPMODULE).

Проще всего понять, как все это работает, посмотрев на пример кода:

#include <windows.h>
#include <tlhelp32.h>

VOID PrintModuleList ( HANDLE CONST hStdOut , DWORD CONST dwProcessId ) {
MODULEENTRY32 meModuleEntry ;
TCHAR szBuff [ 1024 ] ;
DWORD dwTemp ;
HANDLE CONST hSnapshot = CreateToolhelp32Snapshot (
TH32CS_SNAPMODULE , dwProcessId ) ;
if ( INVALID_HANDLE_VALUE == hSnapshot ) {
return ;
}

meModuleEntry. dwSize = sizeof ( MODULEENTRY32 ) ;
Module32First ( hSnapshot , & meModuleEntry ) ;
do {
wsprintf ( szBuff , L »  ba: %08X, bs: %08X, %s r n » ,
meModuleEntry. modBaseAddr , meModuleEntry. modBaseSize ,
meModuleEntry. szModule ) ;
WriteConsole ( hStdOut , szBuff , lstrlen ( szBuff ) , & dwTemp , NULL ) ;
} while ( Module32Next ( hSnapshot , & meModuleEntry ) ) ;

CloseHandle ( hSnapshot ) ;
}

VOID PrintProcessList ( HANDLE CONST hStdOut ) {
PROCESSENTRY32 peProcessEntry ;
TCHAR szBuff [ 1024 ] ;
DWORD dwTemp ;
HANDLE CONST hSnapshot = CreateToolhelp32Snapshot (
TH32CS_SNAPPROCESS , 0 ) ;
if ( INVALID_HANDLE_VALUE == hSnapshot ) {
return ;
}

peProcessEntry. dwSize = sizeof ( PROCESSENTRY32 ) ;
Process32First ( hSnapshot , & peProcessEntry ) ;
do {
wsprintf ( szBuff , L «=== %08X %s === r n » ,
peProcessEntry. th32ProcessID , peProcessEntry. szExeFile ) ;
WriteConsole ( hStdOut , szBuff , lstrlen ( szBuff ) , & dwTemp , NULL ) ;
PrintModuleList ( hStdOut , peProcessEntry. th32ProcessID ) ;
} while ( Process32Next ( hSnapshot , & peProcessEntry ) ) ;

CloseHandle ( hSnapshot ) ;
}

INT main ( ) {
HANDLE CONST hStdOut = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
PrintProcessList ( hStdOut ) ;
ExitProcess ( 0 ) ;
}

Сначала мы получаем список всех процессов в системе, а затем для каждого процесса выводим информацию о нем, а также список модулей. На мой взгляд, код этот очень простой и не нуждается в дополнительных пояснениях.

Как обычно, вы можете собрать эту программу не только под Visual Studio, но и при помощи MinGW, а затем запустить под Wine. В качестве домашнего задания можете изменить программу так, чтобы она также выводила информацию о нитях, используемых в каждом из запущенных процессов. Для этого вам понадобятся процедуры Thread32First , Thread32Next , а также структура THREADENTRY32 .

Если у вас есть вопросы или дополнения, я буду рад ознакомиться с ними в комментариях.

Дополнение: Автозапуск программы на чистом Windows API

EnglishRussianUkrainian