Process Spectator: View All Running Processes with Modules and Thread Details

Environment: VC7, XP (will run, but not tested on other OS)
Tools Used: MFC 7.0, .NET Framework 1.0

Introduction

One day, I was working in VB.NET to see what's new in it. One control, named 'Process,' interested me. So, I dove deeper into it and wrote out code that lists all processes (names only) running.

The next step is to hard code it in VC.NET. Coding it is almost the same as the .NET Framework provides. (Please note here that I am discussing 'Managed Extensions for C++' and .NET because C++ is built on the top of it.) Going on this way, I tried to develop a process viewer like PVIEW and Task Manager.

Most of you know what processes, threads, handles, and modules are, so I do not discuss them in detail. But, for the article's completeness, I'll brief you through them in my own way:

  • Process: Any running task in the system, either visible to the user (for example, Notepad) or not (as in, crss.exe). Process is the execution mode of any program.
  • Thread: In a Windows system, any smallest executable module running is a thread. A process has one or more threads. The process is the primary thread of the given process.
  • Handle: Handle/Pointer to any resource in the system—windows, files, threads, and the like.
  • Module: Executables (DLL, EXE, and so forth) that are required to load (by OS) to run the desired process. A process is said to be dependent on modules.

.NET Classes for It

Before discussing anything further, I do believe that you have some basic knowledge of MC++, such as '__gc' classes, garbage collection, '__value' type, and so on. If you don't have this knowledge, don't worry and proceed. You will know how to get process information. Look at the MSDN for the MC++ language.

Here I discuss the .NET Framework namespaces and classes that I used and required for acquiring details of processes, threads, and modules. Some exception handling .NET classes are also discussed.

The System.Diagonistics namespace

The System namespace is the same as the CObject MFC class—root in the hierarchy (except that the former is the namespace and the latter is the class). The System namespace contains fundamental classes and base classes. (Please look at the MSDN for more info.)

The System.Diagonistics namespace provides classes that allow interaction with system processes, event logs, performance counters, and so on. Our interest is with the classes that provide information related to processes and here they are:

  • Process Class: Provides access to local and remote processes and to start and stop local system processes. The functions used in the application are given below with a brief description:

    Process::GetProcesses(): The most significant method for the application, which returns an array of 'Process' objects (every '__gc' array is derived from the System.Array class—it is a basic datatype array). Let's have a code excerpt before we proceed:

  • // Get all processes in 'p' array
    Diagnostics::Process *p[]=Diagnostics::Process::GetProcesses();
        // Will return array of Process objects
    
    // Run through all processes
    for(int n=p->GetLength(0),i=0; i < n; i++)
        // Argument 0 is dimension desired
    {
      Console::Write(p[i]->ProcessName);  Console::Write("\t");
        // Name of the process (no extension)
      Console::Write(p[i]->Threads->Count);
        // Number of threads
      Console::Write("\t");  Console::Write(p[i]->HandleCount);
        // Number of handles
    
      /*System::TimeSpan ts=p[i]->TotalProcessorTime;
      sprintf(s,"%02d:%02d:%02d",ts.Hours,ts.Minutes,ts.Seconds);*/
    
      Console::WriteLine(p[i]->MainWindowTitle);
        // Title of main window - null if no UI
    }
    // Will someone delete 'p'??
    
  • ProcessThread and ProcessThreadCollection classes

    'ProcessThread' represents a single thread view and 'ProcessThreadCollection' presents a collection of threads (this value is returned by Process::Threads). The 'Item' property of ProcessThreadCollection represents an array of ProcessThread objects and can be accessed like an ordinary array. Have some code:
    // Assume 'g' is a Process object for which thread info desired
    ProcessThreadCollection *tc = g->Threads;
        // Get thread collection of process
    ProcessThread *pt;    // A single thread object
    
    for(i=0;i<tc->Count;i++)
    {
      pt=tc->Item[i];      // Hold up current thread item from
                           // collection
    
      Console::Write(pt->Id);              // Thread ID
      Console::Write(pt->BasePriority);    // Base priority
                                           // (Calculated by OS)
    
      /*System::TimeSpan ts=pt->TotalProcessorTime;
      str.Format("%02d:%02d:%02d",ts.Hours,ts.Minutes,
                                  ts.Seconds);*/
    
      Console::WriteLine(pt->StartAddress);    // Start/Base
                                               // address of thread
    }
    
  • ProcessModule, ProcessModuleCollection, and FileVersionInfo classes

    As with the threads view, 'ProcessModule' and 'ProcessModuleCollection' represent a module view of a process that can be accessed via Process::Modules. 'FileVersionInfo' represents the complete information of a module and is accessed via ProcessModule::FileVersionInfo. Sample code:

    ProcessModuleCollection *mc= g->Modules;;    // Collection of
                                                 // modules
    ProcessModule *pm;
    FileVersionInfo *fv;
    String *s;    // For filename
    
    for(i=0 ;i<mc->Count; i++)
    {
      // Assign this process module to pm
      pm=mc->Item[i];
    
      // Following code stips out path from filename
      s=pm->FileName;
      n=s->LastIndexOf(L'\\') + 1;
      if(n)
        s=s->Substring(n);
      Console::Write(s);
    
      fv=pm->FileVersionInfo;
      /*str.Format("%d.%d.%d.%d",fv->FileMajorPart,
                                 fv->FileMinorPart,
                                 fv->FileBuildPart,
                                 fv->FilePrivatePart);*/
    
      Console::Write(pm->BaseAddress);    // Base address of
                                          // this module
      Console::WriteLine(pm->ModuleMemorySize);
      /*str.Format("%.2fK",pm->ModuleMemorySize/1024.0);*/
    }
    

Exceptions while accessing information

Some definable and undefinable exceptions arise when we access information regarding a process and also while accessing the process object. The code must handle these exceptions. Unlike MFC exceptions, we place .NET exceptions in their original C++ form using a try/catch statement because there is no need to delete the exception objects. Let me discuss known cases that I have coded:

  • An exception raises when the user tries to Kill/Close a process that has already been exited and the view is not refreshed. It is an ArgumentException (for an incorrect argument to a method). All exception classes are in the System namespace. See the following code:

    try {
      Diagnostics::Process *g=Diagnostics::Process
                 ::GetProcessById(pid));  // 'pid' is process ID -
                                          // see source code.
      // Close or kill routine on success
    }
    catch(ArgumentException *) {
      AfxMessageBox("That process has already been terminated.");
    }
    
  • An undefinable (from me) exception is raised when we try to access the Modules property (properties are a special language enchancement of MC++, such as VB) under the 'Process' object. It is undefinable because when and why it raises is not known and also because MSDN states 'SystemException' and exception raises is 'Win32Exception'. For the same reason, I was forced to use catch(...):

    // Set string value that will be used further
    try{
      sprintf(s,"%d",p[i]->Modules->Count);    // On accessing
                                               // Modules and not
                                               // Count
    }
    catch(...){
      sprintf(s,"**");
    }
    pProcess-<SetItemText(i,3,s);
    
  • In the same manner as above, an undefined type of exception raises on accessing the 'FileVersionInfo' property under 'ProcessModule'. One interesting case with this is that it always occurs when accessing the first module (that is, the program itself). Exception handling code is the same as above.

Other Facts

  1. Most of the code is in Developer Studio and no information is provided for MFC.
  2. Other exceptions than those discussed may also be raised. Please notify me if so.
  3. * means title not present/available; ** means 'Access Denied'.
  4. A function named FromMCtoUCStr (from managed code to unmanaged code) is coded to convert a MC++ String to LPCSTR (only ANSI string). It is required because no Win32/MFC function accepts String as parameter, no conversion function/operator exists in the String class, and no 'MultiByteToWideChar' type of function could be found.
  5. Please see a potential problem just above 'RefreshList' or in the "PID Problem.txt" file method about process IDs.
  6. You may use and modify the code in any way. You may inform me if you like.
  7. I do not have knowledge whether this type of article has been posted or not.

Downloads

Download demo project - 41 Kb
Download source - 23 Kb


Comments

  • MFC70.DLL

    Posted by cutton on 01/03/2005 04:37am

    I have downloaded MFC70.dll and still have no joy in installing the demo application. I get the following error: Application has failed to start because MFC70.DLL was not found. Re-installing the application may fix this problem What do I need to do to resolve this?

    Reply
  • Getting Error

    Posted by pradipkj on 07/06/2004 02:35am

    Hi, In your coding for process spectator in visual c++ i found some errors while executing it.so plz help me ERRORS ARE HERE............ --------------------------------------------------------- --------------------Configuration: ProcessViewer - Win32 Debug-------------------- Compiling... ProcessViewer.cpp c:\program files\microsoft visual studio\vc98\include\zmouse.h(137) : error C2146: syntax error : missing ';' before identifier 'HwndMSWheel' c:\program files\microsoft visual studio\vc98\include\zmouse.h(137) : error C2433: 'HWND' : 'inline' not permitted on data declarations c:\program files\microsoft visual studio\vc98\include\zmouse.h(137) : error C2501: 'HWND' : missing storage-class or type specifiers c:\program files\microsoft visual studio\vc98\include\zmouse.h(137) : fatal error C1004: unexpected end of file found Error executing cl.exe. ProcessViewer.exe - 4 error(s), 0 warning(s) ---------------------------------------------------------- ok thanking you.

    Reply
  • Build in VS 2003

    Posted by Legacy on 08/21/2003 12:00am

    Originally posted by: Nigel

    Please supply VS 2003 compatible project/solution/Applciation so that sources can be built directly.
    
    Thanks.

    Reply
  • Missing MFC70D.DLL

    Posted by Legacy on 08/13/2003 12:00am

    Originally posted by: Gerard Nicol

    You are missing the debug version of MFC70.DLL from the example.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • Live Event Date: October 23, 2014 @ 12:00 p.m. ET / 9:00 a.m. PT Despite the current "virtualize everything" mentality, there are advantages to utilizing physical hardware for certain tasks. This is especially true for backups. In many cases, it is clearly in an organization's best interest to make use of physical, purpose-built backup appliances rather than relying on virtual backup software (VBA - Virtual Backup Appliances). Join us for this eSeminar to learn why physical appliances are preferable to …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds