为什么其他文件夹路径也使用 SetX 添加到系统 PATH 而不仅仅是指定的文件夹路径? [英] Why are other folder paths also added to system PATH with SetX and not only the specified folder path?

查看:31
本文介绍了为什么其他文件夹路径也使用 SetX 添加到系统 PATH 而不仅仅是指定的文件夹路径?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

批处理文件:

set KEY_NAME=HKEY_LOCAL_MACHINESOFTWAREAnsoftDesigner2014.0Desktop设置 VALUE_NAME=安装目录注册查询 %KEY_NAME%/v %VALUE_NAME%

C++ 文件:

int main(void){system("CALL C:\HFSS\setup_vars.bat");返回0;}

<小时>

更新 1:

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

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

从命令行运行有效.

代码:

set KEY_NAME=HKLMSOFTWAREAnsoftDesigner2014.0Desktop设置 VALUE_NAME=安装目录FOR/F "usebackq skip=1 tokens=1,2*" %%A IN (`REG QUERY %KEY_NAME%/v %VALUE_NAME%`) DO (设置值名称=%%A设置值类型=%%B设置 ValueValue=%%C)如果定义了 ValueName (@echo 值值 = %ValueValue%) 别的 (@echo %KEY_NAME%\%VALUE_NAME% 未找到.):: 设置路径变量设置 path_str=%PATH%设置 addPath=%ValueValue%;回声%addPath%回声 %ValueValue%回声%PATH%|find/i "%addPath%">NUL如果不是错误级别 1 (SETX 路径 "%PATH%) 别的 (SETX 路径 "%PATH%;%addPath%;"/M)

<小时>

更新 2:

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

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

我不确定为什么会这样.

解决方案

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

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

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

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

并且这应该在不将系统PATH中的环境变量(如%SystemRoot%System32)扩展到C:WindowsSystem32的情况下完成.


更新

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

@echo offsetlocal EnableExtensions DisableDelayedExpansion设置KeyName=HKLMSOFTWAREAnsoftDesigner2014.0Desktop"设置ValueName=InstallationDirectory";对于/F "skip=2 tokens=1,2*";%%N in ('%SystemRoot%System32
eg.exe query "%KeyName%"/v "%ValueName%" 2^>nul') do (如果/I "%%N";==%ValueName%"(设置PathToAdd=%%P"如果定义了 PathToAdd 转到 GetSystemPath))echo 错误:找不到非空值%ValueName%";键下回声 %KeyName%回声/本地端暂停转到:EOF:获取系统路径对于/F "skip=2 tokens=1,2*";%%N in ('%SystemRoot%System32
eg.exe query "HKLMSystemCurrentControlSetControlSession ManagerEnvironment"/v "Path" 2^>nul') do (如果/I "%%N";==路径"(设置SystemPath=%%P";如果定义了 SystemPath 转到 CheckPath))echo 错误:未找到具有非空值的系统环境变量 PATH.回声/本地端暂停转到:EOF:检查路径setlocal EnableDelayedExpansionrem 要添加的文件夹路径必须包含(反斜杠)作为目录rem 分隔符而不是/(斜杠),并且不应以反斜杠结尾.设置PathToAdd=%PathToAdd:/=\%";如果%PathToAdd:~-1%";==";设置PathToAdd=%PathToAdd:~0,-1%";设置分隔符="如果不是!SystemPath:~-1!";==;";设置分隔符=;"设置PathCheck=!SystemPath!%Separator%";如果 "!PathCheck:%PathToAdd%;=!"== "!PathCheck!"(设置PathToSet=!SystemPath!%Separator%!PathToAdd!";设置UseSetx=1"如果不是!PathToSet:~1024,1!";=="设置UseSetx="如果不存在 %SystemRoot%System32setx.exe 设置UseSetx=";如果定义了 UseSetx (%SystemRoot%System32setx.exe 路径!PathToSet!"/M>nul) 别的 (设置ValueType=REG_EXPAND_SZ";如果!PathToSet:%%=!";== "!PathToSet!"设置ValueType=REG_SZ";%SystemRoot%System32
eg.exe 添加HKLMSystemCurrentControlSetControlSession ManagerEnvironment"/f/v 路径/t !ValueType!/d "!PathToSet!";>空))本地端本地端

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

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

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

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

使用 PATH 测试批处理脚本,其中当前包含一个带有感叹号的文件夹路径,并且文件夹路径用双引号括起来,这仅在文件夹路径包含分号时才需要.>

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

  • echo/?
  • endlocal/?
  • for/?
  • 转到/?
  • if/?
  • 暂停/?
  • reg/?reg add/?reg 查询/?
  • set/?
  • setlocal/?
  • setx/?

I have a batch file which I am calling from C++ using system("name.bat"). In that batch file I am trying to read the value of a registry key. Calling the batch file from C++ causes set KEY_NAME=HKEY_LOCAL_MACHINEstuff to fail.

However, when I directly run the batch file (double clicking it), it runs fine. Not sure what I am doing wrong.

Batch file:

set KEY_NAME=HKEY_LOCAL_MACHINESOFTWAREAnsoftDesigner2014.0Desktop
set VALUE_NAME=InstallationDirectory
REG QUERY %KEY_NAME% /v %VALUE_NAME%

C++ file:

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


UPDATE 1:

I found out that the key is actually in the 64-bit registry, and I was building my C++ solution as a 32-bit. Once I fixed that, it found the registry key fine.

Now I am having an issue adding that path to my PATH variable. Instead of creating a system variable, it is creating a user variable PATH and adding it there.

Running from command line works.

Code:

set KEY_NAME=HKLMSOFTWAREAnsoftDesigner2014.0Desktop
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
)


UPDATE 2:

I moved the placement of the option /M and it is now adding to right PATH variable.

However, when I am doing this, it is adding the PATH more than once (3 times) and then it is also adding a path to visual studio amd64 folder.

I'm mot sure why that is happening.

解决方案

Windows creates a copy of the entire environment table of the process starting a new process for the new process. Therefore on start of your C++ application, your application gets the environment table including PATH from parent process, Windows Explorer or in your case Visual Studio. And this PATH is copied for cmd.exe on start of the batch file.

Taking the entire process tree into account from Windows desktop to the batch file, there have been many copies made for PATH and some processes perhaps appended something to their local copy of PATH like Visual Studio has done, or have even removed paths from PATH.

What you do now with SETX PATH "%PATH% is appending the local copy of PATH modified already by the parent processes in process tree completely to system PATH without checking for duplicate paths.

Much better would be to throw away all code using local copy of PATH and instead read the value of system PATH, check if the path you want to add is not already in system PATH and if this is not the case, append the path you want to add to system PATH using setx.

And this should be done without expanding the environment variables in system PATH like %SystemRoot%System32 to C:WindowsSystem32.


UPDATE

Here is the batch code required for your task tested on Windows 7 x64 and Windows XP x86.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "KeyName=HKLMSOFTWAREAnsoftDesigner2014.0Desktop"
set "ValueName=InstallationDirectory"
for /F "skip=2 tokens=1,2*" %%N in ('%SystemRoot%System32
eg.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
eg.exe query "HKLMSystemCurrentControlSetControlSession ManagerEnvironment" /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%System32setx.exe set "UseSetx="
    if defined UseSetx (
        %SystemRoot%System32setx.exe Path "!PathToSet!" /M >nul
    ) else (
        set "ValueType=REG_EXPAND_SZ"
        if "!PathToSet:%%=!" == "!PathToSet!" set "ValueType=REG_SZ"
        %SystemRoot%System32
eg.exe ADD "HKLMSystemCurrentControlSetControlSession ManagerEnvironment" /f /v Path /t !ValueType! /d "!PathToSet!" >nul
    )
)
endlocal
endlocal

The batch code above uses a simple case-insensitive string substitution and a case-sensitive string comparison to check if the folder path to append is present already in system PATH. This works only if it is well known how the folder path was added before and the user has not modified this folder path in PATH in the meantime. For a safer method of checking if PATH contains a folder path see the answer on How to check if directory exists in %PATH%? written by Dave Benham.

Note 1: Command setx is by default not available on Windows XP.

Note 2: Command setx truncates values longer than 1024 characters to 1024 characters.

For that reason the batch file uses command reg to replace system PATH in Windows registry if either setx is not available or new path value is too long for setx. The disadvantage on using reg is that WM_SETTINGCHANGE message is not sent to all top-level windows informing Windows Explorer running as Windows desktop and other applications about this change of system environment variable. So the user must restart Windows which is best done always on changing something on persistent stored Windows system environment variables.

The batch script was tested with PATH containing currently a folder path with an exclamation mark and with a folder path being enclosed in double quotes which is necessary only if the folder path contains a semicolon.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

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

这篇关于为什么其他文件夹路径也使用 SetX 添加到系统 PATH 而不仅仅是指定的文件夹路径?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆