Click here to Skip to main content
Click here to Skip to main content

Process Enumeration in Windows 2000

, 10 Jun 2002
Rate this:
Please Sign up or sign in to vote.
Explains how to use the ToolHelp API to enumerate processes under Windows 2000/XP

Introduction

The advent of NT 5.0 has not only given a new face and improved technology to Windows NT 4.0 users, but has significant improvements for software developers as well, like introduction of COM+, expansion of the Win32 API set, just to name a few.

Under the expansion of the Win32 API, NT 5.0 now supports a new (for Windows NT) set of APIs which help enumerate, amongst other things, the processes and threads in the system. This API set was already present in Windows 95/98, but wasn't there in Windows NT 4.0, where this enumeration required interaction with the system registry.

This article intends to illustrate the enumeration of the processes and threads under a NT 5.0 system using this new set of APIs, which constitute the 32bit TOOLHELP API set (the prototypes are declared in TLHELP32.H). With introduction behind us, lets start enumerating.

The Snapshot

Whenever we use the TOOLHELP API to enumerate the system processes and threads, we have to create, what is called a ToolHelp Snapshot. This snapshot gets the details regarding the processes and threads, amongst other things, at a given point of time (which is the time the snapshot is created). To create the snapshot, we use the CreateToolhelp32Snapshot API whose syntax is:
HANDLE WINAPI CreateToolhelp32Snapshot(
DWORD dwFlags, 
DWORD th32ProcessID 
); 
dwFlags tells the API whose snapshot do we wish to take. Passing the constant TH32CS_SNAPPROCESS takes a snapshot of all the active processes, while TH32CS_SNAPTHREAD does the same for the threads in the system. th32ProcessID is the ID of the process in whose context we intend to take the snapshot. We usually specify 0(zero) when taking snapshots of processes and threads, which aren't specific to a particular process. On the other hand, if we intend to enumerate a process specific entity, say the heap list, then we specify the ID of the process whose heap list we wish to enumerate.

If the snapshot is successfully created, the API returns a HANDLE to the snapshot. Otherwise, -1 is returned.

Onto Enumeration

Once we have the handle to the snapshot of the processes or threads or both (by ORing TH32CS_SNAPPROCESS and TH32CS_SNAPTHREAD and creating a snapshot), we proceed to enumerate the processes or threads.

TOOLHELP API exports two functions for enumerating Processes: Process32First and Process32Next. Process32First has the following prototype:

BOOL WINAPI Process32First(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
); 

and Process32Next has an almost identical one:

BOOL WINAPI Process32Next(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
); 

Both the APIs take the handle to a Process Snapshot and a pointer to a structure which shall contain the information regarding the enumerated process. This structure has the following structure:

typedef struct tagPROCESSENTRY32 {
DWORD dwSize;
DWORD cntUsage; 
DWORD th32ProcessID;
DWORD th32DefaultHeapID;
DWORD th32ModuleID; 
DWORD cntThreads; 
DWORD th32ParentProcessID; 
LONG pcPriClassBase; 
DWORD dwFlags; 
char szExeFile[MAX_PATH]; 
} PROCESSENTRY32; 

typedef PROCESSENTRY32 * PPROCESSENTRY32; 
typedef PROCESSENTRY32 * LPPROCESSENTRY32;

As you can see, LPPROCESSENTRY32 is basically a pointer to PROCESSENTRY32. The various fields of the structure are briefly documented below :

  1. dwSize: contains the size of the structure and must be initialized before passing the pointer to the structure to the API
  2. cntUsage: tells how many processes are using this process. One process may "use" another process, say for example, by opening that process. This is returned after enumeration.
  3. th32ProcessID: contains the ID of the process. This is returned after enumeration.
  4. th32DefaultHeapID: contains the ID of the default heap of the process. This is returned after enumeration.
  5. th32ModuleID: contains the ID of the module associated with the process. This is returned after enumeration.
  6. cntThreads: contains the number of threads belonging to this process. This is returned after enumeration.
  7. th32ParentProcessID: contains the process ID of the process which is parent to this process. This is returned after enumeration.
  8. pcPriClassBase: contains the base priority class of the process. This is returned after enumeration.
  9. dwFlags: officially, its documented as reserved!!!
  10. szExeFile: returns the path to the executable from which this process was created.

To start enumeration, we first call Process32First with the snapshot of the processes and a pointer to PROCESSENTRY32 structure (after filling its dwSize field). The API returns TRUE upon a successful enumeration and FALSE otherwise. Assuming a TRUE response, the PROCESSENTRY32 structure is filled with all the details regarding the process enumerated.

To continue the enumeration, we continue to call Process32Next with the snapshot of the processes and a pointer to PROCESSENTRY32 structure (after filling its dwSize field). Assuming a TRUE response, the PROCESSENTRY32 structure is filled with all the details regarding the process enumerated. Continue to do this repeatedly until the API returns FALSE.

Once the enumeration is complete, DON'T FORGET TO CLOSE THE HANDLE TO THE SNAPSHOT. Below I present the pseudo code to enumerate the process list under NT 5.0. Here it is:

.
#include <tlhelp32.h>
.
.
.
HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_PROCESS,0);
if (hSnapshot==-1)
{
// error: unable to create snapshot
}

PROCESSENTRY32 pe;

// fill up its size
pe.dwSize=sizeof(PROCESSENTRY32);

BOOL retval=Process32First(hSnapshot,&pe);
while(retval)
{
printf("Process ID : %08X\n",pe.th32ProcessID);
pe.dwSize=sizeof(PROCESSENTRY32);
retval=Process32Next(hSnapshot,&pe);
}

// close snapshot handle
CloseHandle(hSnapshot);

// viola.. we are done

Conclusion

So, that's it! The same code now can be used to enumerate processes under Windows 95/98 without any change!! Isn't that a relief... a more portable code. And with quite reduced complexity as compared to how it was done under NT 4.0!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Kumar Gaurav Khanna
Web Developer
United States United States
I hold Early Acheiver in MCSE 2000, MCSE NT 4.0, MCP+I, and actively involved in programming using C/C++, .NET framework, C#, Win32 API, VB, ASP and MFC.
 
I also have various publications to my credit at MSDN Online Peer Journal, Windows Developer Journal (http://www.wdj.com/), Developer 2.0 (http://www.developer2.com/), and PC Quest (http://www.pcquest.com/).

Comments and Discussions

 
GeneralNot bad :) PinmemberPhilip Patrick11-Jun-02 11:04 
GeneralRe: Not bad :) PinmemberIrfan Dawood7-Sep-02 10:06 
GeneralRe: Not bad :) PinsussYves Berquin5-Nov-03 21:59 
GeneralRe: Not bad :) PinmemberRogier29-Sep-04 7:41 
GeneralRe: Not bad :) Pinmemberkkez1-Feb-05 21:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 11 Jun 2002
Article Copyright 2002 by Kumar Gaurav Khanna
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid