EnumProcesses() vs CreateToolhelp32Snapshot()
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.
Related videos on Youtube
Comments
-
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 over 13 yearsLast 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 over 13 yearsActually calling
EnumProcesses()
in a loop is not that of a problem. Just usestd::vector<BYTE>
for managing the buffer lifetime. -
jay.lee over 13 yearsAh, so they do call the same underlying API. That's mostly covers what I wanted to know. Thanks.
-
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 almost 7 yearsTo 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).