.net 获取 cmd.exe 的当前工作目录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/217951/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 10:22:05  来源:igfitidea点击:

Get the current working directory for cmd.exe

.netwinapidirectorycmd

提问by Ash

How can I retrieve the current working directory of cmd.exe?

如何检索 cmd.exe 的当前工作目录?

This seems possible. For example using ProcessExplorer, select CMD.exe, right click, properties, Image tab, "Current Directory" relects the directory set using the CD or CHDIR commands.

这似乎是可能的。例如使用 ProcessExplorer,选择 CMD.exe,右键单击,属性,图像选项卡,“当前目录”反映使用 CD 或 CHDIR 命令设置的目录。

I've looked at the .NET Process and ProcessStartInfo classes (ProcessStartInfo.WorkingDirectory always returns "") and can't seem to find a way of determining this. Nothing at PInvokestands out either.

我查看了 .NET Process 和 ProcessStartInfo 类(ProcessStartInfo.WorkingDirectory 总是返回“”),但似乎找不到确定这一点的方法。PInvoke也没有什么特别突出的。

As an example I'm looking to programmatically be able to say something like: Process.GetCurrentWorkingDirectory(processID) where processID is a Windows process ID of another running process.

作为一个例子,我希望以编程方式能够说出以下内容: Process.GetCurrentWorkingDirectory(processID) 其中 processID 是另一个正在运行的进程的 Windows 进程 ID。

Is there any solution, WinAPI or .NET?

有没有解决方案,WinAPI 或 .NET?

[Update]

[更新]

Reason for asking this question:

问这个问题的原因:

I've used the "Command Prompt Explorer Bar" for a while and it's great except if I "CD" to a new directory, the current Explorer window does not also change. (ie the Sync is only 1 way from Explorer to the commmand prompt). I'm looking to make this 2 way.

我已经使用“命令提示符资源管理器栏”一段时间了,它很棒,除非我“CD”到一个新目录,当前资源管理器窗口也不会改变。(即同步只是从资源管理器到命令提示符的一种方式)。我正在寻找这两种方式。

采纳答案by janm

Untested, a possible approach:

未经测试,一种可能的方法:

Create a DLL with a DllMain that uses GetThreadStartInformation() to find the address of the buffer, and then uses GetCurrentDirectory to populate it. This should be OK, because both of those functions are in kernel32, which is always present. You will need to have some structure there to return success/failure.

创建一个带有 DllMain 的 DLL,该 DllMain 使用 GetThreadStartInformation() 查找缓冲区的地址,然后使用 GetCurrentDirectory 填充它。这应该没问题,因为这两个函数都在 kernel32 中,它始终存在。您需要在那里有一些结构来返回成功/失败。

  1. Get a handle to the cmd.exe process.
  2. Allocate some memory there (VirtualAllocEx)
  3. Put the path to your DLL in the memory. (WriteProcessMemory)
  4. Load your dll into the cmd.exe address space. (CreateRemoteThread with an entry point of LoadLibrary, the argument is the memory you allocated earlier.)
  5. WaitForSingleObject followed by GetExitCodeThread(), gives you the HMODULE of your DLL in the cmd.exe process.
  6. ReadProcessMemory to get the current directory.
  7. Unload your dll from the cmd.exe address space. CreateRemote Thread with an entry point of FreeLibrary, the argument is the HMODULE.
  8. WaitForSingleObject to wait for the DLL to unload.
  1. 获取 cmd.exe 进程的句柄。
  2. 在那里分配一些内存(VirtualAllocEx)
  3. 将 DLL 的路径放在内存中。(写入进程内存)
  4. 将您的 dll 加载到 cmd.exe 地址空间中。(CreateRemoteThread 的入口点是 LoadLibrary,参数是你之前分配的内存。)
  5. WaitForSingleObject 后跟 GetExitCodeThread(),为您提供 cmd.exe 进程中 DLL 的 HMODULE。
  6. ReadProcessMemory 获取当前目录。
  7. 从 cmd.exe 地址空间卸载您的 dll。CreateRemote Thread 的入口点是 FreeLibrary,参数是 HMODULE。
  8. WaitForSingleObject 等待 DLL 卸载。

Broad sketch: Details left as an excercise! Risks: Allocates memory in the cmd.exe address space, changes its state. Care must be taken with the functions called in DllMain.

大纲:细节留作练习!风险:在 cmd.exe 地址空间分配内存,改变其状态。必须注意在 DllMain 中调用的函数。

回答by Veynom

Do you mean the %CD% variable in a batch file ?

您的意思是批处理文件中的 %CD% 变量吗?

Like this:

像这样:

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

Try echo %CD%in a command prompt. :)

在命令提示符下尝试echo %CD%。:)

Well as this is what you need, there here is a PowerShellfunction to do it:

这正是您所需要的,这里有一个PowerShell函数可以做到这一点:

$(get-location)

Hope this helps.

希望这可以帮助。

I found it all from here.

我从这里找到了这一切。

回答by splattne

Maybe this forum entry on the Sysinternals Forumcontains a hint to the solution. Look for this in the GetProcessStrings function:

也许Sysinternals 论坛上的这个论坛条目包含解决方案的提示。在 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.

This CodeProject article "Read Environment Strings of Remote process" could be useful too.

这篇 CodeProject 文章“读取远程进程的环境字符串”也很有用。

回答by splattne

UPDATE:This is notthe solution, see the comments to this answer: "As Janm said .Modules[0].FileName (or MainModuile.FileName) gives the location of the executable running in that process. I'm looking to find the current working directory (that can be changed using the CD or CHDIR commands)."

更新:不是解决方案,请参阅对此答案的评论:“正如 Janm 所说,.Modules[0].FileName(或 MainModuile.FileName)给出了在该进程中运行的可执行文件的位置。我正在寻找当前工作目录(可以使用 CD 或 CHDIR 命令更改)。”

You could use System.Diagnostics Namespace. Here an example as C# console application. From the filename you can easily extract the Path information (System.IO.Path...).

您可以使用System.Diagnostics 命名空间。这里以 C# 控制台应用程序为例。从文件名中,您可以轻松提取路径信息(System.IO.Path...)。

You would make sure to have the permissions (run as admin) to do this.

您将确保拥有执行此操作的权限(以管理员身份运行)。

Hope this helps. Here is the working code(tested):

希望这可以帮助。这是工作代码(已测试):

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);
                }


            }

        }
    }
}

Here the the outputon my machine (I've opened four command lines):

这是我机器上的输出(我打开了四个命令行):

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

替代文字 http://img236.imageshack.us/img236/3547/processworkingdirvn4.png

回答by splattne

Try this simple environment property:

试试这个简单的环境属性:

Environment.CurrentDirectory()

Environment.CurrentDirectory()

回答by ripper234

See my answerto a similar question (by myself). I wrote a command line utility and C# wrapper to read the process environment variables. For my question (getting current dir for java), I simply read the catalina_base directory.

请参阅对类似问题的回答(由我自己)。我编写了一个命令行实用程序和 C# 包装器来读取流程环境变量。对于我的问题(获取 java 的当前目录),我只是阅读了 catalina_base 目录。

I'm not sure if this applies directly to cmd.exe. The utility provided in the Code Project article failed to work with cmd.exe.

我不确定这是否直接适用于 cmd.exe。代码项目文章中提供的实用程序无法与 cmd.exe 一起使用。