Monday, May 21, 2007

Win32: Grab a snapshot of current processes

In the good old days before managed code their was the Win32 API. The grandfather of pretty much all of Microsoft's modern libraries. From this API, you could do just about anything in Windows, which is part of the problem Microsoft faces in its current generation of operation systems, but thats a story for another time. Today I'm going to go over a quick way to capture a snapshot of all the running processes on the system. Using the CreateToolhelp32Snapshot() command.

Note: all code shown was developed in Visual Studio 2005 .NET, so no complaining about not working on the newer IDEs.



Note:The CheckErrorMessages() call is a custom call that does a lookup for the GetLastError() reference number to lookup its readable error state, I'll so the routine another time.

Step 1: The includes: in order to use the CreateToolhelp32Snapshot command you need to include the following



#include <tlhelp32.h>


Simple huh?

Step 2: The call: you'll probably want to reference the MSDN definition of CreateToolhelp32Snapshot() before you try this out.The long and short of it is that it takes 2 parameters the first is a DWORD flag that represents what portions of the system get included in the snapshot and the other is the process id of process to be in the snapshot (Check MSDN for more info)



//Create a snapshot to all of the processes in the system
HANDLE hSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if (hSnap==INVALID_HANDLE_VALUE){
//Display proper error message and exit application
if ((CheckErrorMessages(GetLastError())==0) && (DEBUGPROG==1)){
CloseHandle(hSnap);
return -1;
}
}

Step 3: Getting the first process entry: Basically I'm creating a process entry data structure which will contain all the process information grabbed by CreateToolhelp32Snapshot(). Since there are more than likely quite a few process running on the system you'll need to traverse through the process list, but for now we'll start with the first one



//Setup a process entry and set the size of the structure before using it
PROCESSENTRY32 peEntry;
peEntry.dwSize=sizeof(PROCESSENTRY32);
//Get information about the first process
DWORD dwResult=Process32First(hSnap,&peEntry);

//Check for failure to grab first process
if (dwResult==FALSE){
if ((CheckErrorMessages(GetLastError())==0) && (DEBUGPROG==1)){
_tprintf(_TEXT("Failed to get first process\n"));
}
}


Step 4: Traverse the list of processes: this step should be pretty straightforward but I'll go over it anyway for clarity. you've got the information for the first process in the snapshot list now you need to go through the rest (See the MSDN entry for the process entry structure to see what information you can pull.)



while (dwResult==TRUE){
//Display General Process information
_tprintf(_TEXT("\nProcess Name: %s"),peEntry.szExeFile);
_tprintf(_TEXT("Process ID: %d\n"),peEntry.th32ProcessID);
_tprintf(_TEXT("Thread Count: %d\n"),peEntry.cntThreads);
_tprintf(_TEXT("Usage Count: %d\n"),peEntry.cntUsage);
//...any thing else you want to display
//Go to the next process in the process list
dwResult=Process32Next(hSnap,&peEntry);
}

//Clean up the snapshot your done
CloseHandle(hSnap);


Note: Don't forget to cleanup your handles when your done

No comments: