Обновить переменную среды %PATH% с помощью NSIS

Я читал, что " строки длиннее ${NSIS_MAX_STRLEN} (1024) будет обрезан или поврежден."

Как я могу безопасное обновление %PATH % переменная окружения?

4 ответов


вы можете использовать альтернативную сборку NSIS из специальная страница сборки как большие строки build что определяет NSIS_MAX_STRLEN=8192 и должен помешать вам нарушить путь хоста.

на практике на настольной машине 1024 байта кажется достаточным, но на хосте разработки с множеством установленных инструментов (например, мой) путь может быть нарушен после манипуляции, в то время как сборка строк 8192 байт никогда не возмущала мою машину.

быть очень уверенным, вы можете добавить проверку длины пути перед манипуляцией и прервать установщик сообщением в случае, если путь будет близок к NSIS_MAX_STRLEN константа перед попыткой манипулировать ею.


реальное решение-написать пользовательский плагин или вызвать 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
    System::Call 'ADVAPI32::RegQueryValueEx(ir1,tR2,i0,*i.r2,i0,*i0r3)i.r0'
    ${If}  <> 0
        StrCpy  ${REG_SZ}
        StrCpy  0
    ${EndIf}
    StrLen  $R0
    StrLen  $R1
    IntOp   + 
    IntOp   + 1 ; For 
    !if ${NSIS_CHAR_SIZE} > 1
        IntOp   * ${NSIS_CHAR_SIZE}
    !endif
    IntOp   + 
    System::Alloc 
    System::Call 'ADVAPI32::RegQueryValueEx(ir1,tR2,i0,i0,isr9,*ir4r4)i.r0'
    ${If}  = 0
    ${OrIf}  = ${ERROR_FILE_NOT_FOUND}
        System::Call 'KERNEL32::lstrlen(t)(ir9)i.r0'
        ${If}  <> 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   + 1
        !if ${NSIS_CHAR_SIZE} > 1
            IntOp   * ${NSIS_CHAR_SIZE}
        !endif
        System::Call 'ADVAPI32::RegSetValueEx(ir1,tR2,i0,ir2,ir9,ir0)i.r0'
    ${EndIf}
    System::Free 
    System::Call 'ADVAPI32::RegCloseKey(ir1)'
${EndIf}
Push 
System::Store L
FunctionEnd

Section

Push ${HKEY_CURRENT_USER}
Push "Environment"
Push "Path"
Push ";"
Push "c:\whatever"
Call RegAppendString
Pop 
DetailPrint RegAppendString:Error=

SectionEnd 

я предпочитаю использовать командный процессор Windows (cmd.exe) через NSIS nsExec::Exec команда, которая позволяет добавлять к PATH легко вот так:

; Check if the path entry already exists and write result to 
nsExec::Exec 'echo %PATH% | find "c:\some\new\dir"'
Pop    ; gets result code

${If}  = 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. Командный процессор никогда не ожидает двойных кавычек в строке пути и может вести себя неожиданным образом при добавлении. Он ограничивает пути точкой с запятой (;) только.

также обратите внимание, что эти методы зависят от большие строки build as объяснено Seki в его ответ.

nsExec::Exec отличается от ExecWait в том, что он работает внутри, без появления дополнительных видимых окон командной строки cmd.


Я написал пример NSIS 3.0 для обработки случаев дольше, чем предел, и без необходимости устанавливать что-либо. Ответил на вопрос здесь:установить переменные среды с NSIS в окне 7