Path manipulation with all users/current user selection in run-time
Author: turnec2 (talk, contrib) |
EnvVarUpdate
The AddToPath and un.RemoveFromPath functions in this page have been obsoleted by EnvVarUpdate. The un.RemoveFromPath routine can corrupt the contents of the PATH variable if the path being removed happens to be a subset of another. For example, if PATH contains "C:\Windows\system32\wbem" and you remove "C:\Windows\system32" the result is "\wbem". AddToPath does not prevent the duplication of entries if the user runs the installer multiple times (and the installer code does not otherwise check for duplicates). Nevertheless, these routines have been retained for Windows 9x/ME users in the next section since EnvVarUpdate does not support the update of variables in the autoexec.bat file.
See Environmental_Variables:_append,_prepend,_and_remove_entries for more information.
Function Code
Author: e-circ (talk, contrib) |
Functions for Windows 95, 98, and ME
I adapted Path manipulation routines so you can select to change the path in the all users/current user profile in runtime.
The original message:
Here are two functions, one for adding directories to the search path of Windows and the other to remove them. These functions should work on every version of Windows including 95, 98, ME, NT, 2000, and XP.
For Windows NT/2000/XP they will write to HKEY_CURRENT_USER\Environment\PATH. For 9x/ME they will write to the autoexec.bat file.
Changes on 9x machines will take place after a reboot. These functions do not set the reboot flag so that should be done manually.
These functions require NSIS 2.0b0 and above due to the usage of SendMessage with /TIMEOUT. It is possible to use it with earlier version of NSIS with a litte application I have created called RefreshEnv. It does exactly the same as SendMessage with /TIMEOUT. You can find it at this forum thread.
Usage example:
Section "Add to path" Push $INSTDIR Call AddToPath SectionEnd ... Section "uninstall" # ... Push $INSTDIR Call un.RemoveFromPath # ... SectionEnd
The functions in the flesh:
;---------------------------------------- ; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02" ;---------------------------------------- !verbose 3 !include "WinMessages.NSH" !verbose 4 ;==================================================== ; get_NT_environment ; Returns: the selected environment ; Output : head of the stack ;==================================================== !macro select_NT_profile UN Function ${UN}select_NT_profile MessageBox MB_YESNO|MB_ICONQUESTION "Change the environment for all users?$\r$\nSaying no here will change the envrironment for the current user only.$\r$\n(Administrator permissions required for all users)" \ IDNO environment_single DetailPrint "Selected environment for all users" Push "all" Return environment_single: DetailPrint "Selected environment for current user only." Push "current" Return FunctionEnd !macroend !insertmacro select_NT_profile "" !insertmacro select_NT_profile "un." ;---------------------------------------------------- !define NT_current_env 'HKCU "Environment"' !define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' ;==================================================== ; IsNT - Returns 1 if the current system is NT, 0 ; otherwise. ; Output: head of the stack ;==================================================== !macro IsNT UN Function ${UN}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 !macroend !insertmacro IsNT "" !insertmacro IsNT "un." ;==================================================== ; AddToPath - Adds the given dir to the search path. ; Input - head of the stack ; Note - Win9x systems requires reboot ;==================================================== Function AddToPath Exch $0 Push $1 Push $2 Call IsNT Pop $1 StrCmp $1 1 AddToPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" a FileSeek $1 0 END GetFullPathName /SHORT $0 $0 FileWrite $1 "$\r$\nSET PATH=%PATH%;$0$\r$\n" FileClose $1 Goto AddToPath_done AddToPath_NT: Push $4 Call select_NT_profile Pop $4 AddToPath_NT_selection_done: StrCmp $4 "current" read_path_NT_current ReadRegStr $1 ${NT_all_env} "PATH" Goto read_path_NT_resume read_path_NT_current: ReadRegStr $1 ${NT_current_env} "PATH" read_path_NT_resume: StrCpy $2 $0 StrCmp $1 "" AddToPath_NTdoIt StrCpy $2 "$1;$0" AddToPath_NTdoIt: StrCmp $4 "current" write_path_NT_current ClearErrors WriteRegExpandStr ${NT_all_env} "PATH" $2 IfErrors 0 write_path_NT_resume MessageBox MB_YESNO|MB_ICONQUESTION "The path could not be set for all users$\r$\nShould I try for the current user?" \ IDNO write_path_NT_failed ; change selection StrCpy $4 "current" Goto AddToPath_NT_selection_done write_path_NT_current: ClearErrors WriteRegExpandStr ${NT_current_env} "PATH" $2 IfErrors 0 write_path_NT_resume MessageBox MB_OK|MB_ICONINFORMATION "The path could not be set for the current user." Goto write_path_NT_failed write_path_NT_resume: SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 DetailPrint "added path for user ($4), $0" write_path_NT_failed: Pop $4 AddToPath_done: Pop $2 Pop $1 Pop $0 FunctionEnd ;==================================================== ; RemoveFromPath - Remove a given dir from the path ; Input: head of the stack ;==================================================== Function un.RemoveFromPath Exch $0 Push $1 Push $2 Push $3 Push $4 Call un.IsNT Pop $1 StrCmp $1 1 unRemoveFromPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" r GetTempFileName $4 FileOpen $2 $4 w GetFullPathName /SHORT $0 $0 StrCpy $0 "SET PATH=%PATH%;$0" SetRebootFlag true Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoop: FileRead $1 $3 StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoop StrCmp $3 "$0$\n" unRemoveFromPath_dosLoop StrCmp $3 "$0" unRemoveFromPath_dosLoop StrCmp $3 "" unRemoveFromPath_dosLoopEnd FileWrite $2 $3 Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopEnd: FileClose $2 FileClose $1 StrCpy $1 $WINDIR 2 Delete "$1\autoexec.bat" CopyFiles /SILENT $4 "$1\autoexec.bat" Delete $4 Goto unRemoveFromPath_done unRemoveFromPath_NT: StrLen $2 $0 Call un.select_NT_profile Pop $4 StrCmp $4 "current" un_read_path_NT_current ReadRegStr $1 ${NT_all_env} "PATH" Goto un_read_path_NT_resume un_read_path_NT_current: ReadRegStr $1 ${NT_current_env} "PATH" un_read_path_NT_resume: Push $1 Push $0 Call un.StrStr ; Find $0 in $1 Pop $0 ; pos of our dir IntCmp $0 -1 unRemoveFromPath_done ; else, it is in path StrCpy $3 $1 $0 ; $3 now has the part of the path before our dir IntOp $2 $2 + $0 ; $2 now contains the pos after our dir in the path (';') IntOp $2 $2 + 1 ; $2 now containts the pos after our dir and the semicolon. StrLen $0 $1 StrCpy $1 $1 $0 $2 StrCpy $3 "$3$1" StrCmp $4 "current" un_write_path_NT_current WriteRegExpandStr ${NT_all_env} "PATH" $3 Goto un_write_path_NT_resume un_write_path_NT_current: WriteRegExpandStr ${NT_current_env} "PATH" $3 un_write_path_NT_resume: SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 unRemoveFromPath_done: Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Uninstall sutff ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;==================================================== ; StrStr - Finds a given string in another given string. ; Returns -1 if not found and the pos if found. ; Input: head of the stack - string to find ; second in the stack - string to find in ; Output: head of the stack ;==================================================== Function un.StrStr Push $0 Exch Pop $0 ; $0 now have the string to find Push $1 Exch 2 Pop $1 ; $1 now have the string to find in Exch Push $2 Push $3 Push $4 Push $5 StrCpy $2 -1 StrLen $3 $0 StrLen $4 $1 IntOp $4 $4 - $3 unStrStr_loop: IntOp $2 $2 + 1 IntCmp $2 $4 0 0 unStrStrReturn_notFound StrCpy $5 $1 $3 $2 StrCmp $5 $0 unStrStr_done unStrStr_loop unStrStrReturn_notFound: StrCpy $2 -1 unStrStr_done: Pop $5 Pop $4 Pop $3 Exch $2 Exch 2 Pop $0 Pop $1 FunctionEnd ;====================================================