获取 cmd.exe 的当前工作目录
Posted
技术标签:
【中文标题】获取 cmd.exe 的当前工作目录【英文标题】:Get the current working directory for cmd.exe 【发布时间】:2010-09-18 02:12:38 【问题描述】:如何?
这似乎是可能的。例如使用 ProcessExplorer,选择 CMD.exe,右键单击,属性,图像选项卡,“当前目录”反映使用 CD 或 CHDIR 命令设置的目录。
我查看了 .NET Process 和 ProcessStartInfo 类(ProcessStartInfo.WorkingDirectory 总是返回“”),但似乎找不到确定这一点的方法。 PInvoke 也没有什么突出的。
作为一个例子,我希望能够以编程方式说出类似的内容: Process.GetCurrentWorkingDirectory(processID) 其中 processID 是另一个正在运行的进程的 Windows 进程 ID。
有什么解决方案,WinAPI 还是 .NET?
[更新]
问这个问题的原因:
我已经使用“命令提示符资源管理器栏”有一段时间了,它很棒,除非我“CD”到一个新目录,当前的资源管理器窗口也不会改变。 (即同步只是从资源管理器到命令提示符的一种方式)。我正在寻找这两种方式。
【问题讨论】:
您要求的内容听起来很可疑。一个进程不应干扰另一个进程,除非您正在测试 (QA) 或调试。将其用于“生产”或商业软件是不好的,因为它需要特权。你的产品不会得到。那么,你想完成什么? 公平的问题。没有什么鱼腥味。我已经使用“命令提示符资源管理器栏”有一段时间了,它很棒,除非我“CD”到一个新目录,当前的资源管理器窗口也不会改变。 (即同步只是从资源管理器到命令提示符的一种方式)。我正在寻找这两种方式。 我需要这个用于测试目的 - 我想杀死一个 java Tomcat 进程,并用它来区分它与其他方式。 【参考方案1】:未经测试,一种可能的方法:
使用 DllMain 创建一个 DLL,该 DllMain 使用 GetThreadStartInformation() 来查找缓冲区的地址,然后使用 GetCurrentDirectory 填充它。这应该没问题,因为这两个函数都在 kernel32 中,它始终存在。你需要有一些结构来返回成功/失败。
-
获取 cmd.exe 进程的句柄。
在那里分配一些内存 (VirtualAllocEx)
将 DLL 的路径放入内存中。 (WriteProcessMemory)
将您的 dll 加载到 cmd.exe 地址空间。 (CreateRemoteThread,入口点为LoadLibrary,参数是你之前分配的内存。)
WaitForSingleObject 后跟 GetExitCodeThread(),在 cmd.exe 进程中为您提供 DLL 的 HMODULE。
ReadProcessMemory 获取当前目录。
从 cmd.exe 地址空间卸载您的 dll。 CreateRemote Thread,入口点为 FreeLibrary,参数为 HMODULE。
WaitForSingleObject 等待 DLL 卸载。
粗略的草图:细节留作练习!风险:在 cmd.exe 地址空间分配内存,改变其状态。必须小心在 DllMain 中调用的函数。
【讨论】:
感谢您的详细回复。它看起来确实比查看 GetProcessStrings() 更复杂,但如果这不起作用,我可能会试一试。 没问题。 GetProcessStrings 方法可能适用于 cmd.exe 特殊情况,但我不确定。见上面我的cmets。我的方法适用于不修改环境变量的进程(如果它们更改目录)。 基本上,您不应该在 DllMain() 中执行任何操作,除了 TlsAlloc() 可能,因为“加载程序锁”。只需在谷歌上搜索“loader lock dllmain”,原因有很多,为什么这是一个坏主意。 请注意我的评论:“这应该没问题,因为这两个函数都在 kernel32 中......” 您必须小心不要触发 DLL 加载,否则您将遇到加载程序锁定问题。你受到了很大的限制,但这并不意味着你被 TlsAlloc 限制在任何事情上。【参考方案2】:您是指批处理文件中的 %CD% 变量吗?
像这样:
set OLDDIR=%CD%
.. do stuff ..
chdir /d %OLDDIR% &rem restore current directory
在命令提示符下尝试 echo %CD%。 :)
这正是你所需要的,这里有一个 PowerShell 函数可以做到这一点:
$(get-location)
希望这会有所帮助。
我都是从here找到的。
【讨论】:
我希望以编程方式能够说出类似这样的话: Process.GetCurrentWorkingDirectory(processID) 其中 processID 是 Windows 进程 ID。【参考方案3】:也许这个forum entry on the Sysinternals Forum 包含解决方案的提示。在 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.
这篇 CodeProject 文章“Read Environment Strings of Remote process”也很有用。
【讨论】:
谢谢,我会研究 GetProcessStrings。我认为这可能与此有关。 这种方法可能出现的问题: 1. 读取目标进程的 env 和修改它的目标进程之间的竞争。 2. Windows 版本之间的幻数变化。 3. %CD% 在 cmd.exe 中似乎很特殊,可能不是 envvar。例如。尝试“设置 CD=blah”;它在 cd 上停止变化。【参考方案4】:更新:这不是解决方案,请参阅此答案的 cmets:“正如 Janm 所说 .Modules[0].FileName(或 MainModuile.FileName) 给出 运行的可执行文件的位置 那个过程。我正在寻找 当前工作目录(可以是 使用 CD 或 CHDIR 更改 命令)。”
您可以使用 System.Diagnostics 命名空间。这里以 C# 控制台应用程序为例。从文件名中您可以轻松提取路径信息(System.IO.Path...)。
您将确保拥有执行此操作的权限(以管理员身份运行)。
希望这会有所帮助。这是工作代码(已测试):
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);
这里是我机器上的输出(我打开了四个命令行):
alt text http://img236.imageshack.us/img236/3547/processworkingdirvn4.png
【讨论】:
那不行!这给出了模块的目录,而不是进程的当前目录。在您的测试中,其中一行应该是 C:\Users\stefan。 正如 Janm 所说,.Modules[0].FileName(或 MainModuile.FileName)给出了在该进程中运行的可执行文件的位置。我正在寻找当前的工作目录(可以使用 CD 或 CHDIR 命令更改)。 天啊!如果您研究然后忘记核心问题,就会发生这种情况。我道歉...【参考方案5】:试试这个简单的环境属性:
Environment.CurrentDirectory()
【讨论】:
【参考方案6】:请参阅my answer 到类似的问题(我自己)。我编写了一个命令行实用程序和 C# 包装器来读取进程环境变量。对于我的问题(获取 java 的当前目录),我只需阅读 catalina_base 目录。
我不确定这是否直接适用于 cmd.exe。代码项目文章中提供的实用程序无法与 cmd.exe 一起使用。
【讨论】:
以上是关于获取 cmd.exe 的当前工作目录的主要内容,如果未能解决你的问题,请参考以下文章
如何获取 Xcode Playground 的当前工作目录?