2010-10-04 6 views
47

Si j'exécute un processus avec ShellExecute (ou .net avec System.Diagnostics.Process.Start()), le nom du processus de démarrage n'a pas besoin d'être un chemin d'accès complet.Vérifiez si un exécutable existe dans le chemin d'accès Windows

Si je veux commencer le bloc-notes, je peux utiliser

Process.Start("notepad.exe"); 

au lieu de

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

parce que le direcotry c:\windows\system32 fait partie de la variable d'environnement PATH.

Comment puis-je vérifier si un fichier existe sur le PATH sans exécuter le processus et sans analyser la variable PATH?

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

mais je besoin de quelque chose comme ceci:

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

et

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

Y at-il une classe prédéfinie pour effectuer cette tâche disponible dans le BCL?

+0

Bien qu'une telle classe prédéfinie serait pratique (ou est pratique, si elle existe) n'est pas il seulement une ligne de plus pour obtenir le chemin puis vérifier existe()? Vous auriez pu l'écrire plus rapidement que de poser la question. Raison spéciale/besoin? Je me demandais juste. – mickeyf

+2

Yepp, devrait être très facile. Mais ma conviction est que, si une tâche peut être accomplie avec la bibliothèque existante d'un langage probramming, je préfère de cette façon réinventer la weel encore et encore. S'il n'y a pas de smth disponible, je le fais moi-même. –

Répondre

44

Je pense qu'il ya intégré rien, mais vous pouvez faire quelque chose comme ça avec 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; 
} 
+3

Si vous allez faire cela, je suggère de les transformer en méthodes d'extension ... http: //msdn.microsoft.com/en-us/library/bb383977.aspx –

+5

@Aaron: Êtes-vous sûr de voir 'GetFullPath 'en tant que méthode d'extension pour' string'? Cela me semblerait étrange ... Peut-être pourrait avoir un sens pour 'FileInfo' ... – digEmAll

+0

Oui, il serait étrange lors de l'utilisation d'une chaîne. Cependant, je pense qu'il serait logique d'intégrer la fonctionnalité ci-dessus des deux méthodes dans une seule méthode d'extension intitulée ExistsOnPath qui se bloque FileInfo comme vous l'avez mentionné. –

22

Ceci est risqué, il y a beaucoup plus à ce que la simple recherche les répertoires dans le chemin. Essayez ceci:

Process.Start("wordpad.exe"); 

L'exécutable est stocké dans c: \ Program Files \ Windows NT \ Accessoires sur ma machine, ce répertoire est pas sur le chemin.

Les clés HKCR \ Applications et HKLM \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ App jouent également un rôle dans la recherche d'exécutables. Je suis à peu près certain qu'il existe d'autres mines terrestres comme celle-ci, la virtualisation des répertoires dans les versions 64 bits de Windows pourrait vous faire trébucher par exemple.

Pour rendre cela plus fiable, je pense que vous devez faire une pin-up AssocQueryString(). Pas sûr, n'a jamais eu le besoin. La meilleure approche est certainement de ne pas avoir à poser la question.

+0

l'application que je veux La requête s'enregistre sur le chemin (mysqldump.exe). Sinon, ou si pas installé, je veux désactiver l'option pour utiliser mysqlbackup à partir d'une application Windows Forms. Je ne veux juste pas coder en dur le chemin vers le fichier. –

+0

Il est * très * rare de nos jours que les installateurs modifient le PATH. Surtout pour un utilitaire, vérifiez d'abord. Je voudrais juste utiliser un paramètre avec la portée de l'application et par défaut à "" ici. –

+3

Ceci a fait l'objet d'un récent message de Raymond Chen. Difficile de battre ses compétences de blogueur, autre que j'étais premier. Enjoy: http://blogs.msdn.com/b/oldnewthing/archive/2011/07/25/10189298.aspx –

2

Je suis après la même chose et je pense que la meilleure option que j'ai maintenant est d'utiliser l'appel natif à CreateProcess pour créer un processus suspendu et regarder pour le succès; terminer le processus immédiatement après. Mettre fin à un processus suspendu ne doit pas entraîner de saignement de ressource [la citation nécessaire :)]

Je ne suis peut-être pas en mesure de comprendre le chemin qui a réellement été utilisé, mais pour une exigence simple comme ExistsOnPath() il devrait faire - jusqu'à ce qu'il y ait un meilleure solution.

9

Ok, une meilleure façon je pense ...

Il utilise la commande , qui est disponible au moins sur 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"); 
    } 
} 
Questions connexes