Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
961 views
in Technique[技术] by (71.8m points)

batch file - Why are other folder paths also added to system PATH with SetX and not only the specified folder path?

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.

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 /?

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...