2

I'm trying to do something which should be (and probably is) very simply. I want a user to be able to define a process (Almost certainly taken from Task Manager) and then my application will perform differently depending on which processes are running.

I've been playing with Process.GetProcesses() to get this information, but I'm struggling to understand the data I'm getting and how it relates to what Task Manager displays.

What I really want is a list of process names which are identical to the "Name" field in Task Manager. I can get this using Path.GetFileName(theprocess.MainModule.FileName); but I get a lot of Exceptions when enumerating certain processes. This appears (from Googling) to be expected especially in cross 64bit/32bit platforms, and while I can easily trap and ignore these it becomes an exceptionally slow operation.

So, I'm hoping to use something simply like process.ProcessName. At first glance this seems to be identical to Task Manager, but there are the odd one or two tasks that it pulls back which don't show up in Task Manager.

Should I be doing something else, or should process.ProcessName be sufficient?

By the way, I'm only interesting in enumerating processes for the current user/session.

Here's one of my code examples:

foreach (theprocess in processList)
{
        try
        {
        string fileName = theprocess.MainModule.FileName;
        currentProcessList.Add(fileName.ToLower());
        }

        catch (Exception e)
        {


        }       
 }
Dan
  • 1,958
  • 1
  • 18
  • 26
  • What do you been by 'define a process'? As I'm understanding it, you want a user to select an existing process rather than create a new one. Is this assumption correct? – user2202911 Aug 05 '14 at 14:41
  • Can you give examples of processnames that are different? Are they also different when you run `tasklist` from the command prompt? – rene Aug 05 '14 at 14:45
  • Essentially, the user may choose for my application to do something different if, say chrome.exe is running. They'll probably check in task manager and then define "chrome.exe" in a registry key and then my application which check to see if it's running. I want to make sure my application always "sees" the same names as they do. – Dan Aug 05 '14 at 14:45
  • Can you show some code? Exceptions are slow, but not *that* slow. Consider also revising your question. In particular "Trying to understand ..." is not a question. – BartoszKP Aug 05 '14 at 14:45
  • @BartoszKP Added - I tried without adding to the currentProcessList, too. That code took well over a second to execute. – Dan Aug 05 '14 at 14:51
  • Accessing the process information is the slow part most probably, not exception handling. Also, related: http://stackoverflow.com/questions/8782907/how-to-get-filename-of-process-mainmodule – BartoszKP Aug 05 '14 at 14:54
  • @BartoszKP Perhaps you're correct about that, though I still need a quick solution to get to where I need I guess – Dan Aug 05 '14 at 14:57

1 Answers1

3

I have never used your method, but in my application I use WMI to iterate over processes as follows:

List<ManagementObject> processInfo = processWmi.CreateRequest("SELECT * FROM Win32_Process");

processWmi is a class I use for all of my WMI queries that has extra functionality to kill the query if it is hanging (which WMI seems to do on some servers). The heart of this class is shown below.

private static string _query;
private static string _scope;
private static List<ManagementObject> _data;
private static bool _queryComplete;
private int _timeout = 300;
private static readonly object Locker = new Object();

public List<ManagementObject> CreateRequest(string query, bool eatErrors = false, string scope = null)
    {

        try
        {
            lock (Locker)
            {
                _queryComplete = false;
                AscertainObject.ErrorHandler.WriteToLog("Running WMI Query: " + query + "    Timeout:" + _timeout, true);
                _query = query;
                _scope = scope;

                Thread serviceThread = new Thread(RunQuery) { Priority = ThreadPriority.Lowest, IsBackground = true };
                serviceThread.Start();
                int timeLeft = _timeout * 10;
                while (timeLeft > 0)
                {
                    if (_queryComplete)
                        return _data;
                    timeLeft--;
                    Thread.Sleep(100);
                }
                if (eatErrors == false)
                    AscertainObject.ErrorHandler.WriteToLog("WMI query timeout: " + query, true, "");

                serviceThread.Abort();
            }
        }
        catch (Exception ex)
        {
            if (eatErrors == false)
                AscertainObject.ErrorHandler.WriteToLog("Error Running WMI Query", true, ex.ToString());
        }

        return null;
    }

    public void SetRequestTimeout(int timeoutSeconds)
    {
        _timeout = timeoutSeconds;
        AscertainObject.ErrorHandler.WriteToLog("WMI query timeout changed to " + timeoutSeconds + " seconds", true);
    }

    private void RunQuery()
    {
        try
        {
            ManagementObjectSearcher searcher = _scope != null ? new ManagementObjectSearcher(_scope, _query) : new ManagementObjectSearcher(_query);
            List<ManagementObject> innerData = searcher.Get().Cast<ManagementObject>().ToList();
            _data = innerData;
        }
        catch (Exception ex)
        {
            AscertainObject.ErrorHandler.WriteToLog("WMI query failed, may have invalid namespace", true, null, true);
            _data = null;
        }
        _queryComplete = true;
    }

You can pull the data you want out of the WMI results as follows (type conversions in place to match my Process class):

foreach (ManagementObject item in processInfo)
{
           Process tempProcess = new Process
           {
               id = Convert.ToInt32((UInt32)item["ProcessID"]),
               name = (String)item["Name"],
               path = (String)item["ExecutablePath"],
               parentID = Convert.ToInt32((UInt32)item["ParentProcessID"]),
               handleCount = Convert.ToInt32((UInt32)item["HandleCount"]),
               priority = Convert.ToInt16((UInt32)item["Priority"]),
               threadCount = Convert.ToInt32((UInt32)item["ThreadCount"]),
               workingSetMB = Convert.ToInt64((UInt64)item["WorkingSetSize"]) / 1048576,
               peakWorkingSetMB = Convert.ToInt64((UInt32)item["PeakWorkingSetSize"]) / 1024,
               pageFileUsageMB = Convert.ToInt64((UInt32)item["PageFileUsage"]) / 1024,
               peakPageFileUsage = Convert.ToInt64((UInt32)item["PeakPageFileUsage"]) / 1024
           };
           try
           {  
               //get owner info
               object[] ownerInfo = new object[2];
               item.InvokeMethod("GetOwner", ownerInfo);
               tempProcess.processOwner = (string)ownerInfo[0];
           }
           catch
           { 
            }
}

WMI results are usually returned very quickly with little to no overhead on the system. They also act similar to SQL queries where you can filter the results with proper WHERE clauses.

Here is the link to all the info you can get back from Win32_Process: http://msdn.microsoft.com/en-us/library/aa394372(v=vs.85).aspx

vesuvious
  • 2,753
  • 4
  • 26
  • 39