![](https://habrastorage.org/webt/4f/le/sp/4flespvi4dpramtpfi6fbsxrxsg.jpeg)
Ну, давайте тогда пользоваться тем, что предлагает публичный WinAPI. А предлагает он функцию CreateToolhelp32Snapshot(), которую предлагается использовать как-то вот так. Всё, кажется, хорошо — есть информация о процессах, потоках. Немного расстраивает тот факт, что вместо элегантных колбеков мы вынуждены делать бесконечный пулинг в цикле, но это ладно.
Самая большая проблема здесь — это производительность. Связка CreateToolhelp32Snapshot() + Process32First() + Process32Next() работает ну очень медленно. Возможно, проблема лежит где-то в той же области, что и описанная вот в этой статье проблема с Heap32First() + Heap32Next(). Кратко — в силу исторических причин кое-где проход по линейному списку занимает квадратичное время.
Можно ли как-то всё это ускорить? Можно. Но придётся сойти со светлого пути использования одних лишь публичных функций WinAPI.
Долгое время я считал, что функции WinAPI делятся на публичные (описанные в MSDN, допустимые для использования) и недокументированные (найденные при реверс-инжиниринге системных библиотек, не описанные в MSDN, не поддерживаемые официально). Этот черно-белый мир казался мне простым и логичным: для публичных продуктов используем публичные функции, для личных учебных целей, утилит, внутренних инструментов — можно пытаться использовать и недокументированные.
Но оказалось, что между этими мирами есть и серая зона. Это функции, которые описаны в MSDN (это делает их похожими на публичные), но Microsoft сообщает, что может изменить или удалить их в любой момент (как недокументированные). Почему такие функции существуют? Всё просто — с одной стороны их польза слишком велика, чтобы её прятать, но с другой стороны у будущих версий ОС могут возникнуть внутренние причины их изменить. Такие функции в одной из встреченных мною терминологий называются «приватными». Пример — NtQuerySystemInformation().
Оцените первую строчку в документации — «NtQuerySystemInformation may be altered or unavailable in future versions of Windows. Applications should use the alternate functions listed in this topic» — при этом для половины описанных применений этих самых «альтернативных функций» и не описано. Можно ли пользоваться такими функциями? Каждый решает это для себя сам. Лично мне кажется, что «волков бояться — в лес не ходить». Как-будто любая другая функция в MSDN гарантированно никогда не станет «altered or unavailable in future versions of Windows». Любой код нуждается в проверке на новых версиях ОС. Любой код нуждается в поддержке и адаптации. И если есть функция, которая вот сейчас работает и приносит пользу, то почему бы её не использовать?
А NtQuerySystemInformation приносит существенную пользу. Вот график роста производительности, который получила библиотека MHook при переходе с CreateToolhelp32Snapshot() на NtQuerySystemInformation():
![image](https://habrastorage.org/getpro/habr/post_images/f7a/f7c/164/f7af7c16456d006ccf70a9fa712f07b3.png)
Как использовать NtQuerySystemInformation()? Очень просто:
- Ищем функцию «NtQuerySystemInformation» в библиотеке «ntdll.dll». Теоретически её там может и не найтись, но на практике на всех версиях ОС от Vista до Win10 она есть точно. Не уверен на счёт XP (не было возможности и необходимости проверить)
- Выделяем память для буфера с результатами
- Вызываем функцию с параметром SystemProcessInformation
- Обходим результаты, перемещаясь между записями для отдельных процессов с использованием значения «NextEntryOffset» из структуры описания текущего процесса.
- Не забываем освободить память, выделенную на шаге №2
Примеры кода можно найти здесь или здесь.
Лично мне с помощью перехода с CreateToolhelp32Snapshot() на NtQuerySystemInformation() удалось в одном достаточно ресурсоёмком сценарии выиграть около 2% общей загрузки процессора, что достаточно много.
Мораль этой истории в том, что медленная работа WinAPI функции не всегда является окончательным приговором. Операционная система — большая и сложная штука, в ней вполне может оказаться другой способ получения нужной информации.
Комментарии (5)
Deamhan
26.03.2018 21:08+1Странная статья, вещающая об очевидных (разница в скорости за счёт оверхеда) и вполне известных вещах (NtQuerySystemInformation юзалась ещё во времена Win 2000, если ничего не путаю).
rezdm
Nt* — это всё же не серая зона, а просто native functions, уровнем выше, docs.microsoft.com/en-us/windows-hardware/drivers/kernel/ntxxx-routines.
Как вариант ещё на посмотреть — а что, если копнуть дебагером в sysinternals process monitor/explorer?
Честно говоря, я ещё помню, когда те тулзы были с каким-то кодом открытым, но не сейчас. Сейчас пипл что-то «на стороне» пишет, типа github.com/processhacker/processhacker
Aleksey_M
В procmon всегда драйвер был (его хвосты при закрытом procmon всякие темиды палят).