The System.Diagnostics.Process.Start()
method accepts a ProcessStartInfo
class instance initialized with an executable with no path, such as Notepad.exe
. After the process starts one can find the full path it used, such as C:\Windows\SysWOW64\notepad.exe
. This is perfect, except when you would like to know the full path without actually launching the program. In my case, I'd like to get the icon from the executable ahead of time.
This is similar to the behavior of the windows "where" command, for example:
C:>where notepad.exe
C:>\Windows\System32\notepad.exe
C:>\Windows\notepad.exe
The first response C:\Windows\System32\notepad.exe
is essentially the same as that used by "Process".
The order in which paths are searched is actually registry-dependent, so simply enumerating through the PATH environment variable is not guaranteed to produce the expected result, particularly where there is a file of the expected name in the current working directory. To reliably get the executable path, you will want to call the SearchPath
Win32 function in Kernel32.
There is no framework .NET function that exposes SearchPath
, but the function can be invoked directly through P/Invoke.
The following sample program illustrates the usage of this function. If notepad.exe exists in the system search paths, per the system configuration, it will print the path; if it does not exist, it will print "File not found" instead.
using System;
using System.Text;
using System.Runtime.InteropServices;
class Program
{
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SearchPath(string lpPath,
string lpFileName,
string lpExtension,
int nBufferLength,
[MarshalAs ( UnmanagedType.LPTStr )]
StringBuilder lpBuffer,
out IntPtr lpFilePart);
const int MAX_PATH = 260;
public static void Main()
{
StringBuilder sb = new StringBuilder(MAX_PATH);
IntPtr discard;
var nn = SearchPath(null, "notepad.exe", null, sb.Capacity, sb, out discard);
if (nn == 0)
{
var error = Marshal.GetLastWin32Error();
// ERROR_FILE_NOT_FOUND = 2
if (error == 2) Console.WriteLine("No file found.");
else
throw new System.ComponentModel.Win32Exception(error);
}
else
Console.WriteLine(sb.ToString());
}
}