Newer
Older
dub_jkp / installer / win / EnvVarUpdate.nsh
@eco eco on 28 Feb 2013 10 KB Add Windows installer
  1. /**
  2. * EnvVarUpdate.nsh
  3. * : Environmental Variables: append, prepend, and remove entries
  4. *
  5. * WARNING: If you use StrFunc.nsh header then include it before this file
  6. * with all required definitions. This is to avoid conflicts
  7. *
  8. * Usage:
  9. * ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
  10. *
  11. * Credits:
  12. * Version 1.0
  13. * * Cal Turney (turnec2)
  14. * * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
  15. * function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
  16. * WriteEnvStr, and un.DeleteEnvStr
  17. * * Diego Pedroso (deguix) for StrTok
  18. * * Kevin English (kenglish_hi) for StrContains
  19. * * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry
  20. * (dandaman32) for StrReplace
  21. *
  22. * Version 1.1 (compatibility with StrFunc.nsh)
  23. * * techtonik
  24. *
  25. * http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
  26. *
  27. */
  28. !ifndef ENVVARUPDATE_FUNCTION
  29. !define ENVVARUPDATE_FUNCTION
  30. !verbose push
  31. !verbose 3
  32. !include "LogicLib.nsh"
  33. !include "WinMessages.NSH"
  34. !include "StrFunc.nsh"
  35. ; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
  36. !macro _IncludeStrFunction StrFuncName
  37. !ifndef ${StrFuncName}_INCLUDED
  38. ${${StrFuncName}}
  39. !endif
  40. !ifndef Un${StrFuncName}_INCLUDED
  41. ${Un${StrFuncName}}
  42. !endif
  43. !define un.${StrFuncName} "${Un${StrFuncName}}"
  44. !macroend
  45. !insertmacro _IncludeStrFunction StrTok
  46. !insertmacro _IncludeStrFunction StrStr
  47. !insertmacro _IncludeStrFunction StrRep
  48. ; ---------------------------------- Macro Definitions ----------------------------------------
  49. !macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
  50. Push "${EnvVarName}"
  51. Push "${Action}"
  52. Push "${RegLoc}"
  53. Push "${PathString}"
  54. Call EnvVarUpdate
  55. Pop "${ResultVar}"
  56. !macroend
  57. !define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
  58. !macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
  59. Push "${EnvVarName}"
  60. Push "${Action}"
  61. Push "${RegLoc}"
  62. Push "${PathString}"
  63. Call un.EnvVarUpdate
  64. Pop "${ResultVar}"
  65. !macroend
  66. !define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
  67. ; ---------------------------------- Macro Definitions end-------------------------------------
  68. ;----------------------------------- EnvVarUpdate start----------------------------------------
  69. !define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
  70. !define hkcu_current_user 'HKCU "Environment"'
  71. !macro EnvVarUpdate UN
  72. Function ${UN}EnvVarUpdate
  73. Push $0
  74. Exch 4
  75. Exch $1
  76. Exch 3
  77. Exch $2
  78. Exch 2
  79. Exch $3
  80. Exch
  81. Exch $4
  82. Push $5
  83. Push $6
  84. Push $7
  85. Push $8
  86. Push $9
  87. Push $R0
  88. /* After this point:
  89. -------------------------
  90. $0 = ResultVar (returned)
  91. $1 = EnvVarName (input)
  92. $2 = Action (input)
  93. $3 = RegLoc (input)
  94. $4 = PathString (input)
  95. $5 = Orig EnvVar (read from registry)
  96. $6 = Len of $0 (temp)
  97. $7 = tempstr1 (temp)
  98. $8 = Entry counter (temp)
  99. $9 = tempstr2 (temp)
  100. $R0 = tempChar (temp) */
  101. ; Step 1: Read contents of EnvVarName from RegLoc
  102. ;
  103. ; Check for empty EnvVarName
  104. ${If} $1 == ""
  105. SetErrors
  106. DetailPrint "ERROR: EnvVarName is blank"
  107. Goto EnvVarUpdate_Restore_Vars
  108. ${EndIf}
  109. ; Check for valid Action
  110. ${If} $2 != "A"
  111. ${AndIf} $2 != "P"
  112. ${AndIf} $2 != "R"
  113. SetErrors
  114. DetailPrint "ERROR: Invalid Action - must be A, P, or R"
  115. Goto EnvVarUpdate_Restore_Vars
  116. ${EndIf}
  117. ${If} $3 == HKLM
  118. ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5
  119. ${ElseIf} $3 == HKCU
  120. ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5
  121. ${Else}
  122. SetErrors
  123. DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
  124. Goto EnvVarUpdate_Restore_Vars
  125. ${EndIf}
  126. ; Check for empty PathString
  127. ${If} $4 == ""
  128. SetErrors
  129. DetailPrint "ERROR: PathString is blank"
  130. Goto EnvVarUpdate_Restore_Vars
  131. ${EndIf}
  132.  
  133. ;;khc - here check if length is going to be greater then max string length
  134. ;; and abort if so - also abort if original path empty - may mean
  135. ;; it was too long as well- write message to say set it by hand
  136.  
  137. Push $6
  138. Push $7
  139. Push $8
  140. StrLen $7 $4
  141. StrLen $6 $5
  142. IntOp $8 $6 + $7
  143. ${If} $5 == ""
  144. ${OrIf} $8 >= ${NSIS_MAX_STRLEN}
  145. SetErrors
  146. DetailPrint "Current $1 length ($6) too long to modify in NSIS; set manually if needed"
  147. Pop $8
  148. Pop $7
  149. Pop $6
  150. Goto EnvVarUpdate_Restore_Vars
  151. ${EndIf}
  152. Pop $8
  153. Pop $7
  154. Pop $6
  155. ;;khc
  156.  
  157. ; Make sure we've got some work to do
  158. ${If} $5 == ""
  159. ${AndIf} $2 == "R"
  160. SetErrors
  161. DetailPrint "$1 is empty - Nothing to remove"
  162. Goto EnvVarUpdate_Restore_Vars
  163. ${EndIf}
  164. ; Step 2: Scrub EnvVar
  165. ;
  166. StrCpy $0 $5 ; Copy the contents to $0
  167. ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
  168. ; after the last one are not removed here but instead in Step 3)
  169. ${If} $0 != "" ; If EnvVar is not empty ...
  170. ${Do}
  171. ${${UN}StrStr} $7 $0 " ;"
  172. ${If} $7 == ""
  173. ${ExitDo}
  174. ${EndIf}
  175. ${${UN}StrRep} $0 $0 " ;" ";" ; Remove '<space>;'
  176. ${Loop}
  177. ${Do}
  178. ${${UN}StrStr} $7 $0 "; "
  179. ${If} $7 == ""
  180. ${ExitDo}
  181. ${EndIf}
  182. ${${UN}StrRep} $0 $0 "; " ";" ; Remove ';<space>'
  183. ${Loop}
  184. ${Do}
  185. ${${UN}StrStr} $7 $0 ";;"
  186. ${If} $7 == ""
  187. ${ExitDo}
  188. ${EndIf}
  189. ${${UN}StrRep} $0 $0 ";;" ";"
  190. ${Loop}
  191. ; Remove a leading or trailing semicolon from EnvVar
  192. StrCpy $7 $0 1 0
  193. ${If} $7 == ";"
  194. StrCpy $0 $0 "" 1 ; Change ';<EnvVar>' to '<EnvVar>'
  195. ${EndIf}
  196. StrLen $6 $0
  197. IntOp $6 $6 - 1
  198. StrCpy $7 $0 1 $6
  199. ${If} $7 == ";"
  200. StrCpy $0 $0 $6 ; Change ';<EnvVar>' to '<EnvVar>'
  201. ${EndIf}
  202. ; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug
  203. ${EndIf}
  204. /* Step 3. Remove all instances of the target path/string (even if "A" or "P")
  205. $6 = bool flag (1 = found and removed PathString)
  206. $7 = a string (e.g. path) delimited by semicolon(s)
  207. $8 = entry counter starting at 0
  208. $9 = copy of $0
  209. $R0 = tempChar */
  210. ${If} $5 != "" ; If EnvVar is not empty ...
  211. StrCpy $9 $0
  212. StrCpy $0 ""
  213. StrCpy $8 0
  214. StrCpy $6 0
  215. ${Do}
  216. ${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter
  217. ${If} $7 == "" ; If we've run out of entries,
  218. ${ExitDo} ; were done
  219. ${EndIf} ;
  220. ; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
  221. ${Do}
  222. StrCpy $R0 $7 1
  223. ${If} $R0 != " "
  224. ${ExitDo}
  225. ${EndIf}
  226. StrCpy $7 $7 "" 1 ; Remove leading space
  227. ${Loop}
  228. ${Do}
  229. StrCpy $R0 $7 1 -1
  230. ${If} $R0 != " "
  231. ${ExitDo}
  232. ${EndIf}
  233. StrCpy $7 $7 -1 ; Remove trailing space
  234. ${Loop}
  235. ${If} $7 == $4 ; If string matches, remove it by not appending it
  236. StrCpy $6 1 ; Set 'found' flag
  237. ${ElseIf} $7 != $4 ; If string does NOT match
  238. ${AndIf} $0 == "" ; and the 1st string being added to $0,
  239. StrCpy $0 $7 ; copy it to $0 without a prepended semicolon
  240. ${ElseIf} $7 != $4 ; If string does NOT match
  241. ${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0,
  242. StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon
  243. ${EndIf} ;
  244. IntOp $8 $8 + 1 ; Bump counter
  245. ${Loop} ; Check for duplicates until we run out of paths
  246. ${EndIf}
  247. ; Step 4: Perform the requested Action
  248. ;
  249. ${If} $2 != "R" ; If Append or Prepend
  250. ${If} $6 == 1 ; And if we found the target
  251. DetailPrint "Target is already present in $1. It will be removed and"
  252. ${EndIf}
  253. ${If} $0 == "" ; If EnvVar is (now) empty
  254. StrCpy $0 $4 ; just copy PathString to EnvVar
  255. ${If} $6 == 0 ; If found flag is either 0
  256. ${OrIf} $6 == "" ; or blank (if EnvVarName is empty)
  257. DetailPrint "$1 was empty and has been updated with the target"
  258. ${EndIf}
  259. ${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty),
  260. StrCpy $0 $0;$4 ; append PathString
  261. ${If} $6 == 1
  262. DetailPrint "appended to $1"
  263. ${Else}
  264. DetailPrint "Target was appended to $1"
  265. ${EndIf}
  266. ${Else} ; If Prepend (and EnvVar is not empty),
  267. StrCpy $0 $4;$0 ; prepend PathString
  268. ${If} $6 == 1
  269. DetailPrint "prepended to $1"
  270. ${Else}
  271. DetailPrint "Target was prepended to $1"
  272. ${EndIf}
  273. ${EndIf}
  274. ${Else} ; If Action = Remove
  275. ${If} $6 == 1 ; and we found the target
  276. DetailPrint "Target was found and removed from $1"
  277. ${Else}
  278. DetailPrint "Target was NOT found in $1 (nothing to remove)"
  279. ${EndIf}
  280. ${If} $0 == ""
  281. DetailPrint "$1 is now empty"
  282. ${EndIf}
  283. ${EndIf}
  284. ; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change
  285. ;
  286. ClearErrors
  287. ${If} $3 == HKLM
  288. WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section
  289. ${ElseIf} $3 == HKCU
  290. WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section
  291. ${EndIf}
  292. IfErrors 0 +4
  293. MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
  294. DetailPrint "Could not write updated $1 to $3"
  295. Goto EnvVarUpdate_Restore_Vars
  296. ; "Export" our change
  297. SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=1
  298. EnvVarUpdate_Restore_Vars:
  299. ;
  300. ; Restore the user's variables and return ResultVar
  301. Pop $R0
  302. Pop $9
  303. Pop $8
  304. Pop $7
  305. Pop $6
  306. Pop $5
  307. Pop $4
  308. Pop $3
  309. Pop $2
  310. Pop $1
  311. Push $0 ; Push my $0 (ResultVar)
  312. Exch
  313. Pop $0 ; Restore his $0
  314. FunctionEnd
  315. !macroend ; EnvVarUpdate UN
  316. !insertmacro EnvVarUpdate ""
  317. !insertmacro EnvVarUpdate "un."
  318. ;----------------------------------- EnvVarUpdate end----------------------------------------
  319. !verbose pop
  320. !endif