Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Getting Running Processes List

windows api process list running process tool help

  • Please log in to reply
No replies to this topic

#1 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 25 October 2012 - 12:03 AM

Overview

Sometimes we want to know what processes currently running in the computer in which your application is running. Either you want to check if certain application/process is running, or perhaps you simply want to show list of running processes to your user, or maybe you only want to do some statistic recording.

This tutorial will show you how to get the list of running processes and some details of each process.


PSAPI vs Tool Help

As far as I know, in Windows you have two solutions to get list of running processes, aside from hacking of course. One solution is using PSAPI (Process Status API) library and the other one is using Tool Help library. Personally I believe Tool Help library is using PSAPI library in the background. That is why I found Tool Help is easier to use.

Since I found that Tool Help is easier, in this tutorial we will use Tool Help library to get the running processes information. Maybe in the future we will discuss on using PSAPI.


Getting Running Processes Information with Tool Help Library

In Delphi, Tool Help library was imported in TlHelp32 unit. So you need to add it to your appropriate uses section in order to access this library.

Before digging into the real codes, let's design our classes first. This time we need two classes. One to represent a process, and the other one is a collection to hold references to multiple instance of the process class. Let's name the process class TProcess, and the collection class TProcesses.


TProcess class

Initially we declare this class like shown below. We will complete it as we progress.

  TProcess=class
  public
    // Process ID, assigned by Windows system
    property ID: Cardinal read FID;
    // Path to the executable of the process
    property Path: string read FPath;
    // Name of the process, usually the name of the executable
    property Name: string read FName;
    // combination of the path and the name
    property FullExeName: string read GetFullname;
    // Username of the user who creates the process (executes its executable)
    property User: string read FUser;
    // Domain of the user
    property Domain: string read FDomain;
  end;


TProcesses class

And initially the collection class TProcesses is designed like shown below.

  TProcesses=class
  public
    procedure Clear;
    function Add(const AID:Cardinal; const AName: string): Integer;
    function Find(const AProcessID: Cardinal; var AProcess: TProcess): Boolean; overload;
    function Find(AName: string; var AProcess: TProcess): Boolean; overload;
    function IndexOf(const AProcessID: Cardinal): Integer; overload;
    function IndexOf(AName: string): Integer; overload;

    // Indicates how many TProcess instances currently held
    property Count: Integer read GetCount;
    // Provides easy array-like access to individual TProcess instance
    property Items[Index: Integer]: TProcess read GetItem; default;
  end;

Note that currently TProcesses only has methods and properties similar with common collection class. We will complete it as we progress.


Getting The Running Processes Information

I believe it is obvious that we need a routine or method which reads the current running processes, stored the information into instances of TProcess, and store the TProcess instances into a TProcesses. Also it is obvious that the best place for it is a method in TProcesses. Let's name this method ReadSystem.

Let's add ReadSystem method to public section of TProcesses. It would be something like:

  TProcesses=class
    ...
  public
    ...
    procedure ReadSystem;
    ...
  end;

And its implementation woud be:

procedure TProcesses.ReadSystem;
var
  vSnapshot: THandle;              // to store the tool help snapshot handle
  vProcessEntry: TProcessEntry32;  // temporarily store process information
begin
  // Erase all stored TProcess instances
  Clear;

  // Get the snapshot of the current state
  vSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  try
    // setting up the structure size information
    vProcessEntry.dwSize := SizeOf(TProcessEntry32);

    // make call to get first process information
    if not Process32First(vSnapshot, vProcessEntry) then Exit;

    // Loop to read and store the process information
    repeat
      // add new instance of TProcess storing the supplied process information
      Add(vProcessEntry.th32ProcessID, vProcessEntry.szExeFile);

      // try to retrieve next process information. When this fails, the loop
      // will be stopped
    until not Process32Next(vSnapshot, vProcessEntry);

  finally
    // clean up the snapshot
    CloseHandle(vSnapshot);
  end;
end;

I believe the code structure and the comments explain themselves. However you might want to know more details on the called Tool Help routines/structure. Below are URLs to their respectable MSDN pages along with some note about their use in the above code.


If you inspect the implementation of TProcesses.Add method (quoted below) you will notice that so far we only have two information of a process, the process ID and Name.

function TProcesses.DoAdd(const AID: Cardinal;
  const AName: string): Integer;
var
  P: TProcess;
begin
  P := TProcess.Create(AID, AName);
  Result := FList.AddObject(IntToStr(AID)+'='+AName, P);
end;

function TProcesses.Add(const AID: Cardinal; const AName: string): Integer;
begin
  Result := IndexOf(AID);
  if Result < 0 then
    Result := DoAdd(AID, AName);
end;

While perhaps ID and Name are enough information for many purposes, but we might want more information. So, now it became obvious that we need another routine or method to query more information about a process and store that information to the corresponding TProcess instance. I believe it's good implement this as a method in TProcess. Since it is used to query more information, let's use the name Query. Also because the key information (i.e. the process ID) is already available in the constructor, we can call Query immediately in the constructor.

As example, for each process we want to get information of the executable path and user who created it. As you will see in the code later, codes to query these two are quite different. That is why I created two additional methods, GetPath and GetUserInformation. Both are private.

So now we get TProcess like this.

type
  TProcess=class
  private
    FID: Cardinal;
    FPath: string;
    FName: string;
    FUser: string;
    FDomain: string;
    function GetFullname: string;
  protected
    procedure GetPath;
    procedure GetUserInformation;
  public
    constructor Create(const AID: Cardinal; const AName: string);

    // Retrieve more information about the process, using the process ID already
    // supplied
    procedure Query;

    // Process ID, assigned by Windows system
    property ID: Cardinal read FID;
    // Path to the executable of the process
    property Path: string read FPath;
    // Name of the process, usually the name of the executable
    property Name: string read FName;
    // combination of the path and the name
    property Fullname: string read GetFullname;
    // Username of the user who creates the process (executes its executable)
    property User: string read FUser;
    // Domain of the user
    property Domain: string read FDomain;
  end;
  ...
  ...
 implementation
   ...
   ...

{ TProcess }

constructor TProcess.Create(const AID: Cardinal; const AName: string);
begin
  FID := AID;
  FName := AName;
  Query;
end;

procedure TProcess.GetPath;
var
  vSnapshot: THandle;
  vModuleEntry: TModuleEntry32;
begin
  FPath := '';
  vSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, FID);
  if (vSnapShot=0) or (vSnapshot=INVALID_HANDLE_VALUE) then Exit;
  try
    vModuleEntry.dwSize := SizeOf(TModuleEntry32);
    if not Module32First(vSnapshot, vModuleEntry) then
      raise ESystemError.Create;

    FPath := vModuleEntry.szExePath;
  finally
    CloseHandle(vSnapshot);
  end;
end;

procedure TProcess.GetUserInformation;
type
  PTokenUser = ^TTokenUser;
  TTokenUser = record
    User: TSIDAndAttributes;
  end;
const
  PROCESS_QUERY_LIMITED_INFORMATION = $1000;

var
  vHandle: THandle;
  vToken : THandle;
  vUserName: array[0..255] of char;
  vDomainName: array[0..255] of char;
  vUserNameSize: DWORD;
  vDomainNameSize: DWORD;
  vTokenUser: PTokenUser;
  vInfoSize: Cardinal;
  vUse: SID_NAME_USE;
begin
  FUser := '';
  FDomain := '';

  vHandle := OpenProcess(PROCESS_QUERY_INFORMATION, False, FID);
  if vHandle > 0 then
  try
    if OpenProcessToken(vHandle, TOKEN_QUERY, vToken) then
    try
      GetTokenInformation(vToken, TokenUser, nil, 0, vInfoSize);
      vUserNameSize := SizeOf(vUserName);
      vDomainNameSize := SizeOf(vDomainName);
      vUse := SidTypeUser;
      GetMem(vTokenUser, vInfoSize);
      try
        if not GetTokenInformation(vToken, TokenUser, vTokenUser, vInfoSize, vInfoSize) then
          raise ESystemError.Create;
        LookupAccountSid(nil, vTokenUser.User.Sid, @vUserName, vUserNameSize, @vDomainName, vDomainNameSize, vUse);
        FUser := vUserName;
        FDomain := vDomainName;
      finally
        FreeMem(vTokenUser);
      end;
    finally
      CloseHandle(vToken);
    end;
  finally
    CloseHandle(vHandle);
  end;
end;

procedure TProcess.Query;
begin
  GetPath;
  GetUserInformation;
end;

Note the GetPath method implementation. There we once again use CreateToolhelp32Snapshot. But this time we use TH32CS_SNAPMODULE flag, because we need module information of the corresponding process. Also note that here we only call Module32First, and no call to Module32Next. That because the executable is always be the first module.


Demo Project

I have created a demo project for testing TProcess and TProcesses. And from the result, I believe they are working correctly. Full source code of the demo project and both class is attached in the end of this tutorial. Feel free to use it.


RunTime_000.png

The demo project initial look when executed


RunTime_001_GetRunningProcessesList.png

Running processes information is shown in the memo


RunTime_002_FindRunningProcess.png

Try to find if explorer.exe is running, when it is


RunTime_003_FindNotRunningProcess.png

Try to find if excel.exe is running, when it was not

Attached Files


  • 0





Also tagged with one or more of these keywords: windows api, process list, running process, tool help

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download