If you want to get rid off Win32Exception and get the best performance, let's do this:
- We will use Win32 API to get process file name
- We will implement a cache (only explanation)
First, you need to import Win32 API
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);
[DllImport("psapi.dll")]
static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, [In] [MarshalAs(UnmanagedType.U4)] int nSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
Second, let's write the function that returns process file name.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetProcessName(int pid)
{
var processHandle = OpenProcess(0x0400 | 0x0010, false, pid);
if (processHandle == IntPtr.Zero)
{
return null;
}
const int lengthSb = 4000;
var sb = new StringBuilder(lengthSb);
string result = null;
if (GetModuleFileNameEx(processHandle, IntPtr.Zero, sb, lengthSb) > 0)
{
result = Path.GetFileName(sb.ToString());
}
CloseHandle(processHandle);
return result;
}
Finally, let's implement a cache so we do not need to call this function too often. Create a class ProcessCacheItem with properties (1) process name (2) creation time. Add a const ItemLifetime and set to 60 seconds. Create a dictionary where key - process PID and value is object instance of ProcessCacheItem. When you want to get process name, first check in cache. If item in cache expired, remove it and add refreshed one.