【问题标题】:Update %PATH% environment variable using NSIS使用 NSIS 更新 %PATH% 环境变量
【发布时间】:2015-09-29 04:56:45
【问题描述】:

我了解到“长度超过 ${NSIS_MAX_STRLEN} (1024) 的字符串将被截断/损坏。”

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

【问题讨论】:

    标签: windows path installation environment-variables nsis


    【解决方案1】:

    看到 NSIS 的所有复杂插件和字符限制让我感到沮丧,因此我编写了一个名为 PathEd 的小应用程序来处理所有问题。

    它被设计为部署在您的安装程序中,并且可以像这样从其部署位置调用,例如:

    PathEd.exe add "C:\Program Files\RepoZ" 要么 PathEd.exe remove "C:\Program Files\RepoZ"

    PathEd 负责分号处理、避免重复、不区分大小写检查、用户帐户控制提示、参数引用处理、安全和防御性值删除等。

    请随意使用。但是,别忘了在 GitHub 上给它一个星号。

    https://github.com/awaescher/PathEd

    【讨论】:

      【解决方案2】:

      我更喜欢通过 NSIS nsExec::Exec 命令使用 Windows 命令处理器 (cmd.exe),它允许您像这样轻松地附加到 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}
      

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

          nsExec::Exec 'setx PATH=c:\some\new\dir;%PATH%'
      

      请注意,在构建新的PATH 时包含双引号很重要。命令处理器从不期望 PATH 字符串中有双引号,并且如果添加任何双引号,则可能会以意想不到的方式运行。它仅用分号 (;) 分隔路径。

      另请注意,此方法依赖于 large strings buildexplained by Seki in his answer

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

      【讨论】:

      • 这似乎截断了我的结果。
      • 在命令行上手动运行时出现以下错误:错误:语法无效。键入“SETX /?”供使用
      【解决方案3】:

      我已经编写了 NSIS 3.0 示例来处理超过限制的案例,并且无需安装任何东西。在这里回答了问题:Set environment variables with NSIS in Window 7

      【讨论】:

        【解决方案4】:

        您可以使用来自 special builds page 的替代 NSIS 构建,例如定义 NSIS_MAX_STRLEN=8192large strings build,并且应该可以防止您破坏主机路径。

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

        为了非常确定,您可以在操作之前添加对路径长度的检查,并在尝试操作之前在路径接近 NSIS_MAX_STRLEN 常量的情况下中止安装程序并显示消息。

        【讨论】:

          【解决方案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 
          

          【讨论】:

          • 我只对 RegAppendString 函数做了一些小测试,理想情况下你会强制零终止,检查它是否已经在末尾有分隔符并在循环中执行所有这些以避免字符串更改的问题在对 RegQueryValueEx 的调用之间。
          猜你喜欢
          • 1970-01-01
          • 2012-07-09
          • 1970-01-01
          • 2015-01-21
          • 2016-05-04
          • 1970-01-01
          • 2019-06-30
          • 1970-01-01
          • 2019-05-15
          相关资源
          最近更新 更多