2008-10-20 14 views
15

Comment puis-je récupérer le répertoire de travail actuel de cmd.exe?Obtenez le répertoire de travail actuel pour cmd.exe

Cela semble possible. Par exemple, en utilisant ProcessExplorer, sélectionnez CMD.exe, cliquez avec le bouton droit de la souris, propriétés, onglet Image, "Répertoire actuel" reliant le jeu de répertoires à l'aide des commandes CD ou CHDIR.

J'ai regardé les classes .NET Process et ProcessStartInfo (ProcessStartInfo.WorkingDirectory renvoie toujours "") et n'arrive pas à trouver un moyen de le déterminer. Rien au PInvoke se démarque non plus.

Par exemple, je cherche à dire par programme quelque chose comme: Process.GetCurrentWorkingDirectory (processID) où processID est un identifiant de processus Windows d'un autre processus en cours.

Existe-t-il une solution, WinAPI ou .NET?

[Mise à jour]

Raison de poser cette question:

Je l'ai utilisé le « Command Prompt Explorateur barre » pendant un certain temps et il est super, sauf si je « CD » dans un nouveau répertoire, la La fenêtre actuelle de l'Explorateur ne change pas non plus. (c'est-à-dire que la synchronisation est seulement 1 chemin de l'explorateur à l'invite de commmand). Je cherche à faire 2 façons.

+0

Ce que vous demandez des sons de poisson. Un processus ne doit pas interférer avec un autre à moins que vous soyez en train de tester (QA) ou de déboguer. L'utiliser pour la "production" ou un logiciel commercial est mauvais car il nécessite des privilèges. Ce que votre produit ne recevra pas. Alors, qu'essayez-vous d'accomplir? – jim

+0

Juste question. Rien de poisson. J'ai utilisé le "Command Prompt Explorer Bar" pendant un moment et c'est génial sauf si je "CD" à un nouveau répertoire, la fenêtre actuelle de l'Explorateur ne change pas non plus.(c'est-à-dire que la synchronisation est seulement 1 chemin de l'explorateur à l'invite de commmand). Je cherche à faire 2 façons. – Ash

+0

J'ai besoin de cela à des fins de test - Je veux tuer un processus java Tomcat, et l'utiliser comme un moyen de le distinguer des autres moyens. – ripper234

Répondre

5

Untested, une approche possible:

Créer une DLL avec un DllMain qui utilise GetThreadStartInformation() pour trouver l'adresse du tampon, et utilise ensuite GetCurrentDirectory pour le remplir. Cela devrait être OK, car ces deux fonctions sont dans kernel32, qui est toujours présent. Vous aurez besoin d'une structure pour retourner le succès/l'échec.

  1. Obtenez un handle pour le processus cmd.exe. Allouer de la mémoire là (VirtualAllocEx)
  2. Mettez le chemin d'accès à votre DLL dans la mémoire. (WriteProcessMemory)
  3. Chargez votre DLL dans l'espace adresse cmd.exe. (CreateRemoteThread avec un point d'entrée de LoadLibrary, l'argument est la mémoire que vous avez allouée précédemment.)
  4. WaitForSingleObject suivi de GetExitCodeThread(), vous donne le HMODULE de votre DLL dans le processus cmd.exe.
  5. ReadProcessMemory pour obtenir le répertoire en cours.
  6. Déchargez votre DLL de l'espace adresse cmd.exe. CreateRemote Thread avec un point d'entrée de FreeLibrary, l'argument est le HMODULE.
  7. WaitForSingleObject d'attendre le déchargement de la DLL.

Schéma général: Détails laissés à titre d'exercice! Risques: Alloue de la mémoire dans l'espace d'adressage cmd.exe, change son état. Des précautions doivent être prises avec les fonctions appelées dans DllMain.

+0

Merci pour la réponse détaillée. Cela semble un peu plus complexe que de regarder GetProcessStrings(), mais je pourrais essayer si ça ne marche pas. – Ash

+0

Pas de problème. L'approche GetProcessStrings peut fonctionner dans le cas particulier de cmd.exe, mais je ne suis pas sûr. Voir mes commentaires ci-dessus. Mon approche fonctionnera avec les processus qui ne modifient pas les variables d'environnement lorsqu'ils changent de répertoire. – janm

+0

Fondamentalement, vous ne devriez rien faire dans DllMain() sauf pour TlsAlloc() peut-être, à cause du "loader lock". Juste google pour "loader lock dllmain" pour beaucoup de raisons pour lesquelles c'est une mauvaise idée. –

5

Voulez-vous dire la variable% CD% dans un fichier batch?

Comme ceci:

set OLDDIR=%CD% 
.. do stuff .. 
chdir /d %OLDDIR% &rem restore current directory 

Essayez echo% CD% dans une invite de commande. :)

ainsi que cela est ce que vous avez besoin, il est ici une fonction PowerShell pour le faire:

$(get-location) 

Hope this helps. J'ai trouvé tout cela à here.

+0

Je cherche à pouvoir programmer quelque chose comme: Process.GetCurrentWorkingDirectory (processID) où processID est un identifiant de processus Windows. – Ash

2

MISE À JOUR: Ce est pas la solution, voir les commentaires à cette réponse: « Comme Janm dit .Modules [0] .FileName (ou MainModuile.FileName) donne l'emplacement de le fichier exécutable dans que je cherche à trouver répertoire de travail actuel (qui peut être modifié en utilisant les commandes CD ou CHDIR ). "

Vous pouvez utiliser System.Diagnostics, espace de noms. Voici un exemple en tant qu'application de console C#. A partir du nom de fichier, vous pouvez facilement extraire les informations de chemin (System.IO.Path ...).

Vous devez vous assurer d'avoir les permissions (exécutées en tant qu'administrateur) pour ce faire.

Espérons que cela aide. Voici le code de travail (testé):

using System; 
using System.Diagnostics; 
using System.IO; 

namespace Test 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Process[] procList = Process.GetProcessesByName("cmd"); 

      string sFileName; 

      for (int i = 0; i < procList.Length; i++) 
      { 
       Console.Write(procList[i].Id); 
       Console.Write(" "); 

       try 
       { 
        sFileName = procList[i].Modules[0].FileName; 
        Console.Write("("); 
        Console.Write(Path.GetFileName(sFileName)); 
        Console.Write("): "); 
        Console.WriteLine(Path.GetDirectoryName(sFileName)); 
       } 
       catch (Exception ex) 
       { 
        // catch "Access denied" etc. 
        Console.WriteLine(ex.Message); 
       } 


      } 

     } 
    } 
} 

Voici les sortie sur ma machine (je l'ai ouvert quatre lignes de commande):

alt text http://img236.imageshack.us/img236/3547/processworkingdirvn4.png

+0

Ça ne marche pas! Cela donne le répertoire du module, pas le répertoire courant du processus. Dans votre test, l'une des lignes aurait dû être C: \ Users \ stefan. – janm

+0

Comme Janm a dit .Modules [0] .FileName (ou MainModuile.FileName) donne l'emplacement de l'exécutable en cours d'exécution dans ce processus. Je cherche le répertoire de travail actuel (qui peut être changé en utilisant les commandes CD ou CHDIR). – Ash

+0

D'oh! Cela arrive, si vous faites des recherches et oubliez ensuite la question centrale. Je m'excuse ... – splattne

5

Peut-être que ce forum entry on the Sysinternals Forum contient un indice à la solution. Recherchez ce dans la fonction GetProcessStrings:

// Get Command Line Block 

// At offset 0x00020498 is the process current directory followed by 

// the system PATH. After that is the process full command line, followed 

// by the exe name and the windows station it's running on. 

Cet article CodeProject "Read Environment Strings of Remote process" pourrait être utile aussi.

+0

Merci, je vais regarder dans GetProcessStrings. Je pensais que ça pouvait être quelque chose à voir avec ça. – Ash

+0

Problèmes possibles avec cette approche: 1. Courses entre la lecture de l'env du processus cible et le processus cible le modifiant. 2. Les numéros magiques changent entre les versions de Windows. 3.% CD% semble être spécial dans cmd.exe et peut ne pas être un envvar. par exemple. Essayez "set CD = blah"; ça arrête de changer sur cd. – janm

0

Voir my answer à une question similaire (par moi-même). J'ai écrit un utilitaire de ligne de commande et un wrapper C# pour lire les variables d'environnement de processus. Pour ma question (obtenir le répertoire courant pour java), je lis simplement le répertoire catalina_base.

Je ne suis pas sûr si cela s'applique directement à cmd.exe. L'utilitaire fourni dans l'article Code Project n'a pas pu fonctionner avec cmd.exe.

1

Essayez cette simple propriété d'environnement:

Environment.CurrentDirectory()