EnumProcesses() vs CreateToolhelp32Snapshot()

20,631

Solution 1

I think they are pretty much the same in terms of performance (and results) as they both call the same underlying NT API, though CreateToolhelp32Snapshot() may have a slight overhead as it creates a section object and copies all the information to it whereas EnumProcesses()/EnumProcessModules() works directly with user-supplied buffers. The difference is probably negligible in real world performance, though.

I slightly prefer EnumProcesses() as it is (IMO) a simpler API to use, but CreateToolhelp32Snapshot() returns more information if you need it. The only downside to EnumProcesses() is that you are supposed to call it in a loop as you may not have allocated a large enough buffer; CreateToolhelp32Snapshot() takes care of the buffer management for you. In practice I just allocate a buffer on the stack large enough to hold 1024 process ids or module handles; so far I have not come across a system where either of these limits was even remotely close to being reached. Of course we said the same thing about MAX_PATH not so long ago and now we are running into problems with that...

Solution 2

Here are results from few functions:

  • EnumProcesses: 16 msec, 207 processes
  • CreateToolhelp32Snapshot: 141 msec (16 msec), 207 processes
  • WTSEnumerateProcesses: 16 msec, 207 processes
  • WTSEnumerateProcessesEx(WTS_CURRENT_SESSION): 16 msec, 98 processes
  • WTSEnumerateProcessesEx(WTS_ANY_SESSION): 16 msec, 207 processes

Machine is running Windows 8 with UAC enabled, user is not elevated (e.g. have no access to system processes). Main process is 32-bit, machine is 64-bit, so plenty of 64-bit processes around. There are: session 0 for system, session 1 for current console user, session 2 for another fast-switch user. 207 processes in total (these are both 32- and 64-bit, including pseudo "system" process) - 207 is also confirmed by Process Explorer. Among these 207 processes: 23 processes are for session 2, 98 processes - for session 1, and remaining - for session 0.

Results are for cycle of 10 single function call. They are 100% reproducible on each run.

For CreateToolhelp32Snapshot the main result is call of CreateToolhelp32Snapshot itself, and second result (in brackets) is cycle with First/Next.

I think people confuse "enumerate all processes" (get PIDs) and "get name of process/exe". The first one ("enumerate") has no issues with x32/x64 cross-bitness whatsoever. But the latter one ("get name") does have issues - not every method will work across x32/x64.

Solution 3

I don’t remember exactly, but unlike CreateToolhelp32Snapshot(), EnumProcesses() has one of two or both limitations: 1. Doesn’t enumerate 64-bit processes if called from 32-bit process on x64 OS. 2. Doesn’t enumerate elevated processes on Vista and Win7.

Solution 4

CreateToolhelp32Snapshot FTW. EnumProcesses doesnt enumerate all system processes like all instances of svchost.exe at least on Win XP.

Solution 5

IMO the key difference is in priviledges requirements. I've seen cases in which EnumProcesses() would fail, but CreateToolhelp32Snapshot() ran perfectly well.

So once I needed to write code that would detect a certain process on a system and react appropriately. I wrote it using EnumProcesses() and it worked fine on my machine, but not on testers' machines. I just rewrote it with CreateToolhelp32Snapshot() and I've never heard of any problems with it anymore.

Share:
20,631

Related videos on Youtube

jay.lee
Author by

jay.lee

I likes to program :)

Updated on July 09, 2022

Comments

  • jay.lee
    jay.lee almost 2 years

    I was wondering if there are any differences - mostly performance wise - between the two Win32 API functions EnumProcesses() and CreateToolhelp32Snapshot() for enumerating all active processes and loaded modules. Or if one is better than the other to use and why.

  • Luke
    Luke over 13 years
    Last time I looked EnumProcesses() and CreateToolhelp32Snapshot() both called the same underlying NT API (NtQuerySystemInformation) so I'm not sure how you would get different results.
  • sharptooth
    sharptooth over 13 years
    Actually calling EnumProcesses() in a loop is not that of a problem. Just use std::vector<BYTE> for managing the buffer lifetime.
  • jay.lee
    jay.lee over 13 years
    Ah, so they do call the same underlying API. That's mostly covers what I wanted to know. Thanks.
  • Alex
    Alex over 8 years
    "large enough to hold 1024 process ids" - that could easily be exhausted on Terminal Services/Remote Desktop machine servicing 30 users with 40 processes each.
  • Lexikos
    Lexikos almost 7 years
    To effectively utilise EnumProcesses, one most likely needs to open each process and query information. If one requests PROCESS_QUERY_INFORMATION and PROCESS_VM_READ (which are required by GetModuleBaseName), it will fail for some processes. To avoid the limitations mentioned in Dmitriy's answer, one can open with PROCESS_QUERY_LIMITED_INFORMATION and use GetProcessImageFileName instead (except on ancient versions of Windows).