Nice programing

Windows 경로에 실행 파일이 있는지 확인

nicepro 2020. 12. 29. 08:26
반응형

Windows 경로에 실행 파일이 있는지 확인


프로세스를 실행하는 경우 ShellExecute(또는 .net에서 System.Diagnostics.Process.Start()) 시작할 파일 이름 프로세스가 전체 경로 일 필요는 없습니다.

메모장을 시작하려면 다음을 사용할 수 있습니다.

Process.Start("notepad.exe");

대신에

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

direcotry c:\windows\system32는 PATH 환경 변수의 일부 이기 때문 입니다.

프로세스를 실행하지 않고 PATH 변수를 구문 분석하지 않고 PATH에 파일이 있는지 어떻게 확인할 수 있습니까?

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

하지만 다음과 같은 것이 필요합니다.

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

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

BCL에서이 작업을 수행하기 위해 미리 정의 된 클래스가 있습니까?


내장 된 것이 없다고 생각하지만 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(Path.PathSeparator))
    {
        var fullPath = Path.Combine(path, fileName);
        if (File.Exists(fullPath))
            return fullPath;
    }
    return null;
}

이것은 위험하며 PATH에서 디렉토리를 검색하는 것보다 훨씬 더 많습니다. 이 시도:

 Process.Start("wordpad.exe");

실행 파일은 내 컴퓨터의 c : \ Program Files \ Windows NT \ Accessories에 저장되며 해당 디렉터리는 경로에 없습니다 .

HKCR \ Applications 및 HKLM \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ App Paths 키도 실행 파일을 찾는 데 역할을합니다. 예를 들어 64 비트 버전의 Windows에서 디렉터리 가상화가 발생하면 이와 같은 추가 지뢰가있을 것이라고 확신합니다.

이것을 더 안정적으로 만들려면 AssocQueryString ()을 pinvoke해야한다고 생각합니다. 확실하지 않고 필요가 없었습니다. 더 나은 접근 방식은 확실히 질문을하지 않는 것입니다.


좋아, 내 생각에 더 나은 방법 ...

이것은 적어도 Windows 7 / Server 2003에서 사용할 수 있는 where 명령을 사용합니다 .

public static bool ExistsOnPath(string exeName)
{
    try
    {
        using (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
    {
        using (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");
    }
}

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.


I tried out Dunc's "where" process and it works, but it's slow and resource-heavy and there's the slight danger of having an orphaned process.

I like Eugene Mala's tip about PathFindOnPath, so I fleshed that out as a complete answer. This is what I'm using for our custom in-house tool.

/// <summary>
/// Gets the full path of the given executable filename as if the user had entered this
/// executable in a shell. So, for example, the Windows PATH environment variable will
/// be examined. If the filename can't be found by Windows, null is returned.</summary>
/// <param name="exeName"></param>
/// <returns>The full path if successful, or null otherwise.</returns>
public static string GetFullPathFromWindows(string exeName)
{
    if (exeName.Length >= MAX_PATH)
        throw new ArgumentException($"The executable name '{exeName}' must have less than {MAX_PATH} characters.",
            nameof(exeName));

    StringBuilder sb = new StringBuilder(exeName, MAX_PATH);
    return PathFindOnPath(sb, null) ? sb.ToString() : null;
}

// https://docs.microsoft.com/en-us/windows/desktop/api/shlwapi/nf-shlwapi-pathfindonpathw
// https://www.pinvoke.net/default.aspx/shlwapi.PathFindOnPath
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, SetLastError = false)]
static extern bool PathFindOnPath([In, Out] StringBuilder pszFile, [In] string[] ppszOtherDirs);

// from MAPIWIN.h :
private const int MAX_PATH = 260;

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 :)]

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.

ReferenceURL : https://stackoverflow.com/questions/3855956/check-if-an-executable-exists-in-the-windows-path

반응형