Почему приложение MS sample C # для WMI терпит неудачу, когда я пытаюсь это сделать?

#c# #wmi

#c# #wmi

Вопрос:

Я просмотрел десятки связанных вопросов SO и более сотни страниц MS Docs и до сих пор не могу найти то, чего мне не хватает. Моя конечная цель — создать список нескольких лучших потребителей ЦП и ОЗУ, когда общее использование ЦП или ОЗУ превышает пороговое значение. Получить общее число было относительно легко. Моя загадка — это препятствия, с которыми я сталкиваюсь при каждом подходе, который я пытаюсь использовать для сбора отдельных данных процесса.

Я сначала попробовал Process.GetProcesses() , но половина процессов, которые он возвращает, генерирует исключения, когда я пытаюсь получить доступ к их свойствам использования ресурсов. (Это не так уж плохо, поскольку большинство из них меня не волнуют.) Я могу игнорировать их и использовать то, что работает, но я не могу полагаться на то, что игнорируемые процессы не входят в нужный мне набор.

Затем я углубился в WMI и протестировал скрипт VB, чтобы убедиться, что он может собирать информацию обо всех процессах:

 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 amp; " CPU: " amp; sngProcessTime _
      amp; " MEM: " amp; objProcess.WorkingSetSize/1024 
Next
 

Это так. Номера памяти кажутся неправильными, но это препятствие может подождать. Возвращаясь к C #, я скопировал простой пример из MS Docs, в котором просто перечислены процессы:

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

Я ссылался на Windows 10 SDK для библиотеки DLL MMI. Приложение успешно создает CIMSession , но завершается ошибкой при EnumerateInstances вызове метода с ошибкой «Клиент не может подключиться к месту назначения, указанному в запросе». Я не могу найти никаких указаний на то, чего может не хватать. Что это может быть???

Я не очень против того, чтобы написать какой-нибудь код Win32 C для получения этого, но я так давно не был на C , что забыл вдвое больше, чем помню. Если я должен пойти этим путем, я бы предпочел сделать это с помощью обернутых вызовов из C #.

(Все это на одном компьютере; удаленные компьютеры не задействованы.)

Комментарии:

1. Здесь полный выстрел в темноте, и я знаю его локальный хост, но работает ли ваш брандмауэр? Мне пришлось отключить брандмауэр Windows tasklist.exe , чтобы показать процессы, которые используют WMI.

Ответ №1:

Я считаю, что это то, чего вы хотите. Этот код вернет идентификатор процесса и его загрузку процессора. В показанном примере используется localhost. Здесь есть несколько ошибок. Если вы пытаетесь получить доступ к другому компьютеру в сети, вам необходимо убедиться, что брандмауэр и антивирусное программное обеспечение разрешают WMI / RPC. Также вам может потребоваться предоставить учетные данные для входа на этот компьютер. Те же ошибки применимы к сетевым доменам. Вам обязательно понадобятся учетные данные.

Вот документация Microsoft ManagementScope.

         try
        {
            var scope = new ManagementScope($@"\localhostROOTCIMV2");

            // If you're on a domain you will need to provide credentials
            // 
            //var scope = new ManagementScope(
            //    $@"\{macheName}ROOTCIMV2",
            //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
        }
 

Комментарии:

1. Большое спасибо!! Это меня намного ближе. К сожалению, значение для PercentProcessorTime равно нулю для всех процессов. Возможно, я смогу перейти отсюда к тому, что мне нужно.