Pseudo-processes... [Fernando Vicaria]

The .NET Framework Process class let's you access various aspects (or properties) of a system process. Among these properties are things like the process id (or pid), the process name and the modules (.dll or .exe) it loads. 

This blog entry, my first as a member of the BCL Team, will briefly talk about some special processes and how they are viewed by the Process class.

How many times have you tried to delete or overwrite a file only to find out that you couldn't because some other process had it loaded? What you usually get is a message such as "The process cannot access the file because it is being used by another process" or similar. A quick way to identify who is using the particular exe or dll is to enumerate the modules loaded by each running process on your machine. The code below shows just how to do that.

/// <summary>
/// Simple tool to find out which process have loaded a particular module.
/// </summary>
public class LMod
{    
    // "System Idle Process" pid
    static int IdleProcessID = 0;

    // "System" pid
    static int SystemProcessID
    {
        get
        {
            //Is older than XP...
            if (Environment.OSVersion.Version.Major < 5 ||
                (Environment.OSVersion.Version.Major == 5 &&
                     Environment.OSVersion.Version.Minor == 0))
                return 8;
            else
                return 4;
        }
    }     public static int Main(string[] args)
    {
        int total = 0;
        string m_ModuleName = "";

        if (args.Length == 1)
            m_ModuleName = args[0];
        else
        {
            // wrong number of parameters...
            Console.WriteLine("Usage: LMod module_name");
            return 1;
        }

        // Get all running processes on the machine...
        Process[] m_arrSysProcesses = Process.GetProcesses();
        for (int i = 0; i < m_arrSysProcesses.Length; i++)
        {
            try
            {
                ProcessModuleCollection modules = m_arrSysProcesses[i].Modules;
                int nCount = modules.Count;
 
                if (nCount > 0)
                {
                    for (int j = 0; j < nCount; j++)
                    {
                        // Is it the module we are looking for?
                        if (modules[j].ModuleName == m_ModuleName)
                        {
                            Console.WriteLine("-------------------");
                            Console.WriteLine("Process Name: "
                                 + m_arrSysProcesses[i].ProcessName);
                            Console.WriteLine("Process ID : "
                                 + m_arrSysProcesses[i].Id);
                            Console.WriteLine("Priority : "
                                 + m_arrSysProcesses[i].BasePriority);
                            Console.WriteLine("Memory Usage: "
                                 + (m_arrSysProcesses[i].WorkingSet64 / 1024) + " Kb");
                            Console.WriteLine();

                            total++;
                            break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                // System Idle Process (Idle): represents pseudo-process
// that represents all the processor time not used by
// other processes.
// System (System): represents the processor time
                // used by the kernel itself.
                if (m_arrSysProcesses[i].Id != SystemProcessID
                     && m_arrSysProcesses[i].Id != IdleProcessID)
                {
                    Console.WriteLine("Error: Process "
                         + m_arrSysProcesses[i].ProcessName
                         + " (" + m_arrSysProcesses[i].Id + ") failed!");
                    Console.WriteLine(e);
                    return 2;
                }
            }
        }

        Console.WriteLine();
        Console.WriteLine("There are " + total
             + " processes using module " + m_ModuleName);

        return 100;
    }
}

It's up to you what to do when you get the list of processes back.

A simple output for this program when passed, for example, the mscoree.dll module in my dev machine is:

C:\Temp\Process>Lmod.exe mscoree.dll================================Process Name: iexploreProcess ID : 2496Priority : 8Memory Usage: 46036 Kb================================Process Name: explorerProcess ID : 2628Priority : 8Memory Usage: 26408 Kb================================Process Name: LModProcess ID : 3428Priority : 8Memory Usage: 12140 Kb================================Process Name: aspnet_wpProcess ID : 1456Priority : 8Memory Usage: 58792 KbThere are 4 processes using module mscoree.dll

The main point in this exercise is to note that we had to identify two special processes while iterating through the processes currently running on the machine. These processes are the System Idle Process and the System process. They are really not real processes in the true sense of the word but only pseudo processes.

  • System Idle Process -  This "process" is really a counter which is displayed in the Windows Task Manager (taskmgr) used for measuring how much idle time the CPU is having at any particular time. This counter will display how much CPU Resources, as a percentage are 'idle' and available for use.
  • System - This "process", as with the system idle process, accounts for the time used by the kernel itself.

A simple and quick way to identify these process is via their pid. As you can see in the code above the Idle process has always a pid equal to 0. On the other hand the pid for the System process will vary according to the OS you are using. For a machine with an OS older than Windows XP that value is 8, for XP and newer the pid will be 4.

Previous to Whidbey Beta 2, Process.Modules would return an empty ModuleInfo array. Now if you query any of these two special processes for their loaded modules you will get a System.Win32Exception. This behavior was concluded to be more meaningful to the user of the class.

Another point that is worthy mentioning is that in the next version of Windows, or should I say Vista, the Idle System Process will not be present in the Task Manager anymore.