Memento.nsh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. !verbose push
  2. !verbose 3
  3. !include LogicLib.nsh
  4. !include Sections.nsh
  5. !ifndef ___MEMENTO_NSH___
  6. !define ___MEMENTO_NSH___
  7. #####################################
  8. ### Memento ###
  9. #####################################
  10. /*
  11. Memento is a set of macros that allow installers to remember user selection
  12. across separate runs of the installer. Currently, it can remember the state
  13. of sections and mark new sections as bold. In the future, it'll integrate
  14. InstallOptions and maybe even the Modern UI.
  15. A usage example can be found in `Examples\Memento.nsi`.
  16. */
  17. #####################################
  18. ### Usage Instructions ###
  19. #####################################
  20. /*
  21. 1. Declare usage of Memento by including Memento.nsh at the top of the script.
  22. !include Memento.nsh
  23. 2. Define MEMENTO_REGISTRY_ROOT and MEMENTO_REGISTRY_KEY with the a registry key
  24. where sections' state should be saved.
  25. !define MEMENTO_REGISTRY_ROOT HKLM
  26. !define MEMENTO_REGISTRY_KEY \
  27. Software\Microsoft\Windows\CurrentVersion\Uninstall\MyProgram
  28. 3. Replace Section with ${MementoSection} and SectionEnd with ${MementoSectionEnd}
  29. for sections that whose state should be remembered by Memento.
  30. For sections that should be unselected by default, use ${MementoSection}'s
  31. brother - ${MementoUnselectedSection}.
  32. Sections that don't already have an identifier must be assigned one.
  33. Section identifiers must stay the same across different versions of the
  34. installer or their state will be forgotten.
  35. 4. Use ${MementoSectionDone} after the last ${MementoSection}.
  36. 5. Add a call to ${MementoSectionRestore} to .onInit to restore the state
  37. of all sections from the registry.
  38. Function .onInit
  39. ${MementoSectionRestore}
  40. FunctionEnd
  41. 6. Add a call to ${MementoSectionSave} to .onInstSuccess to save the state
  42. of all sections to the registry.
  43. Function .onInstSuccess
  44. ${MementoSectionSave}
  45. FunctionEnd
  46. 7. Tattoo the location of the chosen registry key on your arm.
  47. */
  48. #####################################
  49. ### User API ###
  50. #####################################
  51. ;
  52. ; ${MementoSection}
  53. ;
  54. ; Defines a section whose state is remembered by Memento.
  55. ;
  56. ; Usage is similar to Section.
  57. ;
  58. ; ${MementoSection} "name" "some_id"
  59. ;
  60. !define MementoSection "!insertmacro MementoSection"
  61. ;
  62. ; ${MementoSectionEnd}
  63. ;
  64. ; Ends a section previously opened using ${MementoSection}.
  65. ;
  66. ; Usage is similar to SectionEnd.
  67. ;
  68. ; ${MementoSection} "name" "some_id"
  69. ; # some code...
  70. ; ${MementoSectionEnd}
  71. ;
  72. ;
  73. ; ${MementoUnselectedSection}
  74. ;
  75. ; Defines a section whose state is remembered by Memento and is
  76. ; unselected by default.
  77. ;
  78. ; Usage is similar to Section with the /o switch.
  79. ;
  80. ; ${MementoUnselectedSection} "name" "some_id"
  81. ;
  82. !define MementoUnselectedSection "!insertmacro MementoUnselectedSection"
  83. ;
  84. ; ${MementoSectionEnd}
  85. ;
  86. ; Ends a section previously opened using ${MementoSection}.
  87. ;
  88. ; Usage is similar to SectionEnd.
  89. ;
  90. ; ${MementoSection} "name" "some_id"
  91. ; # some code...
  92. ; ${MementoSectionEnd}
  93. ;
  94. !define MementoSectionEnd "!insertmacro MementoSectionEnd"
  95. ;
  96. ; ${MementoSectionDone}
  97. ;
  98. ; Used after all ${MementoSection} have been set.
  99. ;
  100. ; ${MementoSection} "name1" "some_id1"
  101. ; # some code...
  102. ; ${MementoSectionEnd}
  103. ;
  104. ; ${MementoSection} "name2" "some_id2"
  105. ; # some code...
  106. ; ${MementoSectionEnd}
  107. ;
  108. ; ${MementoSection} "name3" "some_id3"
  109. ; # some code...
  110. ; ${MementoSectionEnd}
  111. ;
  112. ; ${MementoSectionDone}
  113. ;
  114. !define MementoSectionDone "!insertmacro MementoSectionDone"
  115. ;
  116. ; ${MementoSectionRestore}
  117. ;
  118. ; Restores the state of all Memento sections from the registry.
  119. ;
  120. ; Commonly used in .onInit.
  121. ;
  122. ; Function .onInit
  123. ;
  124. ; ${MementoSectionRestore}
  125. ;
  126. ; FunctionEnd
  127. ;
  128. !define MementoSectionRestore "!insertmacro MementoSectionRestore"
  129. ;
  130. ; ${MementoSectionSave}
  131. ;
  132. ; Saves the state of all Memento sections to the registry.
  133. ;
  134. ; Commonly used in .onInstSuccess.
  135. ;
  136. ; Function .onInstSuccess
  137. ;
  138. ; ${MementoSectionSave}
  139. ;
  140. ; FunctionEnd
  141. ;
  142. !define MementoSectionSave "!insertmacro MementoSectionSave"
  143. ;
  144. ; MementoSection<ReadWrite><Int|Marker>
  145. ;
  146. ; Replacable macros that allow custom storage methods to be used.
  147. ;
  148. !ifmacrondef MementoSectionReadInt
  149. !define __MementoSectionStdRegReadWrite
  150. !macro MementoSectionReadInt outvar name
  151. ReadRegDWord ${outvar} ${MEMENTO_REGISTRY_ROOT} `${MEMENTO_REGISTRY_KEY}` `MementoSection${name}`
  152. !macroend
  153. !macro MementoSectionWriteInt name val
  154. WriteRegDWord ${MEMENTO_REGISTRY_ROOT} `${MEMENTO_REGISTRY_KEY}` `MementoSection${name}` `${val}`
  155. !macroend
  156. !macro MementoSectionReadMarker outvar name
  157. ReadRegStr ${outvar} ${MEMENTO_REGISTRY_ROOT} `${MEMENTO_REGISTRY_KEY}` `MementoSection${name}`
  158. !macroend
  159. !macro MementoSectionWriteMarker name
  160. WriteRegStr ${MEMENTO_REGISTRY_ROOT} `${MEMENTO_REGISTRY_KEY}` `MementoSection${name}` ``
  161. !macroend
  162. !endif
  163. #####################################
  164. ### Internal Defines ###
  165. #####################################
  166. !define __MementoSectionIndex 1
  167. #####################################
  168. ### Internal Macros ###
  169. #####################################
  170. !macro __MementoCheckSettings
  171. !ifdef __MementoSectionStdRegReadWrite
  172. !ifndef MEMENTO_REGISTRY_ROOT | MEMENTO_REGISTRY_KEY
  173. !error "MEMENTO_REGISTRY_ROOT and MEMENTO_REGISTRY_KEY must be defined before using any of Memento's macros"
  174. !endif
  175. !endif
  176. !macroend
  177. !macro __MementoSection flags name id
  178. !insertmacro __MementoCheckSettings
  179. !ifndef __MementoSectionIndex
  180. !error "MementoSectionDone already used!"
  181. !endif
  182. !define __MementoSectionLastSectionId `${id}`
  183. !verbose pop
  184. Section ${flags} `${name}` `${id}`
  185. !verbose push
  186. !verbose 3
  187. !macroend
  188. #####################################
  189. ### User Macros ###
  190. #####################################
  191. !macro MementoSection name id
  192. !verbose push
  193. !verbose 3
  194. !insertmacro __MementoSection "" `${name}` `${id}`
  195. !verbose pop
  196. !macroend
  197. !macro MementoUnselectedSection name id
  198. !verbose push
  199. !verbose 3
  200. !insertmacro __MementoSection /o `${name}` `${id}`
  201. !define __MementoSectionUnselected
  202. !verbose pop
  203. !macroend
  204. !macro MementoSectionEnd
  205. SectionEnd
  206. !verbose push
  207. !verbose 3
  208. !insertmacro __MementoCheckSettings
  209. !ifndef __MementoSectionIndex
  210. !error "MementoSectionDone already used!"
  211. !endif
  212. !define /MATH __MementoSectionIndexNext \
  213. ${__MementoSectionIndex} + 1
  214. Function __MementoSectionMarkNew${__MementoSectionIndex}
  215. ClearErrors
  216. !insertmacro MementoSectionReadInt $0 `_${__MementoSectionLastSectionId}`
  217. ${If} ${Errors}
  218. !insertmacro SetSectionFlag `${${__MementoSectionLastSectionId}}` ${SF_BOLD}
  219. ${EndIf}
  220. GetFunctionAddress $0 __MementoSectionMarkNew${__MementoSectionIndexNext}
  221. Goto $0
  222. FunctionEnd
  223. Function __MementoSectionRestoreStatus${__MementoSectionIndex}
  224. ClearErrors
  225. !insertmacro MementoSectionReadInt $0 `_${__MementoSectionLastSectionId}`
  226. !ifndef __MementoSectionUnselected
  227. ${If} ${Errors}
  228. ${OrIf} $0 != 0
  229. !insertmacro SelectSection `${${__MementoSectionLastSectionId}}`
  230. ${Else}
  231. !insertmacro UnselectSection `${${__MementoSectionLastSectionId}}`
  232. ${EndIf}
  233. !else
  234. !undef __MementoSectionUnselected
  235. ${If} ${Errors}
  236. ${OrIf} $0 == 0
  237. !insertmacro UnselectSection `${${__MementoSectionLastSectionId}}`
  238. ${Else}
  239. !insertmacro SelectSection `${${__MementoSectionLastSectionId}}`
  240. ${EndIf}
  241. !endif
  242. GetFunctionAddress $0 __MementoSectionRestoreStatus${__MementoSectionIndexNext}
  243. Goto $0
  244. FunctionEnd
  245. Function __MementoSectionSaveStatus${__MementoSectionIndex}
  246. ${If} ${SectionIsSelected} `${${__MementoSectionLastSectionId}}`
  247. !insertmacro MementoSectionWriteInt `_${__MementoSectionLastSectionId}` 1
  248. ${Else}
  249. !insertmacro MementoSectionWriteInt `_${__MementoSectionLastSectionId}` 0
  250. ${EndIf}
  251. GetFunctionAddress $0 __MementoSectionSaveStatus${__MementoSectionIndexNext}
  252. Goto $0
  253. FunctionEnd
  254. !undef __MementoSectionIndex
  255. !define __MementoSectionIndex ${__MementoSectionIndexNext}
  256. !undef __MementoSectionIndexNext
  257. !undef __MementoSectionLastSectionId
  258. !verbose pop
  259. !macroend
  260. !macro MementoSectionDone
  261. !verbose push
  262. !verbose 3
  263. !insertmacro __MementoCheckSettings
  264. Function __MementoSectionMarkNew${__MementoSectionIndex}
  265. FunctionEnd
  266. Function __MementoSectionRestoreStatus${__MementoSectionIndex}
  267. FunctionEnd
  268. Function __MementoSectionSaveStatus${__MementoSectionIndex}
  269. FunctionEnd
  270. !undef __MementoSectionIndex
  271. !verbose pop
  272. !macroend
  273. !macro MementoSectionRestore
  274. !verbose push
  275. !verbose 3
  276. !insertmacro __MementoCheckSettings
  277. Push $0
  278. Push $1
  279. Push $2
  280. Push $3
  281. # check for first usage
  282. ClearErrors
  283. !insertmacro MementoSectionReadMarker $0 `Used`
  284. ${If} ${Errors}
  285. # use script defaults on first run
  286. Goto done
  287. ${EndIf}
  288. # mark new components in bold
  289. Call __MementoSectionMarkNew1
  290. # mark section groups in bold
  291. StrCpy $0 0
  292. StrCpy $1 ""
  293. StrCpy $2 ""
  294. StrCpy $3 ""
  295. loop:
  296. ClearErrors
  297. ${If} ${SectionIsBold} $0
  298. ${If} $1 != ""
  299. !insertmacro SetSectionFlag $1 ${SF_BOLD}
  300. ${EndIf}
  301. ${If} $2 != ""
  302. !insertmacro SetSectionFlag $2 ${SF_BOLD}
  303. ${EndIf}
  304. ${If} $3 != ""
  305. !insertmacro SetSectionFlag $3 ${SF_BOLD}
  306. ${EndIf}
  307. ${ElseIf} ${Errors}
  308. Goto loop_end
  309. ${EndIf}
  310. ${If} ${SectionIsSectionGroup} $0
  311. ${If} $1 == ""
  312. StrCpy $1 $0
  313. ${ElseIf} $2 == ""
  314. StrCpy $2 $0
  315. ${ElseIf} $3 == ""
  316. StrCpy $3 $0
  317. ${EndIf}
  318. ${EndIf}
  319. ${If} ${SectionIsSectionGroupEnd} $0
  320. ${If} $3 != ""
  321. StrCpy $3 ""
  322. ${ElseIf} $2 != ""
  323. StrCpy $2 ""
  324. ${ElseIf} $1 != ""
  325. StrCpy $1 ""
  326. ${EndIf}
  327. ${EndIf}
  328. IntOp $0 $0 + 1
  329. Goto loop
  330. loop_end:
  331. # restore sections' status
  332. Call __MementoSectionRestoreStatus1
  333. # all done
  334. done:
  335. Pop $3
  336. Pop $2
  337. Pop $1
  338. Pop $0
  339. !verbose pop
  340. !macroend
  341. !macro MementoSectionSave
  342. !verbose push
  343. !verbose 3
  344. !insertmacro __MementoCheckSettings
  345. Push $0
  346. !insertmacro MementoSectionWriteMarker `Used`
  347. Call __MementoSectionSaveStatus1
  348. Pop $0
  349. !verbose pop
  350. !macroend
  351. !endif # ___MEMENTO_NSH___
  352. !verbose pop