为什么其他文件夹路径也使用 SetX 添加到系统 PATH 而不仅仅是指定的文件夹路径?

use*_*916 2 registry batch-file

我有一个批处理文件,我使用system("name.bat"). 在该批处理文件中,我试图读取注册表项的值。从 C++ 调用批处理文件会导致set KEY_NAME=HKEY_LOCAL_MACHINE\stuff失败。

但是,当我直接运行批处理文件(双击它)时,它运行良好。不知道我做错了什么。

批处理文件:

set KEY_NAME=HKEY_LOCAL_MACHINE\SOFTWARE\Ansoft\Designer\2014.0\Desktop
set VALUE_NAME=InstallationDirectory
REG QUERY %KEY_NAME% /v %VALUE_NAME%
Run Code Online (Sandbox Code Playgroud)

C++文件:

int main(void)
{
    system("CALL C:\\HFSS\\setup_vars.bat");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

更新1:

我发现密钥实际上在 64 位注册表中,并且我正在将 C++ 解决方案构建为 32 位。一旦我解决了这个问题,它就会发现注册表项很好。

现在我在将该路径添加到我的PATH变量时遇到了问题。它不是创建系统变量,而是创建用户变量PATH并将其添加到那里。

从命令行运行有效。

代码:

set KEY_NAME=HKLM\SOFTWARE\Ansoft\Designer\2014.0\Desktop\
set VALUE_NAME=InstallationDirectory

FOR /F "usebackq skip=1 tokens=1,2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME%`) DO (
   set ValueName=%%A
   set ValueType=%%B
   set ValueValue=%%C
)

if defined ValueName (
   @echo Value Value = %ValueValue%
) else (
   @echo %KEY_NAME%\%VALUE_NAME% not found.
)

:: Set PATH Variable
set path_str=%PATH%
set addPath=%ValueValue%;

echo %addPath%
echo %ValueValue%

echo %PATH%| find /i "%addPath%">NUL

if NOT ERRORLEVEL 1 (
   SETX PATH "%PATH%
) else (
   SETX PATH "%PATH%;%addPath%;" /M
)
Run Code Online (Sandbox Code Playgroud)

更新 2:

我移动了选项 /M 的位置,现在它正在添加到正确的PATH变量中。

但是,当我这样做时,它不止一次(3 次)添加了PATH,然后它还添加了一个到 Visual Studio amd64 文件夹的路径。

我不确定为什么会这样。

Mof*_*ofi 5

Windows 创建进程的整个环境表的副本,为新进程启动一个新进程。因此,在您的 C++ 应用程序启动时,您的应用程序会从父进程、Windows 资源管理器或您的情况下的 Visual Studio获取环境表,包括PATH。并在批处理文件开始时复制此PATHcmd.exe

考虑到从 Windows 桌面到批处理文件的整个进程树,已经为PATH制作了许多副本,并且一些进程可能像 Visual Studio 所做的那样将某些内容附加到它们的本地PATH副本,或者甚至从PATH 中删除了路径。

您现在所做的SETX PATH "%PATH%是将已由进程树中的父进程修改的PATH本地副本完全附加到系统PATH 中,而不检查重复路径。

更好的是使用PATH 的本地副本丢弃所有代码,而是读取系统PATH的值,检查您要添加的路径是否已经在系统PATH 中,如果不是这种情况,请附加您想要的路径添加到系统PATH使用setx.

这应该不扩大系统的环境变量进行PATH喜欢%SystemRoot%\System32C:\Windows\System32


更新

这是在 Windows 7 x64 和 Windows XP x86 上测试的任务所需的批处理代码。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "KeyName=HKLM\SOFTWARE\Ansoft\Designer\2014.0\Desktop"
set "ValueName=InstallationDirectory"
for /F "skip=2 tokens=1,2*" %%N in ('%SystemRoot%\System32\reg.exe query "%KeyName%" /v "%ValueName%" 2^>nul') do (
    if /I "%%N" == "%ValueName%" (
        set "PathToAdd=%%P"
        if defined PathToAdd goto GetSystemPath
    )
)
echo Error: Could not find non-empty value "%ValueName%" under key
echo        %KeyName%
echo/
endlocal
pause
goto :EOF

:GetSystemPath
for /F "skip=2 tokens=1,2*" %%N in ('%SystemRoot%\System32\reg.exe query "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" /v "Path" 2^>nul') do (
    if /I "%%N" == "Path" (
        set "SystemPath=%%P"
        if defined SystemPath goto CheckPath
    )
)
echo Error: System environment variable PATH not found with a non-empty value.
echo/
endlocal
pause
goto :EOF

: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%"
set "Separator="
if not "!SystemPath:~-1!" == ";" set "Separator=;"
set "PathCheck=!SystemPath!%Separator%"
if "!PathCheck:%PathToAdd%;=!" == "!PathCheck!" (
    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
    )
)
endlocal
endlocal
Run Code Online (Sandbox Code Playgroud)

上面的批处理代码使用简单的不区分大小写的字符串替换和区分大小写的字符串比较来检查要追加的文件夹路径是否已经存在于系统PATH 中。仅当众所周知之前如何添加文件夹路径并且用户在此期间未在PATH中修改此文件夹路径时,这才有效。有关检查PATH 是否包含文件夹路径的更安全方法,请参阅有关如何检查 %PATH% 中是否存在目录的答案戴夫·本汉姆( Dave Benham)所著。

注 1:命令setx在 Windows XP 上默认不可用。

注 2:命令setx将长度超过 1024 个字符的值截断为 1024 个字符。

由于这个原因,批处理文件使用命令reg来替换系统PATH在Windows注册表如果任一setx不可用,或者新的路径值太长了setx。使用的缺点regWM_SETTINGCHANGE消息不会发送到所有顶级窗口,通知作为 Windows 桌面和其他应用程序运行的 Windows 资源管理器有关系统环境变量的此更改。因此,用户必须重新启动 Windows,最好始终更改持久存储的 Windows 系统环境变量上的某些内容。

批处理脚本已使用PATH进行了测试,该路径当前包含一个带有感叹号的文件夹路径,并且文件夹路径用双引号括起来,仅当文件夹路径包含分号时才需要使用双引号。

要了解使用的命令及其工作原理,请打开命令提示符窗口,在那里执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。

  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • pause /?
  • reg /?reg add /?reg query /?
  • set /?
  • setlocal /?
  • setx /?