Получаем список запущенных процессов на Windows API
11 декабря 2013
А тем временем я все продолжаю ностальгировать по сишечке и WinAPI. Сегодня совместными усилиями мы вспомним, как на WinAPI получить список запущенных процессов, а также динамических библиотек, используемых этими процессами.
Для этого нам понадобятся следующие процедуры и структуры.
CreateToolhelp32Snapshot создает снапшот запущенных процессов, модулей, нитей и так далее. Аргумент dwFlags определяет, снапшот чего именно мы хотим получить. Некоторые возможные значения — TH32CS_SNAPPROCESS, TH32CS_SNAPMODULE, TH32CS_SNAPTHREAD. Параметр dwProcessId задает идентификатор процесса, для которого создается снапшот. Может быть ненужным и устанавливаться в ноль в зависимости от dwFlags. В случае успеха процедура возвращает хэндл снапшота, который должен быть потом закрыт с помощью уже знакомой нам процедуры CloseHandle. В случае ошибки возвращается значение INVALID_HANDLE_VALUE, а подробности поможет узнать GetLastError.
Process32First принимает хэндл, полученный от CreateToolhelp32Snapshot, вызванной с dwFlags = TH32CS_SNAPPROCESS, а также указатель на структуру PROCESSENTRY32. Перед вызовом процедуры поле dwSize этой структуры должно быть установлено в sizeof(PROCESSENTRY32)
. В случае успеха возвращается TRUE, а в peProcessEntry записывается информация о первом процессе. В случае ошибки возвращается FALSE, а подробности поможет узнать GetLastError.
Процедура Process32Next работает полностью аналогично Process32First, но служит для получения второго и последующих процессов.
Еще мы воспользуемся процедурами Module32First и Module32Next, а также структурой MODULEENTRY32. Семантика у этих процедур полностью аналогична Process32First и Process32Next, только служат они для перечисления модулей в заданном процессе (CreateToolhelp32Snapshot с параметром dwFlags, равным TH32CS_SNAPMODULE).
Проще всего понять, как все это работает, посмотрев на пример кода:
#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
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.