Windows 注册表中的“NoWorkingDirectory”字符串值是什么意思?

Windows 注册表中的“NoWorkingDirectory”字符串值是什么意思?

当创建用户定义的右键单击菜单项时,Windows 注册表中通常会使用空的“NoWorkingDirectory”字符串值。例如,为了能够在 Windows 资源管理器中右键单击文件夹背景时打开 PowerShell(而不是右键单击文件夹本身,在这种情况下不使用“NoWorkingDirectory”):

[HKEY_CLASSES_ROOT\Directory\Background\shell\powershell]
@="Open PowerShell Here"
"NoWorkingDirectory"=""

[HKEY_CLASSES_ROOT\Directory\Background\shell\powershell\command]
@="C:\\\\Windows\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe -NoExit -Command Set-Location -LiteralPath '%V'"

但是我不清楚这个值的实际用途。我发现的所有样本中它总是空的。它到底代表什么?

答案1

WorkingDirectory 是 System.Diagnostics.ProcessStartInfo 的一个属性,当您单击右键时,您将启动一个新进程,此设置允许您启动进程,而无需将当前目录变为“工作目录”。然后,它默认为正在运行的命令的 System32。

因此,如果您不希望右键单击的位置在脚本运行期间成为环境路径的一部分,则可以使用“NoWorkingDirectory”。在 90% 的情况下,该设置毫无用处,除非您在多个路径位置都有类似命名的文件,否则除非指定“NoWorkingDirectory”,否则可能会变得棘手。

请点击此处查看更多详细信息。

http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.workingdirectory%28v=vs.110%29.aspx

答案2

对于没有任何编程技能的 Windows 用户的简短回答

通过右键单击目录或文件(在Windows 文件资源管理器窗口)将启动可执行文件,并为该可执行文件设置当前工作目录,

  1. 包含所单击目录/文件的目录(不存在注册表值NoWorkingDirectory
  2. 目录C:\Windows\System32,或者更准确地说是Windows 注册表中存在的%SystemRoot%\system32注册表值。NoWorkingDirectory

许多编码不佳的可执行文件和脚本需要将第一种变体的当前工作目录设置为包含要处理的目录或文件的目录。这就是为什么第一种变体是默认的。

在某些情况下,第一种变体会导致不需要的行为,例如在cmd.exe运行批处理脚本时,该脚本将单击的目录/文件名作为参数传递,并使用其引用目录/文件UNC 路径

Windows 注册表中存在的第二种变体NoWorkingDirectory可用于所有真正编码良好的可执行文件和脚本。


对于对细节感兴趣的 Windows 用户和程序员来说,答案很长

Windows 内核库包含以下函数创建进程它被大多数其他可执行文件使用,这些explorer.exe可执行文件能够运行另一个可执行文件,无需或带有创业信息结构来启动 Windows 可执行文件。该函数的参数之一CreateProcesslpCurrentDirectory– 指向包含目录路径的字符串的长指针,该目录路径用于设置为要创建的进程的当前工作目录。指针值也可以为空,以指示CreateProcess使用调用进程的当前目录CreateProcess作为要创建的进程的当前工作目录。大多数可执行文件调用时都会CreateProcess使用空指针作为函数参数lpCurrentDirectory

Windows 文件资源管理器( explorer.exe) 调用CreateProcess包含目录/文件的目录的目录路径,用户使用辅助(通常是右)指针设备(通常是鼠标)按钮单击该目录/文件并在打开的上下文菜单中单击该项目,从而以单击的目录/文件名作为参数启动可执行文件。

注册表字符串值改变了函数参数的调用NoWorkingDirectory方式。当前目录始终是具有此注册表字符串值的 Windows 系统目录,即在大多数 Windows 机器上扩展为的目录。explorer.exeCreateProcesslpCurrentDirectory%SystemRoot%\System32C:\Windows\System32

如下所示:

请打开命令提示符窗口并运行以下无害的命令:

reg add "HKCU\Software\Classes\Directory\shell\NoWorkingDirectoryTest" /ve /d "No working directory test"
reg add "HKCU\Software\Classes\Directory\shell\NoWorkingDirectoryTest\command" /ve /d "cmd.exe /D /C C:\Temp\DirTest\DirTest.cmd \"%V"\""

md "C:\Temp\DirTest"
echo @echo Current directory is: ^"%^CD%^">"C:\Temp\DirTest\DirTest.cmd"
echo @echo Batch file started with: %0 %*>>"C:\Temp\DirTest\DirTest.cmd"
echo @echo Command line used is: %^CMDCMDLINE%>>"C:\Temp\DirTest\DirTest.cmd"
echo @pause>>"C:\Temp\DirTest\DirTest.cmd"

这两个reg命令行添加到 Windows 注册表:

[HKEY_CURRENT_USER\Software\Classes\Directory\shell\NoWorkingDirectoryTest]
@="No working directory test"

[HKEY_CURRENT_USER\Software\Classes\Directory\shell\NoWorkingDirectoryTest\command]
@="cmd.exe /D /C \"C:\\Temp\\DirTest\\DirTest.cmd\" \"%V\""

该命令md和四条命令行使用以下命令行echo创建批处理文件:C:\Temp\DirTest\DirTest.cmd

@echo Batch file started with: %0 %*
@echo Current directory is: "%CD%"
@echo Command line used is: %CMDCMDLINE%
@pause

现在开始Windows 文件资源管理器尚未运行,并在左侧文件夹树中浏览到目录C:\Windows\System32\drivers。单击鼠标右键在右侧在文件夹上etc,然后在打开的上下文菜单中单击该项目无工作目录测试刚刚添加到 Windows 注册表中。

刚刚创建的批处理文件被执行并显示在控制台窗口中:

Current directory is: "C:\Windows\System32\drivers"
Batch file started with: C:\Temp\DirTest\DirTest.cmd "C:\Windows\System32\drivers\etc"
Command line used is: "cmd.exe" /D /C C:\Temp\DirTest\DirTest.cmd "C:\Windows\System32\drivers\etc"

第一行输出显示了CreateProcesson根据父进程cmd.exe传递的字符串从四个参数开始设置的当前目录。可以看出lpCurrentDirectoryexplorer.exeWindows 文件资源管理器CreateProcess在这种情况下,使用C:\Windows\System32\drivers当前工作目录路径进行调用。

第二行输出显示批处理文件使用哪些参数启动,包括参数 0,它是用于引用添加到 Windows 注册表的批处理文件的字符串。

第三行输出本身是如何被cmd.exe启动的,尽管存储在注册表中而没有被 包围,但被 启动时是如何被 包围的。explorer.exeCreateProcesscmd.exe""explorer.exe

注册表字符串值NoWorkingDirectory目前不存在。这就是为什么当前工作目录cmd.exe设置为右键单击时C:\Windows\System32\drivers的当前目录的原因explorer.exe在右侧etc在当前活动文件夹所在的文件夹中Windows 文件资源管理器存在C:\Windows\System32\drivers

现在右键单击Windows 文件资源管理器 在左侧C:\Windows在当前活动文件夹静止时,在目录的文件夹树中C:\Windows\System32\drivers,左键单击上下文菜单中的项目无工作目录测试

又打开了一个控制台窗口,其中显示以下几行:

Current directory is: "C:\WINDOWS\system32"
Batch file started with: C:\Temp\DirTest\DirTest.cmd "C:\Windows"
Command line used is: "cmd.exe" /D /C C:\Temp\DirTest\DirTest.cmd "C:\Windows"

第二行和第三行符合预期。但当前目录既不是 也不C:\Windows\System32\driversC:\也不是C:\Windows。因此可以看出,当用户在左侧文件夹树中的目录或虚拟 shell 文件夹上单击鼠标右键时,使用包含目录的目录启动可执行文件并不总是按预期工作。

还可以看到,当前工作目录路径甚至不是 Windows 系统目录的真实目录路径,因为在这种情况下会显示C:\Windows\System32而不是。请注意某些字母的大小写差异。这里真正使用的 Windows 系统目录路径是键下的C:\WINDOWS\system32注册表值的连接,该键具有字符串值与固定字符串 的连接。真正的目录路径是。SystemRootHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersionC:\WINDOWS\system32C:\Windows\System32

批处理文件或可执行文件或任何其他旨在由explorer.exe或类似程序通过上下文菜单项执行的脚本应始终考虑到当前目录可能与包含传递的目录/文件名的目录完全不同。进程调用CreateProcess定义了哪个目录是所创建进程的当前目录。

cmd.exe在当前目录路径为 UNC 路径的情况下启动时,它具有特殊行为。在这种情况下,它将当前目录更改为%SystemRoot%(Windows 目录)并输出以下信息:

\\ComputerName\SharedFolder\Resource
CMD.EXE 以上述路径作为当前目录启动。
不支持 UNC 路径。默认为 Windows 目录。

这样做是cmd.exe为了向下兼容,因为许多可执行文件在当前目录路径上不能正确运行,而这个路径不是以驱动器号和冒号开头的。

可以在命令提示符窗口中运行:

reg add "HKCU\Software\Microsoft\Command Processor" /v DisableUNCCheck /t REG_DWORD /d 1 /f

这将禁用命令会话的通用命名约定 (UNC) 检查,并cmd.exe接受具有 UNC 路径的当前目录。

好的,回到注册表值NoWorkingDirectory。现在在命令提示符窗口中执行:

reg add "HKCU\Software\Classes\Directory\shell\NoWorkingDirectoryTest" /v NoWorkingDirectory /t REG_SZ

添加了NoWorkingDirectory没有值的注册表字符串值。因此注册表现在包含:

[HKEY_CURRENT_USER\Software\Classes\Directory\shell\NoWorkingDirectoryTest]
@="No working directory test"
"NoWorkingDirectory"=""

[HKEY_CURRENT_USER\Software\Classes\Directory\shell\NoWorkingDirectoryTest\command]
@="cmd.exe /D /C C:\\Temp\\DirTest\\DirTest.cmd \"%V\""

请注意上面发布的注册表输出中缺少第三行。

Windows 文件资源管理器右键点击在左侧C:\Windows在当前活动文件夹静止的目录上C:\Windows\System32\drivers,左键单击上下文菜单项无工作目录测试与之前完全一样。输出与之前相同。因此,此用例没有变化。

右击下一步在右侧Windows 文件资源管理器在目录etcC:\Windows\System32\drivers,左键单击上下文菜单项无工作目录测试. 将打开一个控制台窗口,其中显示以下几行:

Current directory is: "C:\WINDOWS\system32"
Batch file started with: C:\Temp\DirTest\DirTest.cmd "C:\Windows\System32\drivers\etc"
Command line used is: "cmd.exe" /D /C C:\Temp\DirTest\DirTest.cmd "C:\Windows\System32\drivers\etc"

第一行显示了注册表字符串值的重要区别,NoWorkingDirectory现在为 ,C:\WINDOWS\system32而不是C:\Windows\system32\drives像以前一样。当前工作目录现在始终是用 定义的 Windows 系统目录%SystemRoot%\system32

NoWorkingDirectory添加到注册表中时,如果是没有字符串值,或者像 一样带有字符串值,则无关紧要C:\Windows。甚至可以添加类型为 的注册表值DWORD,名称NoWorkingDirectory为 ,值是01。注册表值类型NoWorkingDirectory及其值对于 Windows shell 来说并不重要(explorer.exe)。唯一重要的是,在用于 shell 扩展的键下的 Windows 注册表中是否存在 名称 的注册表值NoWorkingDirectory

添加的注册表项和批处理文件可用于更多分析,例如使用 UNC 路径浏览网络资源或右键单击文件夹树左侧的虚拟 shell 文件夹。还可以在C:\Temp\DirTest具有名称的目录中创建Development & Test(!) 100%并将此文件夹名称及其完整路径传递给批处理文件或可执行文件或其他脚本,然后查看会发生什么。许多批处理文件无法处理正确的参数字符串,例如"C:\Temp\DirTest\Development & Test(!) 100%"由于空格、感叹号、圆括号和百分号,尽管这是一个仅由 ASCII 字符组成的有效目录名称。

最后,应关闭通过运行打开的所有控制台窗口,并在命令提示符窗口中执行以下命令,删除注册表项和批处理文件以及用于演示行为的创建的目录DirTest.cmd

reg delete "HKCU\Software\Classes\Directory\shell\NoWorkingDirectoryTest" /f
del C:\Temp\DirTest\DirTest.cmd
rd C:\Temp\DirTest
rd C:\Temp

笔记:带有文件扩展名的快捷方式文件的许多属性.lnk定义了传递的值探索者通过CreateProcess其函数参数和结构STARTUPINFO。例如属性开始于lpCurrentDirectory定义利用快捷方式文件启动可执行文件时最终指向的字符串值。

给程序员的提示:

  • C#进程类是 的 C# 包装类CreateProcess
  • Java进程生成器类在 Windows 上是 的 Java 包装类CreateProcess
  • Python子流程模块在 Windows 上是 的 Python 包装模块CreateProcess
  • Windows 命令处理器命令支持使用时start传递给它们的所有选项,例如定义使用函数参数传递给的字符串的选项。CreateProcesscmd.exe/DCreateProcesslpCurrentDirectory

CreateProcess每种支持在 Windows 上运行可执行文件的编程和脚本语言都有一个在 Windows 上调用(带或不带结构)的函数或类STARTUPINFO

答案3

“NoWorkingDirectory”动词属性没有记录,所以这只是一个猜测:

Cmd.exe 不支持远程共享(UNC)作为当前目录,如果您使用这样的工作目录启动 Cmd.exe,它将向控制台打印一条警告消息。

如果您查看“在此处打开命令窗口”注册,您将看到它使用该pushd命令启动 Cmd.exe 并且pushd支持 UNC 路径。NoWorkingDirectory 只是为了避免显示警告消息。

PowerShell 实际上不需要它。

相关内容