C#: 如何获取给定没有路径的文件时,Process.Start将使用的可执行路径?

21 浏览
0 Comments

C#: 如何获取给定没有路径的文件时,Process.Start将使用的可执行路径?

System.Diagnostics.Process.Start() 方法接受一个初始化为没有路径的可执行文件的ProcessStartInfo类实例,比如Notepad.exe。进程启动后,可以找到它所使用的完整路径,比如C:\\Windows\\SysWOW64\\notepad.exe。这很完美,但是当你想要在实际启动程序之前就知道完整路径时就有问题了。在我的情况下,我想提前从可执行文件中获取图标。\n这类似于Windows的\"where\"命令的行为,例如:\n

C:>where notepad.exe
C:>\Windows\System32\notepad.exe
C:>\Windows\notepad.exe

\n第一个响应C:\\Windows\\System32\\notepad.exe本质上与\"Process\"使用的相同。

0
0 Comments

在C#中,当使用不带路径的文件名(如notepad.exe)作为参数调用Process.Start方法时,系统会在当前目录和所有在PATH环境变量中指定的路径中进行搜索。因此,如果想要获取Process.Start将使用的可执行文件路径,需要在PATH环境变量的所有路径中搜索可执行文件,并从中提取图标。

要实现这一目标,可以使用以下方法:首先,获取PATH环境变量的值,这可以通过Environment类的GetEnvironmentVariable方法实现。然后,将返回的字符串按分号进行拆分,以获取所有路径。接下来,遍历这些路径,将文件名与所需的可执行文件名进行匹配。如果找到了匹配项,则可以使用该路径来获取可执行文件的完整路径。

以下是一个示例代码,演示了如何获取Process.Start将使用的可执行文件路径:

string executableName = "notepad.exe";
string[] paths = Environment.GetEnvironmentVariable("PATH").Split(';');
foreach (string path in paths)
{
    string fullPath = Path.Combine(path, executableName);
    
    if (File.Exists(fullPath))
    {
        Console.WriteLine("Executable path: " + fullPath);
        break;
    }
}

通过上述代码,我们可以遍历PATH环境变量中的所有路径,检查每个路径下是否存在指定的可执行文件。如果找到了匹配项,则将其完整路径打印出来。

这样,我们就可以获取到Process.Start将使用的可执行文件路径了。

0
0 Comments

问题的出现原因是在C#中,通过Process.Start方法启动一个没有路径的文件时,无法确定执行文件的路径。这是因为搜索路径的顺序实际上是依赖于注册表的,所以简单地枚举PATH环境变量并不能保证产生预期的结果,特别是当当前工作目录中存在预期名称的文件时。为了可靠地获取可执行文件路径,可以调用Kernel32中的SearchPath Win32函数。

解决方法是通过P/Invoke直接调用SearchPath函数。在.NET框架中没有提供直接暴露SearchPath的函数,但可以通过P/Invoke方式来调用。下面的示例程序演示了如何使用这个函数。如果系统搜索路径中存在notepad.exe文件,将根据系统配置打印出该路径;如果不存在,则打印出"File not found"。

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());
    }
}

这个解决方法类似于"where"命令而不是"Process.Start",它返回的是"C:\Windows\System32\notepad.exe"而不是"C:\Windows\SysWOW64\notepad.exe"。然而,我相信它们在功能上是等效的,无论如何,这个答案对我来说是可行的。感谢提供答案和易于尝试的代码。

0