2012-10-16 270 views
0

我想使用NSIS安裝程序設置環境變量。 如果重要,我將在Windows 7上運行腳本。 謝謝!在Windows 7中使用NSIS設置環境變量

+0

設置它們爲什麼?一個孩子的過程?永久性每用戶還是機器寬? – Anders

+0

對不起,我不知道NSIS,以回答你的問題。我只是想在安裝過程中添加一個新變量。謝謝! –

+0

我的問題不是NSIS特定的,Windows上存在這些「子類型」(基本上,它們來自哪裏以及它們對誰產生影響) – Anders

回答

1

How can I create or change an environment variable

注:更改%path%這種方式是不安全的,並可能破壞的條目,它比NSIS字符串長度更長!

+0

有沒有一些「安全」的方式?謝謝! –

+0

您將不得不直接爲系統插件分配內存並調用字符串和註冊表函數。我不認爲存在這樣做的示例代碼... – Anders

1

您可以創建一個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和-all標誌,那麼cmd.exe進程必須以管理員權限運行。
0

UPDATE:在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