使用NSIS更新%PATH%环境变量

Cyb*_*lor 9 windows installer nsis path environment-variables

我读到"超过$ {NSIS_MAX_STRLEN} (1024)的字符串将被截断/损坏."

如何安全地更新%PATH%环境变量

Sek*_*eki 6

您可以使用特殊构建页面中的备用NSIS构建,例如定义的大型字符串构建,NSIS_MAX_STRLEN=8192并且应该阻止您破坏主机路径.

实际上,在台式机上,1024字节似乎已经足够了,但是在安装了许多工具的开发主机上(如我的),操作后路径可能会被破坏,而8192字节的字符串构建从未扰乱我的机器.

要非常肯定,您可以在操作之前添加对路径长度的检查,并NSIS_MAX_STRLEN在尝试操作路径之前路径将接近常量的情况下使用消息中止安装程序.


And*_*ers 5

真正的解决方案是编写自定义插件或直接使用系统插件调用 Windows API,这样就可以避免 NSIS 缓冲区长度限制:

!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 
Run Code Online (Sandbox Code Playgroud)


jst*_*ine 5

我更喜欢cmd.exe通过 NSISnsExec::Exec命令使用 windows 命令处理器 ( ) ,它允许您PATH像这样轻松地附加到:

; 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}
Run Code Online (Sandbox Code Playgroud)

使用此方法,CMD.EXEPATH内部扩展变量,不受任何 NSIS 字符串长度限制。或者,%PATH%如果您希望您的程序在任何可能以相同名称安装在系统上的任何其他东西之前被首先提取,请更改令牌粘贴的顺序:

    nsExec::Exec 'setx PATH=c:\some\new\dir;%PATH%'
Run Code Online (Sandbox Code Playgroud)

需要注意的是它的重要包括双引号,同时建立新的PATH。命令处理器从不希望在 PATH 字符串中有双引号,并且如果添加双引号,可能会以意想不到的方式运行。它;仅用分号 ( )分隔路径。

另外请注意,此方法依赖于大串打造通过关在他的回答解释

nsExec::Exec不同之处ExecWait在于它在内部运行,不会弹出额外的可见 cmd 提示窗口。