|
| 1 | +!include "WinMessages.nsh" |
| 2 | + |
| 3 | +; see https://support.microsoft.com/en-us/kb/104011 |
| 4 | +!define Environ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' |
| 5 | +; HKEY_LOCAL_MACHINE = 0x80000002 |
| 6 | + |
| 7 | +; AddToPath - Appends dir to PATH |
| 8 | +; (does not work on Win9x/ME) |
| 9 | +; |
| 10 | +; Usage: |
| 11 | +; Push "dir" |
| 12 | +; Call AddToPath |
| 13 | +Function AddToPath |
| 14 | + Exch $0 |
| 15 | + Push $1 |
| 16 | + Push $2 |
| 17 | + Push $3 |
| 18 | + Push $4 |
| 19 | + |
| 20 | + ; NSIS ReadRegStr returns empty string on string overflow |
| 21 | + ; Native calls are used here to check actual length of PATH |
| 22 | + ; $4 = RegOpenKey(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", &$3) |
| 23 | + System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4" |
| 24 | + IntCmp $4 0 0 done done |
| 25 | + |
| 26 | + ; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2)) |
| 27 | + ; RegCloseKey($3) |
| 28 | + System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4" |
| 29 | + System::Call "advapi32::RegCloseKey(i $3)" |
| 30 | + |
| 31 | + IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA |
| 32 | + DetailPrint "AddToPath: original length $2 > ${NSIS_MAX_STRLEN}" |
| 33 | + MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}" |
| 34 | + Goto done |
| 35 | + |
| 36 | + IntCmp $4 0 +5 ; $4 != NO_ERROR |
| 37 | + IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND |
| 38 | + DetailPrint "AddToPath: unexpected error code $4" |
| 39 | + Goto done |
| 40 | + StrCpy $1 "" |
| 41 | + |
| 42 | + ; Check if already in PATH |
| 43 | + Push "$1;" |
| 44 | + Push "$0;" |
| 45 | + Call StrStr |
| 46 | + Pop $2 |
| 47 | + StrCmp $2 "" 0 done |
| 48 | + Push "$1;" |
| 49 | + Push "$0\;" |
| 50 | + Call StrStr |
| 51 | + Pop $2 |
| 52 | + StrCmp $2 "" 0 done |
| 53 | + |
| 54 | + ; Prevent NSIS string overflow |
| 55 | + StrLen $2 $0 |
| 56 | + StrLen $3 $1 |
| 57 | + IntOp $2 $2 + $3 |
| 58 | + IntOp $2 $2 + 2 ; $2 = strlen(dir) + strlen(PATH) + sizeof(";") |
| 59 | + IntCmp $2 ${NSIS_MAX_STRLEN} +4 +4 0 |
| 60 | + DetailPrint "AddToPath: new length $2 > ${NSIS_MAX_STRLEN}" |
| 61 | + MessageBox MB_OK "PATH not updated, new length $2 > ${NSIS_MAX_STRLEN}." |
| 62 | + Goto done |
| 63 | + |
| 64 | + ; Append dir to PATH |
| 65 | + DetailPrint "Add to PATH: $0" |
| 66 | + StrCpy $2 $1 1 -1 |
| 67 | + StrCmp $2 ";" 0 +2 |
| 68 | + StrCpy $1 $1 -1 ; remove trailing ';' |
| 69 | + StrCmp $1 "" +2 ; no leading ';' |
| 70 | + StrCpy $0 "$1;$0" |
| 71 | + |
| 72 | + WriteRegExpandStr ${Environ} "PATH" $0 |
| 73 | + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 |
| 74 | + |
| 75 | +done: |
| 76 | + Pop $4 |
| 77 | + Pop $3 |
| 78 | + Pop $2 |
| 79 | + Pop $1 |
| 80 | + Pop $0 |
| 81 | +FunctionEnd |
| 82 | + |
| 83 | + |
| 84 | +; RemoveFromPath - Removes dir from PATH |
| 85 | +; |
| 86 | +; Usage: |
| 87 | +; Push "dir" |
| 88 | +; Call RemoveFromPath |
| 89 | +Function un.RemoveFromPath |
| 90 | + Exch $0 |
| 91 | + Push $1 |
| 92 | + Push $2 |
| 93 | + Push $3 |
| 94 | + Push $4 |
| 95 | + Push $5 |
| 96 | + Push $6 |
| 97 | + |
| 98 | + ; NSIS ReadRegStr returns empty string on string overflow |
| 99 | + ; Native calls are used here to check actual length of PATH |
| 100 | + ; $4 = RegOpenKey(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", &$3) |
| 101 | + System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4" |
| 102 | + IntCmp $4 0 0 done done |
| 103 | + |
| 104 | + ; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2)) |
| 105 | + ; RegCloseKey($3) |
| 106 | + System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4" |
| 107 | + System::Call "advapi32::RegCloseKey(i $3)" |
| 108 | + |
| 109 | + IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA |
| 110 | + DetailPrint "RemoveFromPath: original length $2 > ${NSIS_MAX_STRLEN}" |
| 111 | + MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}" |
| 112 | + Goto done |
| 113 | + |
| 114 | + IntCmp $4 0 +5 ; $4 != NO_ERROR |
| 115 | + IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND |
| 116 | + DetailPrint "RemoveFromPath: unexpected error code $4" |
| 117 | + Goto done |
| 118 | + StrCpy $1 "" |
| 119 | + |
| 120 | + ; length < ${NSIS_MAX_STRLEN} -> ReadRegStr can be used |
| 121 | + ReadRegStr $1 ${Environ} "PATH" |
| 122 | + StrCpy $5 $1 1 -1 |
| 123 | + StrCmp $5 ";" +2 |
| 124 | + StrCpy $1 "$1;" ; ensure trailing ';' |
| 125 | + Push $1 |
| 126 | + Push "$0;" |
| 127 | + Call un.StrStr |
| 128 | + Pop $2 ; pos of our dir |
| 129 | + StrCmp $2 "" done |
| 130 | + |
| 131 | + DetailPrint "Remove from PATH: $0" |
| 132 | + StrLen $3 "$0;" |
| 133 | + StrLen $4 $2 |
| 134 | + StrCpy $5 $1 -$4 ; $5 is now the part before the path to remove |
| 135 | + StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove |
| 136 | + StrCpy $3 "$5$6" |
| 137 | + StrCpy $5 $3 1 -1 |
| 138 | + StrCmp $5 ";" 0 +2 |
| 139 | + StrCpy $3 $3 -1 ; remove trailing ';' |
| 140 | + WriteRegExpandStr ${Environ} "PATH" $3 |
| 141 | + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 |
| 142 | + |
| 143 | +done: |
| 144 | + Pop $6 |
| 145 | + Pop $5 |
| 146 | + Pop $4 |
| 147 | + Pop $3 |
| 148 | + Pop $2 |
| 149 | + Pop $1 |
| 150 | + Pop $0 |
| 151 | +FunctionEnd |
| 152 | + |
| 153 | + |
0 commit comments