问题
I read that "Strings longer than ${NSIS_MAX_STRLEN} (1024) will get truncated/corrupted."
How can I safely update %PATH% environment variable?
回答1:
You can use an alternative NSIS build from the special builds page like the large strings build that defines NSIS_MAX_STRLEN=8192
and should prevent you from breaking the host path.
In practice, on a desktop machine, 1024 byte seems enough, but on a development host with many tools installed (like mine), the path might be broken after manipulation, while the 8192 bytes strings build had never perturbed my machine.
To be very sure, you can add a check on the path length before manipulation and abort the installer with a message in the case where the path would be close to the NSIS_MAX_STRLEN
constant before trying to manipulate it.
回答2:
The real solution is to write a custom plugin or call the Windows API directly with the system plugin so you can avoid the NSIS buffer length limitation:
!include LogicLib.nsh
!include WinCore.nsh
!ifndef NSIS_CHAR_SIZE
!define NSIS_CHAR_SIZE 1
!endif
Function RegAppendString
System::Store S
Pop $R0 ; append
Pop $R1 ; separator
Pop $R2 ; reg value
Pop $R3 ; reg path
Pop $R4 ; reg hkey
System::Call 'ADVAPI32::RegCreateKey(i$R4,tR3,*i.r1)i.r0'
${If} $0 = 0
System::Call 'ADVAPI32::RegQueryValueEx(ir1,tR2,i0,*i.r2,i0,*i0r3)i.r0'
${If} $0 <> 0
StrCpy $2 ${REG_SZ}
StrCpy $3 0
${EndIf}
StrLen $4 $R0
StrLen $5 $R1
IntOp $4 $4 + $5
IntOp $4 $4 + 1 ; For \0
!if ${NSIS_CHAR_SIZE} > 1
IntOp $4 $4 * ${NSIS_CHAR_SIZE}
!endif
IntOp $4 $4 + $3
System::Alloc $4
System::Call 'ADVAPI32::RegQueryValueEx(ir1,tR2,i0,i0,isr9,*ir4r4)i.r0'
${If} $0 = 0
${OrIf} $0 = ${ERROR_FILE_NOT_FOUND}
System::Call 'KERNEL32::lstrlen(t)(ir9)i.r0'
${If} $0 <> 0
System::Call 'KERNEL32::lstrcat(t)(ir9,tR1)'
${EndIf}
System::Call 'KERNEL32::lstrcat(t)(ir9,tR0)'
System::Call 'KERNEL32::lstrlen(t)(ir9)i.r0'
IntOp $0 $0 + 1
!if ${NSIS_CHAR_SIZE} > 1
IntOp $0 $0 * ${NSIS_CHAR_SIZE}
!endif
System::Call 'ADVAPI32::RegSetValueEx(ir1,tR2,i0,ir2,ir9,ir0)i.r0'
${EndIf}
System::Free $9
System::Call 'ADVAPI32::RegCloseKey(ir1)'
${EndIf}
Push $0
System::Store L
FunctionEnd
Section
Push ${HKEY_CURRENT_USER}
Push "Environment"
Push "Path"
Push ";"
Push "c:\whatever"
Call RegAppendString
Pop $0
DetailPrint RegAppendString:Error=$0
SectionEnd
回答3:
I prefer using windows command processor (cmd.exe
) via the NSIS nsExec::Exec
command, which allows you to append to the PATH
easily like so:
; Check if the path entry already exists and write result to $0
nsExec::Exec 'echo %PATH% | find "c:\some\new\dir"'
Pop $0 ; gets result code
${If} $0 = 0
nsExec::Exec 'setx PATH=%PATH%;c:\some\new\dir'
${EndIf}
Using this method, CMD.EXE
expands the PATH
variable internally, safe from any NSIS string length limits. Alternatively, change the order of %PATH%
token pasting if you want your program to be picked up first, ahead of anything and everything else that might be installed on the system by the same name:
nsExec::Exec 'setx PATH=c:\some\new\dir;%PATH%'
Note that it's important not to include double-quotes while building the new PATH
. The command processor never expects double-quotes in the PATH string and may behave in unexpected ways if you add any. It delimits paths by semicolon (;
) only.
Also note that this methods depends on the large strings build as explained by Seki in his answer.
nsExec::Exec
differs from ExecWait
in that it runs internally, without popping up additional visible cmd prompt windows.
回答4:
I have been wrote the NSIS 3.0 example to handle cases longer than the limit and without a need to install anything. Answered the question here: Set environment variables with NSIS in Window 7
回答5:
I was frustrated looking at all the complicated plugins and char limitations with the NSIS stuff so I wrote a tiny little application called PathEd to take care of all.
It is designed to be deployed within your installer and can be called from its deploy location like this, for example:
PathEd.exe add "C:\Program Files\RepoZ"
or
PathEd.exe remove "C:\Program Files\RepoZ"
PathEd takes care of the semicolon handling, duplicate avoidance, case-insensitive checks, user account control prompts, argument quote handling, safe and defensive value removal and so on.
Feel free to use it. But then, don't forget to give it a star on GitHub.
See https://github.com/awaescher/PathEd
来源:https://stackoverflow.com/questions/31340823/update-path-environment-variable-using-nsis