检查Windows路径中是否存在可执行文件

时间:2021-01-19 06:58:36

If I run a process with ShellExecute (or in .net with System.Diagnostics.Process.Start()) the filename process to start doesn't need to be a full path.

如果我使用ShellExecute(或使用System.Diagnostics.Process.Start()的.net)运行进程,则启动的文件名进程不需要是完整路径。

If I want to start notepad, I can use

如果我想开始记事本,我可以使用

Process.Start("notepad.exe");

instead of

代替

Process.Start(@"c:\windows\system32\notepad.exe");

because the direcotry c:\windows\system32 is part of the PATH environment variable.

因为direcotry c:\ windows \ system32是PATH环境变量的一部分。

how can I check if a file exists on the PATH without executing the process and without parsing the PATH variable?

如何在不执行进程且没有解析PATH变量的情况下检查PATH上是否存在文件?

System.IO.File.Exists("notepad.exe"); // returns false
(new System.IO.FileInfo("notepad.exe")).Exists; // returns false

but I need something like this:

但是我需要这样的东西:

System.IO.File.ExistsOnPath("notepad.exe"); // should return true

and

System.IO.File.GetFullPath("notepad.exe"); // (like unix which cmd) should return
                                           // c:\windows\system32\notepad.exe

Is there a predefined class to do this task available in the BCL?

是否有预定义的类可以在BCL中执行此任务?

5 个解决方案

#1


45  

I think there's nothing built-in, but you could do something like this with System.IO.File.Exists:

我认为没有任何内置功能,但您可以使用System.IO.File.Exists执行类似的操作:

public static bool ExistsOnPath(string fileName)
{
    return GetFullPath(fileName) != null;
}

public static string GetFullPath(string fileName)
{
    if (File.Exists(fileName))
        return Path.GetFullPath(fileName);

    var values = Environment.GetEnvironmentVariable("PATH");
    foreach (var path in values.Split(';'))
    {
        var fullPath = Path.Combine(path, fileName);
        if (File.Exists(fullPath))
            return fullPath;
    }
    return null;
}

#2


22  

This is risky, there's a lot more to it than just searching the directories in the PATH. Try this:

这是有风险的,除了在PATH中搜索目录之外还有很多其他内容。尝试这个:

 Process.Start("wordpad.exe");

The executable is stored in c:\Program Files\Windows NT\Accessories on my machine, that directory is not on the path.

可执行文件存储在我的机器上的c:\ Program Files \ Windows NT \ Accessories中,该目录不在路径上。

The HKCR\Applications and HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths keys also play a role in finding executables. I'm fairly sure there are additional land-mines like this around, directory virtualization in 64-bit versions of Windows could trip you up for example.

HKCR \ Applications和HKLM \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ App Paths键也在查找可执行文件中发挥作用。我很确定还有这样的地雷,64位版本的Windows中的目录虚拟化可能会让你失望。

To make this more reliable I think you need to pinvoke AssocQueryString(). Not sure, never had the need. The better approach is certainly to not have to ask the question.

为了使这更可靠,我认为你需要pinvoke AssocQueryString()。不确定,从来没有必要。更好的方法当然是不必提问。

#3


10  

Ok, a better way I think...

好的,我认为更好的方式......

This uses the where command, which is available at least on Windows 7/Server 2003:

这使用where命令,该命令至少在Windows 7 / Server 2003上可用:

public static bool ExistsOnPath(string exeName)
{
    try
    { 
        Process p = new Process();
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.FileName = "where";
        p.StartInfo.Arguments = exeName;
        p.Start();
        p.WaitForExit();
        return p.ExitCode == 0; 
    }
    catch(Win32Exception)
    {
        throw new Exception("'where' command is not on path");
    }   
}


public static string GetFullPath(string exeName)
{
    try
    { 
        Process p = new Process();
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.FileName = "where";
        p.StartInfo.Arguments = exeName;
        p.StartInfo.RedirectStandardOutput = true;
        p.Start();
        string output = p.StandardOutput.ReadToEnd();
        p.WaitForExit();

        if (p.ExitCode != 0)
            return null;

        // just return first match
        return output.Substring(0, output.IndexOf(Environment.NewLine));
    }
    catch(Win32Exception)
    {
        throw new Exception("'where' command is not on path");
    }   
}

#4


2  

I'm after the same thing and I think the best option that I have right now is to use native call to CreateProcess to create a process suspended and watch for success; terminating the process immediately afterward. Terminating a suspended process should not incur any resource bleeding [citation needed :)]

我正在做同样的事情,我认为我现在最好的选择是使用对CreateProcess的本地调用来创建一个暂停的进程并注意成功;之后立即终止该过程。终止暂停的过程不应导致任何资源流失[引证需要:)]

I may not be able to figure out the path that actually got used but for a simple requirement as ExistsOnPath() it should do - till there's a better solution.

我可能无法弄清楚实际使用的路径,但是对于一个简单的要求,ExistsOnPath()它应该做 - 直到有一个更好的解决方案。

#5


1  

Accepted answer states that there is nothing build-in, but this is not true. There is a standard WinAPI PathFindOnPath for doing this, it is available since Windows 2000.

接受的答案表明没有任何内置,但事实并非如此。有一个标准的WinAPI PathFindOnPath用于执行此操作,它从Windows 2000开始可用。

#1


45  

I think there's nothing built-in, but you could do something like this with System.IO.File.Exists:

我认为没有任何内置功能,但您可以使用System.IO.File.Exists执行类似的操作:

public static bool ExistsOnPath(string fileName)
{
    return GetFullPath(fileName) != null;
}

public static string GetFullPath(string fileName)
{
    if (File.Exists(fileName))
        return Path.GetFullPath(fileName);

    var values = Environment.GetEnvironmentVariable("PATH");
    foreach (var path in values.Split(';'))
    {
        var fullPath = Path.Combine(path, fileName);
        if (File.Exists(fullPath))
            return fullPath;
    }
    return null;
}

#2


22  

This is risky, there's a lot more to it than just searching the directories in the PATH. Try this:

这是有风险的,除了在PATH中搜索目录之外还有很多其他内容。尝试这个:

 Process.Start("wordpad.exe");

The executable is stored in c:\Program Files\Windows NT\Accessories on my machine, that directory is not on the path.

可执行文件存储在我的机器上的c:\ Program Files \ Windows NT \ Accessories中,该目录不在路径上。

The HKCR\Applications and HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths keys also play a role in finding executables. I'm fairly sure there are additional land-mines like this around, directory virtualization in 64-bit versions of Windows could trip you up for example.

HKCR \ Applications和HKLM \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ App Paths键也在查找可执行文件中发挥作用。我很确定还有这样的地雷,64位版本的Windows中的目录虚拟化可能会让你失望。

To make this more reliable I think you need to pinvoke AssocQueryString(). Not sure, never had the need. The better approach is certainly to not have to ask the question.

为了使这更可靠,我认为你需要pinvoke AssocQueryString()。不确定,从来没有必要。更好的方法当然是不必提问。

#3


10  

Ok, a better way I think...

好的,我认为更好的方式......

This uses the where command, which is available at least on Windows 7/Server 2003:

这使用where命令,该命令至少在Windows 7 / Server 2003上可用:

public static bool ExistsOnPath(string exeName)
{
    try
    { 
        Process p = new Process();
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.FileName = "where";
        p.StartInfo.Arguments = exeName;
        p.Start();
        p.WaitForExit();
        return p.ExitCode == 0; 
    }
    catch(Win32Exception)
    {
        throw new Exception("'where' command is not on path");
    }   
}


public static string GetFullPath(string exeName)
{
    try
    { 
        Process p = new Process();
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.FileName = "where";
        p.StartInfo.Arguments = exeName;
        p.StartInfo.RedirectStandardOutput = true;
        p.Start();
        string output = p.StandardOutput.ReadToEnd();
        p.WaitForExit();

        if (p.ExitCode != 0)
            return null;

        // just return first match
        return output.Substring(0, output.IndexOf(Environment.NewLine));
    }
    catch(Win32Exception)
    {
        throw new Exception("'where' command is not on path");
    }   
}

#4


2  

I'm after the same thing and I think the best option that I have right now is to use native call to CreateProcess to create a process suspended and watch for success; terminating the process immediately afterward. Terminating a suspended process should not incur any resource bleeding [citation needed :)]

我正在做同样的事情,我认为我现在最好的选择是使用对CreateProcess的本地调用来创建一个暂停的进程并注意成功;之后立即终止该过程。终止暂停的过程不应导致任何资源流失[引证需要:)]

I may not be able to figure out the path that actually got used but for a simple requirement as ExistsOnPath() it should do - till there's a better solution.

我可能无法弄清楚实际使用的路径,但是对于一个简单的要求,ExistsOnPath()它应该做 - 直到有一个更好的解决方案。

#5


1  

Accepted answer states that there is nothing build-in, but this is not true. There is a standard WinAPI PathFindOnPath for doing this, it is available since Windows 2000.

接受的答案表明没有任何内置,但事实并非如此。有一个标准的WinAPI PathFindOnPath用于执行此操作,它从Windows 2000开始可用。