Why does the MS sample C# app for WMI fail when I try it?

John Whitmire

I have hunted through dozens of related SO questions and over a hundred MS Docs pages and still can't find what I'm missing. My ultimate goal is to create a list of the top few CPU consumers and RAM consumers when total CPU or RAM usage crosses a threshold. Getting the total numbers was relatively easy. My puzzle is the obstacles I run into on each approach I try for collecting individual process data.

I first tried Process.GetProcesses(), but half of the Processes it returns throw exceptions when I try to access their resource usage properties. (That isn't all bad since I don't really care about most of those.) I can ignore those and use what works, but I can't rely on the ignored processes not being in the set I want.

I next dug into WMI and tested a VB Script to see that it can collect the info on all processes:

Set objWMIService = GetObject("winmgmts:")
Set colProcesses = objWMIService.ExecQuery("Select * from Win32_Process")
For Each objProcess in colProcesses
  sngProcessTime = (CSng(objProcess.KernelModeTime) + CSng(objProcess.UserModeTime)) / 10000000
  Wscript.Echo objProcess.Name & " CPU: " & sngProcessTime _
      & " MEM: " & objProcess.WorkingSetSize/1024 
Next

It does. The memory numbers seem way out of line, but that hurdle can wait. Moving back to C#, I copied a simple example from MS Docs that just lists the processes:

using Microsoft.Management.Infrastructure;
. . .
  {
      var cimSession = CimSession.Create("localhost");
      var enumeratedInstances = cimSession.EnumerateInstances(@"root\cimv2", "Win32_Process");
      foreach (CimInstance cimInstance in enumeratedInstances)
          Console.WriteLine("{0}", cimInstance.CimInstanceProperties["Name"].Value.ToString());
    }

I referenced the Windows 10 SDK for the MMI DLL. The app successfully creates the CIMSession but fails on the EnumerateInstances method call with the error, "The client cannot connect to the destination specified in the request." I cannot find any clue to what might be missing. What could it be???

I'm not terribly opposed to writing some Win32 C++ code to get this, but I've been out of C++ so long that I have forgotten double what I remember. If I must go that way, I would greatly prefer to do it with wrapped calls from C#.

(This is all on one PC; no remote computers involved.)

FrankJames

I believe this is what is what you're wanting. This code will return the process Id and it's CPU usage. The example shown uses the localhost. There are a few gotchas here. If you're trying access another computer on the network you will need to ensure that WMI/RPC is allowed by the firewall and the antivirus software. Also you may need to provide login credentials for that machine. The same gotchas apply to network domains. You will definitely need credentials.

Here is Microsoft's ManagementScope documentation.

        try
        {
            var scope = new ManagementScope([email protected]"\\localhost\ROOT\CIMV2");

            // If you're on a domain you will need to provide credentials
            // 
            //var scope = new ManagementScope(
            //    [email protected]"\\{macheName}\ROOT\CIMV2",
            //new ConnectionOptions
            //{
            //    Username = "{Username}",
            //    Password = "{Password}"
            //});

            scope.Connect();

            var query = new ObjectQuery("SELECT * FROM Win32_PerfFormattedData_PerfProc_Process");
            var searcher = new ManagementObjectSearcher(scope, query);

            var queryCollection = searcher.Get();
            foreach (var m in queryCollection)
            {
                var pId = m["IDProcess"];
                var cpuTime = m["PercentProcessorTime"];
            }
        }
        catch
        {
            // ignored
        }

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related