3

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".

rlarkin
  • 45
  • 6
  • I believe it must be the [same search order as for dlls](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682586%28v=vs.85%29.aspx#standard_search_order_for_desktop_applications). – GSerg Oct 27 '15 at 00:27
  • @Gserg, the [`SearchPath` documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365527(v=vs.85).aspx) indicates that "the search order of the `SearchPath` function differs from the search order used by the `LoadLibrary` function." – drf Oct 27 '15 at 01:12

2 Answers2

3

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());
    }
}
drf
  • 8,461
  • 32
  • 50
  • This seems to work like "where" rather than like "Process.Start" in that it returns "C:\Windows\System32\notepad.exe" rather than "C:\Windows\SysWOW64\notepad.exe". However, I believe they are functionally equivalent, and, in any case, your answer will work for me. Thanks for the answer and the easily tried code. – rlarkin Oct 28 '15 at 02:32
1

If you enter an application name (like notepad.exe) in the command line, it searches in the current directory and all paths which are specified in the PATH environment variable. This works similarly when you use Process.Start. So you would need to search in all paths of the PATH environment variable for your executable file and then extract the icon from it.

  • 321polorex123 is correct, search the environment variable path for the file. For an example look here: [http://stackoverflow.com/a/1429712/5356715](http://stackoverflow.com/a/1429712/5356715) – Ejaski Oct 27 '15 at 00:31