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
13Function 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
75done:
76  Pop $4
77  Pop $3
78  Pop $2
79  Pop $1
80  Pop $0
81FunctionEnd
82
83
84; RemoveFromPath - Removes dir from PATH
85;
86; Usage:
87;   Push "dir"
88;   Call RemoveFromPath
89Function 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
143done:
144  Pop $6
145  Pop $5
146  Pop $4
147  Pop $3
148  Pop $2
149  Pop $1
150  Pop $0
151FunctionEnd
152
153
154