在微软Windows 7设置环境变量与NSIS(Set environment variables

2019-08-01 12:58发布

我想用NSIS安装设置环境变量。 我会在Windows 7上运行脚本,如果它是很重要的。 谢谢!

Answer 1:

如何创建或更改环境变量

注:更改%path%这样是不安全的,并可能破坏的条目,它是长于NSIS字符串的长度!



Answer 2:

您可以创建一个Windows批处理文件,与安装就像其他的文件包呢,安装解压到插件目录并执行它:

File "/oname=$PluginsDir\appendvar.bat" "PathToScriptDir\appendvar.bat"

nsExec::ExecToLog '"$SYSDIR\cmd.exe" /C "$PluginsDir\appendvar.bat" -g -all'
Pop $R0 ; last error

Delete "$PluginsDir\appendvar.bat"

该appendvar.bat脚本(某种普遍实施全球和本地追加的):

@echo off

rem Drop last error level
cd .

rem Create local variable's stack
setlocal

set "?~nx0=%~nx0"

rem script flags
rem set variable in global registry for a current user
set __FLAG_SET_GLOBAL_REGISTRY=0
rem Set variable in global registry for all users.
rem Has no meaning if global flag has not used.
set __FLAG_SET_GLOBAL_REGISTRY_ALL_USERS=0
rem If setting global variable, then do include changes for a local cmd.exe process environment (by default, it is excluded)
rem Has no meaning if global flag has not used.
set __FLAG_SET_LOCAL=0
rem Force append even if exist.
set __FLAG_FORCE=0

:FLAGS_LOOP

rem flags always at first
set "__FLAG=%~1"

if not "%__FLAG%" == "" ^
if not "%__FLAG:~0,1%" == "-" set "__FLAG="

if not "%__FLAG%" == "" (
  if "%__FLAG%" == "-g" (
    set __FLAG_SET_GLOBAL_REGISTRY=1
    shift
  ) else if "%__FLAG%" == "-all" (
    if %__FLAG_SET_GLOBAL_REGISTRY% NEQ 0 set __FLAG_SET_GLOBAL_REGISTRY_ALL_USERS=1
    shift
  ) else if "%__FLAG%" == "-l" (
    set __FLAG_SET_LOCAL=1
    shift
  ) else if "%__FLAG%" == "-f" (
    set __FLAG_FORCE=1
    shift
  ) else (
    echo.%?~nx0%: error: invalid flag: %__FLAG%
    exit /b -255
  ) >&2

  rem read until no flags
  goto FLAGS_LOOP
)

if "%~1" == "" (
  echo.%?~nx0%: error: variable name is not set.
  exit /b 1
)

set "__SEPARATOR="
if not "%~3" == "" set "__SEPARATOR=%~3"
if "%__SEPARATOR%" == "" set "__SEPARATOR=;"
set "__SEPARATOR=%__SEPARATOR:~0,1%"

set "__NEW_VALUE=%~2"

rem remove trailing separator character
if not "%__NEW_VALUE%" == "" (
  if "%__SEPARATOR%" == "%__NEW_VALUE:~-1%" (
    set "__NEW_VALUE=%__NEW_VALUE:~0,-1%"
  )
)

rem remove trailing "\" character
if not "%__NEW_VALUE%" == "" (
  if "\" == "%__NEW_VALUE:~-1%" (
    set "__NEW_VALUE=%__NEW_VALUE:~0,-1%"
  )
)

if "%__NEW_VALUE%" == "" (
  if "%~2" == "" exit /b 0
  rem the variable value is a separator character only
  exit /b 2
)

rem set local at least
if %__FLAG_SET_GLOBAL_REGISTRY%%__FLAG_SET_LOCAL% EQU 0 set __FLAG_SET_LOCAL=1
if %__FLAG_SET_GLOBAL_REGISTRY% EQU 0 goto SET_GLOBAL_END

rem global setup
set "__VAR_VALUE="

if %__FLAG_SET_GLOBAL_REGISTRY_ALL_USERS% NEQ 0 (
  set __FLAG_SET_GLOBAL_REGISTRY_WMIC_WHERE_EXP=where "Name='Path' and UserName='<SYSTEM>'"
) else (
  set __FLAG_SET_GLOBAL_REGISTRY_WMIC_WHERE_EXP=where "Name='Path' and UserName!='<SYSTEM>'"
)

for /F "usebackq eol= tokens=1,* delims==" %%i in (`wmic environment %__FLAG_SET_GLOBAL_REGISTRY_WMIC_WHERE_EXP% get VariableValue /VALUE 2^>NUL`) do if "%%i" == "VariableValue" set "__VAR_VALUE=%%j"

if not "%__VAR_VALUE%" == "" (
  if "%__SEPARATOR%" == "%__VAR_VALUE:~-1%" (
    set "__VAR_VALUE=%__VAR_VALUE:~0,-1%"
  )
)

rem check on existance
if %__FLAG_FORCE% NEQ 0 goto SET_GLOBAL_IMPL
if "%__VAR_VALUE%" == "" goto SET_GLOBAL_IMPL

set "__VAR_VALUE_TMP=%__SEPARATOR%%__VAR_VALUE%%__SEPARATOR%"

call set "__VAR_VALUE_TMP_EXCLUDED=%%__VAR_VALUE_TMP:%__SEPARATOR%%__NEW_VALUE%%__SEPARATOR%=%%"

if /i not "%__VAR_VALUE_TMP_EXCLUDED%" == "%__VAR_VALUE_TMP%" goto SET_GLOBAL_END

:SET_GLOBAL_IMPL
if not "%__VAR_VALUE%" == "" (
  wmic environment %__FLAG_SET_GLOBAL_REGISTRY_WMIC_WHERE_EXP% set VariableValue="%__VAR_VALUE%%__SEPARATOR%%__NEW_VALUE%"
) else (
  wmic environment %__FLAG_SET_GLOBAL_REGISTRY_WMIC_WHERE_EXP% set VariableValue="%__NEW_VALUE%"
)

:SET_GLOBAL_END
if %__FLAG_SET_LOCAL% EQU 0 exit /b

rem local setup
call set "__VAR_VALUE=%%%~1%%"

if not "%__VAR_VALUE%" == "" (
  if "%__SEPARATOR%" == "%__VAR_VALUE:~-1%" (
    set "__VAR_VALUE=%__VAR_VALUE:~0,-1%"
  )
)

rem check on existance
if %__FLAG_FORCE% NEQ 0 goto SET_LOCAL_IMPL
if "%__VAR_VALUE%" == "" goto SET_LOCAL_IMPL

set "__VAR_VALUE_TMP=%__SEPARATOR%%__VAR_VALUE%%__SEPARATOR%"

call set "__VAR_VALUE_TMP_EXCLUDED=%%__VAR_VALUE_TMP:%__SEPARATOR%%__NEW_VALUE%%__SEPARATOR%=%%"

if /i not "%__VAR_VALUE_TMP_EXCLUDED%" == "%__VAR_VALUE_TMP%" goto SET_LOCAL_END

:SET_LOCAL_IMPL
if not "%__VAR_VALUE%" == "" (
  endlocal
  set "%~1=%__VAR_VALUE%%__SEPARATOR%%__NEW_VALUE%"
) else (
  endlocal
  set "%~1=%__NEW_VALUE%"
)

:SET_LOCAL_END

exit /b 0

您可以更换

%__VAR_VALUE%%__SEPARATOR%%__NEW_VALUE%

%__NEW_VALUE%%__SEPARATOR%%__VAR_VALUE%

如果要在前面加上一个变量的值。

注:脚本有问题:

  • 值与忽略大小写比较
  • 可以更新变量长于1024个字符(测试),但不超过4096字,我认为(未测试)
  • 如果使用-g和 - 所有标志,那么cmd.exe进程必须以系统管理员权限运行。


Answer 3:

更新 :最新版本的RegAddPathToVar功能是在这里: https://sf.net/p/nsisplus (全面测试例如: https://sf.net/p/nsisplus/NsisSetupLib/HEAD/tree/trunk/tests/ test_RegAddRemovePathGUI / main.nsi )

下面是NSIS 3.0全面和直接实现的例子。

包括3个文件。

的build.bat -构建脚本文件。

@echo off

set "MAKENSIS_EXE=makensis.exe"

"%MAKENSIS_EXE%" /V4 "/Obuild.log" "/XOutFile '%~dp0test.exe'" "%~dp0main.nsi"

echo.Return code: %ERRORLEVEL%

pause

编辑MAKENSIS_EXE变量那里makensis可执行文件是您的系统上。

stack.nsi -辅助函数文件。

!define PushStack11 "!insertmacro PushStack11"
!macro PushStack11 var0 var1 var2 var3 var4 var5 var6 var7 var8 var9 var10
Push `${var0}`
Push `${var1}`
Push `${var2}`
Push `${var3}`
Push `${var4}`
Push `${var5}`
Push `${var6}`
Push `${var7}`
Push `${var8}`
Push `${var9}`
Push `${var10}`
!macroend

!define ExchStack4 "!insertmacro ExchStack4"
!macro ExchStack4 var0 var1 var2 var3
Exch `${var3}`
Exch 1
Exch `${var2}`
Exch 1
Exch 2
Exch `${var1}`
Exch 2
Exch 3
Exch `${var0}`
Exch 3
!macroend

!define PopStack15 "!insertmacro PopStack15"
!macro PopStack15 var0 var1 var2 var3 var4 var5 var6 var7 var8 var9 var10 var11 var12 var13 var14
Pop `${var14}`
Pop `${var13}`
Pop `${var12}`
Pop `${var11}`
Pop `${var10}`
Pop `${var9}`
Pop `${var8}`
Pop `${var7}`
Pop `${var6}`
Pop `${var5}`
Pop `${var4}`
Pop `${var3}`
Pop `${var2}`
Pop `${var1}`
Pop `${var0}`
!macroend

main.nsi -全面落实NSIS例子。

!include "nsDialogs.nsh"
!include "WinCore.nsh"
!include "LogicLib.nsh"
!include "stack.nsi"

RequestExecutionLevel admin ; for all users

Page Custom Show Leave

Var /GLOBAL DialogID
Var /GLOBAL EditID
Var /GLOBAL Edit
Var /GLOBAL ButtonAppendID

!define GotoIf "!insertmacro GotoIf"
!macro GotoIf label exp
${If} ${exp}
  Goto `${label}`
${EndIf}
!macroend

!define RegGetKeyMap "!insertmacro RegGetKeyMap"
!macro RegGetKeyMap var value
  ${Switch} ${value}
    ${Case} "HKCR"
      StrCpy ${var} ${HKEY_CLASSES_ROOT}
    ${Break}
    ${Case} "HKCU"
      StrCpy ${var} ${HKEY_CURRENT_USER}
    ${Break}
    ${Case} "HKLM"
      StrCpy ${var} ${HKEY_LOCAL_MACHINE}
    ${Break}
    ${Case} "HKU"
      StrCpy ${var} ${HKEY_USERS}
    ${Break}
    ${Case} "HKPD"
      StrCpy ${var} ${HKEY_PERFORMANCE_DATA}
    ${Break}
    ${Case} "HKDD"
      StrCpy ${var} ${HKEY_DYN_DATA}
    ${Break}
    ${Case} "HKCC"
      StrCpy ${var} ${HKEY_CURRENT_CONFIG}
    ${Break}
    ${Case} "HKEY_CLASSES_ROOT"
      StrCpy ${var} ${HKEY_CLASSES_ROOT}
    ${Break}
    ${Case} "HKEY_CURRENT_USER"
      StrCpy ${var} ${HKEY_CURRENT_USER}
    ${Break}
    ${Case} "HKEY_LOCAL_MACHINE"
      StrCpy ${var} ${HKEY_LOCAL_MACHINE}
    ${Break}
    ${Case} "HKEY_USERS"
      StrCpy ${var} ${HKEY_USERS}
    ${Break}
    ${Case} "HKEY_PERFORMANCE_DATA"
      StrCpy ${var} ${HKEY_PERFORMANCE_DATA}
    ${Break}
    ${Case} "HKEY_DYN_DATA"
      StrCpy ${var} ${HKEY_DYN_DATA}
    ${Break}
    ${Case} "HKEY_CURRENT_CONFIG"
      StrCpy ${var} ${HKEY_CURRENT_CONFIG}
    ${Break}
    ${Default}
      StrCpy ${var} ${HKEY_CURRENT_USER}
    ${Break}
  ${EndSwitch}
!macroend

; Usage:
; All users:
;   ${Push} "<path>"
;   ${Push} "HKLM"
;   ${Push} "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
;   ${Push} "<env_var>"
;   Call RegAddPathToVar
; Current user only:
;   ${Push} "<path>"
;   ${Push} "HKCU"
;   ${Push} "Environment"
;   ${Push} "<env_var>"
;   Call RegAddPathToVar
!macro Func_RegAddPathToVar un
!ifndef ${un}RegAddPathToVar_INCLUDED
!define ${un}RegAddPathToVar_INCLUDED
Function ${un}RegAddPathToVar
  ${ExchStack4} $R0 $R1 $R2 $R3

  ${PushStack11} $R4 $R5 $R6 $R7 $R8 $R9 $0 $1 $2 $8 $9

  ; WARNING:
  ;   NSIS ReadRegStr returns empty string on string overflow, so native calls are used here:
  ;   1. To check actual length of <env_var>.
  ;   2. To process the PATH variable of any length long.

  ; The IDEAL algorithm for any length long PATH variable, where each subpath is not longer than ${NSIS_MAX_STRLEN}-${NSIS_CHAR_SIZE} bytes:
  ;   1. Init current string list if does not have any before or take as current has created after the previous algorithm run.
  ;   2. Read string of ${NSIS_MAX_STRLEN}-${NSIS_CHAR_SIZE} bytes length into the array of ${NSIS_MAX_STRLEN} bytes length from the input address, add NSIS_CHAR_SIZE nulls at the end.
  ;   3. Go to 20 if empty or nothing else except the ; characters in the array.
  ;   4. Truncate all in the array after the last ; character, where the ; character has found not under " character quoted string (see description in the 6).
  ;   5. Split strings in the array by the ; character if it has found not under " character quoted string into the list.
  ;   6. Move the last string from the list into the next repeat cycle list if it begins by the " character but not ends by the same character (not completely fitted into the limited to ${NSIS_MAX_STRLEN} bytes window).
  ;   7. Unquote all strings in the list and create the second list with flags marked where the quotes has removed.
  ;   8. Search for "$R0" or "$R0\" in the list, if found then raise a flag and leave the algorithm.
  ;   9. Move ${NSIS_MAX_STRLEN} byte window by the array current string length long multiple to NSIS_CHAR_SIZE value along the input address.
  ;  10. Repeat the algorithm.
  ;  20. Append path to the list.
  ;  21. Restore quotes for those strings in the first list what been quoted before by the second list.
  ;  22. Join first list by the separator into one string.

  ; The REAL algorithm for any length long PATH variable, where each subpath is not longer than ${NSIS_MAX_STRLEN}-${NSIS_CHAR_SIZE} bytes:
  ;   1. Read string from registry into dynamic buffer enough to store more characters: length of being searched string + length of separator + length of string to search + length of null character.
  ;   2. Copy string from the buffer to the second dynamic buffer enough to store more characters: length of separator + length of being searched string + length of separator + length of null character.
  ;   3. Prepend and append separator character to second buffer.
  ;   4. Try to find multiple instances of the string to search in the second buffer through the shlwapi::StrStrI, where search instances are:
  ;      `<Separator><StringToSearch><Separator>'
  ;      `<Separator><StringToSearch>\<Separator>'
  ;   5. If found any instance then leave the algorithm.
  ;   6. Append separator character to the first buffer if it does not ending by it.
  ;   7. Append the string to search to the first buffer.

  ; handles and pointers init
  StrCpy $R7 0
  StrCpy $R9 0
  StrCpy $0 0
  StrCpy $1 0
  StrCpy $2 0

  ; keys map
  ${RegGetKeyMap} $R8 $R1

  System::Call "advapi32::RegOpenKey(i R8, t R2, *i.R6) i.R4"
  ${If} $R4 <> 0
    DetailPrint "RegAddPathToVar: advapi32::RegOpenKey error: code=$R4 hive=$\"$R8$\" key=$\"$R2$\""
    MessageBox MB_OK "RegAddPathToVar: advapi32::RegOpenKey error: code=$R4 hive=$\"$R8$\" key=$\"$R2$\"" /SD IDOK
    Goto done
  ${EndIf}

  System::Call "advapi32::RegQueryValueEx(i R6, t R3, i 0, *i .r9, p 0, *i 0 R7) i.R4"
  ${If} $R4 <> 0
    DetailPrint "RegAddPathToVar: advapi32::RegQueryValueEx (1) is failed, unexpected error code: code=$R4 length=$\"$R7$\""
    MessageBox MB_OK "RegAddPathToVar: advapi32::RegQueryValueEx (1) is failed, unexpected error code: code=$R4 length=$\"$R7$\"" /SD IDOK
    Goto done
  ${EndIf}

  ; remove trailing "\" character from the string to search
  StrCpy $R5 $R0 "" -1
  ${If} $R5 == "\"
    StrCpy $R0 $R0 -1
  ${EndIf}

  StrLen $R8 $R0
  ; first buffer: length of being searched string + length of separator + length of string to search + length of null character
  IntOp $R5 $R8 + 1 ; ";"
  IntOp $R5 $R5 * ${NSIS_CHAR_SIZE}
  IntOp $R5 $R5 + $R7 ; already in bytes including null character

  ; allocate first dynamic buffer
  System::Alloc $R5
  Pop $0
  ${If} $0 = 0
    DetailPrint "RegAddPathToVar: System::Alloc (1) is failed: size=$R5"
    MessageBox MB_OK "RegAddPathToVar: System::Alloc (1) is failed: size=$R5" /SD IDOK
    Goto done
  ${EndIf}

  System::Call "advapi32::RegQueryValueEx(i R6, t R3, i 0, i 0, p r0, *i R5 R7) i.R4"
  ${If} $R4 <> 0
    DetailPrint "RegAddPathToVar: advapi32::RegQueryValueEx (2) is failed, unexpected error: code=$R4 length=$\"$R7$\""
    MessageBox MB_OK "RegAddPathToVar: advapi32::RegQueryValueEx (2) is failed, unexpected error: code=$R4 length=$\"$R7$\"" /SD IDOK
    Goto done
  ${EndIf}

  ; strip separator characters from the first buffer end
  ${If} $R7 > ${NSIS_CHAR_SIZE}
    ; excluding null character
    IntOp $R5 $R7 - ${NSIS_CHAR_SIZE}
    IntOp $R5 $R5 - ${NSIS_CHAR_SIZE}
    IntOp $R9 $0 + $R5
strip_loop1:
    System::Call "*$R9(&t1 .r8)"
    ${If} $8 == ";"
      System::Call "*$R9(&t1 '')" ; null character
      IntOp $R7 $R7 - ${NSIS_CHAR_SIZE}
      ${If} $R9 >= ${NSIS_CHAR_SIZE}
        IntOp $R9 $R9 - ${NSIS_CHAR_SIZE}
        Goto strip_loop1
      ${EndIf}
    ${EndIf}
  ${EndIf}

  ; second buffer: length of separator + length of being searched string + length of separator + length of null character
  IntOp $R5 2 * ${NSIS_CHAR_SIZE} ; 2 x ";"
  IntOp $R5 $R5 + $R7 ; already in bytes including null character

  ; allocate second dynamic buffer
  System::Alloc $R5
  Pop $1
  ${If} $1 = 0
    DetailPrint "RegAddPathToVar: System::Alloc (2) is failed: size=$R5"
    MessageBox MB_OK "RegAddPathToVar: System::Alloc (2) is failed: size=$R5" /SD IDOK
    Goto done
  ${EndIf}

  System::Call "*$1(&t1 ';')"

  IntOp $R9 $1 + ${NSIS_CHAR_SIZE}
  System::Call "kernel32::lstrcpyn(p R9, p r0, i R7) p.R4"
  ${If} $R4 = 0
    DetailPrint "RegAddPathToVar: kernel32::lstrcpyn (1) is failed"
    MessageBox MB_OK "RegAddPathToVar: kernel32::lstrcpyn (1) is failed" /SD IDOK
    Goto done
  ${EndIf}

  IntOp $R9 $R9 + $R7
  IntOp $R9 $R9 - ${NSIS_CHAR_SIZE} ; exclude last null character
  System::Call "*$R9(&t1 ';')"
  IntOp $R9 $R9 + ${NSIS_CHAR_SIZE}
  System::Call "*$R9(&t1 '')" ; null character

  ; buffer for the string to search
  IntOp $R5 0 + 4 ; 2 x ";" + "\" + length of null character
  IntOp $R5 $R5 + $R8 ; excluding null character
  IntOp $R5 $R5 * ${NSIS_CHAR_SIZE}

  System::Alloc $R5
  Pop $2
  ${If} $2 = 0
    DetailPrint "RegAddPathToVar: System::Alloc (3) is failed: size=$R5"
    MessageBox MB_OK "RegAddPathToVar: System::Alloc (3) is failed: size=$R5" /SD IDOK
    Goto done
  ${EndIf}

  ; convert R8 (length of R0) to bytes
  IntOp $R8 $R8 * ${NSIS_CHAR_SIZE}

  ; `<Separator><StringToSearch><Separator>'
  System::Call "*$2(&t1 ';')"

  IntOp $R9 $2 + ${NSIS_CHAR_SIZE}
  System::Call "kernel32::lstrcpy(p R9, t R0) p.R4"
  ${If} $R4 = 0
    DetailPrint "RegAddPathToVar: kernel32::lstrcpy (2) is failed"
    MessageBox MB_OK "RegAddPathToVar: kernel32::lstrcpy (2) is failed" /SD IDOK
    Goto done
  ${EndIf}

  IntOp $R9 $R9 + $R8 ; length does not include the last null character
  System::Call "*$R9(&t1 ';')"
  IntOp $R9 $R9 + ${NSIS_CHAR_SIZE}
  System::Call "*$R9(&t1 '')" ; null character

  System::Call "shlwapi::StrStrI(p r1, p r2) p.R4"
  ${GotoIf} done "$R4 <> 0"

  ; `<Separator><StringToSearch>\<Separator>'
  System::Call "*$2(&t1 ';')"

  IntOp $R9 $2 + ${NSIS_CHAR_SIZE}
  IntOp $R9 $R9 + $R8
  System::Call "*$R9(&t1 '\')"
  IntOp $R9 $R9 + ${NSIS_CHAR_SIZE}
  System::Call "*$R9(&t1 ';')"
  IntOp $R9 $R9 + ${NSIS_CHAR_SIZE}
  System::Call "*$R9(&t1 '')" ; null character

  System::Call "shlwapi::StrStrI(p r1, p r2) p.R4"
  ${GotoIf} done "$R4 <> 0"

  ; append to the first buffer
  IntOp $R9 0 + $0
  ${If} $R7 > ${NSIS_CHAR_SIZE}
    IntOp $R9 $R9 + $R7
    IntOp $R9 $R9 - ${NSIS_CHAR_SIZE} ; exclude last null character
    System::Call "*$R9(&t1 ';')"
    IntOp $R9 $R9 + ${NSIS_CHAR_SIZE}
  ${EndIf}

  System::Call "kernel32::lstrcpy(p R9, t R0) p.R4"
  ${If} $R4 = 0
    DetailPrint "RegAddPathToVar: kernel32::lstrcpy (3) is failed"
    MessageBox MB_OK "RegAddPathToVar: kernel32::lstrcpy (3) is failed" /SD IDOK
    Goto done
  ${EndIf}

  IntOp $R9 $R9 + $R8 ; length does not include the last null character
  System::Call "*$R9(&t1 '')" ; null character

  IntOp $R9 $R9 + ${NSIS_CHAR_SIZE}
  IntOp $R5 $R9 - $0

  System::Call "advapi32::RegSetValueEx(i R6, t R3, i 0, i r9, p r0, i R5) i.R4"
  ${If} $R4 <> 0
    DetailPrint "RegAddPathToVar: advapi32::RegSetValueEx (1) is failed"
    MessageBox MB_OK "RegAddPathToVar: advapi32::RegSetValueEx (1) is failed" /SD IDOK
    Goto done
  ${EndIf}

  ; broadcast global event
  SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000

done:
  System::Call "advapi32::RegCloseKey(i $R6)"

  ${If} $0 <> 0
    System::Free $0
  ${EndIf}
  ${If} $1 <> 0
    System::Free $1
  ${EndIf}
  ${If} $2 <> 0
    System::Free $2
  ${EndIf}

  ${PopStack15} $R0 $R1 $R2 $R3 $R4 $R5 $R6 $R7 $R8 $R9 $0 $1 $2 $8 $9
FunctionEnd
!endif
!macroend

!define Call_RegAddPathToVar "!insertmacro Call_RegAddPathToVar"
!macro Call_RegAddPathToVar prefix path hkey hkey_path env_var
Push `${path}`
Push `${hkey}`
Push `${hkey_path}`
Push `${env_var}`
Call ${prefix}RegAddPathToVar
!macroend

!define RegAddPathToVar "!insertmacro RegAddPathToVar"
!macro RegAddPathToVar
!insertmacro Func_RegAddPathToVar ""
!undef RegAddPathToVar
!define RegAddPathToVar "${Call_RegAddPathToVar} ''"
!macroend

!define un.RegAddPathToVar "!insertmacro un.RegAddPathToVar"
!macro un.RegAddPathToVar
!insertmacro Func_RegAddPathToVar "un."
!undef un.RegAddPathToVar
!define un.RegAddPathToVar "${Call_RegAddPathToVar} 'un.'"
!macroend

; include for install only
${RegAddPathToVar}

Function Show
  nsDialogs::Create 1018
  Pop $DialogID

  ${NSD_CreateText} 0 16u 80% 14u "C:\MyPath\bin"
  Pop $EditID

  ${NSD_OnChange} $EditID WndProc

  ${NSD_CreateButton} 80% 16u 20% 14u "Append"
  Pop $ButtonAppendID

  ${NSD_OnClick} $ButtonAppendID WndProc

  StrCpy $R0 -1
  Call Update

  nsDialogs::Show
FunctionEnd

Function Leave
FunctionEnd

Function WndProc
  System::Store SR0
  Call Update
  System::Store L
FunctionEnd

Function Update
  ; read values
  ${If} $R0 = $EditID
  ${OrIf} $R0 = -1
    ${NSD_GetText} $EditID $Edit
  ${EndIf}
  ${If} $R0 = $ButtonAppendID
    ${If} $Edit != ""
      #${RegAddPathToVar} "$Edit" HKCU "Environment" PATH ; for current user
      ${RegAddPathToVar} "$Edit" HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" PATH ; for all users
    ${EndIf}
  ${EndIf}
FunctionEnd

Section -Hidden
SectionEnd


文章来源: Set environment variables with NSIS in Window 7