2010-10-04 14 views
47

Wenn ich einen Prozess mit ShellExecute (oder in .net mit System.Diagnostics.Process.Start()) starte, muss der zu startende Dateiname-Prozess kein vollständiger Pfad sein.Überprüfen, ob eine ausführbare Datei im Windows-Pfad existiert

Wenn ich Notizblock starten wollen, kann ich

Process.Start("notepad.exe"); 

statt

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

verwenden, da die direcotry c:\windows\system32 Teil der Umgebungsvariable PATH ist.

Wie kann ich überprüfen, ob eine Datei im PATH vorhanden ist, ohne den Prozess auszuführen und ohne die PATH-Variable zu analysieren?

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

aber ich brauche etwas wie folgt aus:

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

und

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

Gibt es eine vordefinierte Klasse, diese Aufgabe in der BCL zu tun?

+0

Während eine solche vordefinierte Klasse wäre bequem sein (oder ist praktisch, wenn es vorhanden ist) nicht es nur noch eine Zeile, um den Pfad zu erhalten, dann check exists()? Sie hätten es schneller schreiben können, als die Frage zu stellen. Besonderer Grund/Notwendigkeit? Ich frage mich nur. – mickeyf

+2

Yepp, sollte sehr einfach sein. Aber ich bin der Überzeugung, dass, wenn eine Aufgabe mit der bestehenden Bibliothek einer probammenden Sprache erledigt werden kann, ich diesen Weg vorziehe, um das Weel immer wieder neu zu erfinden. Wenn es nicht verfügbar ist, mache ich es mein eigenes. –

Antwort

44

Ich denke, es gibt nichts eingebaut, aber man konnte mit System.IO.File.Exists etwas tun:

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; 
} 
+3

Wenn Sie dies tun, schlage ich vor, diese in Extension-Methoden zu verwandeln ... http://msdn.microsoft.com/en-us/library/bb383977.aspx –

+5

@Aaron: Sind Sie sicher, Sie würden 'GetFullPath sehen 'als Erweiterungsmethode für' string'? Es würde für mich komisch klingen ... Vielleicht könnte Sinn für 'FileInfo' ... – digEmAll

+0

Ja wäre es seltsam, wenn Sie eine Zeichenfolge verwenden. Ich denke jedoch, dass es sinnvoll wäre, die obige Funktionalität von beiden Methoden in eine einzige Extension-Methode mit dem Titel ExistsOnPath einzubetten, die wie erwähnt von FileInfo abhebt. –

22

Dies ist riskant, da es viel mehr ist als nur die Verzeichnisse in der PATH-Suche. Versuchen Sie folgendes:

Process.Start("wordpad.exe"); 

Die ausführbare Datei in c gespeichert ist: \ Programme \ Windows NT \ Zubehör auf meinem Rechner, das Verzeichnis nicht auf dem Weg ist.

Die HKCR \ Programme und HKLM \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ App Pfade Schlüssel spielen auch eine Rolle beim Finden von ausführbaren Dateien. Ich bin mir ziemlich sicher, dass es zusätzliche Landminen wie diese gibt, die Verzeichnisvirtualisierung in 64-Bit-Versionen von Windows könnte Sie zum Beispiel stolpern.

Um dies zuverlässiger zu machen, denke ich, dass Sie AssocQueryString() anheften müssen. Nicht sicher, hatte nie das Bedürfnis. Der bessere Ansatz ist sicherlich, die Frage nicht stellen zu müssen.

+0

die Anwendung, die ich möchte Abfrage registriert sich selbst auf den Pfad (mysqldump.exe). Wenn nicht, oder wenn nicht installiert, möchte ich die Option zur Verwendung von mysqlbackup aus einer Windows Forms-Anwendung deaktivieren. Ich möchte den Pfad zur Datei nicht hart codieren. –

+0

Heutzutage ist es sehr selten, dass Installateure PATH modifizieren. Besonders für ein Dienstprogramm, überprüfen Sie das zuerst. Ich würde nur eine Einstellung mit Anwendungsumfang und Standard "" hier verwenden. –

+3

Dies war das Thema einer aktuellen Raymond Chen Post. Schwer zu schlagen seine Blogging-Fähigkeiten, außer ich war zuerst. Genießen Sie: http://blogs.msdn.com/b/oldnewthing/archive/2011/07/25/10189298.aspx –

2

Ich bin nach der gleichen Sache und ich denke, die beste Option, die ich jetzt habe, ist native Aufruf an CreateProcess, um einen Prozess ausgesetzt zu erstellen und für den Erfolg zu beobachten; Beenden Sie den Prozess unmittelbar danach. Das Beenden eines ausgesetzten Prozesses sollte kein Ressourcen-Bluten verursachen [Zitat benötigt :)]

Ich kann vielleicht nicht den Weg finden, der tatsächlich verwendet wurde, aber für eine einfache Anforderung wie ExistsOnPath() sollte es tun - bis es ein gibt bessere Lösung.

9

Ok, ein besserer Weg, denke ich ...

Dies verwendet die wo Befehl, die 2003 zumindest unter Windows 7/Server verfügbar:

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"); 
    } 
} 
Verwandte Themen