- NSIS Discussion
- Setting/Removing/Viewing Environment Variables
Archive: Setting/Removing/Viewing Environment Variables
pgg1
6th August 2007 12:58 UTC
Setting/Removing/Viewing Environment Variables
Hi
I have read quite a lot of the forum relating setting/reading/removing environment variables. In particular I am using code from the following thread:
http://forums.winamp.com/showthread....ht=writeenvstr
The file is called writeenvstr.nsh.txt and it’s quite popular as it’s been downloaded 176 times.
I have a few questions.
(1)The code writes the environment variable ok but writes it to “User variablesâ€, how do I write to “System variablesâ€?
For example I want to add something to the end of “PATH†which is in “System variables†How would this be done? Would it be a matter of getting the current path (e.g. ReadEnvStr $0 PATH) and then concatenating ;some\path\ to the end of it.
(2) How do you remove an environment variable?
I mean do you pop the variable on the stack and then call “un.DeleteEnvStr†for each environment variable that you have set? What would the code look like?
Pop SOMEVARIABLE1
Call un.DeleteEnvStr
Pop SOMEVARIABLE2
Call un.DeleteEnvStr
…
Pop SOMEVARIABLEn
Call un.DeleteEnvStr
(3) Once an environment variable has been written is cannot be read until you reboot.
For example:
Push "SOMEDIR"
Push "C:\Some\Directory"
Call WriteEnvStr
After writing an environment variable, this read
only works after a reboot.
ReadEnvStr $0 "Path"
MessageBox MB_OK $0
Obviously this is no good.
Am I doing something wrong?
pgg1
6th August 2007 13:02 UTC
Sorry, typo in previous post.
ReadEnvStr $0 "Path"
should be
ReadEnvStr $0 "SOMEDIR"
pgg1
6th August 2007 14:19 UTC
Here is a concrete example.
outFile "installer.exe"
installDir $DESKTOP
section
setOutPath $INSTDIR
writeUninstaller $INSTDIR\uninstaller.exe
; Write an environment variable.
Push "SOMEDIRE"
Push "C:\Some\Directory"
Call WriteEnvStr
; Read after being set, displays nothing unless you reboot.
; However if you open a shell in Windows and type echo %SOMEDIRE%
; You get "C:\Some\Directory"
ReadEnvStr $0 "SOMEDIRE"
MessageBox MB_OK $0
sectionEnd
section "Uninstall"
delete $INSTDIR\uninstaller.exe
; Remove environment variable.
Push "SOMEDIRE"
Call un.DeleteEnvStr
sectionEnd
;====================================================
; IsNT - Returns 1 if the current system is NT, 0
; otherwise.
; Output: head of the stack
;====================================================
Function IsNT
Push $0
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
StrCmp $0 "" 0 IsNT_yes
; we are not NT.
Pop $0
Push 0
Return
IsNT_yes:
; NT!!!
Pop $0
Push 1
FunctionEnd
;====================================================
; WriteEnvStr - Writes a value to an environment variable
; Input - First push - name. Second - value
; Note - Win9x systems requires reboot
;
; Push "HOMEDIR"
; Push "C:\New Home Dir\"
; Call WriteEnvStr
;====================================================
Function WriteEnvStr
Exch $1 ; $1 has environment variable value
Exch
Exch $0 ; $0 has environment variable name
Push $2
Call IsNT
Pop $2
StrCmp $2 1 WriteEnvStr_NT
; Not on NT
StrCpy $2 $WINDIR 2 ; Copy drive of windows (c:)
FileOpen $2 "$2\autoexec.bat" a
FileSeek $2 0 END
FileWrite $2 "$\r$\nSET $0=$1$\r$\n"
FileClose $2
SetRebootFlag true
Goto WriteEnvStr_done
WriteEnvStr_NT:
WriteEnvStr_NTdoIt:
WriteRegStr HKCU "Environment" $0 $1
GetTempFileName $2
File /oname=$2 "RefreshEnv.exe"
ExecWait $2
Delete $2
WriteEnvStr_done:
Pop $2
Pop $1
Pop $0
FunctionEnd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Uninstall sutff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;====================================================
; un.IsNT - Returns 1 if the current system is NT, 0
; otherwise.
; Output: head of the stack
;====================================================
Function un.IsNT
Push $0
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
StrCmp $0 "" 0 unIsNT_yes
; we are not NT.
Pop $0
Push 0
Return
unIsNT_yes:
; NT!!!
Pop $0
Push 1
FunctionEnd
;====================================================
; un.DeleteEnvStr - Removes an environment variable
; Input: head of the stack
;====================================================
Function un.DeleteEnvStr
Exch $0 ; $0 now has the name of the variable
Push $1
Push $2
Push $3
Push $4
Push $5
Call un.IsNT
Pop $1
StrCmp $1 1 DeleteEnvStr_NT
; Not on NT
StrCpy $1 $WINDIR 2
FileOpen $1 "$1\autoexec.bat" r
GetTempFileName $4
FileOpen $2 $4 w
StrCpy $0 "SET $0="
SetRebootFlag true
DeleteEnvStr_dosLoop:
FileRead $1 $3
StrLen $5 $0
StrCpy $5 $3 $5
StrCmp $5 $0 DeleteEnvStr_dosLoop
StrCmp $5 "" DeleteEnvStr_dosLoopEnd
FileWrite $2 $3
Goto DeleteEnvStr_dosLoop
DeleteEnvStr_dosLoopEnd:
FileClose $2
FileClose $1
StrCpy $1 $WINDIR 2
Delete "$1\autoexec.bat"
CopyFiles /SILENT $4 "$1\autoexec.bat"
Delete $4
Goto DeleteEnvStr_done
DeleteEnvStr_NT:
DeleteRegValue HKCU "Environment" $0
GetTempFileName $0
File /oname=$0 "RefreshEnv.exe"
ExecWait $0
Delete $0
DeleteEnvStr_done:
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
DrDan
6th August 2007 14:29 UTC
I created my own macros...
... to write both system and user environment variables.
Section "4.9.2 Registry, INI, File Instructions" of the NSIS User Manual is your friend :)
pgg1
6th August 2007 15:40 UTC
Thanks for your help,
After reading so much stuff I'm somewhat confused. I'm a bit disappointed with the docs and the forum on this issue.
For example some of the threads lack examples, or you start reading something of interest and the user provides a link that points no where.
In some cases it is clear but the code provided only does half the job, for example writing environment variables to User Variables and not System variables. Why isn’t there a script that does both? Maybe there is and I haven’t found it yet.
There needs to be a section dedicated to writing/reading/removing environment variables as this is fundamental to installing software. What there is (Section "4.9.2 Registry, INI, File Instructions") is sub standard.
Sorry to moan but this needs to be addressed.
demiller9
6th August 2007 23:59 UTC
I wrote my own function to add and remove elements to/from the System PATH variable. It uses the WordAdd macro, and System dll and LogicLib. Since I call it during install and uninstall, the function is wrapped in a macro to define it with and without the 'un.' prefix. WordAdd is perfect for this use because it splits the paths at the semicolon (';') and doesn't duplicate an existing path:
!include "WordFunc.nsh"
!macro DualUseFunctions_ un_
function ${un_}SetPathVar
# stack top: <'string to add'> / <AppendFlag>
Exch $0 ; new string
Exch
Exch $1 ; append = 2, prefix = 1, remove = 0
Push $R0 ; saved working registers
ReadRegStr $R0 HKLM "${REG_ENVIRONMENT}" "Path"
${Select} $1
${Case} 0
${${un_}WordAdd} "$R0" ";" "-$0" $R0
${Case} 1
${${un_}WordAdd} "$0" ";" "+$R0" $R0
${Case} 2
${${un_}WordAdd} "$R0" ";" "+$0" $R0
${EndSelect}
WriteRegExpandStr HKLM "${REG_ENVIRONMENT}" "Path" "$R0"
System::Call 'Kernel32::SetEnvironmentVariableA(t, t) i("PATH", R0).r2'
Pop $R0 ; restore registers
Pop $1
Pop $0
functionEnd
!macroend
!insertmacro DualUseFunctions_ ""
!insertmacro DualUseFunctions_ "un."
I add several paths to the PATH var with these two calls
# Environment Path variable
Push 1 ; prefix
Push "C:\Ipls\dlls"
Call SetPathVar
Push 2 ; append
Push "C:\Ipls\utilities;C:\ipls\utilities\pkzip;C:\ipls\utilities\dumpel;C:\ipls\utilities\WriteToCD;${BuildFolder}\UiClient\Release"
Call SetPathVar
I remove them in the uninstaller like this
# cleanup the Environment Path variable
Push 0 ; 0 = remove
Push "${BuildFolder}\UiClient\Release;C:\Ipls\dlls;C:\Ipls\utilities;C:\ipls\utilities\pkzip;C:\ipls\utilities\dumpel;C:\ipls\utilities\WriteToCD"
Call Un.SetPathVar
Don
pgg1
7th August 2007 15:25 UTC
Thanks a lot for the post, it has helped me a lot. I have used the code above in the following script to test it before I put it into my main script for my installer.
***********************************************************
!include "LogicLib.nsh"
!include "WordFunc.nsh"
!insertmacro WordAdd
!insertmacro un.WordAdd
!define REG_ENVIRONMENT "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
outFile "installer.exe"
installDir $DESKTOP
!macro DualUseFunctions_ un_
function ${un_}SetPathVar
# stack top: <'string to add'> / <AppendFlag>
Exch $0 ; new string
Exch
Exch $1 ; append = 2, prefix = 1, remove = 0
Push $R0 ; saved working registers
ReadRegStr $R0 HKLM "${REG_ENVIRONMENT}" "Path"
${Select} $1
${Case} 0
${${un_}WordAdd} "$R0" ";" "-$0" $R0
${Case} 1
${${un_}WordAdd} "$0" ";" "+$R0" $R0
${Case} 2
${${un_}WordAdd} "$R0" ";" "+$0" $R0
${EndSelect}
WriteRegExpandStr HKLM "${REG_ENVIRONMENT}" "Path" "$R0"
System::Call 'Kernel32::SetEnvironmentVariableA(t, t) i("PATH", R0).r2'
Pop $R0 ; restore registers
Pop $1
Pop $0
functionEnd
!macroend
!insertmacro DualUseFunctions_ ""
!insertmacro DualUseFunctions_ "un."
Function displayPath
ReadRegStr $R0 HKLM "${REG_ENVIRONMENT}" "Path"
MessageBox MB_OK $R0
FunctionEnd
section
setOutPath $INSTDIR
writeUninstaller $INSTDIR\uninstaller.exe
Push 1 ; 1 = append.
Push "C:\some\directory"
call displayPath
Call SetPathVar
call displayPath
sectionEnd
section "Uninstall"
delete $INSTDIR\uninstaller.exe
Push 0 ; 0 = remove
Push "C:\some\directory"
Call Un.SetPathVar
sectionEnd
***********************************************************
I have one question.
The code works well so thank you for that once again. However, once I hace run the code and then open a shell in Windows and type..
echo %PATH%
Why doesn't it show up in the path?
Cheers
Paul
pgg1
7th August 2007 15:37 UTC
One other thing, how do I get my code to show up nice and formatted like yours.
Once again thanks.
pengyou
7th August 2007 16:07 UTC
The NSIS wiki has several pages which explain how to set and remove environment variables and how to change the PATH variable.
PATH manipulation is discussed here:
http://nsis.sourceforge.net/Path_Manipulation
http://nsis.sourceforge.net/Path_man...on_in_run-time
The wiki also explains how to make WriteEnvStr.nsh modify variables for all users and shows how to make changes available without requiring a reboot.
http://nsis.sourceforge.net/Setting_...ment_Variables
pgg1
7th August 2007 16:58 UTC
Thanks for the links, even though I have solved my problem with the help of "demiller9". The links you have provided do not help with the setting of the System Path (they all relate to the users path) which was my first question when the thread originally opened. But thanks anyway.
My last question still stands though which is:
After I run the above script why is it when I open a shell and type:
echo %PATH%
the path I have just added "C:\some\directory" doesn't show?
I think I may have to make a System::Call of some type, therefore after this call the path I have just added will be visible from the command line.
Thanks
Paul
demiller9
7th August 2007 17:57 UTC
After I run the above script why is it when I open a shell and type:
echo %PATH%
the path I have just added "C:\some\directory" doesn't show?
Did you open the command window after the script ran, or was the window already open and you typed 'echo ...' after the script ran? If the window was already open, the new path was not visible because the command window does not reload its environment block. Environment variables are passed to new processes by their caller, the command window should get the variables in use by Explorer. Explorer will load the new environment block if you send it the message
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
I did not have that it my code because my installer will always reboot the system.
how do I get my code to show up nice and formatted like yours.
Use the 'code' tag to format your posts on this message board. The tags are [ code ] and [ /code ] without the extra spaces. The PHP tag also works but watch out if you use it because it removes backslash '\\' chars.
Don
pgg1
8th August 2007 10:31 UTC
Thanks for the reply,
Yes I did open the command window after the script ran. I am aware of the environment block so no worries there.
I've added the "broadcast" line just before the function returns so the window command will be updated when we add to the system path or remove from the system path.
Thanks for your help I'm very grateful.
Paul
pgg1
8th August 2007 10:32 UTC
I forgot to say that it all works as expected, so once again thank you.
Paul
starrider78
22nd August 2007 21:19 UTC
Originally posted by pengyou
The NSIS wiki has several pages which explain how to set and remove environment variables and how to change the PATH variable.
PATH manipulation is discussed here:
http://nsis.sourceforge.net/Path_Manipulation
http://nsis.sourceforge.net/Path_man...on_in_run-time
The wiki also explains how to make WriteEnvStr.nsh modify variables for all users and shows how to make changes available without requiring a reboot.
http://nsis.sourceforge.net/Setting_...ment_Variables
Okay, using that for "adding on to the path"
overwrites the current path. This is not desirable when you are writing to the system path (and is not recoverable via system restore either.)