Получаем список запущенных процессов на Windows API

11 декабря 2013

А тем временем я все продолжаю ностальгировать по сишечке и 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

Метки: , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.