Tengo el siguiente código .NET que llega a la API OpenProcessToken Win32 para recuperar los nombres de propietario de todos los procesos en el sistema:
using System.Security.Principal; using System.Runtime.InteropServices; public class Test { [DllImport("advapi32.dll", SetLastError=true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle); [DllImport("kernel32.dll", SetLastError=true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseHandle(IntPtr hObject); private const UInt32 TOKEN_QUERY = 0x0008; public static List<List<String>> GetProcessWithUsers() { var processes = Process.GetProcesses(); var result = new List<List<string>>(); foreach (var proc in processes) { result.Add(new List<string> { proc.ProcessName, GetProcessUser(proc) }); } return result; } public static string GetProcessUser(Process process) { IntPtr tokenHandle = IntPtr.Zero; try { OpenProcessToken(process.Handle, TOKEN_QUERY, out tokenHandle); WindowsIdentity wi = new WindowsIdentity(tokenHandle); return wi.Name; } catch { return null; } finally { if (tokenHandle != IntPtr.Zero) { CloseHandle(tokenHandle); } } } } Llamar Test.GetProcessWithUsers() (por ejemplo, en LinqPad) toma casi 2 segundos para los 280 procesos en mi sistema.
No considero que sea una cantidad aceptable de tiempo para esta tarea.
Process.GetProcesses() es ágil, la contribución del new WindowsIdentity() es insignificante, entonces, ¿cuál es el retraso con OpenProcessToken() ? ¿Existen funciones alternativas de la API de Win32 que serían más rápidas?
La mayor parte del tiempo que se usa parece deberse a la clase de Process de .NET (excepción de acceso denegado lanzada legítimamente, etc.), así que aquí hay una versión completa de P/Invoke que no la usa pero usa la función nativa CreateToolhelp32Snapshot :
[DllImport("advapi32", SetLastError = true)] private static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, out IntPtr TokenHandle); [DllImport("kernel32", SetLastError = true)] private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); [DllImport("kernel32", SetLastError = true)] private static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32", SetLastError = true)] private static extern IntPtr CreateToolhelp32Snapshot(int dwFlags, int th32ProcessID); [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] private static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe); [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] private static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct PROCESSENTRY32 { public int dwSize; public int cntUsage; public int th32ProcessID; public IntPtr th32DefaultHeapID; public int th32ModuleID; public int cntThreads; public int th32ParentProcessID; public int pcPriClassBase; public int dwFlags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szExeFile; } public static List<List<string>> GetProcessWithUsers() { var result = new List<List<string>>(); const int TH32CS_SNAPPROCESS = 2; var snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); var entry = new PROCESSENTRY32(); entry.dwSize = Marshal.SizeOf<PROCESSENTRY32>(); if (Process32First(snap, ref entry)) { do { const int PROCESS_QUERY_LIMITED_INFORMATION = 0x00001000; var handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, entry.th32ProcessID); result.Add(new List<string> { entry.szExeFile, GetProcessUser(handle) }); if (handle != IntPtr.Zero) { CloseHandle(handle); } } while (Process32Next(snap, ref entry)); } CloseHandle(snap); return result; } public static string GetProcessUser(IntPtr handle) { if (handle == IntPtr.Zero) return null; const int TOKEN_QUERY = 0x0008; if (!OpenProcessToken(handle, TOKEN_QUERY, out var tokenHandle)) return null; var wi = new WindowsIdentity(tokenHandle); CloseHandle(tokenHandle); return wi.Name; }En mi PC, he bajado de 1500 ms a 30 ms (x50).