2 Stimmen

Schnellste und ressourcenschonendste Möglichkeit, eine Liste der laufenden Prozesse mit ihrer ID und ihrem Speicherort in C# zu erhalten

Ich habe ein Modul geschrieben, das alle 250 ms eine Liste der laufenden Prozesse für Windows XP und höher abruft. Ich habe den .Net & WMI Weg ausprobiert, beide sind sehr CPU-intensiv. Beide sind jedoch auf meinem Rechner innerhalb von 80 ms fertig. Die CPU-Auslastung meines Host-Prozesses bleibt in beiden Fällen über 10 bis 14 Prozent. Ich denke, die Eigenschaft Location/ExecutionPath ist der eigentliche Übeltäter. Gibt es einen besseren Weg, um diese Informationen zu erhalten?

Bearbeitung1: In meinem Test - Der .Net-Weg war zwar CPU-intensiver, aber etwas schneller als der WMI-Weg. - Der WMI-Weg war langsamer, aber weniger CPU-intensiv, da er die CPU-Auslastung auf den WMI-Provider-Host verschob

private static int WMIOhne()
{
    string wmiAbfrage = "SELECT ProcessId, ExecutablePath FROM Win32_Process";
    using (var searcher = new ManagementObjectSearcher(wmiQuery))
    {
        using (var results = searcher.Get())
        {
            foreach (ManagementObject oReturn in results)
            {
                if (oReturn["ExecutablePath"] != null)
                {
                    _Processes.Add(new ProcessInfo()
                    {
                        ProcessID = (uint)oReturn["ProcessId"],
                        FilePath = oReturn["ExecutablePath"].ToString(),
                    });
                }
            }
            return results.Count;
        }
    }
}

private static int NetWeg()
{
    var processListe = System.Diagnostics.Process.GetProcesses();
    foreach (System.Diagnostics.Process laufenderProzess in processListe)
    {
        if (laufenderProzess.Id > 4)
        {
            try
            {
                _Processes.Add(new ProcessInfo()
                {
                    ProcessID = (uint)laufenderProzess.Id,
                    FilePath = laufenderProzess.MainModule.FileName,
                });
            }
            catch { }
        }
    }
    return processListe.Length;
}

2voto

02Anant Punkte 318

Zuletzt habe ich mich entschieden, den PInvoke-Weg zu gehen. In meinen Tests stellte sich dies als die beste Lösung heraus. Es reduzierte die CPU-Auslastung auf 2 Prozent und war auch schneller als der .Net- oder WMI-Weg.

private static int PInvokeWay()
{
    uint[] processIds = new uint[1024];
    uint bytesCopied;
    uint processCount = 0;
    if (ProcessApi.EnumProcesses(processIds, (uint)processIds.Length * sizeof(uint), out bytesCopied) || bytesCopied == 0)
    {
        processCount = bytesCopied / sizeof(int);

        for (int i = 0; i < processCount; i++)
        {
            string path;

            if (Environment.OSVersion.Version.Major >= 6)
                path = GetExecutablePathAboveVista(processIds[i]);
            else
                path = GetExecutablePathXP2003(processIds[i]);

            if (!string.IsNullOrWhiteSpace(path))
            {
                _Processes.Add(new ProcessInfo()
                {
                    ProcessID = processIds[i],
                    FilePath = path,
                });
            }
        }
    }
    return (int)processCount;
}

private static string GetExecutablePathAboveVista(uint ProcessId)
{            
    var buffer = new StringBuilder(1024);
    try
    {
        IntPtr hprocess = ProcessApi.OpenProcess(ProcessApi.PROCESS_QUERY_LIMITED_INFORMATION,
                                      false, ProcessId);
        if (hprocess != IntPtr.Zero)
        {
            try
            {
                int size = buffer.Capacity;
                if (ProcessApi.QueryFullProcessImageName(hprocess, 0, buffer, out size))
                {
                    return buffer.ToString();
                }
            }
            finally
            {
                ProcessApi.CloseHandle(hprocess);
            }
        }
    }
    catch { }

    return string.Empty;
}

private static string GetExecutablePathXP2003(uint processId)
{            
    var buffer = new StringBuilder(1024);

    try
    {
        IntPtr process = ProcessApi.OpenProcess(ProcessApi.PROCESS_QUERY_INFORMATION
            | ProcessApi.PROCESS_VM_READ, false, processId);

        if (process != IntPtr.Zero)
        {

            try
            {

                if (ProcessApi.GetModuleFileNameExW(process, IntPtr.Zero, buffer, buffer.Capacity) != 0)
                {
                    return buffer.ToString();
                }
            }
            finally
            {
                ProcessApi.CloseHandle(process);
            }

        }

    }
    catch { }

    return string.Empty;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X