Windows内核库函数创建进程 https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw为新进程创建启动新进程的进程的整个环境表的副本。因此,在启动 C++ 应用程序时,您的应用程序会获取环境表,包括PATH来自父进程,Windows资源管理器或者在你的情况下视觉工作室。和这个PATH被复制为cmd.exe
在批处理文件开始时。
考虑到从Windows桌面到批处理文件的整个进程树,已经制作了多个副本PATH有些进程可能会在其本地副本中附加一些内容PATH like 视觉工作室已经完成,或者甚至已经删除了路径PATH.
你现在做什么SETX PATH "%PATH%
正在附加本地副本PATH进程树中的父进程已将其完全修改为系统PATH而不检查重复的路径。
更好的办法是使用本地副本丢弃所有代码PATH而是读取系统的值PATH,检查你要添加的路径是否已经在系统中PATH如果不是这种情况,请附加您要添加到系统的路径PATH using setx
.
这应该在不扩展系统中的环境变量的情况下完成PATH like %SystemRoot%\System32
to C:\Windows\System32
.
以下是在 Windows XP SP3 x86、Windows 7 SP1 x64 和 Windows 11 22H2 上测试的任务所需的批处理代码。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "KeyName=HKLM\SOFTWARE\Ansoft\Designer\2014.0\Desktop"
set "ValueName=InstallationDirectory"
for /F "skip=2 tokens=1,2*" %%G in ('%SystemRoot%\System32\reg.exe query "%KeyName%" /v "%ValueName%" 2^>nul') do (
if /I "%%G" == "%ValueName%" (
set "PathToAdd=%%I"
if defined PathToAdd goto GetSystemPath
)
)
echo Error: Could not find non-empty value "%ValueName%" under key
echo %KeyName%
echo(
endlocal
pause
exit /B
:GetSystemPath
for /F "skip=2 tokens=1,2*" %%G in ('%SystemRoot%\System32\reg.exe query "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" /v "Path" 2^>nul') do (
if /I "%%G" == "Path" (
set "SystemPath=%%I"
if defined SystemPath goto CheckPath
)
)
echo Error: System environment variable PATH not found with a non-empty value.
echo(
endlocal
pause
exit /B
:CheckPath
setlocal EnableDelayedExpansion
rem The folder path to add must contain \ (backslash) as directory
rem separator and not / (slash) and should not end with a backslash.
set "PathToAdd=!PathToAdd:/=\!"
if "!PathToAdd:~-1!" == "\" set "PathToAdd=!PathToAdd:~0,-1!"
if "!SystemPath:~-1!" == ";" (set "Separator=") else set "Separator=;"
set "PathCheck=!SystemPath!%Separator%"
rem Do nothing if the folder path to add without or with a backslash
rem at end with a semicolon appended for entire folder path check is
rem already in the system PATH value. This code does not work with
rem path to add contains an equal sign which is fortunately very rare.
if not "!PathCheck:%PathToAdd%;=!" == "!PathCheck!" goto EndBatch
if not "!PathCheck:%PathToAdd%\;=!" == "!PathCheck!" goto EndBatch
set "PathToSet=!SystemPath!%Separator%!PathToAdd!"
set "UseSetx=1"
if not "!PathToSet:~1024,1!" == "" set "UseSetx="
if not exist %SystemRoot%\System32\setx.exe set "UseSetx="
if defined UseSetx (
%SystemRoot%\System32\setx.exe Path "!PathToSet!" /M >nul
) else (
set "ValueType=REG_EXPAND_SZ"
if "!PathToSet:%%=!" == "!PathToSet!" set "ValueType=REG_SZ"
%SystemRoot%\System32\reg.exe ADD "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" /f /v Path /t !ValueType! /d "!PathToSet!" >nul
)
:EndBatch
endlocal
endlocal
上面的批处理代码使用简单的不区分大小写的字符串替换和区分大小写的字符串比较来检查要追加的文件夹路径是否已存在于系统中PATH。仅当众所周知文件夹路径之前是如何添加的并且用户未在 中修改此文件夹路径时,此操作才有效PATH同时。为了更安全地检查是否PATH包含一个文件夹路径请参阅答案如何检查%PATH% 中是否存在目录? https://stackoverflow.com/a/8046515/1012053写于戴夫·本纳姆 https://stackoverflow.com/users/1012053/dbenham.
Note 1:命令setx
默认情况下在 Windows XP 上不可用。
Note 2:命令setx
将长度超过 1024 个字符的值截断为 1024 个字符。
因此,批处理文件使用命令reg
取代系统路径在 Windows 注册表中,如果setx
不可用或新路径值太长setx
。使用上的缺点reg
就是它WM_SETTINGCHANGE https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-settingchange消息不会发送到所有顶级窗口,通知作为 Windows 桌面运行的 Windows 资源管理器和其他应用程序有关系统环境变量的此更改。因此,用户必须重新启动 Windows,最好在更改持久存储的 Windows 系统环境变量上的某些内容时执行此操作。
批处理脚本经过测试PATH当前包含带有感叹号的文件夹路径,并且文件夹路径用双引号括起来,仅当文件夹路径包含分号时才需要。
要了解所使用的命令及其工作原理,请打开命令提示符 https://www.howtogeek.com/235101/10-ways-to-open-the-command-prompt-in-windows-10/窗口中,执行以下命令,并完整、仔细地阅读每个命令显示的帮助页面。
echo /?
endlocal /?
exit /?
for /?
goto /?
if /?
pause /?
reg /?
reg add /?
reg query /?
set /?
setlocal /?
setx /?