1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5
6################################################################################
7# Helper defines and macros for toolkit applications
8
9/**
10 * Avoid creating macros / functions that overwrite registers (see the
11 * GetLongPath macro for one way to avoid this)!
12 *
13 * Before using the registers exchange the passed in params and save existing
14 * register values to the stack.
15 *
16 * Exch $R9 ; exhange the original $R9 with the top of the stack
17 * Exch 1   ; exchange the top of the stack with 1 below the top of the stack
18 * Exch $R8 ; exchange the original $R8 with the top of the stack
19 * Exch 2   ; exchange the top of the stack with 2 below the top of the stack
20 * Exch $R7 ; exchange the original $R7 with the top of the stack
21 * Push $R6 ; push the original $R6 onto the top of the stack
22 * Push $R5 ; push the original $R5 onto the top of the stack
23 * Push $R4 ; push the original $R4 onto the top of the stack
24 *
25 * <do stuff>
26 *
27 * ; Restore the values.
28 * Pop $R4  ; restore the value for $R4 from the top of the stack
29 * Pop $R5  ; restore the value for $R5 from the top of the stack
30 * Pop $R6  ; restore the value for $R6 from the top of the stack
31 * Exch $R7 ; exchange the new $R7 value with the top of the stack
32 * Exch 2   ; exchange the top of the stack with 2 below the top of the stack
33 * Exch $R8 ; exchange the new $R8 value with the top of the stack
34 * Exch 1   ; exchange the top of the stack with 2 below the top of the stack
35 * Exch $R9 ; exchange the new $R9 value with the top of the stack
36 *
37 *
38 * When inserting macros in common.nsh from another macro in common.nsh that
39 * can be used from the uninstaller _MOZFUNC_UN will be undefined when it is
40 * inserted. Use the following to redefine _MOZFUNC_UN with its original value
41 * (see the RegCleanMain macro for an example).
42 *
43 * !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
44 * !insertmacro ${_MOZFUNC_UN_TMP}FileJoin
45 * !insertmacro ${_MOZFUNC_UN_TMP}LineFind
46 * !insertmacro ${_MOZFUNC_UN_TMP}TextCompareNoDetails
47 * !insertmacro ${_MOZFUNC_UN_TMP}TrimNewLines
48 * !undef _MOZFUNC_UN
49 * !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
50 * !undef _MOZFUNC_UN_TMP
51 */
52
53; When including a file provided by NSIS check if its verbose macro is defined
54; to prevent loading the file a second time.
55!ifmacrondef TEXTFUNC_VERBOSE
56  !include TextFunc.nsh
57!endif
58
59!ifmacrondef FILEFUNC_VERBOSE
60  !include FileFunc.nsh
61!endif
62
63!ifmacrondef LOGICLIB_VERBOSITY
64  !include LogicLib.nsh
65!endif
66
67!ifndef WINMESSAGES_INCLUDED
68  !include WinMessages.nsh
69!endif
70
71; When including WinVer.nsh check if ___WINVER__NSH___ is defined to prevent
72; loading the file a second time.
73!ifndef ___WINVER__NSH___
74  !include WinVer.nsh
75!endif
76
77; When including x64.nsh check if ___X64__NSH___ is defined to prevent
78; loading the file a second time.
79!ifndef ___X64__NSH___
80  !include x64.nsh
81!endif
82
83; NSIS provided macros that we have overridden.
84!include overrides.nsh
85
86!define SHORTCUTS_LOG "shortcuts_log.ini"
87!define TO_BE_DELETED "tobedeleted"
88
89; !define SHCNF_DWORD     0x0003
90; !define SHCNF_FLUSH     0x1000
91!ifndef SHCNF_DWORDFLUSH
92  !define SHCNF_DWORDFLUSH 0x1003
93!endif
94!ifndef SHCNE_ASSOCCHANGED
95  !define SHCNE_ASSOCCHANGED 0x08000000
96!endif
97
98################################################################################
99# Macros for debugging
100
101/**
102 * The following two macros assist with verifying that a macro doesn't
103 * overwrite any registers.
104 *
105 * Usage:
106 * ${debugSetRegisters}
107 * <do stuff>
108 * ${debugDisplayRegisters}
109 */
110
111/**
112 * Sets all register values to their name to assist with verifying that a macro
113 * doesn't overwrite any registers.
114 */
115!macro debugSetRegisters
116  StrCpy $0 "$$0"
117  StrCpy $1 "$$1"
118  StrCpy $2 "$$2"
119  StrCpy $3 "$$3"
120  StrCpy $4 "$$4"
121  StrCpy $5 "$$5"
122  StrCpy $6 "$$6"
123  StrCpy $7 "$$7"
124  StrCpy $8 "$$8"
125  StrCpy $9 "$$9"
126  StrCpy $R0 "$$R0"
127  StrCpy $R1 "$$R1"
128  StrCpy $R2 "$$R2"
129  StrCpy $R3 "$$R3"
130  StrCpy $R4 "$$R4"
131  StrCpy $R5 "$$R5"
132  StrCpy $R6 "$$R6"
133  StrCpy $R7 "$$R7"
134  StrCpy $R8 "$$R8"
135  StrCpy $R9 "$$R9"
136!macroend
137!define debugSetRegisters "!insertmacro debugSetRegisters"
138
139/**
140 * Displays all register values to assist with verifying that a macro doesn't
141 * overwrite any registers.
142 */
143!macro debugDisplayRegisters
144  MessageBox MB_OK \
145      "Register Values:$\n\
146       $$0 = $0$\n$$1 = $1$\n$$2 = $2$\n$$3 = $3$\n$$4 = $4$\n\
147       $$5 = $5$\n$$6 = $6$\n$$7 = $7$\n$$8 = $8$\n$$9 = $9$\n\
148       $$R0 = $R0$\n$$R1 = $R1$\n$$R2 = $R2$\n$$R3 = $R3$\n$$R4 = $R4$\n\
149       $$R5 = $R5$\n$$R6 = $R6$\n$$R7 = $R7$\n$$R8 = $R8$\n$$R9 = $R9"
150!macroend
151!define debugDisplayRegisters "!insertmacro debugDisplayRegisters"
152
153
154################################################################################
155# Modern User Interface (MUI) override macros
156
157; Removed macros in nsis 2.33u (ported from nsis 2.22)
158;  MUI_LANGUAGEFILE_DEFINE
159;  MUI_LANGUAGEFILE_LANGSTRING_PAGE
160;  MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE
161;  MUI_LANGUAGEFILE_LANGSTRING_DEFINE
162;  MUI_LANGUAGEFILE_UNLANGSTRING_PAGE
163
164!macro MOZ_MUI_LANGUAGEFILE_DEFINE DEFINE NAME
165
166  !ifndef "${DEFINE}"
167    !define "${DEFINE}" "${${NAME}}"
168  !endif
169  !undef "${NAME}"
170
171!macroend
172
173!macro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE PAGE NAME
174
175  !ifdef MUI_${PAGE}PAGE
176    LangString "${NAME}" 0 "${${NAME}}"
177    !undef "${NAME}"
178  !else
179    !undef "${NAME}"
180  !endif
181
182!macroend
183
184!macro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE PAGE NAME
185
186  !ifdef MUI_${PAGE}PAGE | MUI_UN${PAGE}PAGE
187    LangString "${NAME}" 0 "${${NAME}}"
188    !undef "${NAME}"
189  !else
190    !undef "${NAME}"
191  !endif
192
193!macroend
194
195!macro MOZ_MUI_LANGUAGEFILE_LANGSTRING_DEFINE DEFINE NAME
196
197  !ifdef "${DEFINE}"
198    LangString "${NAME}" 0 "${${NAME}}"
199  !endif
200  !undef "${NAME}"
201
202!macroend
203
204!macro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE PAGE NAME
205
206  !ifdef MUI_UNINSTALLER
207    !ifdef MUI_UN${PAGE}PAGE
208      LangString "${NAME}" 0 "${${NAME}}"
209      !undef "${NAME}"
210    !else
211      !undef "${NAME}"
212    !endif
213  !else
214    !undef "${NAME}"
215  !endif
216
217!macroend
218
219; Modified version of the following MUI macros to support Mozilla localization.
220; MUI_LANGUAGE
221; MUI_LANGUAGEFILE_BEGIN
222; MOZ_MUI_LANGUAGEFILE_END
223; See <NSIS App Dir>/Contrib/Modern UI/System.nsh for more information
224!define MUI_INSTALLOPTIONS_READ "!insertmacro MUI_INSTALLOPTIONS_READ"
225
226!macro MOZ_MUI_LANGUAGE LANGUAGE
227  !verbose push
228  !verbose ${MUI_VERBOSE}
229  !include "${LANGUAGE}.nsh"
230  !verbose pop
231!macroend
232
233!macro MOZ_MUI_LANGUAGEFILE_BEGIN LANGUAGE
234  !insertmacro MUI_INSERT
235  !ifndef "MUI_LANGUAGEFILE_${LANGUAGE}_USED"
236    !define "MUI_LANGUAGEFILE_${LANGUAGE}_USED"
237    LoadLanguageFile "${LANGUAGE}.nlf"
238  !else
239    !error "Modern UI language file ${LANGUAGE} included twice!"
240  !endif
241!macroend
242
243; Custom version of MUI_LANGUAGEFILE_END. The macro to add the default MUI
244; strings and the macros for several strings that are part of the NSIS MUI and
245; not in our locale files have been commented out.
246!macro MOZ_MUI_LANGUAGEFILE_END
247
248#  !include "${NSISDIR}\Contrib\Modern UI\Language files\Default.nsh"
249  !ifdef MUI_LANGUAGEFILE_DEFAULT_USED
250    !undef MUI_LANGUAGEFILE_DEFAULT_USED
251    !warning "${LANGUAGE} Modern UI language file version doesn't match. Using default English texts for missing strings."
252  !endif
253
254  !insertmacro MOZ_MUI_LANGUAGEFILE_DEFINE "MUI_${LANGUAGE}_LANGNAME" "MUI_LANGNAME"
255
256  !ifndef MUI_LANGDLL_PUSHLIST
257    !define MUI_LANGDLL_PUSHLIST "'${MUI_${LANGUAGE}_LANGNAME}' ${LANG_${LANGUAGE}} "
258  !else
259    !ifdef MUI_LANGDLL_PUSHLIST_TEMP
260      !undef MUI_LANGDLL_PUSHLIST_TEMP
261    !endif
262    !define MUI_LANGDLL_PUSHLIST_TEMP "${MUI_LANGDLL_PUSHLIST}"
263    !undef MUI_LANGDLL_PUSHLIST
264    !define MUI_LANGDLL_PUSHLIST "'${MUI_${LANGUAGE}_LANGNAME}' ${LANG_${LANGUAGE}} ${MUI_LANGDLL_PUSHLIST_TEMP}"
265  !endif
266
267  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE WELCOME "MUI_TEXT_WELCOME_INFO_TITLE"
268  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE WELCOME "MUI_TEXT_WELCOME_INFO_TEXT"
269
270!ifdef MUI_TEXT_LICENSE_TITLE
271  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_TEXT_LICENSE_TITLE"
272!endif
273!ifdef MUI_TEXT_LICENSE_SUBTITLE
274  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_TEXT_LICENSE_SUBTITLE"
275!endif
276!ifdef MUI_INNERTEXT_LICENSE_TOP
277  !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_TOP"
278!endif
279
280#  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_BOTTOM"
281
282!ifdef MUI_INNERTEXT_LICENSE_BOTTOM_CHECKBOX
283  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_BOTTOM_CHECKBOX"
284!endif
285
286!ifdef MUI_INNERTEXT_LICENSE_BOTTOM_RADIOBUTTONS
287  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_BOTTOM_RADIOBUTTONS"
288!endif
289
290  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE COMPONENTS "MUI_TEXT_COMPONENTS_TITLE"
291  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE COMPONENTS "MUI_TEXT_COMPONENTS_SUBTITLE"
292  !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE COMPONENTS "MUI_INNERTEXT_COMPONENTS_DESCRIPTION_TITLE"
293  !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE COMPONENTS "MUI_INNERTEXT_COMPONENTS_DESCRIPTION_INFO"
294
295  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE DIRECTORY "MUI_TEXT_DIRECTORY_TITLE"
296  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE DIRECTORY "MUI_TEXT_DIRECTORY_SUBTITLE"
297
298  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_TEXT_STARTMENU_TITLE"
299  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_TEXT_STARTMENU_SUBTITLE"
300  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_INNERTEXT_STARTMENU_TOP"
301#  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_INNERTEXT_STARTMENU_CHECKBOX"
302
303  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_INSTALLING_TITLE"
304  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_INSTALLING_SUBTITLE"
305
306  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_FINISH_TITLE"
307  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_FINISH_SUBTITLE"
308
309  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_ABORT_TITLE"
310  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_ABORT_SUBTITLE"
311
312  !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_BUTTONTEXT_FINISH"
313  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_INFO_TITLE"
314  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_INFO_TEXT"
315  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_INFO_REBOOT"
316  !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_REBOOTNOW"
317  !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_REBOOTLATER"
318#  !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_RUN"
319#  !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_SHOWREADME"
320
321; Support for using the existing MUI_TEXT_ABORTWARNING string
322!ifdef MOZ_MUI_CUSTOM_ABORT
323    LangString MOZ_MUI_TEXT_ABORTWARNING 0 "${MUI_TEXT_ABORTWARNING}"
324!endif
325
326  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_DEFINE MUI_ABORTWARNING "MUI_TEXT_ABORTWARNING"
327
328
329  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE WELCOME "MUI_UNTEXT_WELCOME_INFO_TITLE"
330  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE WELCOME "MUI_UNTEXT_WELCOME_INFO_TEXT"
331
332  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE CONFIRM "MUI_UNTEXT_CONFIRM_TITLE"
333  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE CONFIRM "MUI_UNTEXT_CONFIRM_SUBTITLE"
334
335#  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNTEXT_LICENSE_TITLE"
336#  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNTEXT_LICENSE_SUBTITLE"
337
338#  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNINNERTEXT_LICENSE_BOTTOM"
339#  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNINNERTEXT_LICENSE_BOTTOM_CHECKBOX"
340#  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNINNERTEXT_LICENSE_BOTTOM_RADIOBUTTONS"
341
342#  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE COMPONENTS "MUI_UNTEXT_COMPONENTS_TITLE"
343#  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE COMPONENTS "MUI_UNTEXT_COMPONENTS_SUBTITLE"
344
345#  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE DIRECTORY "MUI_UNTEXT_DIRECTORY_TITLE"
346#  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE DIRECTORY  "MUI_UNTEXT_DIRECTORY_SUBTITLE"
347
348  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_UNINSTALLING_TITLE"
349  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_UNINSTALLING_SUBTITLE"
350
351  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_FINISH_TITLE"
352  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_FINISH_SUBTITLE"
353
354  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_ABORT_TITLE"
355  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_ABORT_SUBTITLE"
356
357  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE FINISH "MUI_UNTEXT_FINISH_INFO_TITLE"
358  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE FINISH "MUI_UNTEXT_FINISH_INFO_TEXT"
359  !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE FINISH "MUI_UNTEXT_FINISH_INFO_REBOOT"
360
361  !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_DEFINE MUI_UNABORTWARNING "MUI_UNTEXT_ABORTWARNING"
362
363  !ifndef MUI_LANGDLL_LANGUAGES
364    !define MUI_LANGDLL_LANGUAGES "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' "
365    !define MUI_LANGDLL_LANGUAGES_CP "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' '${LANG_${LANGUAGE}_CP}' "
366  !else
367    !ifdef MUI_LANGDLL_LANGUAGES_TEMP
368      !undef MUI_LANGDLL_LANGUAGES_TEMP
369    !endif
370    !define MUI_LANGDLL_LANGUAGES_TEMP "${MUI_LANGDLL_LANGUAGES}"
371    !undef MUI_LANGDLL_LANGUAGES
372
373    !ifdef MUI_LANGDLL_LANGUAGES_CP_TEMP
374      !undef MUI_LANGDLL_LANGUAGES_CP_TEMP
375    !endif
376    !define MUI_LANGDLL_LANGUAGES_CP_TEMP "${MUI_LANGDLL_LANGUAGES_CP}"
377    !undef MUI_LANGDLL_LANGUAGES_CP
378
379    !define MUI_LANGDLL_LANGUAGES "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' ${MUI_LANGDLL_LANGUAGES_TEMP}"
380    !define MUI_LANGDLL_LANGUAGES_CP "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' '${LANG_${LANGUAGE}_CP}' ${MUI_LANGDLL_LANGUAGES_CP_TEMP}"
381  !endif
382
383!macroend
384
385/**
386 * Creates an InstallOptions file with a UTF-16LE BOM and adds the RTL value
387 * to the Settings section.
388 *
389 * @param   _FILE
390 *          The name of the file to be created in $PLUGINSDIR.
391 */
392!macro InitInstallOptionsFile _FILE
393  Push $R9
394
395  FileOpen $R9 "$PLUGINSDIR\${_FILE}" w
396  FileWriteWord $R9 "65279"
397  FileClose $R9
398  WriteIniStr "$PLUGINSDIR\${_FILE}" "Settings" "RTL" "$(^RTL)"
399
400  Pop $R9
401!macroend
402
403
404################################################################################
405# Macros for handling files in use
406
407/**
408 * Checks for files in use in the $INSTDIR directory. To check files in
409 * sub-directories this macro would need to be rewritten to create
410 * sub-directories in the temporary directory used to backup the files that are
411 * checked.
412 *
413 * Example usage:
414 *
415 *  ; The first string to be pushed onto the stack MUST be "end" to indicate
416 *  ; that there are no more files in the $INSTDIR directory to check.
417 *  Push "end"
418 *  Push "freebl3.dll"
419 *  ; The last file pushed should be the app's main exe so if it is in use this
420 *  ; macro will return after the first check.
421 *  Push "${FileMainEXE}"
422 *  ${CheckForFilesInUse} $R9
423 *
424 * !IMPORTANT - this macro uses the $R7, $R8, and $R9 registers and makes no
425 *              attempt to restore their original values.
426 *
427 * @return  _RESULT
428 *          false if all of the files popped from the stack are not in use.
429 *          True if any of the files popped from the stack are in use.
430 * $R7 = Temporary backup directory where the files will be copied to.
431 * $R8 = value popped from the stack. This will either be a file name for a file
432 *       in the $INSTDIR directory or "end" to indicate that there are no
433 *       additional files to check.
434 * $R9 = _RESULT
435 */
436!macro CheckForFilesInUse
437
438  !ifndef ${_MOZFUNC_UN}CheckForFilesInUse
439    !verbose push
440    !verbose ${_MOZFUNC_VERBOSE}
441    !define ${_MOZFUNC_UN}CheckForFilesInUse "!insertmacro ${_MOZFUNC_UN}CheckForFilesInUseCall"
442
443    Function ${_MOZFUNC_UN}CheckForFilesInUse
444      ; Create a temporary backup directory.
445      GetTempFileName $R7 "$INSTDIR"
446      Delete "$R7"
447      SetOutPath "$R7"
448      StrCpy $R9 "false"
449
450      Pop $R8
451      ${While} $R8 != "end"
452        ${Unless} ${FileExists} "$INSTDIR\$R8"
453          Pop $R8 ; get next file to check before continuing
454          ${Continue}
455        ${EndUnless}
456
457        ClearErrors
458        CopyFiles /SILENT "$INSTDIR\$R8" "$R7\$R8" ; try to copy
459        ${If} ${Errors}
460          ; File is in use
461          StrCpy $R9 "true"
462          ${Break}
463        ${EndIf}
464
465        Delete "$INSTDIR\$R8" ; delete original
466        ${If} ${Errors}
467          ; File is in use
468          StrCpy $R9 "true"
469          Delete "$R7\$R8" ; delete temp copy
470          ${Break}
471        ${EndIf}
472
473        Pop $R8 ; get next file to check
474      ${EndWhile}
475
476      ; clear stack
477      ${While} $R8 != "end"
478        Pop $R8
479      ${EndWhile}
480
481      ; restore everything
482      SetOutPath "$INSTDIR"
483      CopyFiles /SILENT "$R7\*" "$INSTDIR\"
484      RmDir /r "$R7"
485      SetOutPath "$EXEDIR"
486      ClearErrors
487
488      Push $R9
489    FunctionEnd
490
491    !verbose pop
492  !endif
493!macroend
494
495!macro CheckForFilesInUseCall _RESULT
496  !verbose push
497  !verbose ${_MOZFUNC_VERBOSE}
498  Call CheckForFilesInUse
499  Pop ${_RESULT}
500  !verbose pop
501!macroend
502
503!macro un.CheckForFilesInUseCall _RESULT
504  !verbose push
505  !verbose ${_MOZFUNC_VERBOSE}
506  Call un.CheckForFilesInUse
507  Pop ${_RESULT}
508  !verbose pop
509!macroend
510
511!macro un.CheckForFilesInUse
512  !ifndef un.CheckForFilesInUse
513    !verbose push
514    !verbose ${_MOZFUNC_VERBOSE}
515    !undef _MOZFUNC_UN
516    !define _MOZFUNC_UN "un."
517
518    !insertmacro CheckForFilesInUse
519
520    !undef _MOZFUNC_UN
521    !define _MOZFUNC_UN
522    !verbose pop
523  !endif
524!macroend
525
526/**
527 * The macros below will automatically prepend un. to the function names when
528 * they are defined (e.g. !define un.RegCleanMain).
529 */
530!verbose push
531!verbose 3
532!ifndef _MOZFUNC_VERBOSE
533  !define _MOZFUNC_VERBOSE 3
534!endif
535!verbose ${_MOZFUNC_VERBOSE}
536!define MOZFUNC_VERBOSE "!insertmacro MOZFUNC_VERBOSE"
537!define _MOZFUNC_UN
538!define _MOZFUNC_S
539!verbose pop
540
541!macro MOZFUNC_VERBOSE _VERBOSE
542  !verbose push
543  !verbose 3
544  !undef _MOZFUNC_VERBOSE
545  !define _MOZFUNC_VERBOSE ${_VERBOSE}
546  !verbose pop
547!macroend
548
549/**
550 * Displays a MessageBox and then calls abort to prevent continuing to the
551 * next page when the specified Window Class is found.
552 *
553 * @param   _WINDOW_CLASS
554 *          The Window Class to search for with FindWindow.
555 * @param   _MSG
556 *          The message text to display in the message box.
557 *
558 * $R7 = return value from FindWindow
559 * $R8 = _WINDOW_CLASS
560 * $R9 = _MSG
561 */
562!macro ManualCloseAppPrompt
563
564  !ifndef ${_MOZFUNC_UN}ManualCloseAppPrompt
565    !verbose push
566    !verbose ${_MOZFUNC_VERBOSE}
567    !define ${_MOZFUNC_UN}ManualCloseAppPrompt "!insertmacro ${_MOZFUNC_UN}ManualCloseAppPromptCall"
568
569    Function ${_MOZFUNC_UN}ManualCloseAppPrompt
570      Exch $R9
571      Exch 1
572      Exch $R8
573      Push $R7
574
575      FindWindow $R7 "$R8"
576      ${If} $R7 <> 0 ; integer comparison
577        MessageBox MB_OK|MB_ICONQUESTION "$R9"
578        Abort
579      ${EndIf}
580
581      Pop $R7
582      Exch $R8
583      Exch 1
584      Exch $R9
585    FunctionEnd
586
587    !verbose pop
588  !endif
589!macroend
590
591!macro ManualCloseAppPromptCall _WINDOW_CLASS _MSG
592  !verbose push
593  !verbose ${_MOZFUNC_VERBOSE}
594  Push "${_WINDOW_CLASS}"
595  Push "${_MSG}"
596  Call ManualCloseAppPrompt
597  !verbose pop
598!macroend
599
600!macro un.ManualCloseAppPromptCall _WINDOW_CLASS _MSG
601  !verbose push
602  !verbose ${_MOZFUNC_VERBOSE}
603  Push "${_WINDOW_CLASS}"
604  Push "${_MSG}"
605  Call un.ManualCloseAppPrompt
606  !verbose pop
607!macroend
608
609!macro un.ManualCloseAppPrompt
610  !ifndef un.ManualCloseAppPrompt
611    !verbose push
612    !verbose ${_MOZFUNC_VERBOSE}
613    !undef _MOZFUNC_UN
614    !define _MOZFUNC_UN "un."
615
616    !insertmacro ManualCloseAppPrompt
617
618    !undef _MOZFUNC_UN
619    !define _MOZFUNC_UN
620    !verbose pop
621  !endif
622!macroend
623
624
625################################################################################
626# Macros for working with the registry
627
628/**
629 * Writes a registry string using SHCTX and the supplied params and logs the
630 * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1.
631 *
632 * Define NO_LOG to prevent all logging when calling this from the uninstaller.
633 *
634 * @param   _ROOT
635 *          The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.).
636 *          This will only be used for logging.
637 * @param   _KEY
638 *          The subkey in relation to the key root.
639 * @param   _NAME
640 *          The key value name to write to.
641 * @param   _STR
642 *          The string to write to the key value name.
643 * @param   _LOG_UNINSTALL
644 *          0 = don't add to uninstall log, 1 = add to uninstall log.
645 *
646 * $R5 = _ROOT
647 * $R6 = _KEY
648 * $R7 = _NAME
649 * $R8 = _STR
650 * $R9 = _LOG_UNINSTALL
651 */
652!macro WriteRegStr2
653
654  !ifndef ${_MOZFUNC_UN}WriteRegStr2
655    !verbose push
656    !verbose ${_MOZFUNC_VERBOSE}
657    !define ${_MOZFUNC_UN}WriteRegStr2 "!insertmacro ${_MOZFUNC_UN}WriteRegStr2Call"
658
659    Function ${_MOZFUNC_UN}WriteRegStr2
660      Exch $R9
661      Exch 1
662      Exch $R8
663      Exch 2
664      Exch $R7
665      Exch 3
666      Exch $R6
667      Exch 4
668      Exch $R5
669
670      ClearErrors
671      WriteRegStr SHCTX "$R6" "$R7" "$R8"
672
673      !ifndef NO_LOG
674        ${If} ${Errors}
675          ${LogMsg} "** ERROR Adding Registry String: $R5 | $R6 | $R7 | $R8 **"
676        ${Else}
677          ${If} $R9 == 1 ; add to the uninstall log?
678            ${LogUninstall} "RegVal: $R5 | $R6 | $R7"
679          ${EndIf}
680          ${LogMsg} "Added Registry String: $R5 | $R6 | $R7 | $R8"
681        ${EndIf}
682      !endif
683
684      Exch $R5
685      Exch 4
686      Exch $R6
687      Exch 3
688      Exch $R7
689      Exch 2
690      Exch $R8
691      Exch 1
692      Exch $R9
693    FunctionEnd
694
695    !verbose pop
696  !endif
697!macroend
698
699!macro WriteRegStr2Call _ROOT _KEY _NAME _STR _LOG_UNINSTALL
700  !verbose push
701  !verbose ${_MOZFUNC_VERBOSE}
702  Push "${_ROOT}"
703  Push "${_KEY}"
704  Push "${_NAME}"
705  Push "${_STR}"
706  Push "${_LOG_UNINSTALL}"
707  Call WriteRegStr2
708  !verbose pop
709!macroend
710
711!macro un.WriteRegStr2Call _ROOT _KEY _NAME _STR _LOG_UNINSTALL
712  !verbose push
713  !verbose ${_MOZFUNC_VERBOSE}
714  Push "${_ROOT}"
715  Push "${_KEY}"
716  Push "${_NAME}"
717  Push "${_STR}"
718  Push "${_LOG_UNINSTALL}"
719  Call un.WriteRegStr2
720  !verbose pop
721!macroend
722
723!macro un.WriteRegStr2
724  !ifndef un.WriteRegStr2
725    !verbose push
726    !verbose ${_MOZFUNC_VERBOSE}
727    !undef _MOZFUNC_UN
728    !define _MOZFUNC_UN "un."
729
730    !insertmacro WriteRegStr2
731
732    !undef _MOZFUNC_UN
733    !define _MOZFUNC_UN
734    !verbose pop
735  !endif
736!macroend
737
738/**
739 * Writes a registry dword using SHCTX and the supplied params and logs the
740 * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1.
741 *
742 * Define NO_LOG to prevent all logging when calling this from the uninstaller.
743 *
744 * @param   _ROOT
745 *          The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.).
746 *          This will only be used for logging.
747 * @param   _KEY
748 *          The subkey in relation to the key root.
749 * @param   _NAME
750 *          The key value name to write to.
751 * @param   _DWORD
752 *          The dword to write to the key value name.
753 * @param   _LOG_UNINSTALL
754 *          0 = don't add to uninstall log, 1 = add to uninstall log.
755 *
756 * $R5 = _ROOT
757 * $R6 = _KEY
758 * $R7 = _NAME
759 * $R8 = _DWORD
760 * $R9 = _LOG_UNINSTALL
761 */
762!macro WriteRegDWORD2
763
764  !ifndef ${_MOZFUNC_UN}WriteRegDWORD2
765    !verbose push
766    !verbose ${_MOZFUNC_VERBOSE}
767    !define ${_MOZFUNC_UN}WriteRegDWORD2 "!insertmacro ${_MOZFUNC_UN}WriteRegDWORD2Call"
768
769    Function ${_MOZFUNC_UN}WriteRegDWORD2
770      Exch $R9
771      Exch 1
772      Exch $R8
773      Exch 2
774      Exch $R7
775      Exch 3
776      Exch $R6
777      Exch 4
778      Exch $R5
779
780      ClearErrors
781      WriteRegDWORD SHCTX "$R6" "$R7" "$R8"
782
783      !ifndef NO_LOG
784        ${If} ${Errors}
785          ${LogMsg} "** ERROR Adding Registry DWord: $R5 | $R6 | $R7 | $R8 **"
786        ${Else}
787          ${If} $R9 == 1 ; add to the uninstall log?
788            ${LogUninstall} "RegVal: $R5 | $R6 | $R7"
789          ${EndIf}
790          ${LogMsg} "Added Registry DWord: $R5 | $R6 | $R7 | $R8"
791        ${EndIf}
792      !endif
793
794      Exch $R5
795      Exch 4
796      Exch $R6
797      Exch 3
798      Exch $R7
799      Exch 2
800      Exch $R8
801      Exch 1
802      Exch $R9
803    FunctionEnd
804
805    !verbose pop
806  !endif
807!macroend
808
809!macro WriteRegDWORD2Call _ROOT _KEY _NAME _DWORD _LOG_UNINSTALL
810  !verbose push
811  !verbose ${_MOZFUNC_VERBOSE}
812  Push "${_ROOT}"
813  Push "${_KEY}"
814  Push "${_NAME}"
815  Push "${_DWORD}"
816  Push "${_LOG_UNINSTALL}"
817  Call WriteRegDWORD2
818  !verbose pop
819!macroend
820
821!macro un.WriteRegDWORD2Call _ROOT _KEY _NAME _DWORD _LOG_UNINSTALL
822  !verbose push
823  !verbose ${_MOZFUNC_VERBOSE}
824  Push "${_ROOT}"
825  Push "${_KEY}"
826  Push "${_NAME}"
827  Push "${_DWORD}"
828  Push "${_LOG_UNINSTALL}"
829  Call un.WriteRegDWORD2
830  !verbose pop
831!macroend
832
833!macro un.WriteRegDWORD2
834  !ifndef un.WriteRegDWORD2
835    !verbose push
836    !verbose ${_MOZFUNC_VERBOSE}
837    !undef _MOZFUNC_UN
838    !define _MOZFUNC_UN "un."
839
840    !insertmacro WriteRegDWORD2
841
842    !undef _MOZFUNC_UN
843    !define _MOZFUNC_UN
844    !verbose pop
845  !endif
846!macroend
847
848/**
849 * Writes a registry string to HKCR using the supplied params and logs the
850 * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1.
851 *
852 * Define NO_LOG to prevent all logging when calling this from the uninstaller.
853 *
854 * @param   _ROOT
855 *          The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.).
856 *          This will only be used for logging.
857 * @param   _KEY
858 *          The subkey in relation to the key root.
859 * @param   _NAME
860 *          The key value name to write to.
861 * @param   _STR
862 *          The string to write to the key value name.
863 * @param   _LOG_UNINSTALL
864 *          0 = don't add to uninstall log, 1 = add to uninstall log.
865 *
866 * $R5 = _ROOT
867 * $R6 = _KEY
868 * $R7 = _NAME
869 * $R8 = _STR
870 * $R9 = _LOG_UNINSTALL
871 */
872!macro WriteRegStrHKCR
873
874  !ifndef ${_MOZFUNC_UN}WriteRegStrHKCR
875    !verbose push
876    !verbose ${_MOZFUNC_VERBOSE}
877    !define ${_MOZFUNC_UN}WriteRegStrHKCR "!insertmacro ${_MOZFUNC_UN}WriteRegStrHKCRCall"
878
879    Function ${_MOZFUNC_UN}WriteRegStrHKCR
880      Exch $R9
881      Exch 1
882      Exch $R8
883      Exch 2
884      Exch $R7
885      Exch 3
886      Exch $R6
887      Exch 4
888      Exch $R5
889
890      ClearErrors
891      WriteRegStr HKCR "$R6" "$R7" "$R8"
892
893      !ifndef NO_LOG
894        ${If} ${Errors}
895          ${LogMsg} "** ERROR Adding Registry String: $R5 | $R6 | $R7 | $R8 **"
896        ${Else}
897          ${If} $R9 == 1 ; add to the uninstall log?
898            ${LogUninstall} "RegVal: $R5 | $R6 | $R7"
899          ${EndIf}
900          ${LogMsg} "Added Registry String: $R5 | $R6 | $R7 | $R8"
901        ${EndIf}
902      !endif
903
904      Exch $R5
905      Exch 4
906      Exch $R6
907      Exch 3
908      Exch $R7
909      Exch 2
910      Exch $R8
911      Exch 1
912      Exch $R9
913    FunctionEnd
914
915    !verbose pop
916  !endif
917!macroend
918
919!macro WriteRegStrHKCRCall _ROOT _KEY _NAME _STR _LOG_UNINSTALL
920  !verbose push
921  !verbose ${_MOZFUNC_VERBOSE}
922  Push "${_ROOT}"
923  Push "${_KEY}"
924  Push "${_NAME}"
925  Push "${_STR}"
926  Push "${_LOG_UNINSTALL}"
927  Call WriteRegStrHKCR
928  !verbose pop
929!macroend
930
931!macro un.WriteRegStrHKCRCall _ROOT _KEY _NAME _STR _LOG_UNINSTALL
932  !verbose push
933  !verbose ${_MOZFUNC_VERBOSE}
934  Push "${_ROOT}"
935  Push "${_KEY}"
936  Push "${_NAME}"
937  Push "${_STR}"
938  Push "${_LOG_UNINSTALL}"
939  Call un.WriteRegStrHKCR
940  !verbose pop
941!macroend
942
943!macro un.WriteRegStrHKCR
944  !ifndef un.WriteRegStrHKCR
945    !verbose push
946    !verbose ${_MOZFUNC_VERBOSE}
947    !undef _MOZFUNC_UN
948    !define _MOZFUNC_UN "un."
949
950    !insertmacro WriteRegStrHKCR
951
952    !undef _MOZFUNC_UN
953    !define _MOZFUNC_UN
954    !verbose pop
955  !endif
956!macroend
957
958!ifndef KEY_SET_VALUE
959  !define KEY_SET_VALUE 0x0002
960!endif
961!ifndef KEY_WOW64_64KEY
962  !define KEY_WOW64_64KEY 0x0100
963!endif
964!ifndef HAVE_64BIT_BUILD
965  !define CREATE_KEY_SAM ${KEY_SET_VALUE}
966!else
967  !define CREATE_KEY_SAM ${KEY_SET_VALUE}|${KEY_WOW64_64KEY}
968!endif
969
970/**
971 * Creates a registry key. This will log the actions to the install and
972 * uninstall logs. Alternatively you can set a registry value to create the key
973 * and then delete the value.
974 *
975 * Define NO_LOG to prevent all logging when calling this from the uninstaller.
976 *
977 * @param   _ROOT
978 *          The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.).
979 * @param   _KEY
980 *          The subkey in relation to the key root.
981 * @param   _LOG_UNINSTALL
982 *          0 = don't add to uninstall log, 1 = add to uninstall log.
983 *
984 * $R4 = [out] handle to newly created registry key. If this is not a key
985 *       located in one of the predefined registry keys this must be closed
986 *       with RegCloseKey (this should not be needed unless someone decides to
987 *       do something extremely squirrelly with NSIS).
988 * $R5 = return value from RegCreateKeyExW (represented by R5 in the system call).
989 * $R6 = [in] hKey passed to RegCreateKeyExW.
990 * $R7 = _ROOT
991 * $R8 = _KEY
992 * $R9 = _LOG_UNINSTALL
993 */
994!macro CreateRegKey
995
996  !ifndef ${_MOZFUNC_UN}CreateRegKey
997    !verbose push
998    !verbose ${_MOZFUNC_VERBOSE}
999    !define ${_MOZFUNC_UN}CreateRegKey "!insertmacro ${_MOZFUNC_UN}CreateRegKeyCall"
1000
1001    Function ${_MOZFUNC_UN}CreateRegKey
1002      Exch $R9
1003      Exch 1
1004      Exch $R8
1005      Exch 2
1006      Exch $R7
1007      Push $R6
1008      Push $R5
1009      Push $R4
1010
1011      StrCmp $R7 "HKCR" +1 +2
1012      StrCpy $R6 "0x80000000"
1013      StrCmp $R7 "HKCU" +1 +2
1014      StrCpy $R6 "0x80000001"
1015      StrCmp $R7 "HKLM" +1 +2
1016      StrCpy $R6 "0x80000002"
1017
1018      ; see definition of RegCreateKey
1019      System::Call "Advapi32::RegCreateKeyExW(i R6, w R8, i 0, i 0, i 0,\
1020                                              i ${CREATE_KEY_SAM}, i 0, *i .R4,\
1021                                              i 0) i .R5"
1022
1023      !ifndef NO_LOG
1024        ; if $R5 is not 0 then there was an error creating the registry key.
1025        ${If} $R5 <> 0
1026          ${LogMsg} "** ERROR Adding Registry Key: $R7 | $R8 **"
1027        ${Else}
1028          ${If} $R9 == 1 ; add to the uninstall log?
1029            ${LogUninstall} "RegKey: $R7 | $R8"
1030          ${EndIf}
1031          ${LogMsg} "Added Registry Key: $R7 | $R8"
1032        ${EndIf}
1033      !endif
1034
1035      StrCmp $R5 0 +1 +2
1036      System::Call "Advapi32::RegCloseKey(iR4)"
1037
1038      Pop $R4
1039      Pop $R5
1040      Pop $R6
1041      Exch $R7
1042      Exch 2
1043      Exch $R8
1044      Exch 1
1045      Exch $R9
1046    FunctionEnd
1047
1048    !verbose pop
1049  !endif
1050!macroend
1051
1052!macro CreateRegKeyCall _ROOT _KEY _LOG_UNINSTALL
1053  !verbose push
1054  !verbose ${_MOZFUNC_VERBOSE}
1055  Push "${_ROOT}"
1056  Push "${_KEY}"
1057  Push "${_LOG_UNINSTALL}"
1058  Call CreateRegKey
1059  !verbose pop
1060!macroend
1061
1062!macro un.CreateRegKeyCall _ROOT _KEY _LOG_UNINSTALL
1063  !verbose push
1064  !verbose ${_MOZFUNC_VERBOSE}
1065  Push "${_ROOT}"
1066  Push "${_KEY}"
1067  Push "${_LOG_UNINSTALL}"
1068  Call un.CreateRegKey
1069  !verbose pop
1070!macroend
1071
1072!macro un.CreateRegKey
1073  !ifndef un.CreateRegKey
1074    !verbose push
1075    !verbose ${_MOZFUNC_VERBOSE}
1076    !undef _MOZFUNC_UN
1077    !define _MOZFUNC_UN "un."
1078
1079    !insertmacro CreateRegKey
1080
1081    !undef _MOZFUNC_UN
1082    !define _MOZFUNC_UN
1083    !verbose pop
1084  !endif
1085!macroend
1086
1087/**
1088 * Helper for checking for the existence of a registry key.
1089 * SHCTX is the root key to search.
1090 *
1091 * @param   _MAIN_KEY
1092 *          Sub key to iterate for the key in question
1093 * @param   _KEY
1094 *          Key name to search for
1095 * @return  _RESULT
1096 *          'true' / 'false' result
1097 */
1098!macro CheckIfRegistryKeyExists
1099  !ifndef CheckIfRegistryKeyExists
1100    !verbose push
1101    !verbose ${_MOZFUNC_VERBOSE}
1102    !define CheckIfRegistryKeyExists "!insertmacro CheckIfRegistryKeyExistsCall"
1103
1104    Function CheckIfRegistryKeyExists
1105      ; stack: main key, key
1106      Exch $R9 ; main key, stack: old R9, key
1107      Exch 1   ; stack: key, old R9
1108      Exch $R8 ; key, stack: old R8, old R9
1109      Push $R7
1110      Push $R6
1111      Push $R5
1112
1113      StrCpy $R5 "false"
1114      StrCpy $R7 "0" # loop index
1115      ${Do}
1116        EnumRegKey $R6 SHCTX "$R9" "$R7"
1117        ${If} "$R6" == "$R8"
1118          StrCpy $R5 "true"
1119          ${Break}
1120        ${EndIf}
1121        IntOp $R7 $R7 + 1
1122      ${LoopWhile} $R6 != ""
1123      ClearErrors
1124
1125      StrCpy $R9 $R5
1126
1127      Pop $R5
1128      Pop $R6
1129      Pop $R7 ; stack: old R8, old R9
1130      Pop $R8 ; stack: old R9
1131      Exch $R9 ; stack: result
1132    FunctionEnd
1133
1134    !verbose pop
1135  !endif
1136!macroend
1137
1138!macro CheckIfRegistryKeyExistsCall _MAIN_KEY _KEY _RESULT
1139  !verbose push
1140  !verbose ${_MOZFUNC_VERBOSE}
1141  Push "${_KEY}"
1142  Push "${_MAIN_KEY}"
1143  Call CheckIfRegistryKeyExists
1144  Pop ${_RESULT}
1145  !verbose pop
1146!macroend
1147
1148/**
1149 * Read the value of an installer pref that's been set by the product.
1150 *
1151 * @param   _KEY ($R1)
1152 *          Sub key containing all the installer prefs
1153 *          Usually "Software\Mozilla\${AppName}"
1154 * @param   _PREF ($R2)
1155 *          Name of the pref to look up
1156 * @return  _RESULT ($R3)
1157 *          'true' or 'false' (only boolean prefs are supported)
1158 *          If no value exists for the requested pref, the result is 'false'
1159 */
1160!macro GetInstallerRegistryPref
1161  !ifndef ${_MOZFUNC_UN}GetInstallerRegistryPref
1162    !verbose push
1163    !verbose ${_MOZFUNC_VERBOSE}
1164    !define ${_MOZFUNC_UN}GetInstallerRegistryPref "!insertmacro GetInstallerRegistryPrefCall"
1165
1166    Function ${_MOZFUNC_UN}GetInstallerRegistryPref
1167      ; stack: key, pref
1168      Exch $R1 ; key, stack: old R1, pref
1169      Exch 1   ; stack: pref, old R1
1170      Exch $R2 ; pref, stack: old R2, old R1
1171      Push $R3
1172
1173      StrCpy $R3 0
1174
1175      ; These prefs are always stored in the native registry.
1176      SetRegView 64
1177
1178      ClearErrors
1179      ReadRegDWORD $R3 HKCU "$R1\Installer\$AppUserModelID" "$R2"
1180
1181      SetRegView lastused
1182
1183      ${IfNot} ${Errors}
1184      ${AndIf} $R3 != 0
1185        StrCpy $R1 "true"
1186      ${Else}
1187        StrCpy $R1 "false"
1188      ${EndIf}
1189
1190      ; stack: old R3, old R2, old R1
1191      Pop $R3 ; stack: old R2, old R1
1192      Pop $R2 ; stack: old R1
1193      Exch $R1 ; stack: result
1194    FunctionEnd
1195
1196    !verbose pop
1197  !endif
1198!macroend
1199
1200!macro GetInstallerRegistryPrefCall _KEY _PREF _RESULT
1201  !verbose push
1202  !verbose ${_MOZFUNC_VERBOSE}
1203  Push "${_PREF}"
1204  Push "${_KEY}"
1205  Call GetInstallerRegistryPref
1206  Pop ${_RESULT}
1207  !verbose pop
1208!macroend
1209
1210!macro un.GetInstallerRegistryPrefCall _KEY _PREF _RESULT
1211  !verbose push
1212  !verbose ${_MOZFUNC_VERBOSE}
1213  Push "${_PREF}"
1214  Push "${_KEY}"
1215  Call un.GetInstallerRegistryPref
1216  Pop ${_RESULT}
1217  !verbose pop
1218!macroend
1219
1220!macro un.GetInstallerRegistryPref
1221  !ifndef un.GetInstallerRegistryPref
1222    !verbose push
1223    !verbose ${_MOZFUNC_VERBOSE}
1224    !undef _MOZFUNC_UN
1225    !define _MOZFUNC_UN "un."
1226
1227    !insertmacro GetInstallerRegistryPref
1228
1229    !undef _MOZFUNC_UN
1230    !define _MOZFUNC_UN
1231    !verbose pop
1232  !endif
1233!macroend
1234
1235################################################################################
1236# Macros for adding file and protocol handlers
1237
1238/**
1239 * Writes common registry values for a handler using SHCTX.
1240 *
1241 * @param   _KEY
1242 *          The subkey in relation to the key root.
1243 * @param   _VALOPEN
1244 *          The path and args to launch the application.
1245 * @param   _VALICON
1246 *          The path to the binary that contains the icon group for the default icon
1247 *          followed by a comma and either the icon group's resource index or the icon
1248 *          group's resource id prefixed with a minus sign
1249 * @param   _DISPNAME
1250 *          The display name for the handler. If emtpy no value will be set.
1251 * @param   _ISPROTOCOL
1252 *          Sets protocol handler specific registry values when "true".
1253 *          Deletes protocol handler specific registry values when "delete".
1254 *          Otherwise doesn't touch handler specific registry values.
1255 * @param   _ISDDE
1256 *          Sets DDE specific registry values when "true".
1257 *
1258 * $R3 = string value of the current registry key path.
1259 * $R4 = _KEY
1260 * $R5 = _VALOPEN
1261 * $R6 = _VALICON
1262 * $R7 = _DISPNAME
1263 * $R8 = _ISPROTOCOL
1264 * $R9 = _ISDDE
1265 */
1266!macro AddHandlerValues
1267
1268  !ifndef ${_MOZFUNC_UN}AddHandlerValues
1269    !verbose push
1270    !verbose ${_MOZFUNC_VERBOSE}
1271    !define ${_MOZFUNC_UN}AddHandlerValues "!insertmacro ${_MOZFUNC_UN}AddHandlerValuesCall"
1272
1273    Function ${_MOZFUNC_UN}AddHandlerValues
1274      Exch $R9
1275      Exch 1
1276      Exch $R8
1277      Exch 2
1278      Exch $R7
1279      Exch 3
1280      Exch $R6
1281      Exch 4
1282      Exch $R5
1283      Exch 5
1284      Exch $R4
1285      Push $R3
1286
1287      StrCmp "$R7" "" +6 +1
1288      ReadRegStr $R3 SHCTX "$R4" "FriendlyTypeName"
1289
1290      StrCmp "$R3" "" +1 +3
1291      WriteRegStr SHCTX "$R4" "" "$R7"
1292      WriteRegStr SHCTX "$R4" "FriendlyTypeName" "$R7"
1293
1294      StrCmp "$R8" "true" +1 +2
1295      WriteRegStr SHCTX "$R4" "URL Protocol" ""
1296      StrCmp "$R8" "delete" +1 +2
1297      DeleteRegValue SHCTX "$R4" "URL Protocol"
1298      StrCpy $R3 ""
1299      ReadRegDWord $R3 SHCTX "$R4" "EditFlags"
1300      StrCmp $R3 "" +1 +3  ; Only add EditFlags if a value doesn't exist
1301      DeleteRegValue SHCTX "$R4" "EditFlags"
1302      WriteRegDWord SHCTX "$R4" "EditFlags" 0x00000002
1303
1304      StrCmp "$R6" "" +2 +1
1305      WriteRegStr SHCTX "$R4\DefaultIcon" "" "$R6"
1306
1307      StrCmp "$R5" "" +2 +1
1308      WriteRegStr SHCTX "$R4\shell\open\command" "" "$R5"
1309
1310!ifdef DDEApplication
1311      StrCmp "$R9" "true" +1 +11
1312      WriteRegStr SHCTX "$R4\shell\open\ddeexec" "" "$\"%1$\",,0,0,,,,"
1313      WriteRegStr SHCTX "$R4\shell\open\ddeexec" "NoActivateHandler" ""
1314      WriteRegStr SHCTX "$R4\shell\open\ddeexec\Application" "" "${DDEApplication}"
1315      WriteRegStr SHCTX "$R4\shell\open\ddeexec\Topic" "" "WWW_OpenURL"
1316      ; The ifexec key may have been added by another application so try to
1317      ; delete it to prevent it from breaking this app's shell integration.
1318      ; Also, IE 6 and below doesn't remove this key when it sets itself as the
1319      ; default handler and if this key exists IE's shell integration breaks.
1320      DeleteRegKey HKLM "$R4\shell\open\ddeexec\ifexec"
1321      DeleteRegKey HKCU "$R4\shell\open\ddeexec\ifexec"
1322!endif
1323
1324      ClearErrors
1325
1326      Pop $R3
1327      Exch $R4
1328      Exch 5
1329      Exch $R5
1330      Exch 4
1331      Exch $R6
1332      Exch 3
1333      Exch $R7
1334      Exch 2
1335      Exch $R8
1336      Exch 1
1337      Exch $R9
1338    FunctionEnd
1339
1340    !verbose pop
1341  !endif
1342!macroend
1343
1344!macro AddHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL _ISDDE
1345  !verbose push
1346  !verbose ${_MOZFUNC_VERBOSE}
1347  Push "${_KEY}"
1348  Push "${_VALOPEN}"
1349  Push "${_VALICON}"
1350  Push "${_DISPNAME}"
1351  Push "${_ISPROTOCOL}"
1352  Push "${_ISDDE}"
1353  Call AddHandlerValues
1354  !verbose pop
1355!macroend
1356
1357!macro un.AddHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL _ISDDE
1358  !verbose push
1359  !verbose ${_MOZFUNC_VERBOSE}
1360  Push "${_KEY}"
1361  Push "${_VALOPEN}"
1362  Push "${_VALICON}"
1363  Push "${_DISPNAME}"
1364  Push "${_ISPROTOCOL}"
1365  Push "${_ISDDE}"
1366  Call un.AddHandlerValues
1367  !verbose pop
1368!macroend
1369
1370!macro un.AddHandlerValues
1371  !ifndef un.AddHandlerValues
1372    !verbose push
1373    !verbose ${_MOZFUNC_VERBOSE}
1374    !undef _MOZFUNC_UN
1375    !define _MOZFUNC_UN "un."
1376
1377    !insertmacro AddHandlerValues
1378
1379    !undef _MOZFUNC_UN
1380    !define _MOZFUNC_UN
1381    !verbose pop
1382  !endif
1383!macroend
1384
1385/**
1386 * Writes common registry values for a handler that DOES NOT use DDE using SHCTX.
1387 *
1388 * @param   _KEY
1389 *          The key name in relation to the HKCR root. SOFTWARE\Classes is
1390 *          prefixed to this value when using SHCTX.
1391 * @param   _VALOPEN
1392 *          The path and args to launch the application.
1393 * @param   _VALICON
1394 *          The path to the binary that contains the icon group for the default icon
1395 *          followed by a comma and either the icon group's resource index or the icon
1396 *          group's resource id prefixed with a minus sign
1397 * @param   _DISPNAME
1398 *          The display name for the handler. If emtpy no value will be set.
1399 * @param   _ISPROTOCOL
1400 *          Sets protocol handler specific registry values when "true".
1401 *          Deletes protocol handler specific registry values when "delete".
1402 *          Otherwise doesn't touch handler specific registry values.
1403 *
1404 * $R3 = storage for SOFTWARE\Classes
1405 * $R4 = string value of the current registry key path.
1406 * $R5 = _KEY
1407 * $R6 = _VALOPEN
1408 * $R7 = _VALICON
1409 * $R8 = _DISPNAME
1410 * $R9 = _ISPROTOCOL
1411 */
1412!macro AddDisabledDDEHandlerValues
1413
1414  !ifndef ${_MOZFUNC_UN}AddDisabledDDEHandlerValues
1415    !verbose push
1416    !verbose ${_MOZFUNC_VERBOSE}
1417    !define ${_MOZFUNC_UN}AddDisabledDDEHandlerValues "!insertmacro ${_MOZFUNC_UN}AddDisabledDDEHandlerValuesCall"
1418
1419    Function ${_MOZFUNC_UN}AddDisabledDDEHandlerValues
1420      Exch $R9 ; _ISPROTOCOL
1421      Exch 1
1422      Exch $R8 ; FriendlyTypeName
1423      Exch 2
1424      Exch $R7 ; icon index
1425      Exch 3
1426      Exch $R6 ; shell\open\command
1427      Exch 4
1428      Exch $R5 ; reg key
1429      Push $R4 ;
1430      Push $R3 ; base reg class
1431
1432      StrCpy $R3 "SOFTWARE\Classes"
1433      StrCmp "$R8" "" +6 +1
1434      ReadRegStr $R4 SHCTX "$R5" "FriendlyTypeName"
1435
1436      StrCmp "$R4" "" +1 +3
1437      WriteRegStr SHCTX "$R3\$R5" "" "$R8"
1438      WriteRegStr SHCTX "$R3\$R5" "FriendlyTypeName" "$R8"
1439
1440      StrCmp "$R9" "true" +1 +2
1441      WriteRegStr SHCTX "$R3\$R5" "URL Protocol" ""
1442      StrCmp "$R9" "delete" +1 +2
1443      DeleteRegValue SHCTX "$R3\$R5" "URL Protocol"
1444      StrCpy $R4 ""
1445      ReadRegDWord $R4 SHCTX "$R3\$R5" "EditFlags"
1446      StrCmp $R4 "" +1 +3  ; Only add EditFlags if a value doesn't exist
1447      DeleteRegValue SHCTX "$R3\$R5" "EditFlags"
1448      WriteRegDWord SHCTX "$R3\$R5" "EditFlags" 0x00000002
1449
1450      StrCmp "$R7" "" +2 +1
1451      WriteRegStr SHCTX "$R3\$R5\DefaultIcon" "" "$R7"
1452
1453      ; Main command handler for the app
1454      WriteRegStr SHCTX "$R3\$R5\shell" "" "open"
1455      WriteRegStr SHCTX "$R3\$R5\shell\open\command" "" "$R6"
1456
1457      ; Drop support for DDE (bug 491947), and remove old dde entries if
1458      ; they exist.
1459      ;
1460      ; Note, changes in SHCTX should propegate to hkey classes root when
1461      ; current user or local machine entries are written. Windows will also
1462      ; attempt to propegate entries when a handler is used. CR entries are a
1463      ; combination of LM and CU, with CU taking priority.
1464      ;
1465      ; To disable dde, an empty shell/ddeexec key must be created in current
1466      ; user or local machine. Unfortunately, settings have various different
1467      ; behaviors depending on the windows version. The following code attempts
1468      ; to address these differences.
1469      ;
1470      ; IE does not configure ddeexec, so issues with left over ddeexec keys
1471      ; in LM are reduced. We configure an empty ddeexec key with an empty default
1472      ; string in CU to be sure.
1473      ;
1474      DeleteRegKey SHCTX "SOFTWARE\Classes\$R5\shell\open\ddeexec"
1475      WriteRegStr SHCTX "SOFTWARE\Classes\$R5\shell\open\ddeexec" "" ""
1476
1477      ClearErrors
1478
1479      Pop $R3
1480      Pop $R4
1481      Exch $R5
1482      Exch 4
1483      Exch $R6
1484      Exch 3
1485      Exch $R7
1486      Exch 2
1487      Exch $R8
1488      Exch 1
1489      Exch $R9
1490    FunctionEnd
1491
1492    !verbose pop
1493  !endif
1494!macroend
1495
1496!macro AddDisabledDDEHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL
1497  !verbose push
1498  !verbose ${_MOZFUNC_VERBOSE}
1499  Push "${_KEY}"
1500  Push "${_VALOPEN}"
1501  Push "${_VALICON}"
1502  Push "${_DISPNAME}"
1503  Push "${_ISPROTOCOL}"
1504  Call AddDisabledDDEHandlerValues
1505  !verbose pop
1506!macroend
1507
1508!macro un.AddDisabledDDEHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL
1509  !verbose push
1510  !verbose ${_MOZFUNC_VERBOSE}
1511  Push "${_KEY}"
1512  Push "${_VALOPEN}"
1513  Push "${_VALICON}"
1514  Push "${_DISPNAME}"
1515  Push "${_ISPROTOCOL}"
1516  Call un.AddDisabledDDEHandlerValues
1517  !verbose pop
1518!macroend
1519
1520!macro un.AddDisabledDDEHandlerValues
1521  !ifndef un.AddDisabledDDEHandlerValues
1522    !verbose push
1523    !verbose ${_MOZFUNC_VERBOSE}
1524    !undef _MOZFUNC_UN
1525    !define _MOZFUNC_UN "un."
1526
1527    !insertmacro AddDisabledDDEHandlerValues
1528
1529    !undef _MOZFUNC_UN
1530    !define _MOZFUNC_UN
1531    !verbose pop
1532  !endif
1533!macroend
1534
1535
1536################################################################################
1537# Macros for handling DLL registration
1538
1539!macro RegisterDLL DLL
1540
1541  ; The x64 regsvr32.exe registers x86 DLL's properly so just use it
1542  ; when installing on an x64 systems even when installing an x86 application.
1543  ${If} ${RunningX64}
1544  ${OrIf} ${IsNativeARM64}
1545    ${DisableX64FSRedirection}
1546    ExecWait '"$SYSDIR\regsvr32.exe" /s "${DLL}"'
1547    ${EnableX64FSRedirection}
1548  ${Else}
1549    RegDLL "${DLL}"
1550  ${EndIf}
1551
1552!macroend
1553
1554!macro UnregisterDLL DLL
1555
1556  ; The x64 regsvr32.exe registers x86 DLL's properly so just use it
1557  ; when installing on an x64 systems even when installing an x86 application.
1558  ${If} ${RunningX64}
1559  ${OrIf} ${IsNativeARM64}
1560    ${DisableX64FSRedirection}
1561    ExecWait '"$SYSDIR\regsvr32.exe" /s /u "${DLL}"'
1562    ${EnableX64FSRedirection}
1563  ${Else}
1564    UnRegDLL "${DLL}"
1565  ${EndIf}
1566
1567!macroend
1568
1569!define RegisterDLL "!insertmacro RegisterDLL"
1570!define UnregisterDLL "!insertmacro UnregisterDLL"
1571
1572
1573################################################################################
1574# Macros for retrieving special folders
1575
1576/**
1577 * These macro get special folder paths directly, without depending on
1578 * SetShellVarContext.
1579 *
1580 * Usage:
1581 * ${GetProgramsFolder} $0
1582 * ${GetLocalAppDataFolder} $0
1583 * ${GetCommonAppDataFolder} $0
1584 *
1585 */
1586!macro GetSpecialFolder _ID _RESULT
1587  ; This system call gets the directory path. The arguments are:
1588  ;   A null ptr for hwnd
1589  ;   t.s puts the output string on the NSIS stack
1590  ;   id indicates which dir to get
1591  ;   false for fCreate (i.e. Do not create the folder if it doesn't exist)
1592  System::Call "Shell32::SHGetSpecialFolderPathW(p 0, t.s, i ${_ID}, i 0)"
1593  Pop ${_RESULT}
1594!macroend
1595
1596!define CSIDL_PROGRAMS          0x0002
1597!define CSIDL_LOCAL_APPDATA     0x001c
1598!define CSIDL_COMMON_APPDATA    0x0023
1599
1600; Current User's Start Menu Programs
1601!define GetProgramsFolder       "!insertmacro GetSpecialFolder ${CSIDL_PROGRAMS}"
1602
1603; Current User's Local App Data (e.g. C:\Users\<user>\AppData\Local)
1604!define GetLocalAppDataFolder   "!insertmacro GetSpecialFolder ${CSIDL_LOCAL_APPDATA}"
1605
1606; Common App Data (e.g. C:\ProgramData)
1607!define GetCommonAppDataFolder  "!insertmacro GetSpecialFolder ${CSIDL_COMMON_APPDATA}"
1608
1609################################################################################
1610# Macros for retrieving existing install paths
1611
1612/**
1613 * Finds a second installation of the application so we can make informed
1614 * decisions about registry operations. This uses SHCTX to determine the
1615 * registry hive so you must call SetShellVarContext first.
1616 *
1617 * @param   _KEY
1618 *          The registry subkey (typically this will be Software\Mozilla).
1619 * @return  _RESULT
1620 *          false if a second install isn't found, path to the main exe if a
1621 *          second install is found.
1622 *
1623 * $R3 = stores the long path to $INSTDIR
1624 * $R4 = counter for the outer loop's EnumRegKey
1625 * $R5 = return value from ReadRegStr and RemoveQuotesFromPath
1626 * $R6 = return value from GetParent
1627 * $R7 = return value from the loop's EnumRegKey
1628 * $R8 = storage for _KEY
1629 * $R9 = _KEY and _RESULT
1630 */
1631!macro GetSecondInstallPath
1632
1633  !ifndef ${_MOZFUNC_UN}GetSecondInstallPath
1634    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
1635    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
1636    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
1637    !insertmacro ${_MOZFUNC_UN_TMP}RemoveQuotesFromPath
1638    !undef _MOZFUNC_UN
1639    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
1640    !undef _MOZFUNC_UN_TMP
1641
1642    !verbose push
1643    !verbose ${_MOZFUNC_VERBOSE}
1644    !define ${_MOZFUNC_UN}GetSecondInstallPath "!insertmacro ${_MOZFUNC_UN}GetSecondInstallPathCall"
1645
1646    Function ${_MOZFUNC_UN}GetSecondInstallPath
1647      Exch $R9
1648      Push $R8
1649      Push $R7
1650      Push $R6
1651      Push $R5
1652      Push $R4
1653      Push $R3
1654
1655      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R3
1656
1657      StrCpy $R4 0       ; set the counter for the loop to 0
1658      StrCpy $R8 "$R9"   ; Registry key path to search
1659      StrCpy $R9 "false" ; default return value
1660
1661      loop:
1662      EnumRegKey $R7 SHCTX $R8 $R4
1663      StrCmp $R7 "" end +1  ; if empty there are no more keys to enumerate
1664      IntOp $R4 $R4 + 1     ; increment the loop's counter
1665      ClearErrors
1666      ReadRegStr $R5 SHCTX "$R8\$R7\bin" "PathToExe"
1667      IfErrors loop
1668
1669      ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R5" $R5
1670
1671      IfFileExists "$R5" +1 loop
1672      ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
1673      ${${_MOZFUNC_UN}GetParent} "$R5" $R6
1674      StrCmp "$R6" "$R3" loop +1
1675      StrCmp "$R6\${FileMainEXE}" "$R5" +1 loop
1676      StrCpy $R9 "$R5"
1677
1678      end:
1679      ClearErrors
1680
1681      Pop $R3
1682      Pop $R4
1683      Pop $R5
1684      Pop $R6
1685      Pop $R7
1686      Pop $R8
1687      Exch $R9
1688    FunctionEnd
1689
1690    !verbose pop
1691  !endif
1692!macroend
1693
1694!macro GetSecondInstallPathCall _KEY _RESULT
1695  !verbose push
1696  !verbose ${_MOZFUNC_VERBOSE}
1697  Push "${_KEY}"
1698  Call GetSecondInstallPath
1699  Pop ${_RESULT}
1700  !verbose pop
1701!macroend
1702
1703!macro un.GetSecondInstallPathCall _KEY _RESULT
1704  !verbose push
1705  !verbose ${_MOZFUNC_VERBOSE}
1706  Push "${_KEY}"
1707  Call un.GetSecondInstallPath
1708  Pop ${_RESULT}
1709  !verbose pop
1710!macroend
1711
1712!macro un.GetSecondInstallPath
1713  !ifndef un.GetSecondInstallPath
1714    !verbose push
1715    !verbose ${_MOZFUNC_VERBOSE}
1716    !undef _MOZFUNC_UN
1717    !define _MOZFUNC_UN "un."
1718
1719    !insertmacro GetSecondInstallPath
1720
1721    !undef _MOZFUNC_UN
1722    !define _MOZFUNC_UN
1723    !verbose pop
1724  !endif
1725!macroend
1726
1727/**
1728 * Finds an existing installation path for the application based on the
1729 * application's executable name so we can default to using this path for the
1730 * install. If there is zero or more than one installation of the application
1731 * then we default to the default installation path. This uses SHCTX to
1732 * determine the registry hive to read from so you must call SetShellVarContext
1733 * first.
1734 *
1735 * @param   _KEY
1736 *          The registry subkey (typically this will be Software\Mozilla\App Name).
1737 * @return  _RESULT
1738 *          false if a single install location for this app name isn't found,
1739 *          path to the install directory if a single install location is found.
1740 *
1741 * $R5 = counter for the loop's EnumRegKey
1742 * $R6 = return value from EnumRegKey
1743 * $R7 = return value from ReadRegStr
1744 * $R8 = storage for _KEY
1745 * $R9 = _KEY and _RESULT
1746 */
1747!macro GetSingleInstallPath
1748
1749  !ifndef ${_MOZFUNC_UN}GetSingleInstallPath
1750    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
1751    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
1752    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
1753    !insertmacro ${_MOZFUNC_UN_TMP}RemoveQuotesFromPath
1754    !undef _MOZFUNC_UN
1755    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
1756    !undef _MOZFUNC_UN_TMP
1757
1758    !verbose push
1759    !verbose ${_MOZFUNC_VERBOSE}
1760    !define ${_MOZFUNC_UN}GetSingleInstallPath "!insertmacro ${_MOZFUNC_UN}GetSingleInstallPathCall"
1761
1762    Function ${_MOZFUNC_UN}GetSingleInstallPath
1763      Exch $R9
1764      Push $R8
1765      Push $R7
1766      Push $R6
1767      Push $R5
1768
1769      StrCpy $R8 $R9
1770      StrCpy $R9 "false"
1771      StrCpy $R5 0  ; set the counter for the loop to 0
1772
1773      loop:
1774      ClearErrors
1775      EnumRegKey $R6 SHCTX $R8 $R5
1776      IfErrors cleanup
1777      StrCmp $R6 "" cleanup +1  ; if empty there are no more keys to enumerate
1778      IntOp $R5 $R5 + 1         ; increment the loop's counter
1779      ClearErrors
1780      ReadRegStr $R7 SHCTX "$R8\$R6\Main" "PathToExe"
1781      IfErrors loop
1782      ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R7" $R7
1783      GetFullPathName $R7 "$R7"
1784      IfErrors loop
1785
1786      StrCmp "$R9" "false" +1 +3
1787      StrCpy $R9 "$R7"
1788      GoTo Loop
1789
1790      StrCpy $R9 "false"
1791
1792      cleanup:
1793      StrCmp $R9 "false" end +1
1794      ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9
1795      ${${_MOZFUNC_UN}GetParent} "$R9" $R9
1796
1797      end:
1798      ClearErrors
1799
1800      Pop $R5
1801      Pop $R6
1802      Pop $R7
1803      Pop $R8
1804      Exch $R9
1805    FunctionEnd
1806
1807    !verbose pop
1808  !endif
1809!macroend
1810
1811!macro GetSingleInstallPathCall _KEY _RESULT
1812  !verbose push
1813  !verbose ${_MOZFUNC_VERBOSE}
1814  Push "${_KEY}"
1815  Call GetSingleInstallPath
1816  Pop ${_RESULT}
1817  !verbose pop
1818!macroend
1819
1820!macro un.GetSingleInstallPathCall _KEY _RESULT
1821  !verbose push
1822  !verbose ${_MOZFUNC_VERBOSE}
1823  Push "${_KEY}"
1824  Call un.GetSingleInstallPath
1825  Pop ${_RESULT}
1826  !verbose pop
1827!macroend
1828
1829!macro un.GetSingleInstallPath
1830  !ifndef un.GetSingleInstallPath
1831    !verbose push
1832    !verbose ${_MOZFUNC_VERBOSE}
1833    !undef _MOZFUNC_UN
1834    !define _MOZFUNC_UN "un."
1835
1836    !insertmacro GetSingleInstallPath
1837
1838    !undef _MOZFUNC_UN
1839    !define _MOZFUNC_UN
1840    !verbose pop
1841  !endif
1842!macroend
1843
1844/**
1845 * Find the first existing installation for the application.
1846 * This is similar to GetSingleInstallPath, except that it always returns the
1847 * first path it finds, instead of an error when more than one path exists.
1848 *
1849 * The shell context and the registry view should already have been set.
1850 *
1851 * @param   _KEY
1852 *          The registry subkey (typically Software\Mozilla\App Name).
1853 * @return  _RESULT
1854 *          path to the install directory of the first location found, or
1855 *          the string "false" if no existing installation was found.
1856 *
1857 * $R5 = counter for the loop's EnumRegKey
1858 * $R6 = return value from EnumRegKey
1859 * $R7 = return value from ReadRegStr
1860 * $R8 = storage for _KEY
1861 * $R9 = _KEY and _RESULT
1862 */
1863!macro GetFirstInstallPath
1864  !ifndef ${_MOZFUNC_UN}GetFirstInstallPath
1865    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
1866    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
1867    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
1868    !insertmacro ${_MOZFUNC_UN_TMP}RemoveQuotesFromPath
1869    !undef _MOZFUNC_UN
1870    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
1871    !undef _MOZFUNC_UN_TMP
1872
1873    !verbose push
1874    !verbose ${_MOZFUNC_VERBOSE}
1875    !define ${_MOZFUNC_UN}GetFirstInstallPath "!insertmacro ${_MOZFUNC_UN}__GetFirstInstallPathCall"
1876
1877    Function ${_MOZFUNC_UN}__GetFirstInstallPath
1878      Exch $R9
1879      Push $R8
1880      Push $R7
1881      Push $R6
1882      Push $R5
1883
1884      StrCpy $R8 $R9
1885      StrCpy $R9 "false"
1886      StrCpy $R5 0
1887
1888      ${Do}
1889        ClearErrors
1890        EnumRegKey $R6 SHCTX $R8 $R5
1891        ${If} ${Errors}
1892        ${OrIf} $R6 == ""
1893          ${Break}
1894        ${EndIf}
1895
1896        IntOp $R5 $R5 + 1
1897
1898        ReadRegStr $R7 SHCTX "$R8\$R6\Main" "PathToExe"
1899        ${If} ${Errors}
1900          ${Continue}
1901        ${EndIf}
1902
1903        ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R7" $R7
1904        GetFullPathName $R7 "$R7"
1905        ${If} ${Errors}
1906          ${Continue}
1907        ${EndIf}
1908
1909        StrCpy $R9 "$R7"
1910        ${Break}
1911      ${Loop}
1912
1913      ${If} $R9 != "false"
1914        ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9
1915        ${${_MOZFUNC_UN}GetParent} "$R9" $R9
1916      ${EndIf}
1917
1918      Pop $R5
1919      Pop $R6
1920      Pop $R7
1921      Pop $R8
1922      Exch $R9
1923    FunctionEnd
1924
1925    !verbose pop
1926  !endif
1927!macroend
1928
1929!macro __GetFirstInstallPathCall _KEY _RESULT
1930  !verbose push
1931  !verbose ${_MOZFUNC_VERBOSE}
1932  Push "${_KEY}"
1933  Call __GetFirstInstallPath
1934  Pop ${_RESULT}
1935  !verbose pop
1936!macroend
1937
1938!macro un.__GetFirstInstallPathCall _KEY _RESULT
1939  !verbose push
1940  !verbose ${_MOZFUNC_VERBOSE}
1941  Push "${_KEY}"
1942  Call un.__GetFirstInstallPath
1943  Pop ${_RESULT}
1944  !verbose pop
1945!macroend
1946
1947!macro un.__GetFirstInstallPath
1948  !ifndef un.__GetFirstInstallPath
1949    !verbose push
1950    !verbose ${_MOZFUNC_VERBOSE}
1951    !undef _MOZFUNC_UN
1952    !define _MOZFUNC_UN "un."
1953
1954    !insertmacro __GetFirstInstallPath
1955
1956    !undef _MOZFUNC_UN
1957    !define _MOZFUNC_UN
1958    !verbose pop
1959  !endif
1960!macroend
1961
1962
1963################################################################################
1964# Macros for working with the file system
1965
1966/**
1967 * Attempts to delete a file if it exists. This will fail if the file is in use.
1968 *
1969 * @param   _FILE
1970 *          The path to the file that is to be deleted.
1971 */
1972!macro DeleteFile _FILE
1973  ${If} ${FileExists} "${_FILE}"
1974    Delete "${_FILE}"
1975  ${EndIf}
1976!macroend
1977!define DeleteFile "!insertmacro DeleteFile"
1978
1979/**
1980 * Removes a directory if it exists and is empty.
1981 *
1982 * @param   _DIR
1983 *          The path to the directory that is to be removed.
1984 */
1985!macro RemoveDir _DIR
1986  ${If} ${FileExists} "${_DIR}"
1987    RmDir "${_DIR}"
1988  ${EndIf}
1989!macroend
1990!define RemoveDir "!insertmacro RemoveDir"
1991
1992/**
1993 * Checks whether it is possible to create and delete a directory and a file in
1994 * the install directory. Creation and deletion of files and directories are
1995 * checked since a user may have rights for one and not the other. If creation
1996 * and deletion of a file and a directory are successful this macro will return
1997 * true... if not, this it return false.
1998 *
1999 * @return  _RESULT
2000 *          true if files and directories can be created and deleted in the
2001 *          install directory otherwise false.
2002 *
2003 * $R8 = temporary filename in the installation directory returned from
2004 *       GetTempFileName.
2005 * $R9 = _RESULT
2006 */
2007!macro CanWriteToInstallDir
2008
2009  !ifndef ${_MOZFUNC_UN}CanWriteToInstallDir
2010    !verbose push
2011    !verbose ${_MOZFUNC_VERBOSE}
2012    !define ${_MOZFUNC_UN}CanWriteToInstallDir "!insertmacro ${_MOZFUNC_UN}CanWriteToInstallDirCall"
2013
2014    Function ${_MOZFUNC_UN}CanWriteToInstallDir
2015      Push $R9
2016      Push $R8
2017
2018      StrCpy $R9 "true"
2019
2020      ; IfFileExists returns false for $INSTDIR when $INSTDIR is the root of a
2021      ; UNC path so always try to create $INSTDIR
2022      CreateDirectory "$INSTDIR\"
2023      GetTempFileName $R8 "$INSTDIR\"
2024
2025      ${Unless} ${FileExists} $R8 ; Can files be created?
2026        StrCpy $R9 "false"
2027        Goto done
2028      ${EndUnless}
2029
2030      Delete $R8
2031      ${If} ${FileExists} $R8 ; Can files be deleted?
2032        StrCpy $R9 "false"
2033        Goto done
2034      ${EndIf}
2035
2036      CreateDirectory $R8
2037      ${Unless} ${FileExists} $R8  ; Can directories be created?
2038        StrCpy $R9 "false"
2039        Goto done
2040      ${EndUnless}
2041
2042      RmDir $R8
2043      ${If} ${FileExists} $R8  ; Can directories be deleted?
2044        StrCpy $R9 "false"
2045        Goto done
2046      ${EndIf}
2047
2048      done:
2049
2050      RmDir "$INSTDIR\" ; Only remove $INSTDIR if it is empty
2051      ClearErrors
2052
2053      Pop $R8
2054      Exch $R9
2055    FunctionEnd
2056
2057    !verbose pop
2058  !endif
2059!macroend
2060
2061!macro CanWriteToInstallDirCall _RESULT
2062  !verbose push
2063  !verbose ${_MOZFUNC_VERBOSE}
2064  Call CanWriteToInstallDir
2065  Pop ${_RESULT}
2066  !verbose pop
2067!macroend
2068
2069!macro un.CanWriteToInstallDirCall _RESULT
2070  !verbose push
2071  !verbose ${_MOZFUNC_VERBOSE}
2072  Call un.CanWriteToInstallDir
2073  Pop ${_RESULT}
2074  !verbose pop
2075!macroend
2076
2077!macro un.CanWriteToInstallDir
2078  !ifndef un.CanWriteToInstallDir
2079    !verbose push
2080    !verbose ${_MOZFUNC_VERBOSE}
2081    !undef _MOZFUNC_UN
2082    !define _MOZFUNC_UN "un."
2083
2084    !insertmacro CanWriteToInstallDir
2085
2086    !undef _MOZFUNC_UN
2087    !define _MOZFUNC_UN
2088    !verbose pop
2089  !endif
2090!macroend
2091
2092/**
2093 * Checks whether there is sufficient free space available for the installation
2094 * directory using GetDiskFreeSpaceExW which respects disk quotas. This macro
2095 * will calculate the size of all sections that are selected, compare that with
2096 * the free space available, and if there is sufficient free space it will
2097 * return true... if not, it will return false.
2098 *
2099 * @return  _RESULT
2100 *          "true" if there is sufficient free space otherwise "false".
2101 *
2102 * $R5 = return value from SectionGetSize
2103 * $R6 = return value from SectionGetFlags
2104 *       return value from an 'and' comparison of SectionGetFlags (1=selected)
2105 *       return value for lpFreeBytesAvailable from GetDiskFreeSpaceExW
2106 *       return value for System::Int64Op $R6 / 1024
2107 *       return value for System::Int64Op $R6 > $R8
2108 * $R7 = the counter for enumerating the sections
2109 *       the temporary file name for the directory created under $INSTDIR passed
2110 *       to GetDiskFreeSpaceExW.
2111 * $R8 = sum in KB of all selected sections
2112 * $R9 = _RESULT
2113 */
2114!macro CheckDiskSpace
2115
2116  !ifndef ${_MOZFUNC_UN}CheckDiskSpace
2117    !verbose push
2118    !verbose ${_MOZFUNC_VERBOSE}
2119    !define ${_MOZFUNC_UN}CheckDiskSpace "!insertmacro ${_MOZFUNC_UN}CheckDiskSpaceCall"
2120
2121    Function ${_MOZFUNC_UN}CheckDiskSpace
2122      Push $R9
2123      Push $R8
2124      Push $R7
2125      Push $R6
2126      Push $R5
2127
2128      ClearErrors
2129
2130      StrCpy $R9 "true" ; default return value
2131      StrCpy $R8 "0"    ; sum in KB of all selected sections
2132      StrCpy $R7 "0"    ; counter for enumerating sections
2133
2134      ; Enumerate the sections and sum up the sizes of the sections that are
2135      ; selected.
2136      SectionGetFlags $R7 $R6
2137      IfErrors +7 +1
2138      IntOp $R6 ${SF_SELECTED} & $R6
2139      IntCmp $R6 0 +3 +1 +1
2140      SectionGetSize $R7 $R5
2141      IntOp $R8 $R8 + $R5
2142      IntOp $R7 $R7 + 1
2143      GoTo -7
2144
2145      ; The directory passed to GetDiskFreeSpaceExW must exist for the call to
2146      ; succeed.  Since the CanWriteToInstallDir macro is called prior to this
2147      ; macro the call to CreateDirectory will always succeed.
2148
2149      ; IfFileExists returns false for $INSTDIR when $INSTDIR is the root of a
2150      ; UNC path so always try to create $INSTDIR
2151      CreateDirectory "$INSTDIR\"
2152      GetTempFileName $R7 "$INSTDIR\"
2153      Delete "$R7"
2154      CreateDirectory "$R7"
2155
2156      System::Call 'kernel32::GetDiskFreeSpaceExW(w, *l, *l, *l) i(R7, .R6, ., .) .'
2157
2158      ; Convert to KB for comparison with $R8 which is in KB
2159      System::Int64Op $R6 / 1024
2160      Pop $R6
2161
2162      System::Int64Op $R6 > $R8
2163      Pop $R6
2164
2165      IntCmp $R6 1 end +1 +1
2166      StrCpy $R9 "false"
2167
2168      end:
2169      RmDir "$R7"
2170      RmDir "$INSTDIR\" ; Only remove $INSTDIR if it is empty
2171
2172      ClearErrors
2173
2174      Pop $R5
2175      Pop $R6
2176      Pop $R7
2177      Pop $R8
2178      Exch $R9
2179    FunctionEnd
2180
2181    !verbose pop
2182  !endif
2183!macroend
2184
2185!macro CheckDiskSpaceCall _RESULT
2186  !verbose push
2187  !verbose ${_MOZFUNC_VERBOSE}
2188  Call CheckDiskSpace
2189  Pop ${_RESULT}
2190  !verbose pop
2191!macroend
2192
2193!macro un.CheckDiskSpaceCall _RESULT
2194  !verbose push
2195  !verbose ${_MOZFUNC_VERBOSE}
2196  Call un.CheckDiskSpace
2197  Pop ${_RESULT}
2198  !verbose pop
2199!macroend
2200
2201!macro un.CheckDiskSpace
2202  !ifndef un.CheckDiskSpace
2203    !verbose push
2204    !verbose ${_MOZFUNC_VERBOSE}
2205    !undef _MOZFUNC_UN
2206    !define _MOZFUNC_UN "un."
2207
2208    !insertmacro CheckDiskSpace
2209
2210    !undef _MOZFUNC_UN
2211    !define _MOZFUNC_UN
2212    !verbose pop
2213  !endif
2214!macroend
2215
2216/**
2217* Returns the path found within a passed in string. The path is quoted or not
2218* with the exception of an unquoted non 8dot3 path without arguments that is
2219* also not a DefaultIcon path, is a 8dot3 path or not, has command line
2220* arguments, or is a registry DefaultIcon path (e.g. <path to binary>,# where #
2221* is the icon's resuorce id). The string does not need to be a valid path or
2222* exist. It is up to the caller to pass in a string of one of the forms noted
2223* above and to verify existence if necessary.
2224*
2225* Examples:
2226* In:  C:\PROGRA~1\MOZILL~1\FIREFOX.EXE -flag "%1"
2227* In:  C:\PROGRA~1\MOZILL~1\FIREFOX.EXE,0
2228* In:  C:\PROGRA~1\MOZILL~1\FIREFOX.EXE
2229* In:  "C:\PROGRA~1\MOZILL~1\FIREFOX.EXE"
2230* In:  "C:\PROGRA~1\MOZILL~1\FIREFOX.EXE" -flag "%1"
2231* Out: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE
2232*
2233* In:  "C:\Program Files\Mozilla Firefox\firefox.exe" -flag "%1"
2234* In:  C:\Program Files\Mozilla Firefox\firefox.exe,0
2235* In:  "C:\Program Files\Mozilla Firefox\firefox.exe"
2236* Out: C:\Program Files\Mozilla Firefox\firefox.exe
2237*
2238* @param   _IN_PATH
2239*          The string containing the path.
2240* @param   _OUT_PATH
2241*          The register to store the path to.
2242*
2243* $R7 = counter for the outer loop's EnumRegKey
2244* $R8 = return value from ReadRegStr
2245* $R9 = _IN_PATH and _OUT_PATH
2246*/
2247!macro GetPathFromString
2248
2249  !ifndef ${_MOZFUNC_UN}GetPathFromString
2250    !verbose push
2251    !verbose ${_MOZFUNC_VERBOSE}
2252    !define ${_MOZFUNC_UN}GetPathFromString "!insertmacro ${_MOZFUNC_UN}GetPathFromStringCall"
2253
2254    Function ${_MOZFUNC_UN}GetPathFromString
2255      Exch $R9
2256      Push $R8
2257      Push $R7
2258
2259      StrCpy $R7 0          ; Set the counter to 0.
2260
2261      ; Handle quoted paths with arguments.
2262      StrCpy $R8 $R9 1      ; Copy the first char.
2263      StrCmp $R8 '"' +2 +1  ; Is it a "?
2264      StrCmp $R8 "'" +1 +9  ; Is it a '?
2265      StrCpy $R9 $R9 "" 1   ; Remove the first char.
2266      IntOp $R7 $R7 + 1     ; Increment the counter.
2267      StrCpy $R8 $R9 1 $R7  ; Starting from the counter copy the next char.
2268      StrCmp $R8 "" end +1  ; Are there no more chars?
2269      StrCmp $R8 '"' +2 +1  ; Is it a " char?
2270      StrCmp $R8 "'" +1 -4  ; Is it a ' char?
2271      StrCpy $R9 $R9 $R7    ; Copy chars up to the counter.
2272      GoTo end
2273
2274      ; Handle DefaultIcon paths. DefaultIcon paths are not quoted and end with
2275      ; a , and a number.
2276      IntOp $R7 $R7 - 1     ; Decrement the counter.
2277      StrCpy $R8 $R9 1 $R7  ; Copy one char from the end minus the counter.
2278      StrCmp $R8 '' +4 +1   ; Are there no more chars?
2279      StrCmp $R8 ',' +1 -3  ; Is it a , char?
2280      StrCpy $R9 $R9 $R7    ; Copy chars up to the end minus the counter.
2281      GoTo end
2282
2283      ; Handle unquoted paths with arguments. An unquoted path with arguments
2284      ; must be an 8dot3 path.
2285      StrCpy $R7 -1          ; Set the counter to -1 so it will start at 0.
2286      IntOp $R7 $R7 + 1      ; Increment the counter.
2287      StrCpy $R8 $R9 1 $R7   ; Starting from the counter copy the next char.
2288      StrCmp $R8 "" end +1   ; Are there no more chars?
2289      StrCmp $R8 " " +1 -3   ; Is it a space char?
2290      StrCpy $R9 $R9 $R7     ; Copy chars up to the counter.
2291
2292      end:
2293      ClearErrors
2294
2295      Pop $R7
2296      Pop $R8
2297      Exch $R9
2298    FunctionEnd
2299
2300    !verbose pop
2301  !endif
2302!macroend
2303
2304!macro GetPathFromStringCall _IN_PATH _OUT_PATH
2305  !verbose push
2306  !verbose ${_MOZFUNC_VERBOSE}
2307  Push "${_IN_PATH}"
2308  Call GetPathFromString
2309  Pop ${_OUT_PATH}
2310  !verbose pop
2311!macroend
2312
2313!macro un.GetPathFromStringCall _IN_PATH _OUT_PATH
2314  !verbose push
2315  !verbose ${_MOZFUNC_VERBOSE}
2316  Push "${_IN_PATH}"
2317  Call un.GetPathFromString
2318  Pop ${_OUT_PATH}
2319  !verbose pop
2320!macroend
2321
2322!macro un.GetPathFromString
2323  !ifndef un.GetPathFromString
2324    !verbose push
2325    !verbose ${_MOZFUNC_VERBOSE}
2326    !undef _MOZFUNC_UN
2327    !define _MOZFUNC_UN "un."
2328
2329    !insertmacro GetPathFromString
2330
2331    !undef _MOZFUNC_UN
2332    !define _MOZFUNC_UN
2333    !verbose pop
2334  !endif
2335!macroend
2336
2337/**
2338 * Removes the quotes from each end of a string if present.
2339 *
2340 * @param   _IN_PATH
2341 *          The string containing the path.
2342 * @param   _OUT_PATH
2343 *          The register to store the long path.
2344 *
2345 * $R7 = storage for single character comparison
2346 * $R8 = storage for _IN_PATH
2347 * $R9 = _IN_PATH and _OUT_PATH
2348 */
2349!macro RemoveQuotesFromPath
2350
2351  !ifndef ${_MOZFUNC_UN}RemoveQuotesFromPath
2352    !verbose push
2353    !verbose ${_MOZFUNC_VERBOSE}
2354    !define ${_MOZFUNC_UN}RemoveQuotesFromPath "!insertmacro ${_MOZFUNC_UN}RemoveQuotesFromPathCall"
2355
2356    Function ${_MOZFUNC_UN}RemoveQuotesFromPath
2357      Exch $R9
2358      Push $R8
2359      Push $R7
2360
2361      StrCpy $R7 "$R9" 1
2362      StrCmp $R7 "$\"" +1 +2
2363      StrCpy $R9 "$R9" "" 1
2364
2365      StrCpy $R7 "$R9" "" -1
2366      StrCmp $R7 "$\"" +1 +2
2367      StrCpy $R9 "$R9" -1
2368
2369      Pop $R7
2370      Pop $R8
2371      Exch $R9
2372    FunctionEnd
2373
2374    !verbose pop
2375  !endif
2376!macroend
2377
2378!macro RemoveQuotesFromPathCall _IN_PATH _OUT_PATH
2379  !verbose push
2380  !verbose ${_MOZFUNC_VERBOSE}
2381  Push "${_IN_PATH}"
2382  Call RemoveQuotesFromPath
2383  Pop ${_OUT_PATH}
2384  !verbose pop
2385!macroend
2386
2387!macro un.RemoveQuotesFromPathCall _IN_PATH _OUT_PATH
2388  !verbose push
2389  !verbose ${_MOZFUNC_VERBOSE}
2390  Push "${_IN_PATH}"
2391  Call un.RemoveQuotesFromPath
2392  Pop ${_OUT_PATH}
2393  !verbose pop
2394!macroend
2395
2396!macro un.RemoveQuotesFromPath
2397  !ifndef un.RemoveQuotesFromPath
2398    !verbose push
2399    !verbose ${_MOZFUNC_VERBOSE}
2400    !undef _MOZFUNC_UN
2401    !define _MOZFUNC_UN "un."
2402
2403    !insertmacro RemoveQuotesFromPath
2404
2405    !undef _MOZFUNC_UN
2406    !define _MOZFUNC_UN
2407    !verbose pop
2408  !endif
2409!macroend
2410
2411/**
2412 * Returns the long path for an existing file or directory. GetLongPathNameW
2413 * may not be available on Win95 if Microsoft Layer for Unicode is not
2414 * installed and GetFullPathName only returns a long path for the last file or
2415 * directory that doesn't end with a \ in the path that it is passed. If the
2416 * path does not exist on the file system this will return an empty string. To
2417 * provide a consistent result trailing back-slashes are always removed.
2418 *
2419 * Note: 1024 used by GetLongPathNameW is the maximum NSIS string length.
2420 *
2421 * @param   _IN_PATH
2422 *          The string containing the path.
2423 * @param   _OUT_PATH
2424 *          The register to store the long path.
2425 *
2426 * $R4 = counter value when the previous \ was found
2427 * $R5 = directory or file name found during loop
2428 * $R6 = return value from GetLongPathNameW and loop counter
2429 * $R7 = long path from GetLongPathNameW and single char from path for comparison
2430 * $R8 = storage for _IN_PATH
2431 * $R9 = _IN_PATH _OUT_PATH
2432 */
2433!macro GetLongPath
2434
2435  !ifndef ${_MOZFUNC_UN}GetLongPath
2436    !verbose push
2437    !verbose ${_MOZFUNC_VERBOSE}
2438    !define ${_MOZFUNC_UN}GetLongPath "!insertmacro ${_MOZFUNC_UN}GetLongPathCall"
2439
2440    Function ${_MOZFUNC_UN}GetLongPath
2441      Exch $R9
2442      Push $R8
2443      Push $R7
2444      Push $R6
2445      Push $R5
2446      Push $R4
2447
2448      ClearErrors
2449
2450      GetFullPathName $R8 "$R9"
2451      IfErrors end_GetLongPath +1 ; If the path doesn't exist return an empty string.
2452
2453      ; Make the drive letter uppercase.
2454      StrCpy $R9 "$R8" 1    ; Copy the first char.
2455      StrCpy $R8 "$R8" "" 1 ; Copy everything after the first char.
2456      ; Convert the first char to uppercase.
2457      System::Call "User32::CharUpper(w R9 R9)i"
2458      StrCpy $R8 "$R9$R8"   ; Copy the uppercase char and the rest of the chars.
2459
2460      ; Do it the hard way.
2461      StrCpy $R4 0     ; Stores the position in the string of the last \ found.
2462      StrCpy $R6 -1    ; Set the counter to -1 so it will start at 0.
2463
2464      loop_GetLongPath:
2465      IntOp $R6 $R6 + 1      ; Increment the counter.
2466      StrCpy $R7 $R8 1 $R6   ; Starting from the counter copy the next char.
2467      StrCmp $R7 "" +2 +1    ; Are there no more chars?
2468      StrCmp $R7 "\" +1 -3   ; Is it a \?
2469
2470      ; Copy chars starting from the previously found \ to the counter.
2471      StrCpy $R5 $R8 $R6 $R4
2472
2473      ; If this is the first \ found we want to swap R9 with R5 so a \ will
2474      ; be appended to the drive letter and colon (e.g. C: will become C:\).
2475      StrCmp $R4 0 +1 +3
2476      StrCpy $R9 $R5
2477      StrCpy $R5 ""
2478
2479      GetFullPathName $R9 "$R9\$R5"
2480
2481      StrCmp $R7 "" end_GetLongPath +1 ; Are there no more chars?
2482
2483      ; Store the counter for the current \ and prefix it for StrCpy operations.
2484      StrCpy $R4 "+$R6"
2485      IntOp $R6 $R6 + 1      ; Increment the counter so we skip over the \.
2486      StrCpy $R8 $R8 "" $R6  ; Copy chars starting from the counter to the end.
2487      StrCpy $R6 -1          ; Reset the counter to -1 so it will start over at 0.
2488      GoTo loop_GetLongPath
2489
2490      end_GetLongPath:
2491      ; If there is a trailing slash remove it
2492      StrCmp $R9 "" +4 +1
2493      StrCpy $R8 "$R9" "" -1
2494      StrCmp $R8 "\" +1 +2
2495      StrCpy $R9 "$R9" -1
2496
2497      ClearErrors
2498
2499      Pop $R4
2500      Pop $R5
2501      Pop $R6
2502      Pop $R7
2503      Pop $R8
2504      Exch $R9
2505    FunctionEnd
2506
2507    !verbose pop
2508  !endif
2509!macroend
2510
2511!macro GetLongPathCall _IN_PATH _OUT_PATH
2512  !verbose push
2513  !verbose ${_MOZFUNC_VERBOSE}
2514  Push "${_IN_PATH}"
2515  Call GetLongPath
2516  Pop ${_OUT_PATH}
2517  !verbose pop
2518!macroend
2519
2520!macro un.GetLongPathCall _IN_PATH _OUT_PATH
2521  !verbose push
2522  !verbose ${_MOZFUNC_VERBOSE}
2523  Push "${_IN_PATH}"
2524  Call un.GetLongPath
2525  Pop ${_OUT_PATH}
2526  !verbose pop
2527!macroend
2528
2529!macro un.GetLongPath
2530  !ifndef un.GetLongPath
2531    !verbose push
2532    !verbose ${_MOZFUNC_VERBOSE}
2533    !undef _MOZFUNC_UN
2534    !define _MOZFUNC_UN "un."
2535
2536    !insertmacro GetLongPath
2537
2538    !undef _MOZFUNC_UN
2539    !define _MOZFUNC_UN
2540    !verbose pop
2541  !endif
2542!macroend
2543
2544
2545################################################################################
2546# Macros for cleaning up the registry and file system
2547
2548/**
2549 * Removes registry keys that reference this install location and for paths that
2550 * no longer exist. This uses SHCTX to determine the registry hive so you must
2551 * call SetShellVarContext first.
2552 *
2553 * @param   _KEY
2554 *          The registry subkey (typically this will be Software\Mozilla).
2555 *
2556 * $0  = loop counter
2557 * $1  = temporary value used for string searches
2558 * $R0 = on x64 systems set to 'false' at the beginning of the macro when
2559 *       enumerating the x86 registry view and set to 'true' when enumerating
2560 *       the x64 registry view.
2561 * $R1 = stores the long path to $INSTDIR
2562 * $R2 = return value from the stack from the GetParent and GetLongPath macros
2563 * $R3 = return value from the outer loop's EnumRegKey and ESR string
2564 * $R4 = return value from the inner loop's EnumRegKey
2565 * $R5 = return value from ReadRegStr
2566 * $R6 = counter for the outer loop's EnumRegKey
2567 * $R7 = counter for the inner loop's EnumRegKey
2568 * $R8 = return value from the stack from the RemoveQuotesFromPath macro
2569 * $R9 = _KEY
2570 */
2571!macro RegCleanMain
2572
2573  !ifndef ${_MOZFUNC_UN}RegCleanMain
2574    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
2575    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
2576    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
2577    !insertmacro ${_MOZFUNC_UN_TMP}RemoveQuotesFromPath
2578    !undef _MOZFUNC_UN
2579    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
2580    !undef _MOZFUNC_UN_TMP
2581
2582    !verbose push
2583    !verbose ${_MOZFUNC_VERBOSE}
2584    !define ${_MOZFUNC_UN}RegCleanMain "!insertmacro ${_MOZFUNC_UN}RegCleanMainCall"
2585
2586    Function ${_MOZFUNC_UN}RegCleanMain
2587      Exch $R9
2588      Push $R8
2589      Push $R7
2590      Push $R6
2591      Push $R5
2592      Push $R4
2593      Push $R3
2594      Push $R2
2595      Push $R1
2596      Push $R0
2597      Push $0
2598      Push $1
2599
2600      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R1
2601      StrCpy $R6 0  ; set the counter for the outer loop to 0
2602
2603      ${If} ${RunningX64}
2604      ${OrIf} ${IsNativeARM64}
2605        StrCpy $R0 "false"
2606        ; Set the registry to the 32 bit registry for 64 bit installations or to
2607        ; the 64 bit registry for 32 bit installations at the beginning so it can
2608        ; easily be set back to the correct registry view when finished.
2609        !ifdef HAVE_64BIT_BUILD
2610          SetRegView 32
2611        !else
2612          SetRegView 64
2613        !endif
2614      ${EndIf}
2615
2616      outerloop:
2617      EnumRegKey $R3 SHCTX $R9 $R6
2618      StrCmp $R3 "" end +1  ; if empty there are no more keys to enumerate
2619      IntOp $R6 $R6 + 1     ; increment the outer loop's counter
2620      ClearErrors
2621      ReadRegStr $R5 SHCTX "$R9\$R3\bin" "PathToExe"
2622      IfErrors 0 outercontinue
2623      StrCpy $R7 0  ; set the counter for the inner loop to 0
2624
2625      innerloop:
2626      EnumRegKey $R4 SHCTX "$R9\$R3" $R7
2627      StrCmp $R4 "" outerloop +1  ; if empty there are no more keys to enumerate
2628      IntOp $R7 $R7 + 1  ; increment the inner loop's counter
2629      ClearErrors
2630      ReadRegStr $R5 SHCTX "$R9\$R3\$R4\Main" "PathToExe"
2631      IfErrors innerloop
2632
2633      ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R5" $R8
2634      ${${_MOZFUNC_UN}GetParent} "$R8" $R2
2635      ${${_MOZFUNC_UN}GetLongPath} "$R2" $R2
2636      IfFileExists "$R2" +1 innerloop
2637      StrCmp "$R2" "$R1" +1 innerloop
2638
2639      ClearErrors
2640      DeleteRegKey SHCTX "$R9\$R3\$R4"
2641      IfErrors innerloop
2642      IntOp $R7 $R7 - 1 ; decrement the inner loop's counter when the key is deleted successfully.
2643      ClearErrors
2644      DeleteRegKey /ifempty SHCTX "$R9\$R3"
2645      IfErrors innerloop outerdecrement
2646
2647      outercontinue:
2648      ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R5" $R8
2649      ${${_MOZFUNC_UN}GetParent} "$R8" $R2
2650      ${${_MOZFUNC_UN}GetLongPath} "$R2" $R2
2651      IfFileExists "$R2" +1 outerloop
2652      StrCmp "$R2" "$R1" +1 outerloop
2653
2654      ClearErrors
2655      DeleteRegKey SHCTX "$R9\$R3"
2656      IfErrors outerloop
2657
2658      outerdecrement:
2659      IntOp $R6 $R6 - 1 ; decrement the outer loop's counter when the key is deleted successfully.
2660      GoTo outerloop
2661
2662      end:
2663      ; Check if _KEY\${BrandFullNameInternal} refers to a key that's been
2664      ; removed, either just now by this function or earlier by something else,
2665      ; and if so either update it to a key that does exist or remove it if we
2666      ; can't find anything to update it to.
2667      ; We'll run this check twice, once looking for non-ESR keys and then again
2668      ; looking specifically for the separate ESR keys.
2669      StrCpy $R3 ""
2670      ${For} $0 0 1
2671        ClearErrors
2672        ReadRegStr $R5 SHCTX "$R9\${BrandFullNameInternal}$R3" "CurrentVersion"
2673        ${IfNot} ${Errors}
2674          ReadRegStr $R5 SHCTX "$R9\${BrandFullNameInternal}\$R5" ""
2675          ${If} ${Errors}
2676            ; Key doesn't exist, update or remove CurrentVersion and default.
2677            StrCpy $R5 ""
2678            StrCpy $R6 0
2679            EnumRegKey $R4 SHCTX "$R9\${BrandFullNameInternal}" $R6
2680            ${While} $R4 != ""
2681              ClearErrors
2682              ${WordFind} "$R4" "esr" "E#" $1
2683              ${If} $R3 == ""
2684                ; The key we're looking to update is a non-ESR, so we need to
2685                ; select only another non-ESR to update it with.
2686                ${If} ${Errors}
2687                  StrCpy $R5 "$R4"
2688                  ${Break}
2689                ${EndIf}
2690              ${Else}
2691                ; The key we're looking to update is an ESR, so we need to
2692                ; select only another ESR to update it with.
2693                ${IfNot} ${Errors}
2694                  StrCpy $R5 "$R4"
2695                  ${Break}
2696                ${EndIf}
2697              ${EndIf}
2698
2699              IntOp $R6 $R6 + 1
2700              EnumRegKey $R4 SHCTX "$R9\${BrandFullNameInternal}" $R6
2701            ${EndWhile}
2702
2703            ${If} $R5 == ""
2704              ; We didn't find an install to update the key with, so delete the
2705              ; CurrentVersion value and the entire key if it has no subkeys.
2706              DeleteRegValue SHCTX "$R9\${BrandFullNameInternal}$R3" "CurrentVersion"
2707              DeleteRegValue SHCTX "$R9\${BrandFullNameInternal}$R3" ""
2708              DeleteRegKey /ifempty SHCTX "$R9\${BrandFullNameInternal}$R3"
2709            ${Else}
2710              ; We do have another still-existing install, so update the key to
2711              ; that version.
2712              WriteRegStr SHCTX "$R9\${BrandFullNameInternal}$R3" \
2713                                "CurrentVersion" "$R5"
2714              ${WordFind} "$R5" " " "+1{" $R5
2715              WriteRegStr SHCTX "$R9\${BrandFullNameInternal}$R3" "" "$R5"
2716            ${EndIf}
2717          ${EndIf}
2718          ; Else, the key referenced in CurrentVersion still exists,
2719          ; so there's nothing to update or remove.
2720        ${EndIf}
2721
2722        ; Set up for the second iteration of the loop, where we'll be looking
2723        ; for the separate ESR keys.
2724        StrCpy $R3 " ESR"
2725      ${Next}
2726
2727      ${If} ${RunningX64}
2728      ${OrIf} ${IsNativeARM64}
2729        ${If} "$R0" == "false"
2730          ; Set the registry to the correct view.
2731          !ifdef HAVE_64BIT_BUILD
2732            SetRegView 64
2733          !else
2734            SetRegView 32
2735          !endif
2736
2737          StrCpy $R6 0  ; set the counter for the outer loop to 0
2738          StrCpy $R0 "true"
2739          GoTo outerloop
2740        ${EndIf}
2741      ${EndIf}
2742
2743      ClearErrors
2744
2745      Pop $1
2746      Pop $0
2747      Pop $R0
2748      Pop $R1
2749      Pop $R2
2750      Pop $R3
2751      Pop $R4
2752      Pop $R5
2753      Pop $R6
2754      Pop $R7
2755      Pop $R8
2756      Exch $R9
2757    FunctionEnd
2758
2759    !verbose pop
2760  !endif
2761!macroend
2762
2763!macro RegCleanMainCall _KEY
2764  !verbose push
2765  !verbose ${_MOZFUNC_VERBOSE}
2766  Push "${_KEY}"
2767  Call RegCleanMain
2768  !verbose pop
2769!macroend
2770
2771!macro un.RegCleanMainCall _KEY
2772  !verbose push
2773  !verbose ${_MOZFUNC_VERBOSE}
2774  Push "${_KEY}"
2775  Call un.RegCleanMain
2776  !verbose pop
2777!macroend
2778
2779!macro un.RegCleanMain
2780  !ifndef un.RegCleanMain
2781    !verbose push
2782    !verbose ${_MOZFUNC_VERBOSE}
2783    !undef _MOZFUNC_UN
2784    !define _MOZFUNC_UN "un."
2785
2786    !insertmacro RegCleanMain
2787
2788    !undef _MOZFUNC_UN
2789    !define _MOZFUNC_UN
2790    !verbose pop
2791  !endif
2792!macroend
2793
2794
2795/**
2796 * Removes registry keys that reference this install location and for paths that
2797 * no longer exist.
2798 *
2799 * @param   _KEY ($R1)
2800 *          The registry subkey
2801 *          (typically this will be Software\Mozilla\${AppName}).
2802 */
2803!macro RegCleanPrefs
2804  !ifndef ${_MOZFUNC_UN}RegCleanPrefs
2805    !verbose push
2806    !verbose ${_MOZFUNC_VERBOSE}
2807    !define ${_MOZFUNC_UN}RegCleanPrefs "!insertmacro ${_MOZFUNC_UN}RegCleanPrefsCall"
2808
2809    Function ${_MOZFUNC_UN}RegCleanPrefs
2810      Exch $R1 ; get _KEY from the stack
2811
2812      ; These prefs are always stored in the native registry.
2813      SetRegView 64
2814
2815      ; Delete the installer prefs key for this installation, if one exists.
2816      DeleteRegKey HKCU "$R1\Installer\$AppUserModelID"
2817
2818      ; If there aren't any more installer prefs keys, delete the parent key.
2819      DeleteRegKey /ifempty HKCU "$R1\Installer"
2820
2821      SetRegView lastused
2822
2823      Pop $R1 ; restore the previous $R1
2824    FunctionEnd
2825
2826    !verbose pop
2827  !endif
2828!macroend
2829
2830!macro RegCleanPrefsCall _KEY
2831  !verbose push
2832  !verbose ${_MOZFUNC_VERBOSE}
2833  Push "${_KEY}"
2834  Call RegCleanPrefs
2835  !verbose pop
2836!macroend
2837
2838!macro un.RegCleanPrefsCall _KEY
2839  !verbose push
2840  !verbose ${_MOZFUNC_VERBOSE}
2841  Push "${_KEY}"
2842  Call un.RegCleanPrefs
2843  !verbose pop
2844!macroend
2845
2846!macro un.RegCleanPrefs
2847  !ifndef un.RegCleanPrefs
2848    !verbose push
2849    !verbose ${_MOZFUNC_VERBOSE}
2850    !undef _MOZFUNC_UN
2851    !define _MOZFUNC_UN "un."
2852
2853    !insertmacro RegCleanPrefs
2854
2855    !undef _MOZFUNC_UN
2856    !define _MOZFUNC_UN
2857    !verbose pop
2858  !endif
2859!macroend
2860
2861/**
2862 * Removes all registry keys from \Software\Windows\CurrentVersion\Uninstall
2863 * that reference this install location in both the 32 bit and 64 bit registry
2864 * view. This macro uses SHCTX to determine the registry hive so you must call
2865 * SetShellVarContext first.
2866 *
2867 * $R3 = on x64 systems set to 'false' at the beginning of the macro when
2868 *       enumerating the x86 registry view and set to 'true' when enumerating
2869 *       the x64 registry view.
2870 * $R4 = stores the long path to $INSTDIR
2871 * $R5 = return value from ReadRegStr
2872 * $R6 = string for the base reg key (e.g. Software\Microsoft\Windows\CurrentVersion\Uninstall)
2873 * $R7 = return value from EnumRegKey
2874 * $R8 = counter for EnumRegKey
2875 * $R9 = return value from the stack from the RemoveQuotesFromPath and GetLongPath macros
2876 */
2877!macro RegCleanUninstall
2878
2879  !ifndef ${_MOZFUNC_UN}RegCleanUninstall
2880    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
2881    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
2882    !insertmacro ${_MOZFUNC_UN_TMP}RemoveQuotesFromPath
2883    !undef _MOZFUNC_UN
2884    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
2885    !undef _MOZFUNC_UN_TMP
2886
2887    !verbose push
2888    !verbose ${_MOZFUNC_VERBOSE}
2889    !define ${_MOZFUNC_UN}RegCleanUninstall "!insertmacro ${_MOZFUNC_UN}RegCleanUninstallCall"
2890
2891    Function ${_MOZFUNC_UN}RegCleanUninstall
2892      Push $R9
2893      Push $R8
2894      Push $R7
2895      Push $R6
2896      Push $R5
2897      Push $R4
2898      Push $R3
2899
2900      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R4
2901      StrCpy $R6 "Software\Microsoft\Windows\CurrentVersion\Uninstall"
2902      StrCpy $R7 ""
2903      StrCpy $R8 0
2904
2905      ${If} ${RunningX64}
2906      ${OrIf} ${IsNativeARM64}
2907        StrCpy $R3 "false"
2908        ; Set the registry to the 32 bit registry for 64 bit installations or to
2909        ; the 64 bit registry for 32 bit installations at the beginning so it can
2910        ; easily be set back to the correct registry view when finished.
2911        !ifdef HAVE_64BIT_BUILD
2912          SetRegView 32
2913        !else
2914          SetRegView 64
2915        !endif
2916      ${EndIf}
2917
2918      loop:
2919      EnumRegKey $R7 SHCTX $R6 $R8
2920      StrCmp $R7 "" end +1
2921      IntOp $R8 $R8 + 1 ; Increment the counter
2922      ClearErrors
2923      ReadRegStr $R5 SHCTX "$R6\$R7" "InstallLocation"
2924      IfErrors loop
2925      ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R5" $R9
2926
2927      ; Detect when the path is just a drive letter without a trailing
2928      ; backslash (e.g., "C:"), and add a backslash. If we don't, the Win32
2929      ; calls in GetLongPath will interpret that syntax as a shorthand
2930      ; for the working directory, because that's the DOS 2.0 convention,
2931      ; and will return the path to that directory instead of just the drive.
2932      ; Back here, we would then successfully match that with our $INSTDIR,
2933      ; and end up deleting a registry key that isn't really ours.
2934      StrLen $R5 "$R9"
2935      ${If} $R5 == 2
2936        StrCpy $R5 "$R9" 1 1
2937        ${If} "$R5" == ":"
2938          StrCpy $R9 "$R9\"
2939        ${EndIf}
2940      ${EndIf}
2941
2942      ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9
2943      StrCmp "$R9" "$R4" +1 loop
2944      ClearErrors
2945      DeleteRegKey SHCTX "$R6\$R7"
2946      IfErrors loop +1
2947      IntOp $R8 $R8 - 1 ; Decrement the counter on successful deletion
2948      GoTo loop
2949
2950      end:
2951      ${If} ${RunningX64}
2952      ${OrIf} ${IsNativeARM64}
2953        ${If} "$R3" == "false"
2954          ; Set the registry to the correct view.
2955          !ifdef HAVE_64BIT_BUILD
2956            SetRegView 64
2957          !else
2958            SetRegView 32
2959          !endif
2960
2961          StrCpy $R7 ""
2962          StrCpy $R8 0
2963          StrCpy $R3 "true"
2964          GoTo loop
2965        ${EndIf}
2966      ${EndIf}
2967
2968      ClearErrors
2969
2970      Pop $R3
2971      Pop $R4
2972      Pop $R5
2973      Pop $R6
2974      Pop $R7
2975      Pop $R8
2976      Pop $R9
2977    FunctionEnd
2978
2979    !verbose pop
2980  !endif
2981!macroend
2982
2983!macro RegCleanUninstallCall
2984  !verbose push
2985  !verbose ${_MOZFUNC_VERBOSE}
2986  Call RegCleanUninstall
2987  !verbose pop
2988!macroend
2989
2990!macro un.RegCleanUninstallCall
2991  !verbose push
2992  !verbose ${_MOZFUNC_VERBOSE}
2993  Call un.RegCleanUninstall
2994  !verbose pop
2995!macroend
2996
2997!macro un.RegCleanUninstall
2998  !ifndef un.RegCleanUninstall
2999    !verbose push
3000    !verbose ${_MOZFUNC_VERBOSE}
3001    !undef _MOZFUNC_UN
3002    !define _MOZFUNC_UN "un."
3003
3004    !insertmacro RegCleanUninstall
3005
3006    !undef _MOZFUNC_UN
3007    !define _MOZFUNC_UN
3008    !verbose pop
3009  !endif
3010!macroend
3011
3012/**
3013 * Removes an application specific handler registry key under Software\Classes
3014 * for both HKCU and HKLM when its open command refers to this install
3015 * location or the install location doesn't exist.
3016 *
3017 * @param   _HANDLER_NAME
3018 *          The registry name for the handler.
3019 *
3020 * $R7 = stores the long path to the $INSTDIR
3021 * $R8 = stores the path to the open command's parent directory
3022 * $R9 = _HANDLER_NAME
3023 */
3024!macro RegCleanAppHandler
3025
3026  !ifndef ${_MOZFUNC_UN}RegCleanAppHandler
3027    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
3028    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
3029    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
3030    !insertmacro ${_MOZFUNC_UN_TMP}GetPathFromString
3031    !undef _MOZFUNC_UN
3032    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
3033    !undef _MOZFUNC_UN_TMP
3034
3035    !verbose push
3036    !verbose ${_MOZFUNC_VERBOSE}
3037    !define ${_MOZFUNC_UN}RegCleanAppHandler "!insertmacro ${_MOZFUNC_UN}RegCleanAppHandlerCall"
3038
3039    Function ${_MOZFUNC_UN}RegCleanAppHandler
3040      Exch $R9
3041      Push $R8
3042      Push $R7
3043
3044      ClearErrors
3045      ReadRegStr $R8 HKCU "Software\Classes\$R9\shell\open\command" ""
3046      IfErrors next +1
3047      ${${_MOZFUNC_UN}GetPathFromString} "$R8" $R8
3048      ${${_MOZFUNC_UN}GetParent} "$R8" $R8
3049      IfFileExists "$R8" +3 +1
3050      DeleteRegKey HKCU "Software\Classes\$R9"
3051      GoTo next
3052
3053      ${${_MOZFUNC_UN}GetLongPath} "$R8" $R8
3054      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R7
3055      StrCmp "$R7" "$R8" +1 next
3056      DeleteRegKey HKCU "Software\Classes\$R9"
3057
3058      next:
3059      ReadRegStr $R8 HKLM "Software\Classes\$R9\shell\open\command" ""
3060      IfErrors end
3061      ${${_MOZFUNC_UN}GetPathFromString} "$R8" $R8
3062      ${${_MOZFUNC_UN}GetParent} "$R8" $R8
3063      IfFileExists "$R8" +3 +1
3064      DeleteRegKey HKLM "Software\Classes\$R9"
3065      GoTo end
3066
3067      ${${_MOZFUNC_UN}GetLongPath} "$R8" $R8
3068      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R7
3069      StrCmp "$R7" "$R8" +1 end
3070      DeleteRegKey HKLM "Software\Classes\$R9"
3071
3072      end:
3073
3074      Pop $R7
3075      Pop $R8
3076      Exch $R9
3077    FunctionEnd
3078
3079    !verbose pop
3080  !endif
3081!macroend
3082
3083!macro RegCleanAppHandlerCall _HANDLER_NAME
3084  !verbose push
3085  !verbose ${_MOZFUNC_VERBOSE}
3086  Push "${_HANDLER_NAME}"
3087  Call RegCleanAppHandler
3088  !verbose pop
3089!macroend
3090
3091!macro un.RegCleanAppHandlerCall _HANDLER_NAME
3092  !verbose push
3093  !verbose ${_MOZFUNC_VERBOSE}
3094  Push "${_HANDLER_NAME}"
3095  Call un.RegCleanAppHandler
3096  !verbose pop
3097!macroend
3098
3099!macro un.RegCleanAppHandler
3100  !ifndef un.RegCleanAppHandler
3101    !verbose push
3102    !verbose ${_MOZFUNC_VERBOSE}
3103    !undef _MOZFUNC_UN
3104    !define _MOZFUNC_UN "un."
3105
3106    !insertmacro RegCleanAppHandler
3107
3108    !undef _MOZFUNC_UN
3109    !define _MOZFUNC_UN
3110    !verbose pop
3111  !endif
3112!macroend
3113
3114/**
3115 * Cleans up the registry for a protocol handler when its open command
3116 * refers to this install location. For HKCU the registry key is deleted
3117 * and for HKLM the values set by the application are deleted.
3118 *
3119 * @param   _HANDLER_NAME
3120 *          The registry name for the handler.
3121 *
3122 * $R7 = stores the long path to $INSTDIR
3123 * $R8 = stores the the long path to the open command's parent directory
3124 * $R9 = _HANDLER_NAME
3125 */
3126!macro un.RegCleanProtocolHandler
3127
3128  !ifndef un.RegCleanProtocolHandler
3129    !insertmacro un.GetLongPath
3130    !insertmacro un.GetParent
3131    !insertmacro un.GetPathFromString
3132
3133    !verbose push
3134    !verbose ${_MOZFUNC_VERBOSE}
3135    !define un.RegCleanProtocolHandler "!insertmacro un.RegCleanProtocolHandlerCall"
3136
3137    Function un.RegCleanProtocolHandler
3138      Exch $R9
3139      Push $R8
3140      Push $R7
3141
3142      ReadRegStr $R8 HKCU "Software\Classes\$R9\shell\open\command" ""
3143      ${un.GetLongPath} "$INSTDIR" $R7
3144
3145      StrCmp "$R8" "" next +1
3146      ${un.GetPathFromString} "$R8" $R8
3147      ${un.GetParent} "$R8" $R8
3148      ${un.GetLongPath} "$R8" $R8
3149      StrCmp "$R7" "$R8" +1 next
3150      DeleteRegKey HKCU "Software\Classes\$R9"
3151
3152      next:
3153      ReadRegStr $R8 HKLM "Software\Classes\$R9\shell\open\command" ""
3154      StrCmp "$R8" "" end +1
3155      ${un.GetLongPath} "$INSTDIR" $R7
3156      ${un.GetPathFromString} "$R8" $R8
3157      ${un.GetParent} "$R8" $R8
3158      ${un.GetLongPath} "$R8" $R8
3159      StrCmp "$R7" "$R8" +1 end
3160      DeleteRegValue HKLM "Software\Classes\$R9\DefaultIcon" ""
3161      DeleteRegValue HKLM "Software\Classes\$R9\shell\open" ""
3162      DeleteRegValue HKLM "Software\Classes\$R9\shell\open\command" ""
3163      DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec" ""
3164      DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec\Application" ""
3165      DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec\Topic" ""
3166
3167      end:
3168
3169      Pop $R7
3170      Pop $R8
3171      Exch $R9
3172    FunctionEnd
3173
3174    !verbose pop
3175  !endif
3176!macroend
3177
3178!macro un.RegCleanProtocolHandlerCall _HANDLER_NAME
3179  !verbose push
3180  !verbose ${_MOZFUNC_VERBOSE}
3181  Push "${_HANDLER_NAME}"
3182  Call un.RegCleanProtocolHandler
3183  !verbose pop
3184!macroend
3185
3186/**
3187 * Cleans up the registry for a file handler when the passed in value equals
3188 * the default value for the file handler. For HKCU the registry key is deleted
3189 * and for HKLM the default value is deleted.
3190 *
3191 * @param   _HANDLER_NAME
3192 *          The registry name for the handler.
3193 * @param   _DEFAULT_VALUE
3194 *          The value to check for against the handler's default value.
3195 *
3196 * $R6 = stores the long path to $INSTDIR
3197 * $R7 = _DEFAULT_VALUE
3198 * $R9 = _HANDLER_NAME
3199 */
3200!macro RegCleanFileHandler
3201
3202  !ifndef ${_MOZFUNC_UN}RegCleanFileHandler
3203    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
3204    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
3205    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
3206    !insertmacro ${_MOZFUNC_UN_TMP}GetPathFromString
3207    !undef _MOZFUNC_UN
3208    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
3209    !undef _MOZFUNC_UN_TMP
3210
3211    !verbose push
3212    !verbose ${_MOZFUNC_VERBOSE}
3213    !define ${_MOZFUNC_UN}RegCleanFileHandler "!insertmacro ${_MOZFUNC_UN}RegCleanFileHandlerCall"
3214
3215    Function ${_MOZFUNC_UN}RegCleanFileHandler
3216      Exch $R9
3217      Exch 1
3218      Exch $R8
3219      Push $R7
3220
3221      DeleteRegValue HKCU "Software\Classes\$R9\OpenWithProgids" $R8
3222      EnumRegValue $R7 HKCU "Software\Classes\$R9\OpenWithProgids" 0
3223      StrCmp "$R7" "" +1 +2
3224      DeleteRegKey HKCU "Software\Classes\$R9\OpenWithProgids"
3225      ReadRegStr $R7 HKCU "Software\Classes\$R9" ""
3226      StrCmp "$R7" "$R8" +1 +2
3227      DeleteRegKey HKCU "Software\Classes\$R9"
3228
3229      DeleteRegValue HKLM "Software\Classes\$R9\OpenWithProgids" $R8
3230      EnumRegValue $R7 HKLM "Software\Classes\$R9\OpenWithProgids" 0
3231      StrCmp "$R7" "" +1 +2
3232      DeleteRegKey HKLM "Software\Classes\$R9\OpenWithProgids"
3233      ReadRegStr $R7 HKLM "Software\Classes\$R9" ""
3234      StrCmp "$R7" "$R8" +1 +2
3235      DeleteRegValue HKLM "Software\Classes\$R9" ""
3236
3237      ClearErrors
3238
3239      Pop $R7
3240      Exch $R8
3241      Exch 1
3242      Exch $R9
3243    FunctionEnd
3244
3245    !verbose pop
3246  !endif
3247!macroend
3248
3249!macro RegCleanFileHandlerCall _HANDLER_NAME _DEFAULT_VALUE
3250  !verbose push
3251  !verbose ${_MOZFUNC_VERBOSE}
3252  Push "${_DEFAULT_VALUE}"
3253  Push "${_HANDLER_NAME}"
3254  Call RegCleanFileHandler
3255  !verbose pop
3256!macroend
3257
3258!macro un.RegCleanFileHandlerCall _HANDLER_NAME _DEFAULT_VALUE
3259  !verbose push
3260  !verbose ${_MOZFUNC_VERBOSE}
3261  Push "${_DEFAULT_VALUE}"
3262  Push "${_HANDLER_NAME}"
3263  Call un.RegCleanFileHandler
3264  !verbose pop
3265!macroend
3266
3267!macro un.RegCleanFileHandler
3268  !ifndef un.RegCleanFileHandler
3269    !verbose push
3270    !verbose ${_MOZFUNC_VERBOSE}
3271    !undef _MOZFUNC_UN
3272    !define _MOZFUNC_UN "un."
3273
3274    !insertmacro RegCleanFileHandler
3275
3276    !undef _MOZFUNC_UN
3277    !define _MOZFUNC_UN
3278    !verbose pop
3279  !endif
3280!macroend
3281
3282/**
3283 * Checks if a handler's open command points to this installation directory.
3284 * Uses SHCTX to determine the registry hive (e.g. HKLM or HKCU) to check.
3285 *
3286 * @param   _HANDLER_NAME
3287 *          The registry name for the handler.
3288 * @param   _RESULT
3289 *          true if it is the handler's open command points to this
3290 *          installation directory and false if it does not.
3291 *
3292 * $R7 = stores the value of the open command and the path macros return values
3293 * $R8 = stores the handler's registry key name
3294 * $R9 = _DEFAULT_VALUE and _RESULT
3295 */
3296!macro IsHandlerForInstallDir
3297
3298  !ifndef ${_MOZFUNC_UN}IsHandlerForInstallDir
3299    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
3300    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
3301    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
3302    !insertmacro ${_MOZFUNC_UN_TMP}GetPathFromString
3303    !undef _MOZFUNC_UN
3304    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
3305    !undef _MOZFUNC_UN_TMP
3306
3307    !verbose push
3308    !verbose ${_MOZFUNC_VERBOSE}
3309    !define ${_MOZFUNC_UN}IsHandlerForInstallDir "!insertmacro ${_MOZFUNC_UN}IsHandlerForInstallDirCall"
3310
3311    Function ${_MOZFUNC_UN}IsHandlerForInstallDir
3312      Exch $R9
3313      Push $R8
3314      Push $R7
3315
3316      StrCpy $R8 "$R9"
3317      StrCpy $R9 "false"
3318      ReadRegStr $R7 SHCTX "Software\Classes\$R8\shell\open\command" ""
3319
3320      ${If} $R7 != ""
3321        ${GetPathFromString} "$R7" $R7
3322        ${GetParent} "$R7" $R7
3323        ${GetLongPath} "$R7" $R7
3324        ${If} $R7 == $INSTDIR
3325          StrCpy $R9 "true"
3326        ${EndIf}
3327      ${EndIf}
3328
3329      ClearErrors
3330
3331      Pop $R7
3332      Pop $R8
3333      Exch $R9
3334    FunctionEnd
3335
3336    !verbose pop
3337  !endif
3338!macroend
3339
3340!macro IsHandlerForInstallDirCall _HANDLER_NAME _RESULT
3341  !verbose push
3342  !verbose ${_MOZFUNC_VERBOSE}
3343  Push "${_HANDLER_NAME}"
3344  Call IsHandlerForInstallDir
3345  Pop "${_RESULT}"
3346  !verbose pop
3347!macroend
3348
3349!macro un.IsHandlerForInstallDirCall _HANDLER_NAME _RESULT
3350  !verbose push
3351  !verbose ${_MOZFUNC_VERBOSE}
3352  Push "${_HANDLER_NAME}"
3353  Call un.IsHandlerForInstallDir
3354  Pop "${_RESULT}"
3355  !verbose pop
3356!macroend
3357
3358!macro un.IsHandlerForInstallDir
3359  !ifndef un.IsHandlerForInstallDir
3360    !verbose push
3361    !verbose ${_MOZFUNC_VERBOSE}
3362    !undef _MOZFUNC_UN
3363    !define _MOZFUNC_UN "un."
3364
3365    !insertmacro IsHandlerForInstallDir
3366
3367    !undef _MOZFUNC_UN
3368    !define _MOZFUNC_UN
3369    !verbose pop
3370  !endif
3371!macroend
3372
3373/**
3374 * Removes the application's VirtualStore directory if present when the
3375 * installation directory is a sub-directory of the program files directory.
3376 *
3377 * $R3 = Local App Data dir
3378 * $R4 = $PROGRAMFILES/$PROGRAMFILES64 for CleanVirtualStore_Internal
3379 * $R5 = various path values.
3380 * $R6 = length of the long path to $PROGRAMFILES32 or $PROGRAMFILES64
3381 * $R7 = long path to $PROGRAMFILES32 or $PROGRAMFILES64
3382 * $R8 = length of the long path to $INSTDIR
3383 * $R9 = long path to $INSTDIR
3384 */
3385!macro CleanVirtualStore
3386
3387  !ifndef ${_MOZFUNC_UN}CleanVirtualStore
3388    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
3389    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
3390    !undef _MOZFUNC_UN
3391    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
3392    !undef _MOZFUNC_UN_TMP
3393
3394    !verbose push
3395    !verbose ${_MOZFUNC_VERBOSE}
3396    !define ${_MOZFUNC_UN}CleanVirtualStore "!insertmacro ${_MOZFUNC_UN}CleanVirtualStoreCall"
3397
3398    Function ${_MOZFUNC_UN}CleanVirtualStore
3399      Push $R9
3400      Push $R8
3401      Push $R7
3402      Push $R6
3403      Push $R5
3404      Push $R4
3405      Push $R3
3406
3407      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R9
3408      ${If} "$R9" != ""
3409        StrLen $R8 "$R9"
3410
3411        StrCpy $R4 $PROGRAMFILES32
3412        Call ${_MOZFUNC_UN}CleanVirtualStore_Internal
3413
3414        ${If} ${RunningX64}
3415        ${OrIf} ${IsNativeARM64}
3416          StrCpy $R4 $PROGRAMFILES64
3417          Call ${_MOZFUNC_UN}CleanVirtualStore_Internal
3418        ${EndIf}
3419
3420      ${EndIf}
3421
3422      ClearErrors
3423
3424      Pop $R3
3425      Pop $R4
3426      Pop $R5
3427      Pop $R6
3428      Pop $R7
3429      Pop $R8
3430      Pop $R9
3431    FunctionEnd
3432
3433    Function ${_MOZFUNC_UN}CleanVirtualStore_Internal
3434      ${${_MOZFUNC_UN}GetLongPath} "" $R7
3435      ${If} "$R7" != ""
3436        StrLen $R6 "$R7"
3437        ${If} $R8 < $R6
3438          ; Copy from the start of $INSTDIR the length of $PROGRAMFILES64
3439          StrCpy $R5 "$R9" $R6
3440          ${If} "$R5" == "$R7"
3441            ; Remove the drive letter and colon from the $INSTDIR long path
3442            StrCpy $R5 "$R9" "" 2
3443            ${GetLocalAppDataFolder} $R3
3444            StrCpy $R5 "$R3\VirtualStore$R5"
3445            ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
3446            ${If} "$R5" != ""
3447            ${AndIf} ${FileExists} "$R5"
3448              RmDir /r "$R5"
3449            ${EndIf}
3450          ${EndIf}
3451        ${EndIf}
3452      ${EndIf}
3453    FunctionEnd
3454
3455    !verbose pop
3456  !endif
3457!macroend
3458
3459!macro CleanVirtualStoreCall
3460  !verbose push
3461  !verbose ${_MOZFUNC_VERBOSE}
3462  Call CleanVirtualStore
3463  !verbose pop
3464!macroend
3465
3466!macro un.CleanVirtualStoreCall
3467  !verbose push
3468  !verbose ${_MOZFUNC_VERBOSE}
3469  Call un.CleanVirtualStore
3470  !verbose pop
3471!macroend
3472
3473!macro un.CleanVirtualStore
3474  !ifndef un.CleanVirtualStore
3475    !verbose push
3476    !verbose ${_MOZFUNC_VERBOSE}
3477    !undef _MOZFUNC_UN
3478    !define _MOZFUNC_UN "un."
3479
3480    !insertmacro CleanVirtualStore
3481
3482    !undef _MOZFUNC_UN
3483    !define _MOZFUNC_UN
3484    !verbose pop
3485  !endif
3486!macroend
3487
3488/**
3489 * If present removes the updates directory located in the profile's local
3490 * directory for this installation.
3491 *
3492 * @param   _OLD_REL_PATH
3493 *          The relative path to the profile directory from Local AppData.
3494 *          Calculated for the old update directory not based on a hash.
3495 * @param   _NEW_REL_PATH
3496 *          The relative path to the profile directory from Local AppData.
3497 *          Calculated for the new update directory based on a hash.
3498 *
3499 * $R9 = Local AppData
3500 * $R8 = _NEW_REL_PATH
3501 * $R7 = _OLD_REL_PATH
3502 * $R1 = taskBar ID hash located in registry at SOFTWARE\_OLD_REL_PATH\TaskBarIDs
3503 * $R2 = various path values.
3504 * $R3 = length of the long path to $PROGRAMFILES
3505 * $R4 = length of the long path to $INSTDIR
3506 * $R5 = long path to $PROGRAMFILES
3507 * $R6 = long path to $INSTDIR
3508 * $R0 = path to the new update directory built from _NEW_REL_PATH and
3509 *       the taskbar ID.
3510 */
3511!macro CleanUpdateDirectories
3512
3513  !ifndef ${_MOZFUNC_UN}CleanUpdateDirectories
3514    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
3515    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
3516    !undef _MOZFUNC_UN
3517    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
3518    !undef _MOZFUNC_UN_TMP
3519
3520    !verbose push
3521    !verbose ${_MOZFUNC_VERBOSE}
3522    !define ${_MOZFUNC_UN}CleanUpdateDirectories "!insertmacro ${_MOZFUNC_UN}CleanUpdateDirectoriesCall"
3523
3524    Function ${_MOZFUNC_UN}CleanUpdateDirectories
3525      Exch $R8
3526      Exch 1
3527      Exch $R7
3528      Push $R6
3529      Push $R5
3530      Push $R4
3531      Push $R3
3532      Push $R2
3533      Push $R1
3534      Push $R0
3535      Push $R9
3536
3537      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R6
3538      StrLen $R4 "$R6"
3539
3540!ifdef HAVE_64BIT_BUILD
3541      ${${_MOZFUNC_UN}GetLongPath} "$PROGRAMFILES64" $R5
3542!else
3543      ${${_MOZFUNC_UN}GetLongPath} "$PROGRAMFILES" $R5
3544!endif
3545      StrLen $R3 "$R5"
3546      ${GetLocalAppDataFolder} $R9
3547
3548      ${If} $R7 != "" ; _OLD_REL_PATH was passed
3549      ${AndIf} $R6 != "" ; We have the install dir path
3550      ${AndIf} $R5 != "" ; We the program files path
3551      ${AndIf} $R4 > $R3 ; The length of $INSTDIR > the length of $PROGRAMFILES
3552
3553        ; Copy from the start of $INSTDIR the length of $PROGRAMFILES
3554        StrCpy $R2 "$R6" $R3
3555
3556        ; Check if $INSTDIR is under $PROGRAMFILES
3557        ${If} $R2 == $R5
3558
3559          ; Copy the relative path to $INSTDIR from $PROGRAMFILES
3560          StrCpy $R2 "$R6" "" $R3
3561
3562          ; Concatenate the local AppData path ($R9) to the relative profile path and
3563          ; the relative path to $INSTDIR from $PROGRAMFILES
3564          StrCpy $R2 "$R9\$R7$R2"
3565          ${${_MOZFUNC_UN}GetLongPath} "$R2" $R2
3566
3567          ${If} $R2 != ""
3568            ; Backup the old update directory logs and delete the directory
3569            ${If} ${FileExists} "$R2\updates\last-update.log"
3570              Rename "$R2\updates\last-update.log" "$TEMP\moz-update-old-1-last-update.log"
3571            ${EndIf}
3572
3573            ${If} ${FileExists} "$R2\updates\backup-update.log"
3574              Rename "$R2\updates\backup-update.log" "$TEMP\moz-update-old-1-backup-update.log"
3575            ${EndIf}
3576
3577            ${If} ${FileExists} "$R2\updates"
3578                RmDir /r "$R2"
3579            ${EndIf}
3580          ${EndIf}
3581        ${EndIf}
3582
3583        ; Get the taskbar ID hash for this installation path
3584        ReadRegStr $R1 HKLM "SOFTWARE\$R7\TaskBarIDs" $R6
3585        ${If} $R1 == ""
3586          ReadRegStr $R1 HKCU "SOFTWARE\$R7\TaskBarIDs" $R6
3587        ${EndIf}
3588
3589        ; If the taskbar ID hash exists then delete the new update directory
3590        ; Backup its logs before deleting it.
3591        ${If} $R1 != ""
3592          StrCpy $R0 "$R9\$R8\$R1"
3593
3594          ${If} ${FileExists} "$R0\updates\last-update.log"
3595            Rename "$R0\updates\last-update.log" "$TEMP\moz-update-old-2-last-update.log"
3596          ${EndIf}
3597
3598          ${If} ${FileExists} "$R0\updates\backup-update.log"
3599            Rename "$R0\updates\backup-update.log" "$TEMP\moz-update-old-2-backup-update.log"
3600          ${EndIf}
3601
3602          ; Remove the old updates directory, located in the user's Windows profile directory
3603          ${If} ${FileExists} "$R0\updates"
3604            RmDir /r "$R0"
3605          ${EndIf}
3606
3607          ${GetCommonAppDataFolder} $R0
3608          StrCpy $R0 "$R0\$R8\$R1"
3609
3610          ${If} ${FileExists} "$R0\updates\last-update.log"
3611            Rename "$R0\updates\last-update.log" "$TEMP\moz-update-old-3-last-update.log"
3612          ${EndIf}
3613
3614          ${If} ${FileExists} "$R0\updates\backup-update.log"
3615            Rename "$R0\updates\backup-update.log" "$TEMP\moz-update-old-3-backup-update.log"
3616          ${EndIf}
3617
3618          ; Even though this is an old update directory, completely clear it out
3619          ; on uninstall only, not on installation. If this is an installation,
3620          ; it may be a paveover install and there may be un-migrated settings
3621          ; in the update directory that we don't want to lose.
3622          ; On install though, we should still remove pending updates and update
3623          ; metadata since migrating that data could potentially confuse Firefox
3624          ; into thinking that it failed to apply an update.
3625          !if "${_MOZFUNC_UN}" == "un."
3626            ${If} ${FileExists} "$R0"
3627              RmDir /r "$R0"
3628            ${EndIf}
3629          !else
3630            ${If} ${FileExists} "$R0\updates"
3631              RmDir /r "$R0\updates"
3632            ${EndIf}
3633            Delete "$R0\active-update.xml"
3634          !endif
3635
3636          ${GetCommonAppDataFolder} $R0
3637          StrCpy $R0 "$R0\Mozilla-1de4eec8-1241-4177-a864-e594e8d1fb38\updates\$R1"
3638
3639          ${If} ${FileExists} "$R0\updates\last-update.log"
3640            Rename "$R0\updates\last-update.log" "$TEMP\moz-update-newest-last-update.log"
3641          ${EndIf}
3642
3643          ${If} ${FileExists} "$R0\updates\backup-update.log"
3644            Rename "$R0\updates\backup-update.log" "$TEMP\moz-update-newest-backup-update.log"
3645          ${EndIf}
3646
3647          ; The update directory is shared across all users of this
3648          ; installation, and it contains a number of things. Which files we
3649          ; want to keep and which we want to delete depends on if we are
3650          ; installing or uninstalling.
3651          ; If we are installing, we want to clear out any in-progress updates.
3652          ; Otherwise we could potentially install an old, pending update when
3653          ; Firefox first launches. The updates themselves live in the "updates"
3654          ; subdirectory, and the update metadata lives in active-update.xml.
3655          ; If we are uninstalling, we want to clear out the updates, the
3656          ; update history, and the per-installation update configuration data.
3657          ; In this case, we can just delete the whole update directory.
3658          !if "${_MOZFUNC_UN}" == "un."
3659            ${If} ${FileExists} "$R0"
3660              RmDir /r "$R0"
3661            ${EndIf}
3662          !else
3663            ${If} ${FileExists} "$R0\updates"
3664              RmDir /r "$R0\updates"
3665            ${EndIf}
3666            Delete "$R0\active-update.xml"
3667          !endif
3668
3669          ; Also remove the secure log files that our updater may have created
3670          ; inside the maintenance service path. There are several files named
3671          ; with the install hash and an extension indicating the kind of file.
3672          ; so use a wildcard to delete them all.
3673          Delete "$PROGRAMFILES32\Mozilla Maintenance Service\UpdateLogs\$R1.*"
3674
3675          ; If the UpdateLogs directory is now empty, then delete it.
3676          ; The Maintenance Service uninstaller should do this, but it may not
3677          ; be up to date enough because of bug 1665193, so doing this here as
3678          ; well lets us make sure it really happens.
3679          RmDir "$PROGRAMFILES32\Mozilla Maintenance Service\UpdateLogs"
3680        ${EndIf}
3681      ${EndIf}
3682
3683      ClearErrors
3684
3685      Pop $R9
3686      Pop $R0
3687      Pop $R1
3688      Pop $R2
3689      Pop $R3
3690      Pop $R4
3691      Pop $R5
3692      Pop $R6
3693      Exch $R7
3694      Exch 1
3695      Exch $R8
3696    FunctionEnd
3697
3698    !verbose pop
3699  !endif
3700!macroend
3701
3702!macro CleanUpdateDirectoriesCall _OLD_REL_PATH _NEW_REL_PATH
3703  !verbose push
3704  !verbose ${_MOZFUNC_VERBOSE}
3705  Push "${_OLD_REL_PATH}"
3706  Push "${_NEW_REL_PATH}"
3707  Call CleanUpdateDirectories
3708  !verbose pop
3709!macroend
3710
3711!macro un.CleanUpdateDirectoriesCall _OLD_REL_PATH _NEW_REL_PATH
3712  !verbose push
3713  !verbose ${_MOZFUNC_VERBOSE}
3714  Push "${_OLD_REL_PATH}"
3715  Push "${_NEW_REL_PATH}"
3716  Call un.CleanUpdateDirectories
3717  !verbose pop
3718!macroend
3719
3720!macro un.CleanUpdateDirectories
3721  !ifndef un.CleanUpdateDirectories
3722    !verbose push
3723    !verbose ${_MOZFUNC_VERBOSE}
3724    !undef _MOZFUNC_UN
3725    !define _MOZFUNC_UN "un."
3726
3727    !insertmacro CleanUpdateDirectories
3728
3729    !undef _MOZFUNC_UN
3730    !define _MOZFUNC_UN
3731    !verbose pop
3732  !endif
3733!macroend
3734
3735/**
3736 * Deletes shortcuts and Start Menu directories under Programs as specified by
3737 * the shortcuts log ini file and on Windows 7 unpins TaskBar and Start Menu
3738 * shortcuts. The shortcuts will not be deleted if the shortcut target isn't for
3739 * this install location which is determined by the shortcut having a target of
3740 * $INSTDIR\${FileMainEXE}. The context (All Users or Current User) of the
3741 * $DESKTOP and $SMPROGRAMS constants depends on the
3742 * SetShellVarContext setting and must be set by the caller of this macro. There
3743 * is no All Users context for $QUICKLAUNCH but this will not cause a problem
3744 * since the macro will just continue past the $QUICKLAUNCH shortcut deletion
3745 * section on subsequent calls.
3746 *
3747 * The ini file sections must have the following format (the order of the
3748 * sections in the ini file is not important):
3749 * [SMPROGRAMS]
3750 * ; RelativePath is the directory relative from the Start Menu
3751 * ; Programs directory.
3752 * RelativePath=Mozilla App
3753 * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so
3754 * ; on. There must not be a break in the sequence of the numbers.
3755 * Shortcut1=Mozilla App.lnk
3756 * Shortcut2=Mozilla App (Safe Mode).lnk
3757 * [DESKTOP]
3758 * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so
3759 * ; on. There must not be a break in the sequence of the numbers.
3760 * Shortcut1=Mozilla App.lnk
3761 * Shortcut2=Mozilla App (Safe Mode).lnk
3762 * [QUICKLAUNCH]
3763 * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so
3764 * ; on. There must not be a break in the sequence of the numbers for the
3765 * ; suffix.
3766 * Shortcut1=Mozilla App.lnk
3767 * Shortcut2=Mozilla App (Safe Mode).lnk
3768 * [STARTMENU]
3769 * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so
3770 * ; on. There must not be a break in the sequence of the numbers for the
3771 * ; suffix.
3772 * Shortcut1=Mozilla App.lnk
3773 * Shortcut2=Mozilla App (Safe Mode).lnk
3774 *
3775 * $R4 = counter for appending to Shortcut for enumerating the ini file entries
3776 * $R5 = return value from ShellLink::GetShortCutTarget and
3777 *       ApplicationID::UninstallPinnedItem
3778 * $R6 = find handle and the long path to the Start Menu Programs directory
3779 *       (e.g. $SMPROGRAMS)
3780 * $R7 = path to the $QUICKLAUNCH\User Pinned directory and the return value
3781 *       from ReadINIStr for the relative path to the applications directory
3782 *       under the Start Menu Programs directory and the long path to this
3783 *       directory
3784 * $R8 = return filename from FindFirst / FindNext and the return value from
3785 *       ReadINIStr for enumerating shortcuts
3786 * $R9 = long path to the shortcuts log ini file
3787 */
3788!macro DeleteShortcuts
3789
3790  !ifndef ${_MOZFUNC_UN}DeleteShortcuts
3791    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
3792    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
3793    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
3794    !undef _MOZFUNC_UN
3795    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
3796    !undef _MOZFUNC_UN_TMP
3797
3798    !verbose push
3799    !verbose ${_MOZFUNC_VERBOSE}
3800    !define ${_MOZFUNC_UN}DeleteShortcuts "!insertmacro ${_MOZFUNC_UN}DeleteShortcutsCall"
3801
3802    Function ${_MOZFUNC_UN}DeleteShortcuts
3803      Push $R9
3804      Push $R8
3805      Push $R7
3806      Push $R6
3807      Push $R5
3808      Push $R4
3809
3810      ${If} ${AtLeastWin7}
3811        ; Since shortcuts that are pinned can later be removed without removing
3812        ; the pinned shortcut unpin the pinned shortcuts for the application's
3813        ; main exe using the pinned shortcuts themselves.
3814        StrCpy $R7 "$QUICKLAUNCH\User Pinned"
3815
3816        ${If} ${FileExists} "$R7\TaskBar"
3817          ; Delete TaskBar pinned shortcuts for the application's main exe
3818          FindFirst $R6 $R8 "$R7\TaskBar\*.lnk"
3819          ${Do}
3820            ${If} ${FileExists} "$R7\TaskBar\$R8"
3821              ShellLink::GetShortCutTarget "$R7\TaskBar\$R8"
3822              Pop $R5
3823              ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
3824              ${If} "$R5" == "$INSTDIR\${FileMainEXE}"
3825                ApplicationID::UninstallPinnedItem "$R7\TaskBar\$R8"
3826                Pop $R5
3827              ${EndIf}
3828            ${EndIf}
3829            ClearErrors
3830            FindNext $R6 $R8
3831            ${If} ${Errors}
3832              ${ExitDo}
3833            ${EndIf}
3834          ${Loop}
3835          FindClose $R6
3836        ${EndIf}
3837
3838        ${If} ${FileExists} "$R7\StartMenu"
3839          ; Delete Start Menu pinned shortcuts for the application's main exe
3840          FindFirst $R6 $R8 "$R7\StartMenu\*.lnk"
3841          ${Do}
3842            ${If} ${FileExists} "$R7\StartMenu\$R8"
3843              ShellLink::GetShortCutTarget "$R7\StartMenu\$R8"
3844              Pop $R5
3845              ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
3846              ${If} "$R5" == "$INSTDIR\${FileMainEXE}"
3847                  ApplicationID::UninstallPinnedItem "$R7\StartMenu\$R8"
3848                  Pop $R5
3849              ${EndIf}
3850            ${EndIf}
3851            ClearErrors
3852            FindNext $R6 $R8
3853            ${If} ${Errors}
3854              ${ExitDo}
3855            ${EndIf}
3856          ${Loop}
3857          FindClose $R6
3858        ${EndIf}
3859      ${EndIf}
3860
3861      ; Don't call ApplicationID::UninstallPinnedItem since pinned items for
3862      ; this application were removed above and removing them below will remove
3863      ; the association of side by side installations.
3864      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" $R9
3865      ${If} ${FileExists} "$R9"
3866        ; Delete Start Menu shortcuts for this application
3867        StrCpy $R4 -1
3868        ${Do}
3869          IntOp $R4 $R4 + 1 ; Increment the counter
3870          ClearErrors
3871          ReadINIStr $R8 "$R9" "STARTMENU" "Shortcut$R4"
3872          ${If} ${Errors}
3873            ${ExitDo}
3874          ${EndIf}
3875
3876          ${If} ${FileExists} "$SMPROGRAMS\$R8"
3877            ShellLink::GetShortCutTarget "$SMPROGRAMS\$R8"
3878            Pop $R5
3879            ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
3880            ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
3881              Delete "$SMPROGRAMS\$R8"
3882            ${EndIf}
3883          ${EndIf}
3884        ${Loop}
3885        ; There might also be a shortcut with a different name created by a
3886        ; previous version of the installer.
3887        ${If} ${FileExists} "$SMPROGRAMS\${BrandFullName}.lnk"
3888          ShellLink::GetShortCutTarget "$SMPROGRAMS\${BrandFullName}.lnk"
3889          Pop $R5
3890          ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
3891          ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
3892            Delete "$SMPROGRAMS\${BrandFullName}.lnk"
3893          ${EndIf}
3894        ${EndIf}
3895
3896        ; Delete Quick Launch shortcuts for this application
3897        StrCpy $R4 -1
3898        ${Do}
3899          IntOp $R4 $R4 + 1 ; Increment the counter
3900          ClearErrors
3901          ReadINIStr $R8 "$R9" "QUICKLAUNCH" "Shortcut$R4"
3902          ${If} ${Errors}
3903            ${ExitDo}
3904          ${EndIf}
3905
3906          ${If} ${FileExists} "$QUICKLAUNCH\$R8"
3907            ShellLink::GetShortCutTarget "$QUICKLAUNCH\$R8"
3908            Pop $R5
3909            ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
3910            ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
3911              Delete "$QUICKLAUNCH\$R8"
3912            ${EndIf}
3913          ${EndIf}
3914        ${Loop}
3915        ; There might also be a shortcut with a different name created by a
3916        ; previous version of the installer.
3917        ${If} ${FileExists} "$QUICKLAUNCH\${BrandFullName}.lnk"
3918          ShellLink::GetShortCutTarget "$QUICKLAUNCH\${BrandFullName}.lnk"
3919          Pop $R5
3920          ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
3921          ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
3922            Delete "$QUICKLAUNCH\${BrandFullName}.lnk"
3923          ${EndIf}
3924        ${EndIf}
3925
3926        ; Delete Desktop shortcuts for this application
3927        StrCpy $R4 -1
3928        ${Do}
3929          IntOp $R4 $R4 + 1 ; Increment the counter
3930          ClearErrors
3931          ReadINIStr $R8 "$R9" "DESKTOP" "Shortcut$R4"
3932          ${If} ${Errors}
3933            ${ExitDo}
3934          ${EndIf}
3935
3936          ${If} ${FileExists} "$DESKTOP\$R8"
3937            ShellLink::GetShortCutTarget "$DESKTOP\$R8"
3938            Pop $R5
3939            ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
3940            ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
3941              Delete "$DESKTOP\$R8"
3942            ${EndIf}
3943          ${EndIf}
3944        ${Loop}
3945        ; There might also be a shortcut with a different name created by a
3946        ; previous version of the installer.
3947        ${If} ${FileExists} "$DESKTOP\${BrandFullName}.lnk"
3948          ShellLink::GetShortCutTarget "$DESKTOP\${BrandFullName}.lnk"
3949          Pop $R5
3950          ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
3951          ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
3952            Delete "$DESKTOP\${BrandFullName}.lnk"
3953          ${EndIf}
3954        ${EndIf}
3955
3956        ${${_MOZFUNC_UN}GetLongPath} "$SMPROGRAMS" $R6
3957
3958        ; Delete Start Menu Programs shortcuts for this application
3959        ClearErrors
3960        ReadINIStr $R7 "$R9" "SMPROGRAMS" "RelativePathToDir"
3961        ${${_MOZFUNC_UN}GetLongPath} "$R6\$R7" $R7
3962        ${Unless} "$R7" == ""
3963          StrCpy $R4 -1
3964          ${Do}
3965            IntOp $R4 $R4 + 1 ; Increment the counter
3966            ClearErrors
3967            ReadINIStr $R8 "$R9" "SMPROGRAMS" "Shortcut$R4"
3968            ${If} ${Errors}
3969              ${ExitDo}
3970            ${EndIf}
3971
3972            ${If} ${FileExists} "$R7\$R8"
3973              ShellLink::GetShortCutTarget "$R7\$R8"
3974              Pop $R5
3975              ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
3976              ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
3977                Delete "$R7\$R8"
3978              ${EndIf}
3979            ${EndIf}
3980          ${Loop}
3981
3982          ; Delete Start Menu Programs directories for this application
3983          ${Do}
3984            ClearErrors
3985            ${If} "$R6" == "$R7"
3986              ${ExitDo}
3987            ${EndIf}
3988            RmDir "$R7"
3989            ${If} ${Errors}
3990              ${ExitDo}
3991            ${EndIf}
3992            ${${_MOZFUNC_UN}GetParent} "$R7" $R7
3993          ${Loop}
3994        ${EndUnless}
3995      ${EndIf}
3996
3997      ClearErrors
3998
3999      Pop $R4
4000      Pop $R5
4001      Pop $R6
4002      Pop $R7
4003      Pop $R8
4004      Pop $R9
4005    FunctionEnd
4006
4007    !verbose pop
4008  !endif
4009!macroend
4010
4011!macro DeleteShortcutsCall
4012  !verbose push
4013  !verbose ${_MOZFUNC_VERBOSE}
4014  Call DeleteShortcuts
4015  !verbose pop
4016!macroend
4017
4018!macro un.DeleteShortcutsCall
4019  !verbose push
4020  !verbose ${_MOZFUNC_VERBOSE}
4021  Call un.DeleteShortcuts
4022  !verbose pop
4023!macroend
4024
4025!macro un.DeleteShortcuts
4026  !ifndef un.DeleteShortcuts
4027    !verbose push
4028    !verbose ${_MOZFUNC_VERBOSE}
4029    !undef _MOZFUNC_UN
4030    !define _MOZFUNC_UN "un."
4031
4032    !insertmacro DeleteShortcuts
4033
4034    !undef _MOZFUNC_UN
4035    !define _MOZFUNC_UN
4036    !verbose pop
4037  !endif
4038!macroend
4039
4040
4041################################################################################
4042# Macros for parsing and updating the uninstall.log
4043
4044/**
4045 * Updates the uninstall.log with new files added by software update.
4046 *
4047 * When modifying this macro be aware that LineFind uses all registers except
4048 * $R0-$R3 and TextCompareNoDetails uses all registers except $R0-$R9 so be
4049 * cautious. Callers of this macro are not affected.
4050 */
4051!macro UpdateUninstallLog
4052
4053  !ifndef UpdateUninstallLog
4054    !insertmacro FileJoin
4055    !insertmacro LineFind
4056    !insertmacro TextCompareNoDetails
4057    !insertmacro TrimNewLines
4058
4059    !verbose push
4060    !verbose ${_MOZFUNC_VERBOSE}
4061    !define UpdateUninstallLog "!insertmacro UpdateUninstallLogCall"
4062
4063    Function UpdateUninstallLog
4064      Push $R3
4065      Push $R2
4066      Push $R1
4067      Push $R0
4068
4069      ClearErrors
4070
4071      GetFullPathName $R3 "$INSTDIR\uninstall"
4072      ${If} ${FileExists} "$R3\uninstall.update"
4073        ${LineFind} "$R3\uninstall.update" "" "1:-1" "CleanupUpdateLog"
4074
4075        GetTempFileName $R2 "$R3"
4076        FileOpen $R1 "$R2" w
4077        ${TextCompareNoDetails} "$R3\uninstall.update" "$R3\uninstall.log" "SlowDiff" "CreateUpdateDiff"
4078        FileClose $R1
4079
4080        IfErrors +2 0
4081        ${FileJoin} "$R3\uninstall.log" "$R2" "$R3\uninstall.log"
4082
4083        ${DeleteFile} "$R2"
4084      ${EndIf}
4085
4086      ClearErrors
4087
4088      Pop $R0
4089      Pop $R1
4090      Pop $R2
4091      Pop $R3
4092    FunctionEnd
4093
4094    ; This callback MUST use labels vs. relative line numbers.
4095    Function CleanupUpdateLog
4096      StrCpy $R2 "$R9" 12
4097      StrCmp "$R2" "EXECUTE ADD " +1 skip
4098      StrCpy $R9 "$R9" "" 12
4099
4100      Push $R6
4101      Push $R5
4102      Push $R4
4103      StrCpy $R4 ""         ; Initialize to an empty string.
4104      StrCpy $R6 -1         ; Set the counter to -1 so it will start at 0.
4105
4106      loop:
4107      IntOp $R6 $R6 + 1     ; Increment the counter.
4108      StrCpy $R5 $R9 1 $R6  ; Starting from the counter copy the next char.
4109      StrCmp $R5 "" copy    ; Are there no more chars?
4110      StrCmp $R5 "/" +1 +2  ; Is the char a /?
4111      StrCpy $R5 "\"        ; Replace the char with a \.
4112
4113      StrCpy $R4 "$R4$R5"
4114      GoTo loop
4115
4116      copy:
4117      StrCpy $R9 "File: \$R4"
4118      Pop $R6
4119      Pop $R5
4120      Pop $R4
4121      GoTo end
4122
4123      skip:
4124      StrCpy $0 "SkipWrite"
4125
4126      end:
4127      Push $0
4128    FunctionEnd
4129
4130    Function CreateUpdateDiff
4131      ${TrimNewLines} "$9" $9
4132      ${If} $9 != ""
4133        FileWrite $R1 "$9$\r$\n"
4134      ${EndIf}
4135
4136      Push 0
4137    FunctionEnd
4138
4139    !verbose pop
4140  !endif
4141!macroend
4142
4143!macro UpdateUninstallLogCall
4144  !verbose push
4145  !verbose ${_MOZFUNC_VERBOSE}
4146  Call UpdateUninstallLog
4147  !verbose pop
4148!macroend
4149
4150/**
4151 * Copies files from a source directory to a destination directory with logging
4152 * to the uninstall.log. If any destination files are in use a reboot will be
4153 * necessary to complete the installation and the reboot flag (see IfRebootFlag
4154 * in the NSIS documentation).
4155 *
4156 * @param   _PATH_TO_SOURCE
4157 *          Source path to copy the files from. This must not end with a \.
4158 *
4159 * @param   _PATH_TO_DESTINATION
4160 *          Destination path to copy the files to. This must not end with a \.
4161 *
4162 * @param   _PREFIX_ERROR_CREATEDIR
4163 *          Prefix for the directory creation error message. The directory path
4164 *          will be inserted below this string.
4165 *
4166 * @param   _SUFFIX_ERROR_CREATEDIR
4167 *          Suffix for the directory creation error message. The directory path
4168 *          will be inserted above this string.
4169 *
4170 * $0  = destination file's parent directory used in the create_dir label
4171 * $R0 = copied value from $R6 (e.g. _PATH_TO_SOURCE)
4172 * $R1 = copied value from $R7 (e.g. _PATH_TO_DESTINATION)
4173 * $R2 = string length of the path to source
4174 * $R3 = relative path from the path to source
4175 * $R4 = copied value from $R8 (e.g. _PREFIX_ERROR_CREATEDIR)
4176 * $R5 = copied value from $R9 (e.g. _SUFFIX_ERROR_CREATEDIR)
4177 * note: the LocateNoDetails macro uses these registers so we copy the values
4178 *       to other registers.
4179 * $R6 = initially _PATH_TO_SOURCE and then set to "size" ($R6="" if directory,
4180 *       $R6="0" if file with /S=)"path\name" in callback
4181 * $R7 = initially _PATH_TO_DESTINATION and then set to "name" in callback
4182 * $R8 = initially _PREFIX_ERROR_CREATEDIR and then set to "path" in callback
4183 * $R9 = initially _SUFFIX_ERROR_CREATEDIR and then set to "path\name" in
4184 *       callback
4185 */
4186!macro CopyFilesFromDir
4187
4188  !ifndef CopyFilesFromDir
4189    !insertmacro LocateNoDetails
4190    !insertmacro OnEndCommon
4191    !insertmacro WordReplace
4192
4193    !verbose push
4194    !verbose ${_MOZFUNC_VERBOSE}
4195    !define CopyFilesFromDir "!insertmacro CopyFilesFromDirCall"
4196
4197    Function CopyFilesFromDir
4198      Exch $R9
4199      Exch 1
4200      Exch $R8
4201      Exch 2
4202      Exch $R7
4203      Exch 3
4204      Exch $R6
4205      Push $R5
4206      Push $R4
4207      Push $R3
4208      Push $R2
4209      Push $R1
4210      Push $R0
4211      Push $0
4212
4213      StrCpy $R0 "$R6"
4214      StrCpy $R1 "$R7"
4215      StrCpy $R4 "$R8"
4216      StrCpy $R5 "$R9"
4217
4218      StrLen $R2 "$R0"
4219
4220      ${LocateNoDetails} "$R0" "/L=FD" "CopyFileCallback"
4221
4222      Pop $0
4223      Pop $R0
4224      Pop $R1
4225      Pop $R2
4226      Pop $R3
4227      Pop $R4
4228      Pop $R5
4229      Exch $R6
4230      Exch 3
4231      Exch $R7
4232      Exch 2
4233      Exch $R8
4234      Exch 1
4235      Exch $R9
4236    FunctionEnd
4237
4238    Function CopyFileCallback
4239      StrCpy $R3 $R8 "" $R2 ; $R3 always begins with a \.
4240
4241      retry:
4242      ClearErrors
4243      StrCmp $R6 "" +1 copy_file
4244      IfFileExists "$R1$R3\$R7" end +1
4245      StrCpy $0 "$R1$R3\$R7"
4246
4247      create_dir:
4248      ClearErrors
4249      CreateDirectory "$0"
4250      IfFileExists "$0" +1 err_create_dir  ; protect against looping.
4251      ${LogMsg} "Created Directory: $0"
4252      StrCmp $R6 "" end copy_file
4253
4254      err_create_dir:
4255      ${LogMsg} "** ERROR Creating Directory: $0 **"
4256      MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$R4$\r$\n$\r$\n$0$\r$\n$\r$\n$R5" IDRETRY retry
4257      ${OnEndCommon}
4258      Quit
4259
4260      copy_file:
4261      StrCpy $0 "$R1$R3"
4262      StrCmp "$0" "$INSTDIR" +2 +1
4263      IfFileExists "$0" +1 create_dir
4264
4265      ClearErrors
4266      ${DeleteFile} "$R1$R3\$R7"
4267      IfErrors +1 dest_clear
4268      ClearErrors
4269      Rename "$R1$R3\$R7" "$R1$R3\$R7.moz-delete"
4270      IfErrors +1 reboot_delete
4271
4272      ; file will replace destination file on reboot
4273      Rename "$R9" "$R9.moz-upgrade"
4274      CopyFiles /SILENT "$R9.moz-upgrade" "$R1$R3"
4275      Rename /REBOOTOK "$R1$R3\$R7.moz-upgrade" "$R1$R3\$R7"
4276      ${LogMsg} "Copied File: $R1$R3\$R7.moz-upgrade"
4277      ${LogMsg} "Delayed Install File (Reboot Required): $R1$R3\$R7"
4278      GoTo log_uninstall
4279
4280      ; file will be deleted on reboot
4281      reboot_delete:
4282      CopyFiles /SILENT $R9 "$R1$R3"
4283      Delete /REBOOTOK "$R1$R3\$R7.moz-delete"
4284      ${LogMsg} "Installed File: $R1$R3\$R7"
4285      ${LogMsg} "Delayed Delete File (Reboot Required): $R1$R3\$R7.moz-delete"
4286      GoTo log_uninstall
4287
4288      ; destination file doesn't exist - coast is clear
4289      dest_clear:
4290      CopyFiles /SILENT $R9 "$R1$R3"
4291      ${LogMsg} "Installed File: $R1$R3\$R7"
4292
4293      log_uninstall:
4294      ; If the file is installed into the installation directory remove the
4295      ; installation directory's path from the file path when writing to the
4296      ; uninstall.log so it will be a relative path. This allows the same
4297      ; helper.exe to be used with zip builds if we supply an uninstall.log.
4298      ${WordReplace} "$R1$R3\$R7" "$INSTDIR" "" "+" $R3
4299      ${LogUninstall} "File: $R3"
4300
4301      end:
4302      Push 0
4303    FunctionEnd
4304
4305    !verbose pop
4306  !endif
4307!macroend
4308
4309!macro CopyFilesFromDirCall _PATH_TO_SOURCE _PATH_TO_DESTINATION \
4310                            _PREFIX_ERROR_CREATEDIR _SUFFIX_ERROR_CREATEDIR
4311  !verbose push
4312  !verbose ${_MOZFUNC_VERBOSE}
4313  Push "${_PATH_TO_SOURCE}"
4314  Push "${_PATH_TO_DESTINATION}"
4315  Push "${_PREFIX_ERROR_CREATEDIR}"
4316  Push "${_SUFFIX_ERROR_CREATEDIR}"
4317  Call CopyFilesFromDir
4318  !verbose pop
4319!macroend
4320
4321/**
4322 * Parses the uninstall.log on install to first remove a previous installation's
4323 * files and then their directories if empty prior to installing.
4324 *
4325 * When modifying this macro be aware that LineFind uses all registers except
4326 * $R0-$R3 so be cautious. Callers of this macro are not affected.
4327 */
4328!macro OnInstallUninstall
4329
4330  !ifndef OnInstallUninstall
4331    !insertmacro GetParent
4332    !insertmacro LineFind
4333    !insertmacro TrimNewLines
4334
4335    !verbose push
4336    !verbose ${_MOZFUNC_VERBOSE}
4337    !define OnInstallUninstall "!insertmacro OnInstallUninstallCall"
4338
4339    Function OnInstallUninstall
4340      Push $R9
4341      Push $R8
4342      Push $R7
4343      Push $R6
4344      Push $R5
4345      Push $R4
4346      Push $R3
4347      Push $R2
4348      Push $R1
4349      Push $R0
4350      Push $TmpVal
4351
4352      IfFileExists "$INSTDIR\uninstall\uninstall.log" +1 end
4353
4354      ${LogHeader} "Removing Previous Installation"
4355
4356      ; Copy the uninstall log file to a temporary file
4357      GetTempFileName $TmpVal
4358      CopyFiles /SILENT /FILESONLY "$INSTDIR\uninstall\uninstall.log" "$TmpVal"
4359
4360      ; Delete files
4361      ${LineFind} "$TmpVal" "/NUL" "1:-1" "RemoveFilesCallback"
4362
4363      ; Remove empty directories
4364      ${LineFind} "$TmpVal" "/NUL" "1:-1" "RemoveDirsCallback"
4365
4366      ; Delete the temporary uninstall log file
4367      Delete /REBOOTOK "$TmpVal"
4368
4369      ; Delete the uninstall log file
4370      Delete "$INSTDIR\uninstall\uninstall.log"
4371
4372      end:
4373      ClearErrors
4374
4375      Pop $TmpVal
4376      Pop $R0
4377      Pop $R1
4378      Pop $R2
4379      Pop $R3
4380      Pop $R4
4381      Pop $R5
4382      Pop $R6
4383      Pop $R7
4384      Pop $R8
4385      Pop $R9
4386    FunctionEnd
4387
4388    Function RemoveFilesCallback
4389      ${TrimNewLines} "$R9" $R9
4390      StrCpy $R1 "$R9" 5       ; Copy the first five chars
4391
4392      StrCmp "$R1" "File:" +1 end
4393      StrCpy $R9 "$R9" "" 6    ; Copy string starting after the 6th char
4394      StrCpy $R0 "$R9" 1       ; Copy the first char
4395
4396      StrCmp "$R0" "\" +1 end  ; If this isn't a relative path goto end
4397      StrCmp "$R9" "\install.log" end +1 ; Skip the install.log
4398      StrCmp "$R9" "\MapiProxy_InUse.dll" end +1 ; Skip the MapiProxy_InUse.dll
4399      StrCmp "$R9" "\mozMapi32_InUse.dll" end +1 ; Skip the mozMapi32_InUse.dll
4400
4401      StrCpy $R1 "$INSTDIR$R9" ; Copy the install dir path and suffix it with the string
4402      IfFileExists "$R1" +1 end
4403
4404      ClearErrors
4405      Delete "$R1"
4406      ${Unless} ${Errors}
4407        ${LogMsg} "Deleted File: $R1"
4408        Goto end
4409      ${EndUnless}
4410
4411      ClearErrors
4412      Rename "$R1" "$R1.moz-delete"
4413      ${Unless} ${Errors}
4414        Delete /REBOOTOK "$R1.moz-delete"
4415        ${LogMsg} "Delayed Delete File (Reboot Required): $R1.moz-delete"
4416        GoTo end
4417      ${EndUnless}
4418
4419      ; Check if the file exists in the source. If it does the new file will
4420      ; replace the existing file when the system is rebooted. If it doesn't
4421      ; the file will be deleted when the system is rebooted.
4422      ${Unless} ${FileExists} "$EXEDIR\core$R9"
4423      ${AndUnless}  ${FileExists} "$EXEDIR\optional$R9"
4424        Delete /REBOOTOK "$R1"
4425        ${LogMsg} "Delayed Delete File (Reboot Required): $R1"
4426      ${EndUnless}
4427
4428      end:
4429      ClearErrors
4430
4431      Push 0
4432    FunctionEnd
4433
4434    ; Using locate will leave file handles open to some of the directories
4435    ; which will prevent the deletion of these directories. This parses the
4436    ; uninstall.log and uses the file entries to find / remove empty
4437    ; directories.
4438    Function RemoveDirsCallback
4439      ${TrimNewLines} "$R9" $R9
4440      StrCpy $R0 "$R9" 5          ; Copy the first five chars
4441      StrCmp "$R0" "File:" +1 end
4442
4443      StrCpy $R9 "$R9" "" 6       ; Copy string starting after the 6th char
4444      StrCpy $R0 "$R9" 1          ; Copy the first char
4445
4446      StrCpy $R1 "$INSTDIR$R9"    ; Copy the install dir path and suffix it with the string
4447      StrCmp "$R0" "\" loop end   ; If this isn't a relative path goto end
4448
4449      loop:
4450      ${GetParent} "$R1" $R1         ; Get the parent directory for the path
4451      StrCmp "$R1" "$INSTDIR" end +1 ; If the directory is the install dir goto end
4452
4453      IfFileExists "$R1" +1 loop  ; Only try to remove the dir if it exists
4454      ClearErrors
4455      RmDir "$R1"     ; Remove the dir
4456      IfErrors end +1  ; If we fail there is no use trying to remove its parent dir
4457      ${LogMsg} "Deleted Directory: $R1"
4458      GoTo loop
4459
4460      end:
4461      ClearErrors
4462
4463      Push 0
4464    FunctionEnd
4465
4466    !verbose pop
4467  !endif
4468!macroend
4469
4470!macro OnInstallUninstallCall
4471  !verbose push
4472  !verbose ${_MOZFUNC_VERBOSE}
4473  Call OnInstallUninstall
4474  !verbose pop
4475!macroend
4476
4477/**
4478 * Parses the precomplete file to remove an installation's files and
4479 * directories.
4480 *
4481 * @param   _CALLBACK
4482 *          The function address of a callback function for progress or "false"
4483 *          if there is no callback function.
4484 *
4485 * $R3 = false if all files were deleted or moved to the tobedeleted directory.
4486 *       true if file(s) could not be moved to the tobedeleted directory.
4487 * $R4 = Path to temporary precomplete file.
4488 * $R5 = File handle for the temporary precomplete file.
4489 * $R6 = String returned from FileRead.
4490 * $R7 = First seven characters of the string returned from FileRead.
4491 * $R8 = Temporary file path used to rename files that are in use.
4492 * $R9 = _CALLBACK
4493 */
4494!macro RemovePrecompleteEntries
4495
4496  !ifndef ${_MOZFUNC_UN}RemovePrecompleteEntries
4497    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
4498    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
4499    !insertmacro ${_MOZFUNC_UN_TMP}TrimNewLines
4500    !insertmacro ${_MOZFUNC_UN_TMP}WordReplace
4501    !undef _MOZFUNC_UN
4502    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
4503    !undef _MOZFUNC_UN_TMP
4504
4505    !verbose push
4506    !verbose ${_MOZFUNC_VERBOSE}
4507    !define ${_MOZFUNC_UN}RemovePrecompleteEntries "!insertmacro ${_MOZFUNC_UN}RemovePrecompleteEntriesCall"
4508
4509    Function ${_MOZFUNC_UN}RemovePrecompleteEntries
4510      Exch $R9
4511      Push $R8
4512      Push $R7
4513      Push $R6
4514      Push $R5
4515      Push $R4
4516      Push $R3
4517
4518      ${If} ${FileExists} "$INSTDIR\precomplete"
4519        StrCpy $R3 "false"
4520
4521        RmDir /r "$INSTDIR\${TO_BE_DELETED}"
4522        CreateDirectory "$INSTDIR\${TO_BE_DELETED}"
4523        GetTempFileName $R4 "$INSTDIR\${TO_BE_DELETED}"
4524        Delete "$R4"
4525        Rename "$INSTDIR\precomplete" "$R4"
4526
4527        ClearErrors
4528        ; Rename and then remove files
4529        FileOpen $R5 "$R4" r
4530        ${Do}
4531          FileRead $R5 $R6
4532          ${If} ${Errors}
4533            ${Break}
4534          ${EndIf}
4535
4536          ${${_MOZFUNC_UN}TrimNewLines} "$R6" $R6
4537          ; Replace all occurrences of "/" with "\".
4538          ${${_MOZFUNC_UN}WordReplace} "$R6" "/" "\" "+" $R6
4539
4540          ; Copy the first 7 chars
4541          StrCpy $R7 "$R6" 7
4542          ${If} "$R7" == "remove "
4543            ; Copy the string starting after the 8th char
4544            StrCpy $R6 "$R6" "" 8
4545            ; Copy all but the last char to remove the double quote.
4546            StrCpy $R6 "$R6" -1
4547            ${If} ${FileExists} "$INSTDIR\$R6"
4548              ${Unless} "$R9" == "false"
4549                Call $R9
4550              ${EndUnless}
4551
4552              ClearErrors
4553              Delete "$INSTDIR\$R6"
4554              ${If} ${Errors}
4555                GetTempFileName $R8 "$INSTDIR\${TO_BE_DELETED}"
4556                Delete "$R8"
4557                ClearErrors
4558                Rename "$INSTDIR\$R6" "$R8"
4559                ${Unless} ${Errors}
4560                  Delete /REBOOTOK "$R8"
4561
4562                  ClearErrors
4563                ${EndUnless}
4564!ifdef __UNINSTALL__
4565                ${If} ${Errors}
4566                  Delete /REBOOTOK "$INSTDIR\$R6"
4567                  StrCpy $R3 "true"
4568                  ClearErrors
4569                ${EndIf}
4570!endif
4571              ${EndIf}
4572            ${EndIf}
4573          ${ElseIf} "$R7" == "rmdir $\""
4574            ; Copy the string starting after the 7th char.
4575            StrCpy $R6 "$R6" "" 7
4576            ; Copy all but the last two chars to remove the slash and the double quote.
4577            StrCpy $R6 "$R6" -2
4578            ${If} ${FileExists} "$INSTDIR\$R6"
4579              ; Ignore directory removal errors
4580              RmDir "$INSTDIR\$R6"
4581              ClearErrors
4582            ${EndIf}
4583          ${EndIf}
4584        ${Loop}
4585        FileClose $R5
4586
4587        ; Delete the temporary precomplete file
4588        Delete /REBOOTOK "$R4"
4589
4590        RmDir /r /REBOOTOK "$INSTDIR\${TO_BE_DELETED}"
4591
4592        ${If} ${RebootFlag}
4593        ${AndIf} "$R3" == "false"
4594          ; Clear the reboot flag if all files were deleted or moved to the
4595          ; tobedeleted directory.
4596          SetRebootFlag false
4597        ${EndIf}
4598      ${EndIf}
4599
4600      ClearErrors
4601
4602      Pop $R3
4603      Pop $R4
4604      Pop $R5
4605      Pop $R6
4606      Pop $R7
4607      Pop $R8
4608      Exch $R9
4609    FunctionEnd
4610
4611    !verbose pop
4612  !endif
4613!macroend
4614
4615!macro RemovePrecompleteEntriesCall _CALLBACK
4616  !verbose push
4617  Push "${_CALLBACK}"
4618  !verbose ${_MOZFUNC_VERBOSE}
4619  Call RemovePrecompleteEntries
4620  !verbose pop
4621!macroend
4622
4623!macro un.RemovePrecompleteEntriesCall _CALLBACK
4624  !verbose push
4625  !verbose ${_MOZFUNC_VERBOSE}
4626  Push "${_CALLBACK}"
4627  Call un.RemovePrecompleteEntries
4628  !verbose pop
4629!macroend
4630
4631!macro un.RemovePrecompleteEntries
4632  !ifndef un.RemovePrecompleteEntries
4633    !verbose push
4634    !verbose ${_MOZFUNC_VERBOSE}
4635    !undef _MOZFUNC_UN
4636    !define _MOZFUNC_UN "un."
4637
4638    !insertmacro RemovePrecompleteEntries
4639
4640    !undef _MOZFUNC_UN
4641    !define _MOZFUNC_UN
4642    !verbose pop
4643  !endif
4644!macroend
4645
4646/**
4647 * Parses the uninstall.log to unregister dll's, remove files, and remove
4648 * empty directories for this installation.
4649 *
4650 * When modifying this macro be aware that LineFind uses all registers except
4651 * $R0-$R3 so be cautious. Callers of this macro are not affected.
4652 */
4653!macro un.ParseUninstallLog
4654
4655  !ifndef un.ParseUninstallLog
4656    !insertmacro un.GetParent
4657    !insertmacro un.LineFind
4658    !insertmacro un.TrimNewLines
4659
4660    !verbose push
4661    !verbose ${_MOZFUNC_VERBOSE}
4662    !define un.ParseUninstallLog "!insertmacro un.ParseUninstallLogCall"
4663
4664    Function un.ParseUninstallLog
4665      Push $R9
4666      Push $R8
4667      Push $R7
4668      Push $R6
4669      Push $R5
4670      Push $R4
4671      Push $R3
4672      Push $R2
4673      Push $R1
4674      Push $R0
4675      Push $TmpVal
4676
4677      IfFileExists "$INSTDIR\uninstall\uninstall.log" +1 end
4678
4679      ; Copy the uninstall log file to a temporary file
4680      GetTempFileName $TmpVal
4681      CopyFiles /SILENT /FILESONLY "$INSTDIR\uninstall\uninstall.log" "$TmpVal"
4682
4683      ; Unregister DLL's
4684      ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.UnRegDLLsCallback"
4685
4686      ; Delete files
4687      ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.RemoveFilesCallback"
4688
4689      ; Remove empty directories
4690      ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.RemoveDirsCallback"
4691
4692      ; Delete the temporary uninstall log file
4693      Delete /REBOOTOK "$TmpVal"
4694
4695      end:
4696
4697      Pop $TmpVal
4698      Pop $R0
4699      Pop $R1
4700      Pop $R2
4701      Pop $R3
4702      Pop $R4
4703      Pop $R5
4704      Pop $R6
4705      Pop $R7
4706      Pop $R8
4707      Pop $R9
4708    FunctionEnd
4709
4710    Function un.RemoveFilesCallback
4711      ${un.TrimNewLines} "$R9" $R9
4712      StrCpy $R1 "$R9" 5
4713
4714      StrCmp "$R1" "File:" +1 end
4715      StrCpy $R9 "$R9" "" 6
4716      StrCpy $R0 "$R9" 1
4717
4718      StrCpy $R1 "$INSTDIR$R9"
4719      StrCmp "$R0" "\" +2 +1
4720      StrCpy $R1 "$R9"
4721
4722      IfFileExists "$R1" +1 end
4723      Delete "$R1"
4724      IfErrors +1 end
4725      ClearErrors
4726      Rename "$R1" "$R1.moz-delete"
4727      IfErrors +1 +3
4728      Delete /REBOOTOK "$R1"
4729      GoTo end
4730
4731      Delete /REBOOTOK "$R1.moz-delete"
4732
4733      end:
4734      ClearErrors
4735
4736      Push 0
4737    FunctionEnd
4738
4739    Function un.UnRegDLLsCallback
4740      ${un.TrimNewLines} "$R9" $R9
4741      StrCpy $R1 "$R9" 7
4742
4743      StrCmp $R1 "DLLReg:" +1 end
4744      StrCpy $R9 "$R9" "" 8
4745      StrCpy $R0 "$R9" 1
4746
4747      StrCpy $R1 "$INSTDIR$R9"
4748      StrCmp $R0 "\" +2 +1
4749      StrCpy $R1 "$R9"
4750
4751      ${UnregisterDLL} $R1
4752
4753      end:
4754      ClearErrors
4755
4756      Push 0
4757    FunctionEnd
4758
4759    ; Using locate will leave file handles open to some of the directories
4760    ; which will prevent the deletion of these directories. This parses the
4761    ; uninstall.log and uses the file entries to find / remove empty
4762    ; directories.
4763    Function un.RemoveDirsCallback
4764      ${un.TrimNewLines} "$R9" $R9
4765      StrCpy $R0 "$R9" 5          ; Copy the first five chars
4766      StrCmp "$R0" "File:" +1 end
4767
4768      StrCpy $R9 "$R9" "" 6       ; Copy string starting after the 6th char
4769      StrCpy $R0 "$R9" 1          ; Copy the first char
4770
4771      StrCpy $R1 "$INSTDIR$R9"    ; Copy the install dir path and suffix it with the string
4772      StrCmp "$R0" "\" loop       ; If this is a relative path goto the loop
4773      StrCpy $R1 "$R9"            ; Already a full path so copy the string
4774
4775      loop:
4776      ${un.GetParent} "$R1" $R1   ; Get the parent directory for the path
4777      StrCmp "$R1" "$INSTDIR" end ; If the directory is the install dir goto end
4778
4779      ; We only try to remove empty directories but the Desktop, StartMenu, and
4780      ; QuickLaunch directories can be empty so guard against removing them.
4781      SetShellVarContext all          ; Set context to all users
4782      StrCmp "$R1" "$DESKTOP" end     ; All users desktop
4783      StrCmp "$R1" "$STARTMENU" end   ; All users start menu
4784
4785      SetShellVarContext current      ; Set context to all users
4786      StrCmp "$R1" "$DESKTOP" end     ; Current user desktop
4787      StrCmp "$R1" "$STARTMENU" end   ; Current user start menu
4788      StrCmp "$R1" "$QUICKLAUNCH" end ; Current user quick launch
4789
4790      IfFileExists "$R1" +1 +3  ; Only try to remove the dir if it exists
4791      ClearErrors
4792      RmDir "$R1"    ; Remove the dir
4793      IfErrors end   ; If we fail there is no use trying to remove its parent dir
4794
4795      StrCmp "$R0" "\" loop end  ; Only loop when the path is relative to the install dir
4796
4797      end:
4798      ClearErrors
4799
4800      Push 0
4801    FunctionEnd
4802
4803    !verbose pop
4804  !endif
4805!macroend
4806
4807!macro un.ParseUninstallLogCall
4808  !verbose push
4809  !verbose ${_MOZFUNC_VERBOSE}
4810  Call un.ParseUninstallLog
4811  !verbose pop
4812!macroend
4813
4814/**
4815 * Finds a valid Start Menu shortcut in the uninstall log and returns the
4816 * relative path from the Start Menu's Programs directory to the shortcut's
4817 * directory.
4818 *
4819 * When modifying this macro be aware that LineFind uses all registers except
4820 * $R0-$R3 so be cautious. Callers of this macro are not affected.
4821 *
4822 * @return  _REL_PATH_TO_DIR
4823 *          The relative path to the application's Start Menu directory from the
4824 *          Start Menu's Programs directory.
4825 */
4826!macro FindSMProgramsDir
4827
4828  !ifndef FindSMProgramsDir
4829    !insertmacro GetParent
4830    !insertmacro LineFind
4831    !insertmacro TrimNewLines
4832
4833    !verbose push
4834    !verbose ${_MOZFUNC_VERBOSE}
4835    !define FindSMProgramsDir "!insertmacro FindSMProgramsDirCall"
4836
4837    Function FindSMProgramsDir
4838      Exch $R3
4839      Push $R2
4840      Push $R1
4841      Push $R0
4842
4843      StrCpy $R3 ""
4844      ${If} ${FileExists} "$INSTDIR\uninstall\uninstall.log"
4845        ${LineFind} "$INSTDIR\uninstall\uninstall.log" "/NUL" "1:-1" "FindSMProgramsDirRelPath"
4846      ${EndIf}
4847      ClearErrors
4848
4849      Pop $R0
4850      Pop $R1
4851      Pop $R2
4852      Exch $R3
4853    FunctionEnd
4854
4855    ; This callback MUST use labels vs. relative line numbers.
4856    Function FindSMProgramsDirRelPath
4857      Push 0
4858      ${TrimNewLines} "$R9" $R9
4859      StrCpy $R4 "$R9" 5
4860
4861      StrCmp "$R4" "File:" +1 end_FindSMProgramsDirRelPath
4862      StrCpy $R9 "$R9" "" 6
4863      StrCpy $R4 "$R9" 1
4864
4865      StrCmp "$R4" "\" end_FindSMProgramsDirRelPath +1
4866
4867      SetShellVarContext all
4868      ${GetLongPath} "$SMPROGRAMS" $R4
4869      StrLen $R2 "$R4"
4870      StrCpy $R1 "$R9" $R2
4871      StrCmp "$R1" "$R4" +1 end_FindSMProgramsDirRelPath
4872      IfFileExists "$R9" +1 end_FindSMProgramsDirRelPath
4873      ShellLink::GetShortCutTarget "$R9"
4874      Pop $R0
4875      StrCmp "$INSTDIR\${FileMainEXE}" "$R0" +1 end_FindSMProgramsDirRelPath
4876      ${GetParent} "$R9" $R3
4877      IntOp $R2 $R2 + 1
4878      StrCpy $R3 "$R3" "" $R2
4879
4880      Pop $R4             ; Remove the previously pushed 0 from the stack and
4881      push "StopLineFind" ; push StopLineFind to stop finding more lines.
4882
4883      end_FindSMProgramsDirRelPath:
4884      ClearErrors
4885
4886    FunctionEnd
4887
4888    !verbose pop
4889  !endif
4890!macroend
4891
4892!macro FindSMProgramsDirCall _REL_PATH_TO_DIR
4893  !verbose push
4894  !verbose ${_MOZFUNC_VERBOSE}
4895  Call FindSMProgramsDir
4896  Pop ${_REL_PATH_TO_DIR}
4897  !verbose pop
4898!macroend
4899
4900
4901################################################################################
4902# Macros for custom branding
4903
4904/**
4905 * Sets BrandFullName and / or BrandShortName to values provided in the specified
4906 * ini file and defaults to BrandShortName and BrandFullName as defined in
4907 * branding.nsi when the associated ini file entry is not specified.
4908 *
4909 * ini file format:
4910 * [Branding]
4911 * BrandFullName=Custom Full Name
4912 * BrandShortName=Custom Short Name
4913 *
4914 * @param   _PATH_TO_INI
4915 *          Path to the ini file.
4916 *
4917 * $R6 = return value from ReadINIStr
4918 * $R7 = stores BrandShortName
4919 * $R8 = stores BrandFullName
4920 * $R9 = _PATH_TO_INI
4921 */
4922!macro SetBrandNameVars
4923
4924  !ifndef ${_MOZFUNC_UN}SetBrandNameVars
4925    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
4926    !insertmacro ${_MOZFUNC_UN_TMP}WordReplace
4927    !undef _MOZFUNC_UN
4928    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
4929    !undef _MOZFUNC_UN_TMP
4930
4931    ; Prevent declaring vars twice when the SetBrandNameVars macro is
4932    ; inserted into both the installer and uninstaller.
4933    !ifndef SetBrandNameVars
4934      Var BrandFullName
4935      Var BrandFullNameDA
4936      Var BrandShortName
4937      Var BrandProductName
4938    !endif
4939
4940    !verbose push
4941    !verbose ${_MOZFUNC_VERBOSE}
4942    !define ${_MOZFUNC_UN}SetBrandNameVars "!insertmacro ${_MOZFUNC_UN}SetBrandNameVarsCall"
4943
4944    Function ${_MOZFUNC_UN}SetBrandNameVars
4945      Exch $R9
4946      Push $R8
4947      Push $R7
4948      Push $R6
4949      Push $R5
4950
4951      StrCpy $R8 "${BrandFullName}"
4952      StrCpy $R7 "${BrandShortName}"
4953      StrCpy $R6 "${BrandProductName}"
4954
4955      IfFileExists "$R9" +1 finish
4956
4957      ClearErrors
4958      ReadINIStr $R5 $R9 "Branding" "BrandFullName"
4959      IfErrors +2 +1
4960      StrCpy $R8 "$R5"
4961
4962      ClearErrors
4963      ReadINIStr $R5 $R9 "Branding" "BrandShortName"
4964      IfErrors +2 +1
4965      StrCpy $R7 "$R5"
4966
4967      ClearErrors
4968      ReadINIStr $R5 $R9 "Branding" "BrandProductName"
4969      IfErrors +2 +1
4970      StrCpy $R6 "$R5"
4971
4972      finish:
4973      StrCpy $BrandFullName "$R8"
4974      ${${_MOZFUNC_UN}WordReplace} "$R8" "&" "&&" "+" $R8
4975      StrCpy $BrandFullNameDA "$R8"
4976      StrCpy $BrandShortName "$R7"
4977      StrCpy $BrandProductName "$R6"
4978
4979      Pop $R5
4980      Pop $R6
4981      Pop $R7
4982      Pop $R8
4983      Exch $R9
4984    FunctionEnd
4985
4986    !verbose pop
4987  !endif
4988!macroend
4989
4990!macro SetBrandNameVarsCall _PATH_TO_INI
4991  !verbose push
4992  !verbose ${_MOZFUNC_VERBOSE}
4993  Push "${_PATH_TO_INI}"
4994  Call SetBrandNameVars
4995  !verbose pop
4996!macroend
4997
4998!macro un.SetBrandNameVarsCall _PATH_TO_INI
4999  !verbose push
5000  !verbose ${_MOZFUNC_VERBOSE}
5001  Push "${_PATH_TO_INI}"
5002  Call un.SetBrandNameVars
5003  !verbose pop
5004!macroend
5005
5006!macro un.SetBrandNameVars
5007  !ifndef un.SetBrandNameVars
5008    !verbose push
5009    !verbose ${_MOZFUNC_VERBOSE}
5010    !undef _MOZFUNC_UN
5011    !define _MOZFUNC_UN "un."
5012
5013    !insertmacro SetBrandNameVars
5014
5015    !undef _MOZFUNC_UN
5016    !define _MOZFUNC_UN
5017    !verbose pop
5018  !endif
5019!macroend
5020
5021/**
5022 * Replaces the wizard's header image with the one specified.
5023 *
5024 * @param   _PATH_TO_IMAGE
5025 *          Fully qualified path to the bitmap to use for the header image.
5026 *
5027 * $R8 = hwnd for the control returned from GetDlgItem.
5028 * $R9 = _PATH_TO_IMAGE
5029 */
5030!macro ChangeMUIHeaderImage
5031
5032  !ifndef ${_MOZFUNC_UN}ChangeMUIHeaderImage
5033    Var hHeaderBitmap
5034
5035    !verbose push
5036    !verbose ${_MOZFUNC_VERBOSE}
5037    !define ${_MOZFUNC_UN}ChangeMUIHeaderImage "!insertmacro ${_MOZFUNC_UN}ChangeMUIHeaderImageCall"
5038
5039    Function ${_MOZFUNC_UN}ChangeMUIHeaderImage
5040      Exch $R9
5041      Push $R8
5042
5043      GetDlgItem $R8 $HWNDPARENT 1046
5044      ${SetStretchedImageOLE} $R8 "$R9" $hHeaderBitmap
5045      ; There is no way to specify a show function for a custom page so hide
5046      ; and then show the control to force the bitmap to redraw.
5047      ShowWindow $R8 ${SW_HIDE}
5048      ShowWindow $R8 ${SW_SHOW}
5049
5050      Pop $R8
5051      Exch $R9
5052    FunctionEnd
5053
5054    !verbose pop
5055  !endif
5056!macroend
5057
5058!macro ChangeMUIHeaderImageCall _PATH_TO_IMAGE
5059  !verbose push
5060  !verbose ${_MOZFUNC_VERBOSE}
5061  Push "${_PATH_TO_IMAGE}"
5062  Call ChangeMUIHeaderImage
5063  !verbose pop
5064!macroend
5065
5066!macro un.ChangeMUIHeaderImageCall _PATH_TO_IMAGE
5067  !verbose push
5068  !verbose ${_MOZFUNC_VERBOSE}
5069  Push "${_PATH_TO_IMAGE}"
5070  Call un.ChangeMUIHeaderImage
5071  !verbose pop
5072!macroend
5073
5074!macro un.ChangeMUIHeaderImage
5075  !ifndef un.ChangeMUIHeaderImage
5076    !verbose push
5077    !verbose ${_MOZFUNC_VERBOSE}
5078    !undef _MOZFUNC_UN
5079    !define _MOZFUNC_UN "un."
5080
5081    !insertmacro ChangeMUIHeaderImage
5082
5083    !undef _MOZFUNC_UN
5084    !define _MOZFUNC_UN
5085    !verbose pop
5086  !endif
5087!macroend
5088
5089/**
5090 * Replaces the sidebar image on the wizard's welcome and finish pages.
5091 *
5092 * @param   _PATH_TO_IMAGE
5093 *          Fully qualified path to the bitmap to use for the header image.
5094 *
5095 * $R8 = hwnd for the bitmap control
5096 * $R9 = _PATH_TO_IMAGE
5097 */
5098!macro ChangeMUISidebarImage
5099
5100  !ifndef ${_MOZFUNC_UN}ChangeMUISidebarImage
5101    Var hSidebarBitmap
5102
5103    !verbose push
5104    !verbose ${_MOZFUNC_VERBOSE}
5105    !define ${_MOZFUNC_UN}ChangeMUISidebarImage "!insertmacro ${_MOZFUNC_UN}ChangeMUISidebarImageCall"
5106
5107    Function ${_MOZFUNC_UN}ChangeMUISidebarImage
5108      Exch $R9
5109      Push $R8
5110
5111      ; Make sure we're not about to leak an existing handle.
5112      ${If} $hSidebarBitmap <> 0
5113        System::Call "gdi32::DeleteObject(p $hSidebarBitmap)"
5114        StrCpy $hSidebarBitmap 0
5115      ${EndIf}
5116      ; The controls on the welcome and finish pages aren't in the dialog
5117      ; template, they're always created manually from the INI file, so we need
5118      ; to query it to find the right HWND.
5119      ReadINIStr $R8 "$PLUGINSDIR\ioSpecial.ini" "Field 1" "HWND"
5120      ${SetStretchedImageOLE} $R8 "$R9" $hSidebarBitmap
5121
5122      Pop $R8
5123      Exch $R9
5124    FunctionEnd
5125
5126    !verbose pop
5127  !endif
5128!macroend
5129
5130!macro ChangeMUISidebarImageCall _PATH_TO_IMAGE
5131  !verbose push
5132  !verbose ${_MOZFUNC_VERBOSE}
5133  Push "${_PATH_TO_IMAGE}"
5134  Call ChangeMUISidebarImage
5135  !verbose pop
5136!macroend
5137
5138!macro un.ChangeMUISidebarImageCall _PATH_TO_IMAGE
5139  !verbose push
5140  !verbose ${_MOZFUNC_VERBOSE}
5141  Push "${_PATH_TO_IMAGE}"
5142  Call un.ChangeMUISidebarImage
5143  !verbose pop
5144!macroend
5145
5146!macro un.ChangeMUISidebarImage
5147  !ifndef un.ChangeMUISidebarImage
5148    !verbose push
5149    !verbose ${_MOZFUNC_VERBOSE}
5150    !undef _MOZFUNC_UN
5151    !define _MOZFUNC_UN "un."
5152
5153    !insertmacro ChangeMUISidebarImage
5154
5155    !undef _MOZFUNC_UN
5156    !define _MOZFUNC_UN
5157    !verbose pop
5158  !endif
5159!macroend
5160
5161################################################################################
5162# User interface callback helper defines and macros
5163
5164/* Install type defines */
5165!ifndef INSTALLTYPE_BASIC
5166  !define INSTALLTYPE_BASIC     1
5167!endif
5168
5169!ifndef INSTALLTYPE_CUSTOM
5170  !define INSTALLTYPE_CUSTOM    2
5171!endif
5172
5173/**
5174 * Checks whether to display the current page (e.g. if not performing a custom
5175 * install don't display the custom pages).
5176 */
5177!macro CheckCustomCommon
5178
5179  !ifndef CheckCustomCommon
5180    !verbose push
5181    !verbose ${_MOZFUNC_VERBOSE}
5182    !define CheckCustomCommon "!insertmacro CheckCustomCommonCall"
5183
5184    Function CheckCustomCommon
5185
5186      ; Abort if not a custom install
5187      IntCmp $InstallType ${INSTALLTYPE_CUSTOM} +2 +1 +1
5188      Abort
5189
5190    FunctionEnd
5191
5192    !verbose pop
5193  !endif
5194!macroend
5195
5196!macro CheckCustomCommonCall
5197  !verbose push
5198  !verbose ${_MOZFUNC_VERBOSE}
5199  Call CheckCustomCommon
5200  !verbose pop
5201!macroend
5202
5203/**
5204 * Unloads dll's and releases references when the installer and uninstaller
5205 * exit.
5206 */
5207!macro OnEndCommon
5208
5209  !ifndef ${_MOZFUNC_UN}OnEndCommon
5210    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
5211    !insertmacro ${_MOZFUNC_UN_TMP}UnloadUAC
5212    !undef _MOZFUNC_UN
5213    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
5214    !undef _MOZFUNC_UN_TMP
5215
5216    !verbose push
5217    !verbose ${_MOZFUNC_VERBOSE}
5218    !define ${_MOZFUNC_UN}OnEndCommon "!insertmacro ${_MOZFUNC_UN}OnEndCommonCall"
5219
5220    Function ${_MOZFUNC_UN}OnEndCommon
5221
5222      ${${_MOZFUNC_UN}UnloadUAC}
5223      StrCmp $hHeaderBitmap "" +3 +1
5224      System::Call "gdi32::DeleteObject(i s)" $hHeaderBitmap
5225      StrCpy $hHeaderBitmap ""
5226      ; If ChangeMUISidebarImage was called, then we also need to clean up the
5227      ; GDI bitmap handle that it would have created.
5228      !ifdef ${_MOZFUNC_UN}ChangeMUISidebarImage
5229        StrCmp $hSidebarBitmap "" +3 +1
5230        System::Call "gdi32::DeleteObject(i s)" $hSidebarBitmap
5231        StrCpy $hSidebarBitmap ""
5232      !endif
5233
5234      System::Free 0
5235
5236    FunctionEnd
5237
5238    !verbose pop
5239  !endif
5240!macroend
5241
5242!macro OnEndCommonCall
5243  !verbose push
5244  !verbose ${_MOZFUNC_VERBOSE}
5245  Call OnEndCommon
5246  !verbose pop
5247!macroend
5248
5249!macro un.OnEndCommonCall
5250  !verbose push
5251  !verbose ${_MOZFUNC_VERBOSE}
5252  Call un.OnEndCommon
5253  !verbose pop
5254!macroend
5255
5256!macro un.OnEndCommon
5257  !ifndef un.OnEndCommon
5258    !verbose push
5259    !verbose ${_MOZFUNC_VERBOSE}
5260    !undef _MOZFUNC_UN
5261    !define _MOZFUNC_UN "un."
5262
5263    !insertmacro OnEndCommon
5264
5265    !undef _MOZFUNC_UN
5266    !define _MOZFUNC_UN
5267    !verbose pop
5268  !endif
5269!macroend
5270
5271/**
5272 * Reads a flag option from the command line and sets a variable with its state,
5273 * if the option is present on the command line.
5274 *
5275 * @param   FULL_COMMAND_LINE
5276 *          The entire installer command line, such as from ${GetParameters}
5277 * @param   OPTION
5278 *          Name of the option to look for
5279 * @param   OUTPUT
5280 *          Variable/register to write the output to. Will be set to "0" if the
5281 *          option was present with the value "false", will be set to "1" if the
5282 *          option was present with another value, and will be untouched if the
5283 *          option was not on the command line at all.
5284 */
5285!macro InstallGetOption FULL_COMMAND_LINE OPTION OUTPUT
5286  Push $0
5287  ClearErrors
5288  ${GetOptions} ${FULL_COMMAND_LINE} "/${OPTION}" $0
5289  ${IfNot} ${Errors}
5290    ; Any valid command-line option triggers a silent installation.
5291    SetSilent silent
5292
5293    ${If} $0 == "=false"
5294      StrCpy ${OUTPUT} "0"
5295    ${Else}
5296      StrCpy ${OUTPUT} "1"
5297    ${EndIf}
5298  ${EndIf}
5299  Pop $0
5300!macroend
5301!define InstallGetOption "!insertmacro InstallGetOption"
5302
5303/**
5304 * Called from the installer's .onInit function not to be confused with the
5305 * uninstaller's .onInit or the uninstaller's un.onInit functions.
5306 *
5307 * @param   _WARN_UNSUPPORTED_MSG
5308 *          Message displayed when the Windows version is not supported.
5309 *
5310 * $R4 = keeps track of whether a custom install path was specified on either
5311 *       the command line or in an INI file
5312 * $R5 = return value from the GetSize macro
5313 * $R6 = general string values, return value from GetTempFileName, return
5314 *       value from the GetSize macro
5315 * $R7 = full path to the configuration ini file
5316 * $R8 = used for OS Version and Service Pack detection and the return value
5317 *       from the GetParameters macro
5318 * $R9 = _WARN_UNSUPPORTED_MSG
5319 */
5320!macro InstallOnInitCommon
5321
5322  !ifndef InstallOnInitCommon
5323    !insertmacro ElevateUAC
5324    !insertmacro GetOptions
5325    !insertmacro GetParameters
5326    !insertmacro GetSize
5327
5328    !verbose push
5329    !verbose ${_MOZFUNC_VERBOSE}
5330    !define InstallOnInitCommon "!insertmacro InstallOnInitCommonCall"
5331
5332    Function InstallOnInitCommon
5333      Exch $R9
5334      Push $R8
5335      Push $R7
5336      Push $R6
5337      Push $R5
5338      Push $R4
5339
5340      ; Don't install on systems that don't support SSE2. The parameter value of
5341      ; 10 is for PF_XMMI64_INSTRUCTIONS_AVAILABLE which will check whether the
5342      ; SSE2 instruction set is available.
5343      System::Call "kernel32::IsProcessorFeaturePresent(i 10)i .R8"
5344      ${If} "$R8" == "0"
5345        MessageBox MB_OK|MB_ICONSTOP "$R9"
5346        ; Nothing initialized so no need to call OnEndCommon
5347        Quit
5348      ${EndIf}
5349
5350      ; Windows NT 6.0 (Vista/Server 2008) and lower are not supported.
5351      ${Unless} ${AtLeastWin7}
5352        MessageBox MB_OK|MB_ICONSTOP "$R9"
5353        ; Nothing initialized so no need to call OnEndCommon
5354        Quit
5355      ${EndUnless}
5356
5357      !ifdef HAVE_64BIT_BUILD
5358        SetRegView 64
5359      !endif
5360
5361      StrCpy $R4 0 ; will be set to 1 if a custom install path is set
5362
5363      ${GetParameters} $R8
5364      ${If} $R8 != ""
5365        ; Default install type
5366        StrCpy $InstallType ${INSTALLTYPE_BASIC}
5367
5368        ${Unless} ${Silent}
5369          ; NSIS should check for /S for us, but we've had issues with it such
5370          ; as bug 506867 in the past, so we'll check for it ourselves also.
5371          ClearErrors
5372          ${GetOptions} "$R8" "/S" $R7
5373          ${Unless} ${Errors}
5374            SetSilent silent
5375          ${Else}
5376            ; NSIS dropped support for the deprecated -ms argument, but we don't
5377            ; want to break backcompat, so we'll check for it here too.
5378            ClearErrors
5379            ${GetOptions} "$R8" "-ms" $R7
5380            ${Unless} ${Errors}
5381              SetSilent silent
5382            ${EndUnless}
5383          ${EndUnless}
5384        ${EndUnless}
5385
5386        ; Support for specifying an installation configuration file.
5387        ClearErrors
5388        ${GetOptions} "$R8" "/INI=" $R7
5389        ${Unless} ${Errors}
5390          ; The configuration file must also exist
5391          ${If} ${FileExists} "$R7"
5392            ; Any valid command-line option triggers a silent installation.
5393            SetSilent silent
5394
5395            ReadINIStr $R8 $R7 "Install" "InstallDirectoryName"
5396            ${If} $R8 != ""
5397              StrCpy $R4 1
5398              !ifdef HAVE_64BIT_BUILD
5399                StrCpy $INSTDIR "$PROGRAMFILES64\$R8"
5400              !else
5401                StrCpy $INSTDIR "$PROGRAMFILES32\$R8"
5402              !endif
5403            ${Else}
5404              ReadINIStr $R8 $R7 "Install" "InstallDirectoryPath"
5405              ${If} $R8 != ""
5406                StrCpy $R4 1
5407                StrCpy $INSTDIR "$R8"
5408              ${EndIf}
5409            ${EndIf}
5410
5411            ReadINIStr $R8 $R7 "Install" "QuickLaunchShortcut"
5412            ${If} $R8 == "false"
5413              StrCpy $AddQuickLaunchSC "0"
5414            ${Else}
5415              StrCpy $AddQuickLaunchSC "1"
5416            ${EndIf}
5417
5418            ReadINIStr $R8 $R7 "Install" "DesktopShortcut"
5419            ${If} $R8 == "false"
5420              StrCpy $AddDesktopSC "0"
5421            ${Else}
5422              StrCpy $AddDesktopSC "1"
5423            ${EndIf}
5424
5425            ReadINIStr $R8 $R7 "Install" "StartMenuShortcuts"
5426            ${If} $R8 == "false"
5427              StrCpy $AddStartMenuSC "0"
5428            ${Else}
5429              StrCpy $AddStartMenuSC "1"
5430            ${EndIf}
5431
5432            ; We still accept the plural version for backwards compatibility,
5433            ; but the singular version takes priority.
5434            ClearErrors
5435            ReadINIStr $R8 $R7 "Install" "StartMenuShortcut"
5436            ${If} $R8 == "false"
5437              StrCpy $AddStartMenuSC "0"
5438            ${ElseIfNot} ${Errors}
5439              StrCpy $AddStartMenuSC "1"
5440            ${EndIf}
5441
5442            ReadINIStr $R8 $R7 "Install" "TaskbarShortcut"
5443            ${If} $R8 == "false"
5444              StrCpy $AddTaskbarSC "0"
5445            ${Else}
5446              StrCpy $AddTaskbarSC "1"
5447            ${EndIf}
5448
5449            ReadINIStr $R8 $R7 "Install" "MaintenanceService"
5450            ${If} $R8 == "false"
5451              StrCpy $InstallMaintenanceService "0"
5452            ${Else}
5453              StrCpy $InstallMaintenanceService "1"
5454            ${EndIf}
5455
5456            ReadINIStr $R8 $R7 "Install" "RegisterDefaultAgent"
5457            ${If} $R8 == "false"
5458              StrCpy $RegisterDefaultAgent "0"
5459            ${Else}
5460              StrCpy $RegisterDefaultAgent "1"
5461            ${EndIf}
5462
5463            !ifdef MOZ_OPTIONAL_EXTENSIONS
5464              ReadINIStr $R8 $R7 "Install" "OptionalExtensions"
5465              ${If} $R8 == "false"
5466                StrCpy $InstallOptionalExtensions "0"
5467              ${Else}
5468                StrCpy $InstallOptionalExtensions "1"
5469              ${EndIf}
5470            !endif
5471
5472            !ifndef NO_STARTMENU_DIR
5473              ReadINIStr $R8 $R7 "Install" "StartMenuDirectoryName"
5474              ${If} $R8 != ""
5475                StrCpy $StartMenuDir "$R8"
5476              ${EndIf}
5477            !endif
5478          ${EndIf}
5479        ${EndUnless}
5480
5481        ; Check for individual command line parameters after evaluating the INI
5482        ; file, because these should override the INI entires.
5483        ${GetParameters} $R8
5484        ${GetOptions} $R8 "/InstallDirectoryName=" $R7
5485        ${If} $R7 != ""
5486          StrCpy $R4 1
5487          !ifdef HAVE_64BIT_BUILD
5488            StrCpy $INSTDIR "$PROGRAMFILES64\$R7"
5489          !else
5490            StrCpy $INSTDIR "$PROGRAMFILES32\$R7"
5491          !endif
5492        ${Else}
5493          ${GetOptions} $R8 "/InstallDirectoryPath=" $R7
5494          ${If} $R7 != ""
5495            StrCpy $R4 1
5496            StrCpy $INSTDIR "$R7"
5497          ${EndIf}
5498        ${EndIf}
5499
5500        ${InstallGetOption} $R8 "QuickLaunchShortcut" $AddQuickLaunchSC
5501        ${InstallGetOption} $R8 "DesktopShortcut" $AddDesktopSC
5502        ${InstallGetOption} $R8 "StartMenuShortcuts" $AddStartMenuSC
5503        ; We still accept the plural version for backwards compatibility,
5504        ; but the singular version takes priority.
5505        ${InstallGetOption} $R8 "StartMenuShortcut" $AddStartMenuSC
5506        ${InstallGetOption} $R8 "TaskbarShortcut" $AddTaskbarSC
5507        ${InstallGetOption} $R8 "MaintenanceService" $InstallMaintenanceService
5508        ${InstallGetOption} $R8 "RegisterDefaultAgent" $RegisterDefaultAgent
5509        !ifdef MOZ_OPTIONAL_EXTENSIONS
5510          ${InstallGetOption} $R8 "OptionalExtensions" $InstallOptionalExtensions
5511        !endif
5512
5513        ; Installing the service always requires elevated privileges.
5514        ${If} $InstallMaintenanceService == "1"
5515          ${ElevateUAC}
5516        ${EndIf}
5517      ${EndIf}
5518
5519      ${If} $R4 == 1
5520        ; Any valid command-line option triggers a silent installation.
5521        SetSilent silent
5522
5523        ; Quit if we are unable to create the installation directory or we are
5524        ; unable to write to a file in the installation directory.
5525        ClearErrors
5526        ${If} ${FileExists} "$INSTDIR"
5527          GetTempFileName $R6 "$INSTDIR"
5528          FileOpen $R5 "$R6" w
5529          FileWrite $R5 "Write Access Test"
5530          FileClose $R5
5531          Delete $R6
5532          ${If} ${Errors}
5533            ; Attempt to elevate and then try again.
5534            ${ElevateUAC}
5535            GetTempFileName $R6 "$INSTDIR"
5536            FileOpen $R5 "$R6" w
5537            FileWrite $R5 "Write Access Test"
5538            FileClose $R5
5539            Delete $R6
5540            ${If} ${Errors}
5541              ; Nothing initialized so no need to call OnEndCommon
5542              Quit
5543            ${EndIf}
5544          ${EndIf}
5545        ${Else}
5546          CreateDirectory "$INSTDIR"
5547          ${If} ${Errors}
5548            ; Attempt to elevate and then try again.
5549            ${ElevateUAC}
5550            CreateDirectory "$INSTDIR"
5551            ${If} ${Errors}
5552              ; Nothing initialized so no need to call OnEndCommon
5553              Quit
5554            ${EndIf}
5555          ${EndIf}
5556        ${EndIf}
5557      ${Else}
5558        ; If we weren't given a custom path parameter, then try to elevate now.
5559        ; We'll check the user's permission level later on to determine the
5560        ; default install path (which will be the real install path for /S).
5561        ; If an INI file is used, we try to elevate down that path when needed.
5562        ${ElevateUAC}
5563      ${EndIf}
5564
5565      Pop $R4
5566      Pop $R5
5567      Pop $R6
5568      Pop $R7
5569      Pop $R8
5570      Exch $R9
5571    FunctionEnd
5572
5573    !verbose pop
5574  !endif
5575!macroend
5576
5577!macro InstallOnInitCommonCall _WARN_UNSUPPORTED_MSG
5578  !verbose push
5579  !verbose ${_MOZFUNC_VERBOSE}
5580  Push "${_WARN_UNSUPPORTED_MSG}"
5581  Call InstallOnInitCommon
5582  !verbose pop
5583!macroend
5584
5585/**
5586 * Called from the uninstaller's .onInit function not to be confused with the
5587 * installer's .onInit or the uninstaller's un.onInit functions.
5588 */
5589!macro UninstallOnInitCommon
5590
5591  !ifndef UninstallOnInitCommon
5592    !insertmacro ElevateUAC
5593    !insertmacro GetLongPath
5594    !insertmacro GetOptions
5595    !insertmacro GetParameters
5596    !insertmacro GetParent
5597    !insertmacro UnloadUAC
5598    !insertmacro UpdateShortcutAppModelIDs
5599    !insertmacro UpdateUninstallLog
5600
5601    !verbose push
5602    !verbose ${_MOZFUNC_VERBOSE}
5603    !define UninstallOnInitCommon "!insertmacro UninstallOnInitCommonCall"
5604
5605    Function UninstallOnInitCommon
5606      ; Prevents breaking apps that don't use SetBrandNameVars
5607      !ifdef SetBrandNameVars
5608        ${SetBrandNameVars} "$EXEDIR\distribution\setup.ini"
5609      !endif
5610
5611      ; Prevent launching the application when a reboot is required and this
5612      ; executable is the main application executable
5613      IfFileExists "$EXEDIR\${FileMainEXE}.moz-upgrade" +1 +4
5614      MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UPGRADE)" IDNO +2
5615      Reboot
5616      Quit ; Nothing initialized so no need to call OnEndCommon
5617
5618      ${GetParent} "$EXEDIR" $INSTDIR
5619      ${GetLongPath} "$INSTDIR" $INSTDIR
5620      IfFileExists "$INSTDIR\${FileMainEXE}" +2 +1
5621      Quit ; Nothing initialized so no need to call OnEndCommon
5622
5623!ifmacrodef InitHashAppModelId
5624      ; setup the application model id registration value
5625      !ifdef AppName
5626      ${InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs"
5627      !endif
5628!endif
5629
5630      ; Prevents breaking apps that don't use SetBrandNameVars
5631      !ifdef SetBrandNameVars
5632        ${SetBrandNameVars} "$INSTDIR\distribution\setup.ini"
5633      !endif
5634
5635      ; Application update uses a directory named tobedeleted in the $INSTDIR to
5636      ; delete files on OS reboot when they are in use. Try to delete this
5637      ; directory if it exists.
5638      ${If} ${FileExists} "$INSTDIR\${TO_BE_DELETED}"
5639        RmDir /r "$INSTDIR\${TO_BE_DELETED}"
5640      ${EndIf}
5641
5642      ; Prevent all operations (e.g. set as default, postupdate, etc.) when a
5643      ; reboot is required and the executable launched is helper.exe
5644      IfFileExists "$INSTDIR\${FileMainEXE}.moz-upgrade" +1 +4
5645      MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UPGRADE)" IDNO +2
5646      Reboot
5647      Quit ; Nothing initialized so no need to call OnEndCommon
5648
5649      !ifdef HAVE_64BIT_BUILD
5650        SetRegView 64
5651      !endif
5652
5653      ${GetParameters} $R0
5654
5655      ${Unless} ${Silent}
5656        ; Manually check for /S in the command line due to Bug 506867
5657        ClearErrors
5658        ${GetOptions} "$R0" "/S" $R2
5659        ${Unless} ${Errors}
5660          SetSilent silent
5661        ${Else}
5662          ; Support for the deprecated -ms command line argument.
5663          ClearErrors
5664          ${GetOptions} "$R0" "-ms" $R2
5665          ${Unless} ${Errors}
5666            SetSilent silent
5667          ${EndUnless}
5668        ${EndUnless}
5669      ${EndUnless}
5670
5671      StrCmp "$R0" "" continue +1
5672
5673      ; Require elevation if the user can elevate
5674      hideshortcuts:
5675      ClearErrors
5676      ${GetOptions} "$R0" "/HideShortcuts" $R2
5677      IfErrors showshortcuts +1
5678!ifndef NONADMIN_ELEVATE
5679      ${ElevateUAC}
5680!endif
5681      ${HideShortcuts}
5682      GoTo finish
5683
5684      ; Require elevation if the user can elevate
5685      showshortcuts:
5686      ClearErrors
5687      ${GetOptions} "$R0" "/ShowShortcuts" $R2
5688      IfErrors defaultappuser +1
5689!ifndef NONADMIN_ELEVATE
5690      ${ElevateUAC}
5691!endif
5692      ${ShowShortcuts}
5693      GoTo finish
5694
5695      ; Require elevation if the the StartMenuInternet registry keys require
5696      ; updating and the user can elevate
5697      defaultappuser:
5698      ClearErrors
5699      ${GetOptions} "$R0" "/SetAsDefaultAppUser" $R2
5700      IfErrors defaultappglobal +1
5701      ${SetAsDefaultAppUser}
5702      GoTo finish
5703
5704      ; Require elevation if the user can elevate
5705      defaultappglobal:
5706      ClearErrors
5707      ${GetOptions} "$R0" "/SetAsDefaultAppGlobal" $R2
5708      IfErrors postupdate +1
5709      ${ElevateUAC}
5710      ${SetAsDefaultAppGlobal}
5711      GoTo finish
5712
5713      ; Do not attempt to elevate. The application launching this executable is
5714      ; responsible for elevation if it is required.
5715      postupdate:
5716      ${WordReplace} "$R0" "$\"" "" "+" $R0
5717      ClearErrors
5718      ${GetOptions} "$R0" "/PostUpdate" $R2
5719      IfErrors continue +1
5720      ; If the uninstall.log does not exist don't perform post update
5721      ; operations. This prevents updating the registry for zip builds.
5722      IfFileExists "$EXEDIR\uninstall.log" +2 +1
5723      Quit ; Nothing initialized so no need to call OnEndCommon
5724      ${PostUpdate}
5725      ClearErrors
5726      ${GetOptions} "$R0" "/UninstallLog=" $R2
5727      IfErrors updateuninstalllog +1
5728      StrCmp "$R2" "" finish +1
5729      GetFullPathName $R3 "$R2"
5730      IfFileExists "$R3" +1 finish
5731      Delete "$INSTDIR\uninstall\*wizard*"
5732      Delete "$INSTDIR\uninstall\uninstall.log"
5733      CopyFiles /SILENT /FILESONLY "$R3" "$INSTDIR\uninstall\"
5734      ${GetParent} "$R3" $R4
5735      Delete "$R3"
5736      RmDir "$R4"
5737      GoTo finish
5738
5739      ; Do not attempt to elevate. The application launching this executable is
5740      ; responsible for elevation if it is required.
5741      updateuninstalllog:
5742      ${UpdateUninstallLog}
5743
5744      finish:
5745      ${UnloadUAC}
5746      ${RefreshShellIcons}
5747      Quit ; Nothing initialized so no need to call OnEndCommon
5748
5749      continue:
5750
5751      ; If the uninstall.log does not exist don't perform uninstall
5752      ; operations. This prevents running the uninstaller for zip builds.
5753      IfFileExists "$INSTDIR\uninstall\uninstall.log" +2 +1
5754      Quit ; Nothing initialized so no need to call OnEndCommon
5755
5756      ; When silent, try to avoid elevation if we have a chance to succeed.  We
5757      ; can succeed when we can write to (hence delete from) the install
5758      ; directory and when we can clean up all registry entries.  Now, the
5759      ; installer when elevated writes privileged registry entries for the use
5760      ; of the Maintenance Service, even when the service is not and will not be
5761      ; installed.  (In fact, even when a service installed in the future will
5762      ; never update the installation, for example due to not being in a
5763      ; privileged location.)  In practice this means we can only truly silently
5764      ; remove an unelevated install: an elevated installer writing to an
5765      ; unprivileged install directory will still write privileged registry
5766      ; entries, requiring an elevated uninstaller to completely clean up.
5767      ;
5768      ; This avoids a wrinkle, whereby an uninstaller which runs unelevated will
5769      ; never itself launch the Maintenance Service uninstaller, because it will
5770      ; fail to remove its own service registration (removing the relevant
5771      ; registry key would require elevation).  Therefore the check for the
5772      ; service being unused will fail, which will prevent running the service
5773      ; uninstaller.  That's both subtle and possibly leaves the service
5774      ; registration hanging around, which might be a security risk.
5775      ;
5776      ; That is why we look for a privileged service registration for this
5777      ; installation when deciding to elevate, and elevate unconditionally if we
5778      ; find one, regardless of the result of the write check that would avoid
5779      ; elevation.
5780
5781      ; The reason for requiring elevation, or "" for not required.
5782      StrCpy $R4 ""
5783
5784      ${IfNot} ${Silent}
5785        ; In normal operation, require elevation if the user can elevate so that
5786        ; we are most likely to succeed.
5787        StrCpy $R4 "not silent"
5788      ${EndIf}
5789
5790      GetTempFileName $R6 "$INSTDIR"
5791      FileOpen $R5 "$R6" w
5792      FileWrite $R5 "Write Access Test"
5793      FileClose $R5
5794      Delete $R6
5795      ${If} ${Errors}
5796        StrCpy $R4 "write"
5797      ${EndIf}
5798
5799      !ifdef MOZ_MAINTENANCE_SERVICE
5800        ; We don't necessarily have $MaintCertKey, so use temporary registers.
5801        ServicesHelper::PathToUniqueRegistryPath "$INSTDIR"
5802        Pop $R5
5803
5804        ${If} $R5 != ""
5805          ; Always use the 64bit registry for certs on 64bit systems.
5806          ${If} ${RunningX64}
5807          ${OrIf} ${IsNativeARM64}
5808            SetRegView 64
5809          ${EndIf}
5810
5811          EnumRegKey $R6 HKLM $R5 0
5812          ClearErrors
5813
5814          ${If} ${RunningX64}
5815          ${OrIf} ${IsNativeARM64}
5816            SetRegView lastused
5817          ${EndIf}
5818
5819          ${IfNot} "$R6" == ""
5820            StrCpy $R4 "mms"
5821          ${EndIf}
5822        ${EndIf}
5823      !endif
5824
5825      ${If} "$R4" != ""
5826        ; In the future, we might not try to elevate to remain truly silent.  Or
5827        ; we might add a command line arguments to specify behaviour.  One
5828        ; reason to not do that immediately is that we have no great way to
5829        ; signal that we exited without taking action.
5830        ${ElevateUAC}
5831      ${EndIf}
5832
5833      ; Now we've elevated, try the write access test again.
5834      ClearErrors
5835      GetTempFileName $R6 "$INSTDIR"
5836      FileOpen $R5 "$R6" w
5837      FileWrite $R5 "Write Access Test"
5838      FileClose $R5
5839      Delete $R6
5840      ${If} ${Errors}
5841        ; Nothing initialized so no need to call OnEndCommon
5842        Quit
5843      ${EndIf}
5844
5845      !ifdef MOZ_MAINTENANCE_SERVICE
5846        ; And verify that if we need to, we're going to clean up the registry
5847        ; correctly.
5848        ${If} "$R4" == "mms"
5849          WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" "Write Test"
5850          ${If} ${Errors}
5851            ; Nothing initialized so no need to call OnEndCommon
5852            Quit
5853          ${Endif}
5854          DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
5855        ${EndIf}
5856      !endif
5857
5858      ; If we made it this far then this installer is being used as an uninstaller.
5859      WriteUninstaller "$EXEDIR\uninstaller.exe"
5860
5861      ${If} ${Silent}
5862        StrCpy $R1 "$\"$EXEDIR\uninstaller.exe$\" /S"
5863      ${Else}
5864        StrCpy $R1 "$\"$EXEDIR\uninstaller.exe$\""
5865      ${EndIf}
5866
5867      ; When the uninstaller is launched it copies itself to the temp directory
5868      ; so it won't be in use so it can delete itself.
5869      ExecWait $R1
5870      ${DeleteFile} "$EXEDIR\uninstaller.exe"
5871      ${UnloadUAC}
5872      SetErrorLevel 0
5873      Quit ; Nothing initialized so no need to call OnEndCommon
5874
5875    FunctionEnd
5876
5877    !verbose pop
5878  !endif
5879!macroend
5880
5881!macro UninstallOnInitCommonCall
5882  !verbose push
5883  !verbose ${_MOZFUNC_VERBOSE}
5884  Call UninstallOnInitCommon
5885  !verbose pop
5886!macroend
5887
5888/**
5889 * Called from the uninstaller's un.onInit function not to be confused with the
5890 * installer's .onInit or the uninstaller's .onInit functions.
5891 */
5892!macro un.UninstallUnOnInitCommon
5893
5894  !ifndef un.UninstallUnOnInitCommon
5895    !insertmacro un.GetLongPath
5896    !insertmacro un.GetParent
5897    !insertmacro un.SetBrandNameVars
5898
5899    !verbose push
5900    !verbose ${_MOZFUNC_VERBOSE}
5901    !define un.UninstallUnOnInitCommon "!insertmacro un.UninstallUnOnInitCommonCall"
5902
5903    Function un.UninstallUnOnInitCommon
5904      ${un.GetParent} "$INSTDIR" $INSTDIR
5905      ${un.GetLongPath} "$INSTDIR" $INSTDIR
5906      ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}"
5907        Abort
5908      ${EndUnless}
5909
5910      !ifdef HAVE_64BIT_BUILD
5911        SetRegView 64
5912      !endif
5913
5914      ; Prevents breaking apps that don't use SetBrandNameVars
5915      !ifdef un.SetBrandNameVars
5916        ${un.SetBrandNameVars} "$INSTDIR\distribution\setup.ini"
5917      !endif
5918
5919      ; Initialize $hHeaderBitmap to prevent redundant changing of the bitmap if
5920      ; the user clicks the back button
5921      StrCpy $hHeaderBitmap ""
5922    FunctionEnd
5923
5924    !verbose pop
5925  !endif
5926!macroend
5927
5928!macro un.UninstallUnOnInitCommonCall
5929  !verbose push
5930  !verbose ${_MOZFUNC_VERBOSE}
5931  Call un.UninstallUnOnInitCommon
5932  !verbose pop
5933!macroend
5934
5935/**
5936 * Called from the MUI leaveOptions function to set the value of $INSTDIR.
5937 */
5938!macro LeaveOptionsCommon
5939
5940  !ifndef LeaveOptionsCommon
5941    !insertmacro CanWriteToInstallDir
5942    !insertmacro GetLongPath
5943
5944!ifndef NO_INSTDIR_FROM_REG
5945    !insertmacro GetSingleInstallPath
5946!endif
5947
5948    !verbose push
5949    !verbose ${_MOZFUNC_VERBOSE}
5950    !define LeaveOptionsCommon "!insertmacro LeaveOptionsCommonCall"
5951
5952    Function LeaveOptionsCommon
5953      Push $R9
5954
5955      StrCpy $R9 "false"
5956
5957!ifndef NO_INSTDIR_FROM_REG
5958      SetShellVarContext all      ; Set SHCTX to HKLM
5959
5960      ${If} ${IsNativeAMD64}
5961      ${OrIf} ${IsNativeARM64}
5962        SetRegView 64
5963        ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
5964        SetRegView lastused
5965      ${EndIf}
5966
5967      StrCmp "$R9" "false" +1 finish_get_install_dir
5968
5969      SetRegView 32
5970      ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
5971      SetRegView lastused
5972
5973      StrCmp "$R9" "false" +1 finish_get_install_dir
5974
5975      SetShellVarContext current  ; Set SHCTX to HKCU
5976      ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
5977
5978      finish_get_install_dir:
5979      StrCmp "$R9" "false" +2 +1
5980      StrCpy $INSTDIR "$R9"
5981!endif
5982
5983      ; If the user doesn't have write access to the installation directory set
5984      ; the installation directory to a subdirectory of the user's local
5985      ; application directory (e.g. non-roaming).
5986      ${CanWriteToInstallDir} $R9
5987      ${If} "$R9" == "false"
5988        ; NOTE: This SetShellVarContext isn't directly needed anymore, but to
5989        ; leave the state consistent with earlier code I'm leaving it here.
5990        SetShellVarContext all      ; Set SHCTX to All Users
5991        ${GetLocalAppDataFolder} $R9
5992        StrCpy $INSTDIR "$R9\${BrandFullName}\"
5993        ${CanWriteToInstallDir} $R9
5994      ${EndIf}
5995
5996      IfFileExists "$INSTDIR" +3 +1
5997      Pop $R9
5998      Return
5999
6000      ; Always display the long path if the path already exists.
6001      ${GetLongPath} "$INSTDIR" $INSTDIR
6002
6003      ; The call to GetLongPath returns a long path without a trailing
6004      ; back-slash. Append a \ to the path to prevent the directory
6005      ; name from being appended when using the NSIS create new folder.
6006      ; http://www.nullsoft.com/free/nsis/makensis.htm#InstallDir
6007      StrCpy $INSTDIR "$INSTDIR\"
6008
6009      Pop $R9
6010    FunctionEnd
6011
6012    !verbose pop
6013  !endif
6014!macroend
6015
6016!macro LeaveOptionsCommonCall
6017  !verbose push
6018  !verbose ${_MOZFUNC_VERBOSE}
6019  Call LeaveOptionsCommon
6020  !verbose pop
6021!macroend
6022
6023/**
6024 * Called from the MUI preDirectory function to verify there is enough disk
6025 * space for the installation and the installation directory is writable.
6026 *
6027 * $R9 = returned value from CheckDiskSpace and CanWriteToInstallDir macros
6028 */
6029!macro PreDirectoryCommon
6030
6031  !ifndef PreDirectoryCommon
6032    !insertmacro CanWriteToInstallDir
6033    !insertmacro CheckDiskSpace
6034
6035    !verbose push
6036    !verbose ${_MOZFUNC_VERBOSE}
6037    !define PreDirectoryCommon "!insertmacro PreDirectoryCommonCall"
6038
6039    Function PreDirectoryCommon
6040      Push $R9
6041
6042      IntCmp $InstallType ${INSTALLTYPE_CUSTOM} end +1 +1
6043      ${CanWriteToInstallDir} $R9
6044      StrCmp "$R9" "false" end +1
6045      ${CheckDiskSpace} $R9
6046      StrCmp "$R9" "false" end +1
6047      Abort
6048
6049      end:
6050
6051      Pop $R9
6052    FunctionEnd
6053
6054    !verbose pop
6055  !endif
6056!macroend
6057
6058!macro PreDirectoryCommonCall
6059  !verbose push
6060  !verbose ${_MOZFUNC_VERBOSE}
6061  Call PreDirectoryCommon
6062  !verbose pop
6063!macroend
6064
6065/**
6066 * Called from the MUI leaveDirectory function
6067 *
6068 * @param   _WARN_DISK_SPACE
6069 *          Message displayed when there isn't enough disk space to perform the
6070 *          installation.
6071 * @param   _WARN_WRITE_ACCESS
6072 *          Message displayed when the installer does not have write access to
6073 *          $INSTDIR.
6074 *
6075 * $R7 = returned value from CheckDiskSpace and CanWriteToInstallDir macros
6076 * $R8 = _WARN_DISK_SPACE
6077 * $R9 = _WARN_WRITE_ACCESS
6078 */
6079!macro LeaveDirectoryCommon
6080
6081  !ifndef LeaveDirectoryCommon
6082    !insertmacro CheckDiskSpace
6083    !insertmacro CanWriteToInstallDir
6084
6085    !verbose push
6086    !verbose ${_MOZFUNC_VERBOSE}
6087    !define LeaveDirectoryCommon "!insertmacro LeaveDirectoryCommonCall"
6088
6089    Function LeaveDirectoryCommon
6090      Exch $R9
6091      Exch 1
6092      Exch $R8
6093      Push $R7
6094
6095      ${CanWriteToInstallDir} $R7
6096      ${If} $R7 == "false"
6097        MessageBox MB_OK|MB_ICONEXCLAMATION "$R9"
6098        Abort
6099      ${EndIf}
6100
6101      ${CheckDiskSpace} $R7
6102      ${If} $R7 == "false"
6103        MessageBox MB_OK|MB_ICONEXCLAMATION "$R8"
6104        Abort
6105      ${EndIf}
6106
6107      Pop $R7
6108      Exch $R8
6109      Exch 1
6110      Exch $R9
6111    FunctionEnd
6112
6113    !verbose pop
6114  !endif
6115!macroend
6116
6117!macro LeaveDirectoryCommonCall _WARN_DISK_SPACE _WARN_WRITE_ACCESS
6118  !verbose push
6119  Push "${_WARN_DISK_SPACE}"
6120  Push "${_WARN_WRITE_ACCESS}"
6121  !verbose ${_MOZFUNC_VERBOSE}
6122  Call LeaveDirectoryCommon
6123  !verbose pop
6124!macroend
6125
6126
6127################################################################################
6128# Install Section common macros.
6129
6130/**
6131 * Performs common cleanup operations prior to the actual installation.
6132 * This macro should be called first when installation starts.
6133 */
6134!macro InstallStartCleanupCommon
6135
6136  !ifndef InstallStartCleanupCommon
6137    !insertmacro CleanVirtualStore
6138    !insertmacro EndUninstallLog
6139    !insertmacro OnInstallUninstall
6140
6141    !verbose push
6142    !verbose ${_MOZFUNC_VERBOSE}
6143    !define InstallStartCleanupCommon "!insertmacro InstallStartCleanupCommonCall"
6144
6145    Function InstallStartCleanupCommon
6146
6147      ; Remove files not removed by parsing the uninstall.log
6148      Delete "$INSTDIR\install_wizard.log"
6149      Delete "$INSTDIR\install_status.log"
6150
6151      RmDir /r "$INSTDIR\updates"
6152      Delete "$INSTDIR\updates.xml"
6153      Delete "$INSTDIR\active-update.xml"
6154
6155      ; Remove files from the uninstall directory.
6156      ${If} ${FileExists} "$INSTDIR\uninstall"
6157        Delete "$INSTDIR\uninstall\*wizard*"
6158        Delete "$INSTDIR\uninstall\uninstall.ini"
6159        Delete "$INSTDIR\uninstall\cleanup.log"
6160        Delete "$INSTDIR\uninstall\uninstall.update"
6161        ${OnInstallUninstall}
6162      ${EndIf}
6163
6164      ; Since we write to the uninstall.log in this directory during the
6165      ; installation create the directory if it doesn't already exist.
6166      IfFileExists "$INSTDIR\uninstall" +2 +1
6167      CreateDirectory "$INSTDIR\uninstall"
6168
6169      ; Application update uses a directory named tobedeleted in the $INSTDIR to
6170      ; delete files on OS reboot when they are in use. Try to delete this
6171      ; directory if it exists.
6172      ${If} ${FileExists} "$INSTDIR\${TO_BE_DELETED}"
6173        RmDir /r "$INSTDIR\${TO_BE_DELETED}"
6174      ${EndIf}
6175
6176      ; Remove files that may be left behind by the application in the
6177      ; VirtualStore directory.
6178      ${CleanVirtualStore}
6179    FunctionEnd
6180
6181    !verbose pop
6182  !endif
6183!macroend
6184
6185!macro InstallStartCleanupCommonCall
6186  !verbose push
6187  !verbose ${_MOZFUNC_VERBOSE}
6188  Call InstallStartCleanupCommon
6189  !verbose pop
6190!macroend
6191
6192/**
6193 * Performs common cleanup operations after the actual installation.
6194 * This macro should be called last during the installation.
6195 */
6196!macro InstallEndCleanupCommon
6197
6198  !ifndef InstallEndCleanupCommon
6199    !insertmacro EndUninstallLog
6200
6201    !verbose push
6202    !verbose ${_MOZFUNC_VERBOSE}
6203    !define InstallEndCleanupCommon "!insertmacro InstallEndCleanupCommonCall"
6204
6205    Function InstallEndCleanupCommon
6206
6207      ; Close the file handle to the uninstall.log
6208      ${EndUninstallLog}
6209
6210    FunctionEnd
6211
6212    !verbose pop
6213  !endif
6214!macroend
6215
6216!macro InstallEndCleanupCommonCall
6217  !verbose push
6218  !verbose ${_MOZFUNC_VERBOSE}
6219  Call InstallEndCleanupCommon
6220  !verbose pop
6221!macroend
6222
6223
6224################################################################################
6225# UAC Related Macros
6226
6227/**
6228 * Provides UAC elevation support (requires the UAC plugin).
6229 *
6230 * $0 = return values from calls to the UAC plugin (always uses $0)
6231 * $R9 = return values from GetParameters and GetOptions macros
6232 */
6233!macro ElevateUAC
6234
6235  !ifndef ${_MOZFUNC_UN}ElevateUAC
6236    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
6237    !insertmacro ${_MOZFUNC_UN_TMP}GetOptions
6238    !insertmacro ${_MOZFUNC_UN_TMP}GetParameters
6239    !undef _MOZFUNC_UN
6240    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
6241    !undef _MOZFUNC_UN_TMP
6242
6243    !verbose push
6244    !verbose ${_MOZFUNC_VERBOSE}
6245    !define ${_MOZFUNC_UN}ElevateUAC "!insertmacro ${_MOZFUNC_UN}ElevateUACCall"
6246
6247    Function ${_MOZFUNC_UN}ElevateUAC
6248      Push $R9
6249      Push $0
6250
6251!ifndef NONADMIN_ELEVATE
6252      UAC::IsAdmin
6253      ; If the user is not an admin already
6254      ${If} "$0" != "1"
6255        UAC::SupportsUAC
6256        ; If the system supports UAC
6257        ${If} "$0" == "1"
6258          UAC::GetElevationType
6259          ; If the user account has a split token
6260          ${If} "$0" == "3"
6261            UAC::RunElevated
6262            UAC::Unload
6263            ; Nothing besides UAC initialized so no need to call OnEndCommon
6264            Quit
6265          ${EndIf}
6266        ${EndIf}
6267      ${Else}
6268        ${GetParameters} $R9
6269        ${If} $R9 != ""
6270          ClearErrors
6271          ${GetOptions} "$R9" "/UAC:" $0
6272          ; If the command line contains /UAC then we need to initialize
6273          ; the UAC plugin to use UAC::ExecCodeSegment to execute code in
6274          ; the non-elevated context.
6275          ${Unless} ${Errors}
6276            UAC::RunElevated
6277          ${EndUnless}
6278        ${EndIf}
6279      ${EndIf}
6280!else
6281      UAC::IsAdmin
6282      ; If the user is not an admin already
6283      ${If} "$0" != "1"
6284        UAC::SupportsUAC
6285        ; If the system supports UAC require that the user elevate
6286        ${If} "$0" == "1"
6287          UAC::GetElevationType
6288          ; If the user account has a split token
6289          ${If} "$0" == "3"
6290            UAC::RunElevated
6291            ${If} "$0" == "0" ; Was elevation successful
6292              UAC::Unload
6293              ; Nothing besides UAC initialized so no need to call OnEndCommon
6294              Quit
6295            ${EndIf}
6296            ; Unload UAC since the elevation request was not successful and
6297            ; install anyway.
6298            UAC::Unload
6299          ${EndIf}
6300        ${Else}
6301          ; Check if UAC is enabled. If the user has turned UAC on or off
6302          ; without rebooting this value will be incorrect. This is an
6303          ; edgecase that we have to live with when trying to allow
6304          ; installing when the user doesn't have privileges such as a public
6305          ; computer while trying to also achieve UAC elevation. When this
6306          ; happens the user will be presented with the runas dialog if the
6307          ; value is 1 and won't be presented with the UAC dialog when the
6308          ; value is 0.
6309          ReadRegDWord $R9 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "EnableLUA"
6310          ${If} "$R9" == "1"
6311            ; This will display the UAC version of the runas dialog which
6312            ; requires a password for an existing user account.
6313            UAC::RunElevated
6314            ${If} "$0" == "0" ; Was elevation successful
6315              UAC::Unload
6316              ; Nothing besides UAC initialized so no need to call OnEndCommon
6317              Quit
6318            ${EndIf}
6319            ; Unload UAC since the elevation request was not successful and
6320            ; install anyway.
6321            UAC::Unload
6322          ${EndIf}
6323        ${EndIf}
6324      ${Else}
6325        ClearErrors
6326        ${${_MOZFUNC_UN}GetParameters} $R9
6327        ${${_MOZFUNC_UN}GetOptions} "$R9" "/UAC:" $R9
6328        ; If the command line contains /UAC then we need to initialize the UAC
6329        ; plugin to use UAC::ExecCodeSegment to execute code in the
6330        ; non-elevated context.
6331        ${Unless} ${Errors}
6332          UAC::RunElevated
6333        ${EndUnless}
6334      ${EndIf}
6335!endif
6336
6337      ClearErrors
6338
6339      Pop $0
6340      Pop $R9
6341    FunctionEnd
6342
6343    !verbose pop
6344  !endif
6345!macroend
6346
6347!macro ElevateUACCall
6348  !verbose push
6349  !verbose ${_MOZFUNC_VERBOSE}
6350  Call ElevateUAC
6351  !verbose pop
6352!macroend
6353
6354!macro un.ElevateUACCall
6355  !verbose push
6356  !verbose ${_MOZFUNC_VERBOSE}
6357  Call un.ElevateUAC
6358  !verbose pop
6359!macroend
6360
6361!macro un.ElevateUAC
6362  !ifndef un.ElevateUAC
6363    !verbose push
6364    !verbose ${_MOZFUNC_VERBOSE}
6365    !undef _MOZFUNC_UN
6366    !define _MOZFUNC_UN "un."
6367
6368    !insertmacro ElevateUAC
6369
6370    !undef _MOZFUNC_UN
6371    !define _MOZFUNC_UN
6372    !verbose pop
6373  !endif
6374!macroend
6375
6376/**
6377 * Unloads the UAC plugin so the NSIS plugins can be removed when the installer
6378 * and uninstaller exit.
6379 *
6380 * $R9 = return values from GetParameters and GetOptions macros
6381 */
6382!macro UnloadUAC
6383
6384  !ifndef ${_MOZFUNC_UN}UnloadUAC
6385    !define _MOZFUNC_UN_TMP_UnloadUAC ${_MOZFUNC_UN}
6386    !insertmacro ${_MOZFUNC_UN_TMP_UnloadUAC}GetOptions
6387    !insertmacro ${_MOZFUNC_UN_TMP_UnloadUAC}GetParameters
6388    !undef _MOZFUNC_UN
6389    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP_UnloadUAC}
6390    !undef _MOZFUNC_UN_TMP_UnloadUAC
6391
6392    !verbose push
6393    !verbose ${_MOZFUNC_VERBOSE}
6394    !define ${_MOZFUNC_UN}UnloadUAC "!insertmacro ${_MOZFUNC_UN}UnloadUACCall"
6395
6396    Function ${_MOZFUNC_UN}UnloadUAC
6397      Push $R9
6398
6399      ClearErrors
6400      ${${_MOZFUNC_UN}GetParameters} $R9
6401      ${${_MOZFUNC_UN}GetOptions} "$R9" "/UAC:" $R9
6402      ; If the command line contains /UAC then we need to unload the UAC plugin
6403      IfErrors +2 +1
6404      UAC::Unload
6405
6406      ClearErrors
6407
6408      Pop $R9
6409    FunctionEnd
6410
6411    !verbose pop
6412  !endif
6413!macroend
6414
6415!macro UnloadUACCall
6416  !verbose push
6417  !verbose ${_MOZFUNC_VERBOSE}
6418  Call UnloadUAC
6419  !verbose pop
6420!macroend
6421
6422!macro un.UnloadUACCall
6423  !verbose push
6424  !verbose ${_MOZFUNC_VERBOSE}
6425  Call un.UnloadUAC
6426  !verbose pop
6427!macroend
6428
6429!macro un.UnloadUAC
6430  !ifndef un.UnloadUAC
6431    !verbose push
6432    !verbose ${_MOZFUNC_VERBOSE}
6433    !undef _MOZFUNC_UN
6434    !define _MOZFUNC_UN "un."
6435
6436    !insertmacro UnloadUAC
6437
6438    !undef _MOZFUNC_UN
6439    !define _MOZFUNC_UN
6440    !verbose pop
6441  !endif
6442!macroend
6443
6444
6445################################################################################
6446# Macros for uninstall.log and install.log logging
6447#
6448# Since these are used by other macros they should be inserted first. All of
6449# these macros can be easily inserted using the _LoggingCommon macro.
6450
6451/**
6452 * Adds all logging macros in the correct order in one fell swoop as well as
6453 * the vars for the install.log and uninstall.log file handles.
6454 */
6455!macro _LoggingCommon
6456  Var /GLOBAL fhInstallLog
6457  Var /GLOBAL fhUninstallLog
6458  !insertmacro StartInstallLog
6459  !insertmacro EndInstallLog
6460  !insertmacro StartUninstallLog
6461  !insertmacro EndUninstallLog
6462!macroend
6463!define _LoggingCommon "!insertmacro _LoggingCommon"
6464
6465/**
6466 * Creates a file named install.log in the install directory (e.g. $INSTDIR)
6467 * and adds the installation started message to the install.log for this
6468 * installation. This also adds the fhInstallLog and fhUninstallLog vars used
6469 * for logging.
6470 *
6471 * $fhInstallLog = filehandle for $INSTDIR\install.log
6472 *
6473 * @param   _APP_NAME
6474 *          Typically the BrandFullName
6475 * @param   _AB_CD
6476 *          The locale identifier
6477 * @param   _APP_VERSION
6478 *          The application version
6479 * @param   _GRE_VERSION
6480 *          The Gecko Runtime Engine version
6481 *
6482 * $R6 = _APP_NAME
6483 * $R7 = _AB_CD
6484 * $R8 = _APP_VERSION
6485 * $R9 = _GRE_VERSION
6486 */
6487!macro StartInstallLog
6488
6489  !ifndef StartInstallLog
6490    !insertmacro GetTime
6491
6492    !verbose push
6493    !verbose ${_MOZFUNC_VERBOSE}
6494    !define StartInstallLog "!insertmacro StartInstallLogCall"
6495
6496    Function StartInstallLog
6497      Exch $R9
6498      Exch 1
6499      Exch $R8
6500      Exch 2
6501      Exch $R7
6502      Exch 3
6503      Exch $R6
6504      Push $R5
6505      Push $R4
6506      Push $R3
6507      Push $R2
6508      Push $R1
6509      Push $R0
6510      Push $9
6511
6512      ${DeleteFile} "$INSTDIR\install.log"
6513      FileOpen $fhInstallLog "$INSTDIR\install.log" w
6514      FileWriteWord $fhInstallLog "65279"
6515
6516      ${GetTime} "" "L" $9 $R0 $R1 $R2 $R3 $R4 $R5
6517      FileWriteUTF16LE $fhInstallLog "$R6 Installation Started: $R1-$R0-$9 $R3:$R4:$R5"
6518      ${WriteLogSeparator}
6519
6520      ${LogHeader} "Installation Details"
6521      ${LogMsg} "Install Dir: $INSTDIR"
6522      ${LogMsg} "Locale     : $R7"
6523      ${LogMsg} "App Version: $R8"
6524      ${LogMsg} "GRE Version: $R9"
6525
6526      ${If} ${IsWin7}
6527        ${LogMsg} "OS Name    : Windows 7"
6528      ${ElseIf} ${IsWin8}
6529        ${LogMsg} "OS Name    : Windows 8"
6530      ${ElseIf} ${IsWin8.1}
6531        ${LogMsg} "OS Name    : Windows 8.1"
6532      ${ElseIf} ${IsWin10}
6533        ${LogMsg} "OS Name    : Windows 10"
6534      ${ElseIf} ${AtLeastWin10}
6535        ${LogMsg} "OS Name    : Above Windows 10"
6536      ${Else}
6537        ${LogMsg} "OS Name    : Unable to detect"
6538      ${EndIf}
6539
6540      ${LogMsg} "Target CPU : ${ARCH}"
6541
6542      Pop $9
6543      Pop $R0
6544      Pop $R1
6545      Pop $R2
6546      Pop $R3
6547      Pop $R4
6548      Pop $R5
6549      Exch $R6
6550      Exch 3
6551      Exch $R7
6552      Exch 2
6553      Exch $R8
6554      Exch 1
6555      Exch $R9
6556    FunctionEnd
6557
6558    !verbose pop
6559  !endif
6560!macroend
6561
6562!macro StartInstallLogCall _APP_NAME _AB_CD _APP_VERSION _GRE_VERSION
6563  !verbose push
6564  !verbose ${_MOZFUNC_VERBOSE}
6565  Push "${_APP_NAME}"
6566  Push "${_AB_CD}"
6567  Push "${_APP_VERSION}"
6568  Push "${_GRE_VERSION}"
6569  Call StartInstallLog
6570  !verbose pop
6571!macroend
6572
6573/**
6574 * Writes the installation finished message to the install.log and closes the
6575 * file handles to the install.log and uninstall.log
6576 *
6577 * @param   _APP_NAME
6578 *
6579 * $R9 = _APP_NAME
6580 */
6581!macro EndInstallLog
6582
6583  !ifndef EndInstallLog
6584    !insertmacro GetTime
6585
6586    !verbose push
6587    !verbose ${_MOZFUNC_VERBOSE}
6588    !define EndInstallLog "!insertmacro EndInstallLogCall"
6589
6590    Function EndInstallLog
6591      Exch $R9
6592      Push $R8
6593      Push $R7
6594      Push $R6
6595      Push $R5
6596      Push $R4
6597      Push $R3
6598      Push $R2
6599
6600      ${WriteLogSeparator}
6601      ${GetTime} "" "L" $R2 $R3 $R4 $R5 $R6 $R7 $R8
6602      FileWriteUTF16LE $fhInstallLog "$R9 Installation Finished: $R4-$R3-$R2 $R6:$R7:$R8$\r$\n"
6603      FileClose $fhInstallLog
6604
6605      Pop $R2
6606      Pop $R3
6607      Pop $R4
6608      Pop $R5
6609      Pop $R6
6610      Pop $R7
6611      Pop $R8
6612      Exch $R9
6613    FunctionEnd
6614
6615    !verbose pop
6616  !endif
6617!macroend
6618
6619!macro EndInstallLogCall _APP_NAME
6620  !verbose push
6621  !verbose ${_MOZFUNC_VERBOSE}
6622  Push "${_APP_NAME}"
6623  Call EndInstallLog
6624  !verbose pop
6625!macroend
6626
6627/**
6628 * Opens the file handle to the uninstall.log.
6629 *
6630 * $fhUninstallLog = filehandle for $INSTDIR\uninstall\uninstall.log
6631 */
6632!macro StartUninstallLog
6633
6634  !ifndef StartUninstallLog
6635    !verbose push
6636    !verbose ${_MOZFUNC_VERBOSE}
6637    !define StartUninstallLog "!insertmacro StartUninstallLogCall"
6638
6639    Function StartUninstallLog
6640      FileOpen $fhUninstallLog "$INSTDIR\uninstall\uninstall.log" w
6641    FunctionEnd
6642
6643    !verbose pop
6644  !endif
6645!macroend
6646
6647!macro StartUninstallLogCall
6648  !verbose push
6649  !verbose ${_MOZFUNC_VERBOSE}
6650  Call StartUninstallLog
6651  !verbose pop
6652!macroend
6653
6654/**
6655 * Closes the file handle to the uninstall.log.
6656 */
6657!macro EndUninstallLog
6658
6659  !ifndef EndUninstallLog
6660
6661    !verbose push
6662    !verbose ${_MOZFUNC_VERBOSE}
6663    !define EndUninstallLog "!insertmacro EndUninstallLogCall"
6664
6665    Function EndUninstallLog
6666      FileClose $fhUninstallLog
6667    FunctionEnd
6668
6669    !verbose pop
6670  !endif
6671!macroend
6672
6673!macro EndUninstallLogCall
6674  !verbose push
6675  !verbose ${_MOZFUNC_VERBOSE}
6676  Call EndUninstallLog
6677  !verbose pop
6678!macroend
6679
6680/**
6681 * Adds a section header to the human readable log.
6682 *
6683 * @param   _HEADER
6684 *          The header text to write to the log.
6685 */
6686!macro LogHeader _HEADER
6687  ${WriteLogSeparator}
6688  FileWriteUTF16LE $fhInstallLog "${_HEADER}"
6689  ${WriteLogSeparator}
6690!macroend
6691!define LogHeader "!insertmacro LogHeader"
6692
6693/**
6694 * Adds a section message to the human readable log.
6695 *
6696 * @param   _MSG
6697 *          The message text to write to the log.
6698 */
6699!macro LogMsg _MSG
6700  FileWriteUTF16LE $fhInstallLog "  ${_MSG}$\r$\n"
6701!macroend
6702!define LogMsg "!insertmacro LogMsg"
6703
6704/**
6705 * Adds an uninstall entry to the uninstall log.
6706 *
6707 * @param   _MSG
6708 *          The message text to write to the log.
6709 */
6710!macro LogUninstall _MSG
6711  FileWrite $fhUninstallLog "${_MSG}$\r$\n"
6712!macroend
6713!define LogUninstall "!insertmacro LogUninstall"
6714
6715/**
6716 * Adds a section divider to the human readable log.
6717 */
6718!macro WriteLogSeparator
6719  FileWriteUTF16LE $fhInstallLog "$\r$\n----------------------------------------\
6720                                  ---------------------------------------$\r$\n"
6721!macroend
6722!define WriteLogSeparator "!insertmacro WriteLogSeparator"
6723
6724
6725################################################################################
6726# Macros for managing the shortcuts log ini file
6727
6728/**
6729 * Adds the most commonly used shortcut logging macros for the installer in one
6730 * fell swoop.
6731 */
6732!macro _LoggingShortcutsCommon
6733  !insertmacro LogDesktopShortcut
6734  !insertmacro LogQuickLaunchShortcut
6735  !insertmacro LogSMProgramsShortcut
6736!macroend
6737!define _LoggingShortcutsCommon "!insertmacro _LoggingShortcutsCommon"
6738
6739/**
6740 * Creates the shortcuts log ini file with a UTF-16LE BOM if it doesn't exist.
6741 */
6742!macro initShortcutsLog
6743  Push $R9
6744
6745  IfFileExists "$INSTDIR\uninstall\${SHORTCUTS_LOG}" +4 +1
6746  FileOpen $R9 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" w
6747  FileWriteWord $R9 "65279"
6748  FileClose $R9
6749
6750  Pop $R9
6751!macroend
6752!define initShortcutsLog "!insertmacro initShortcutsLog"
6753
6754/**
6755 * Adds shortcut entries to the shortcuts log ini file. This macro is primarily
6756 * a helper used by the LogDesktopShortcut, LogQuickLaunchShortcut, and
6757 * LogSMProgramsShortcut macros but it can be used by other code if desired. If
6758 * the value already exists the the value is not written to the file.
6759 *
6760 * @param   _SECTION_NAME
6761 *          The section name to write to in the shortcut log ini file
6762 * @param   _FILE_NAME
6763 *          The shortcut's file name
6764 *
6765 * $R6 = return value from ReadIniStr for the shortcut file name
6766 * $R7 = counter for supporting multiple shortcuts in the same location
6767 * $R8 = _SECTION_NAME
6768 * $R9 = _FILE_NAME
6769 */
6770!macro LogShortcut
6771
6772  !ifndef LogShortcut
6773    !verbose push
6774    !verbose ${_MOZFUNC_VERBOSE}
6775    !define LogShortcut "!insertmacro LogShortcutCall"
6776
6777    Function LogShortcut
6778      Exch $R9
6779      Exch 1
6780      Exch $R8
6781      Push $R7
6782      Push $R6
6783
6784      ClearErrors
6785
6786      !insertmacro initShortcutsLog
6787
6788      StrCpy $R6 ""
6789      StrCpy $R7 -1
6790
6791      StrCmp "$R6" "$R9" +5 +1 ; if the shortcut already exists don't add it
6792      IntOp $R7 $R7 + 1 ; increment the counter
6793      ReadIniStr $R6 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "$R8" "Shortcut$R7"
6794      IfErrors +1 -3
6795      WriteINIStr "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "$R8" "Shortcut$R7" "$R9"
6796
6797      ClearErrors
6798
6799      Pop $R6
6800      Pop $R7
6801      Exch $R8
6802      Exch 1
6803      Exch $R9
6804    FunctionEnd
6805
6806    !verbose pop
6807  !endif
6808!macroend
6809
6810!macro LogShortcutCall _SECTION_NAME _FILE_NAME
6811  !verbose push
6812  !verbose ${_MOZFUNC_VERBOSE}
6813  Push "${_SECTION_NAME}"
6814  Push "${_FILE_NAME}"
6815  Call LogShortcut
6816  !verbose pop
6817!macroend
6818
6819/**
6820 * Adds a Desktop shortcut entry to the shortcuts log ini file.
6821 *
6822 * @param   _FILE_NAME
6823 *          The shortcut file name (e.g. shortcut.lnk)
6824 */
6825!macro LogDesktopShortcut
6826
6827  !ifndef LogDesktopShortcut
6828    !insertmacro LogShortcut
6829
6830    !verbose push
6831    !verbose ${_MOZFUNC_VERBOSE}
6832    !define LogDesktopShortcut "!insertmacro LogDesktopShortcutCall"
6833
6834    Function LogDesktopShortcut
6835      Call LogShortcut
6836    FunctionEnd
6837
6838    !verbose pop
6839  !endif
6840!macroend
6841
6842!macro LogDesktopShortcutCall _FILE_NAME
6843  !verbose push
6844  !verbose ${_MOZFUNC_VERBOSE}
6845  Push "DESKTOP"
6846  Push "${_FILE_NAME}"
6847  Call LogDesktopShortcut
6848  !verbose pop
6849!macroend
6850
6851/**
6852 * Adds a QuickLaunch shortcut entry to the shortcuts log ini file.
6853 *
6854 * @param   _FILE_NAME
6855 *          The shortcut file name (e.g. shortcut.lnk)
6856 */
6857!macro LogQuickLaunchShortcut
6858
6859  !ifndef LogQuickLaunchShortcut
6860    !insertmacro LogShortcut
6861
6862    !verbose push
6863    !verbose ${_MOZFUNC_VERBOSE}
6864    !define LogQuickLaunchShortcut "!insertmacro LogQuickLaunchShortcutCall"
6865
6866    Function LogQuickLaunchShortcut
6867      Call LogShortcut
6868    FunctionEnd
6869
6870    !verbose pop
6871  !endif
6872!macroend
6873
6874!macro LogQuickLaunchShortcutCall _FILE_NAME
6875  !verbose push
6876  !verbose ${_MOZFUNC_VERBOSE}
6877  Push "QUICKLAUNCH"
6878  Push "${_FILE_NAME}"
6879  Call LogQuickLaunchShortcut
6880  !verbose pop
6881!macroend
6882
6883/**
6884 * Adds a Start Menu shortcut entry to the shortcuts log ini file.
6885 *
6886 * @param   _FILE_NAME
6887 *          The shortcut file name (e.g. shortcut.lnk)
6888 */
6889!macro LogStartMenuShortcut
6890
6891  !ifndef LogStartMenuShortcut
6892    !insertmacro LogShortcut
6893
6894    !verbose push
6895    !verbose ${_MOZFUNC_VERBOSE}
6896    !define LogStartMenuShortcut "!insertmacro LogStartMenuShortcutCall"
6897
6898    Function LogStartMenuShortcut
6899      Call LogShortcut
6900    FunctionEnd
6901
6902    !verbose pop
6903  !endif
6904!macroend
6905
6906!macro LogStartMenuShortcutCall _FILE_NAME
6907  !verbose push
6908  !verbose ${_MOZFUNC_VERBOSE}
6909  Push "STARTMENU"
6910  Push "${_FILE_NAME}"
6911  Call LogStartMenuShortcut
6912  !verbose pop
6913!macroend
6914
6915/**
6916 * Adds a Start Menu Programs shortcut entry to the shortcuts log ini file.
6917 *
6918 * @param   _FILE_NAME
6919 *          The shortcut file name (e.g. shortcut.lnk)
6920 */
6921!macro LogSMProgramsShortcut
6922
6923  !ifndef LogSMProgramsShortcut
6924    !insertmacro LogShortcut
6925
6926    !verbose push
6927    !verbose ${_MOZFUNC_VERBOSE}
6928    !define LogSMProgramsShortcut "!insertmacro LogSMProgramsShortcutCall"
6929
6930    Function LogSMProgramsShortcut
6931      Call LogShortcut
6932    FunctionEnd
6933
6934    !verbose pop
6935  !endif
6936!macroend
6937
6938!macro LogSMProgramsShortcutCall _FILE_NAME
6939  !verbose push
6940  !verbose ${_MOZFUNC_VERBOSE}
6941  Push "SMPROGRAMS"
6942  Push "${_FILE_NAME}"
6943  Call LogSMProgramsShortcut
6944  !verbose pop
6945!macroend
6946
6947/**
6948 * Adds the relative path from the Start Menu Programs directory for the
6949 * application's Start Menu directory if it is different from the existing value
6950 * to the shortcuts log ini file.
6951 *
6952 * @param   _REL_PATH_TO_DIR
6953 *          The relative path from the Start Menu Programs directory to the
6954 *          program's directory.
6955 *
6956 * $R9 = _REL_PATH_TO_DIR
6957 */
6958!macro LogSMProgramsDirRelPath _REL_PATH_TO_DIR
6959  Push $R9
6960
6961  !insertmacro initShortcutsLog
6962
6963  ReadINIStr $R9 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" "RelativePathToDir"
6964  StrCmp "$R9" "${_REL_PATH_TO_DIR}" +2 +1
6965  WriteINIStr "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" "RelativePathToDir" "${_REL_PATH_TO_DIR}"
6966
6967  Pop $R9
6968!macroend
6969!define LogSMProgramsDirRelPath "!insertmacro LogSMProgramsDirRelPath"
6970
6971/**
6972 * Copies the value for the relative path from the Start Menu programs directory
6973 * (e.g. $SMPROGRAMS) to the Start Menu directory as it is stored in the
6974 * shortcuts log ini file to the variable specified in the first parameter.
6975 */
6976!macro GetSMProgramsDirRelPath _VAR
6977  ReadINIStr ${_VAR} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" \
6978             "RelativePathToDir"
6979!macroend
6980!define GetSMProgramsDirRelPath "!insertmacro GetSMProgramsDirRelPath"
6981
6982/**
6983 * Copies the shortcuts log ini file path to the variable specified in the
6984 * first parameter.
6985 */
6986!macro GetShortcutsLogPath _VAR
6987  StrCpy ${_VAR} "$INSTDIR\uninstall\${SHORTCUTS_LOG}"
6988!macroend
6989!define GetShortcutsLogPath "!insertmacro GetShortcutsLogPath"
6990
6991/**
6992 * Deletes the shortcuts log ini file.
6993 */
6994!macro DeleteShortcutsLogFile
6995  ${DeleteFile} "$INSTDIR\uninstall\${SHORTCUTS_LOG}"
6996!macroend
6997!define DeleteShortcutsLogFile "!insertmacro DeleteShortcutsLogFile"
6998
6999
7000################################################################################
7001# Macros for managing specific Windows version features
7002
7003/**
7004 * Sets the permitted layered service provider (LSP) categories
7005 * for the application. Consumers should call this after an
7006 * installation log section has completed since this macro will log the results
7007 * to the installation log along with a header.
7008 *
7009 * !IMPORTANT - When calling this macro from an uninstaller do not specify a
7010 *              parameter. The paramter is hardcoded with 0x00000000 to remove
7011 *              the LSP category for the application when performing an
7012 *              uninstall.
7013 *
7014 * @param   _LSP_CATEGORIES
7015 *          The permitted LSP categories for the application. When called by an
7016 *          uninstaller this will always be 0x00000000.
7017 *
7018 * $R5 = error code popped from the stack for the WSCSetApplicationCategory call
7019 * $R6 = return value from the WSCSetApplicationCategory call
7020 * $R7 = string length for the long path to the main application executable
7021 * $R8 = long path to the main application executable
7022 * $R9 = _LSP_CATEGORIES
7023 */
7024!macro SetAppLSPCategories
7025
7026  !ifndef ${_MOZFUNC_UN}SetAppLSPCategories
7027    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
7028    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
7029    !undef _MOZFUNC_UN
7030    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
7031    !undef _MOZFUNC_UN_TMP
7032
7033    !verbose push
7034    !verbose ${_MOZFUNC_VERBOSE}
7035    !define ${_MOZFUNC_UN}SetAppLSPCategories "!insertmacro ${_MOZFUNC_UN}SetAppLSPCategoriesCall"
7036
7037    Function ${_MOZFUNC_UN}SetAppLSPCategories
7038      Exch $R9
7039      Push $R8
7040      Push $R7
7041      Push $R6
7042      Push $R5
7043
7044      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR\${FileMainEXE}" $R8
7045      StrLen $R7 "$R8"
7046
7047      ; Remove existing categories by setting the permitted categories to
7048      ; 0x00000000 since new categories are ANDed with existing categories. If
7049      ; the param value stored in $R9 is 0x00000000 then skip the removal since
7050      ; the categories  will be removed by the second call to
7051      ; WSCSetApplicationCategory.
7052      StrCmp "$R9" "0x00000000" +2 +1
7053      System::Call "Ws2_32::WSCSetApplicationCategory(w R8, i R7, w n, i 0,\
7054                                                      i 0x00000000, i n, *i) i"
7055
7056      ; Set the permitted LSP categories
7057      System::Call "Ws2_32::WSCSetApplicationCategory(w R8, i R7, w n, i 0,\
7058                                                      i R9, i n, *i .s) i.R6"
7059      Pop $R5
7060
7061!ifndef NO_LOG
7062      ${LogHeader} "Setting Permitted LSP Categories"
7063      StrCmp "$R6" 0 +3 +1
7064      ${LogMsg} "** ERROR Setting LSP Categories: $R5 **"
7065      GoTo +2
7066      ${LogMsg} "Permitted LSP Categories: $R9"
7067!endif
7068
7069      ClearErrors
7070
7071      Pop $R5
7072      Pop $R6
7073      Pop $R7
7074      Pop $R8
7075      Exch $R9
7076    FunctionEnd
7077
7078    !verbose pop
7079  !endif
7080!macroend
7081
7082!macro SetAppLSPCategoriesCall _LSP_CATEGORIES
7083  !verbose push
7084  !verbose ${_MOZFUNC_VERBOSE}
7085  Push "${_LSP_CATEGORIES}"
7086  Call SetAppLSPCategories
7087  !verbose pop
7088!macroend
7089
7090!macro un.SetAppLSPCategoriesCall
7091  !verbose push
7092  !verbose ${_MOZFUNC_VERBOSE}
7093  Push "0x00000000"
7094  Call un.SetAppLSPCategories
7095  !verbose pop
7096!macroend
7097
7098!macro un.SetAppLSPCategories
7099  !ifndef un.SetAppLSPCategories
7100    !verbose push
7101    !verbose ${_MOZFUNC_VERBOSE}
7102    !undef _MOZFUNC_UN
7103    !define _MOZFUNC_UN "un."
7104
7105    !insertmacro SetAppLSPCategories
7106
7107    !undef _MOZFUNC_UN
7108    !define _MOZFUNC_UN
7109    !verbose pop
7110  !endif
7111!macroend
7112
7113/**
7114 * Checks if any pinned TaskBar lnk files point to the executable's path passed
7115 * to the macro.
7116 *
7117 * @param   _EXE_PATH
7118 *          The executable path
7119 * @return  _RESULT
7120 *          false if no pinned shotcuts were found for this install location.
7121 *          true if pinned shotcuts were found for this install location.
7122 *
7123 * $R5 = stores whether a TaskBar lnk file has been found for the executable
7124 * $R6 = long path returned from GetShortCutTarget and GetLongPath
7125 * $R7 = file name returned from FindFirst and FindNext
7126 * $R8 = find handle for FindFirst and FindNext
7127 * $R9 = _EXE_PATH and _RESULT
7128 */
7129!macro IsPinnedToTaskBar
7130
7131  !ifndef IsPinnedToTaskBar
7132    !insertmacro GetLongPath
7133
7134    !verbose push
7135    !verbose ${_MOZFUNC_VERBOSE}
7136    !define IsPinnedToTaskBar "!insertmacro IsPinnedToTaskBarCall"
7137
7138    Function IsPinnedToTaskBar
7139      Exch $R9
7140      Push $R8
7141      Push $R7
7142      Push $R6
7143      Push $R5
7144
7145      StrCpy $R5 "false"
7146
7147      ${If} ${AtLeastWin7}
7148      ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar"
7149        FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\TaskBar\*.lnk"
7150        ${Do}
7151          ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar\$R7"
7152            ShellLink::GetShortCutTarget "$QUICKLAUNCH\User Pinned\TaskBar\$R7"
7153            Pop $R6
7154            ${GetLongPath} "$R6" $R6
7155            ${If} "$R6" == "$R9"
7156              StrCpy $R5 "true"
7157              ${ExitDo}
7158            ${EndIf}
7159          ${EndIf}
7160          ClearErrors
7161          FindNext $R8 $R7
7162          ${If} ${Errors}
7163            ${ExitDo}
7164          ${EndIf}
7165        ${Loop}
7166        FindClose $R8
7167      ${EndIf}
7168
7169      ClearErrors
7170
7171      StrCpy $R9 $R5
7172
7173      Pop $R5
7174      Pop $R6
7175      Pop $R7
7176      Pop $R8
7177      Exch $R9
7178    FunctionEnd
7179
7180    !verbose pop
7181  !endif
7182!macroend
7183
7184!macro IsPinnedToTaskBarCall _EXE_PATH _RESULT
7185  !verbose push
7186  !verbose ${_MOZFUNC_VERBOSE}
7187  Push "${_EXE_PATH}"
7188  Call IsPinnedToTaskBar
7189  Pop ${_RESULT}
7190  !verbose pop
7191!macroend
7192
7193/**
7194 * Checks if any pinned Start Menu lnk files point to the executable's path
7195 * passed to the macro.
7196 *
7197 * @param   _EXE_PATH
7198 *          The executable path
7199 * @return  _RESULT
7200 *          false if no pinned shotcuts were found for this install location.
7201 *          true if pinned shotcuts were found for this install location.
7202 *
7203 * $R5 = stores whether a Start Menu lnk file has been found for the executable
7204 * $R6 = long path returned from GetShortCutTarget and GetLongPath
7205 * $R7 = file name returned from FindFirst and FindNext
7206 * $R8 = find handle for FindFirst and FindNext
7207 * $R9 = _EXE_PATH and _RESULT
7208 */
7209!macro IsPinnedToStartMenu
7210
7211  !ifndef IsPinnedToStartMenu
7212    !insertmacro GetLongPath
7213
7214    !verbose push
7215    !verbose ${_MOZFUNC_VERBOSE}
7216    !define IsPinnedToStartMenu "!insertmacro IsPinnedToStartMenuCall"
7217
7218    Function IsPinnedToStartMenu
7219      Exch $R9
7220      Push $R8
7221      Push $R7
7222      Push $R6
7223      Push $R5
7224
7225      StrCpy $R5 "false"
7226
7227      ${If} ${AtLeastWin7}
7228      ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu"
7229        FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\StartMenu\*.lnk"
7230        ${Do}
7231          ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu\$R7"
7232            ShellLink::GetShortCutTarget "$QUICKLAUNCH\User Pinned\StartMenu\$R7"
7233            Pop $R6
7234            ${GetLongPath} "$R6" $R6
7235            ${If} "$R6" == "$R9"
7236              StrCpy $R5 "true"
7237              ${ExitDo}
7238            ${EndIf}
7239          ${EndIf}
7240          ClearErrors
7241          FindNext $R8 $R7
7242          ${If} ${Errors}
7243            ${ExitDo}
7244          ${EndIf}
7245        ${Loop}
7246        FindClose $R8
7247      ${EndIf}
7248
7249      ClearErrors
7250
7251      StrCpy $R9 $R5
7252
7253      Pop $R5
7254      Pop $R6
7255      Pop $R7
7256      Pop $R8
7257      Exch $R9
7258    FunctionEnd
7259
7260    !verbose pop
7261  !endif
7262!macroend
7263
7264!macro IsPinnedToStartMenuCall _EXE_PATH _RESULT
7265  !verbose push
7266  !verbose ${_MOZFUNC_VERBOSE}
7267  Push "${_EXE_PATH}"
7268  Call IsPinnedToStartMenu
7269  Pop ${_RESULT}
7270  !verbose pop
7271!macroend
7272
7273/**
7274 * Gets the number of pinned shortcut lnk files pinned to the Task Bar.
7275 *
7276 * @return  _RESULT
7277 *          number of pinned shortcut lnk files.
7278 *
7279 * $R7 = file name returned from FindFirst and FindNext
7280 * $R8 = find handle for FindFirst and FindNext
7281 * $R9 = _RESULT
7282 */
7283!macro PinnedToTaskBarLnkCount
7284
7285  !ifndef PinnedToTaskBarLnkCount
7286    !insertmacro GetLongPath
7287
7288    !verbose push
7289    !verbose ${_MOZFUNC_VERBOSE}
7290    !define PinnedToTaskBarLnkCount "!insertmacro PinnedToTaskBarLnkCountCall"
7291
7292    Function PinnedToTaskBarLnkCount
7293      Push $R9
7294      Push $R8
7295      Push $R7
7296
7297      StrCpy $R9 0
7298
7299      ${If} ${AtLeastWin7}
7300      ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar"
7301        FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\TaskBar\*.lnk"
7302        ${Do}
7303          ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar\$R7"
7304            IntOp $R9 $R9 + 1
7305          ${EndIf}
7306          ClearErrors
7307          FindNext $R8 $R7
7308          ${If} ${Errors}
7309            ${ExitDo}
7310          ${EndIf}
7311        ${Loop}
7312        FindClose $R8
7313      ${EndIf}
7314
7315      ClearErrors
7316
7317      Pop $R7
7318      Pop $R8
7319      Exch $R9
7320    FunctionEnd
7321
7322    !verbose pop
7323  !endif
7324!macroend
7325
7326!macro PinnedToTaskBarLnkCountCall _RESULT
7327  !verbose push
7328  !verbose ${_MOZFUNC_VERBOSE}
7329  Call PinnedToTaskBarLnkCount
7330  Pop ${_RESULT}
7331  !verbose pop
7332!macroend
7333
7334/**
7335 * Gets the number of pinned shortcut lnk files pinned to the Start Menu.
7336 *
7337 * @return  _RESULT
7338 *          number of pinned shortcut lnk files.
7339 *
7340 * $R7 = file name returned from FindFirst and FindNext
7341 * $R8 = find handle for FindFirst and FindNext
7342 * $R9 = _RESULT
7343 */
7344!macro PinnedToStartMenuLnkCount
7345
7346  !ifndef PinnedToStartMenuLnkCount
7347    !insertmacro GetLongPath
7348
7349    !verbose push
7350    !verbose ${_MOZFUNC_VERBOSE}
7351    !define PinnedToStartMenuLnkCount "!insertmacro PinnedToStartMenuLnkCountCall"
7352
7353    Function PinnedToStartMenuLnkCount
7354      Push $R9
7355      Push $R8
7356      Push $R7
7357
7358      StrCpy $R9 0
7359
7360      ${If} ${AtLeastWin7}
7361      ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu"
7362        FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\StartMenu\*.lnk"
7363        ${Do}
7364          ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu\$R7"
7365            IntOp $R9 $R9 + 1
7366          ${EndIf}
7367          ClearErrors
7368          FindNext $R8 $R7
7369          ${If} ${Errors}
7370            ${ExitDo}
7371          ${EndIf}
7372        ${Loop}
7373        FindClose $R8
7374      ${EndIf}
7375
7376      ClearErrors
7377
7378      Pop $R7
7379      Pop $R8
7380      Exch $R9
7381    FunctionEnd
7382
7383    !verbose pop
7384  !endif
7385!macroend
7386
7387!macro PinnedToStartMenuLnkCountCall _RESULT
7388  !verbose push
7389  !verbose ${_MOZFUNC_VERBOSE}
7390  Call PinnedToStartMenuLnkCount
7391  Pop ${_RESULT}
7392  !verbose pop
7393!macroend
7394
7395/**
7396 * Update Start Menu / TaskBar lnk files that point to the executable's path
7397 * passed to the macro and all other shortcuts installed by the application with
7398 * the current application user model ID. Requires ApplicationID.
7399 *
7400 * NOTE: this does not update Desktop shortcut application user model ID due to
7401 *       bug 633728.
7402 *
7403 * @param   _EXE_PATH
7404 *          The main application executable path
7405 * @param   _APP_ID
7406 *          The application user model ID for the current install
7407 * @return  _RESULT
7408 *          false if no pinned shotcuts were found for this install location.
7409 *          true if pinned shotcuts were found for this install location.
7410 */
7411!macro UpdateShortcutAppModelIDs
7412
7413  !ifndef UpdateShortcutAppModelIDs
7414    !insertmacro GetLongPath
7415
7416    !verbose push
7417    !verbose ${_MOZFUNC_VERBOSE}
7418    !define UpdateShortcutAppModelIDs "!insertmacro UpdateShortcutAppModelIDsCall"
7419
7420    Function UpdateShortcutAppModelIDs
7421      ; stack: path, appid
7422      Exch $R9 ; stack: $R9, appid | $R9 = path
7423      Exch 1   ; stack: appid, $R9
7424      Exch $R8 ; stack: $R8, $R9   | $R8 = appid
7425      Push $R7 ; stack: $R7, $R8, $R9
7426      Push $R6
7427      Push $R5
7428      Push $R4
7429      Push $R3 ; stack: $R3, $R5, $R6, $R7, $R8, $R9
7430      Push $R2
7431
7432      ; $R9 = main application executable path
7433      ; $R8 = appid
7434      ; $R7 = path to the application's start menu programs directory
7435      ; $R6 = path to the shortcut log ini file
7436      ; $R5 = shortcut filename
7437      ; $R4 = GetShortCutTarget result
7438
7439      StrCpy $R3 "false"
7440
7441      ${If} ${AtLeastWin7}
7442        ; installed shortcuts
7443        ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" $R6
7444        ${If} ${FileExists} "$R6"
7445          ; Update the Start Menu shortcuts' App ID for this application
7446          StrCpy $R2 -1
7447          ${Do}
7448            IntOp $R2 $R2 + 1 ; Increment the counter
7449            ClearErrors
7450            ReadINIStr $R5 "$R6" "STARTMENU" "Shortcut$R2"
7451            ${If} ${Errors}
7452              ${ExitDo}
7453            ${EndIf}
7454
7455            ${If} ${FileExists} "$SMPROGRAMS\$R5"
7456              ShellLink::GetShortCutTarget "$SMPROGRAMS\$$R5"
7457              Pop $R4
7458              ${GetLongPath} "$R4" $R4
7459              ${If} "$R4" == "$R9" ; link path == install path
7460                ApplicationID::Set "$SMPROGRAMS\$R5" "$R8" "true"
7461                Pop $R4
7462              ${EndIf}
7463            ${EndIf}
7464          ${Loop}
7465
7466          ; Update the Quick Launch shortcuts' App ID for this application
7467          StrCpy $R2 -1
7468          ${Do}
7469            IntOp $R2 $R2 + 1 ; Increment the counter
7470            ClearErrors
7471            ReadINIStr $R5 "$R6" "QUICKLAUNCH" "Shortcut$R2"
7472            ${If} ${Errors}
7473              ${ExitDo}
7474            ${EndIf}
7475
7476            ${If} ${FileExists} "$QUICKLAUNCH\$R5"
7477              ShellLink::GetShortCutTarget "$QUICKLAUNCH\$R5"
7478              Pop $R4
7479              ${GetLongPath} "$R4" $R4
7480              ${If} "$R4" == "$R9" ; link path == install path
7481                ApplicationID::Set "$QUICKLAUNCH\$R5" "$R8" "true"
7482                Pop $R4
7483              ${EndIf}
7484            ${EndIf}
7485          ${Loop}
7486
7487          ; Update the Start Menu Programs shortcuts' App ID for this application
7488          ClearErrors
7489          ReadINIStr $R7 "$R6" "SMPROGRAMS" "RelativePathToDir"
7490          ${Unless} ${Errors}
7491            ${${_MOZFUNC_UN}GetLongPath} "$SMPROGRAMS\$R7" $R7
7492            ${Unless} "$R7" == ""
7493              StrCpy $R2 -1
7494              ${Do}
7495                IntOp $R2 $R2 + 1 ; Increment the counter
7496                ClearErrors
7497                ReadINIStr $R5 "$R6" "SMPROGRAMS" "Shortcut$R2"
7498                ${If} ${Errors}
7499                  ${ExitDo}
7500                ${EndIf}
7501
7502                ${If} ${FileExists} "$R7\$R5"
7503                  ShellLink::GetShortCutTarget "$R7\$R5"
7504                  Pop $R4
7505                  ${GetLongPath} "$R4" $R4
7506                  ${If} "$R4" == "$R9" ; link path == install path
7507                    ApplicationID::Set "$R7\$R5" "$R8" "true"
7508                    Pop $R4
7509                  ${EndIf}
7510                ${EndIf}
7511              ${Loop}
7512            ${EndUnless}
7513          ${EndUnless}
7514        ${EndIf}
7515
7516        StrCpy $R7 "$QUICKLAUNCH\User Pinned"
7517        StrCpy $R3 "false"
7518
7519        ; $R9 = main application executable path
7520        ; $R8 = appid
7521        ; $R7 = user pinned path
7522        ; $R6 = find handle
7523        ; $R5 = found filename
7524        ; $R4 = GetShortCutTarget result
7525
7526        ; TaskBar links
7527        FindFirst $R6 $R5 "$R7\TaskBar\*.lnk"
7528        ${Do}
7529          ${If} ${FileExists} "$R7\TaskBar\$R5"
7530            ShellLink::GetShortCutTarget "$R7\TaskBar\$R5"
7531            Pop $R4
7532            ${If} "$R4" == "$R9" ; link path == install path
7533              ApplicationID::Set "$R7\TaskBar\$R5" "$R8" "true"
7534              Pop $R4 ; pop Set result off the stack
7535              StrCpy $R3 "true"
7536            ${EndIf}
7537          ${EndIf}
7538          ClearErrors
7539          FindNext $R6 $R5
7540          ${If} ${Errors}
7541            ${ExitDo}
7542          ${EndIf}
7543        ${Loop}
7544        FindClose $R6
7545
7546        ; Start menu links
7547        FindFirst $R6 $R5 "$R7\StartMenu\*.lnk"
7548        ${Do}
7549          ${If} ${FileExists} "$R7\StartMenu\$R5"
7550            ShellLink::GetShortCutTarget "$R7\StartMenu\$R5"
7551            Pop $R4
7552            ${If} "$R4" == "$R9" ; link path == install path
7553              ApplicationID::Set "$R7\StartMenu\$R5" "$R8" "true"
7554              Pop $R4 ; pop Set result off the stack
7555              StrCpy $R3 "true"
7556            ${EndIf}
7557          ${EndIf}
7558          ClearErrors
7559          FindNext $R6 $R5
7560          ${If} ${Errors}
7561            ${ExitDo}
7562          ${EndIf}
7563        ${Loop}
7564        FindClose $R6
7565      ${EndIf}
7566
7567      ClearErrors
7568
7569      StrCpy $R9 $R3
7570
7571      Pop $R2
7572      Pop $R3  ; stack: $R4, $R5, $R6, $R7, $R8, $R9
7573      Pop $R4  ; stack: $R5, $R6, $R7, $R8, $R9
7574      Pop $R5  ; stack: $R6, $R7, $R8, $R9
7575      Pop $R6  ; stack: $R7, $R8, $R9
7576      Pop $R7  ; stack: $R8, $R9
7577      Exch $R8 ; stack: appid, $R9 | $R8 = old $R8
7578      Exch 1   ; stack: $R9, appid
7579      Exch $R9 ; stack: path, appid | $R9 = old $R9
7580    FunctionEnd
7581
7582    !verbose pop
7583  !endif
7584!macroend
7585
7586!macro UpdateShortcutAppModelIDsCall _EXE_PATH _APP_ID _RESULT
7587  !verbose push
7588  !verbose ${_MOZFUNC_VERBOSE}
7589  Push "${_APP_ID}"
7590  Push "${_EXE_PATH}"
7591  Call UpdateShortcutAppModelIDs
7592  Pop ${_RESULT}
7593  !verbose pop
7594!macroend
7595
7596!macro IsUserAdmin
7597  ; Copied from: http://nsis.sourceforge.net/IsUserAdmin
7598  Function IsUserAdmin
7599    Push $R0
7600    Push $R1
7601    Push $R2
7602
7603    ClearErrors
7604    UserInfo::GetName
7605    IfErrors Win9x
7606    Pop $R1
7607    UserInfo::GetAccountType
7608    Pop $R2
7609
7610    StrCmp $R2 "Admin" 0 Continue
7611    StrCpy $R0 "true"
7612    Goto Done
7613
7614    Continue:
7615
7616    StrCmp $R2 "" Win9x
7617    StrCpy $R0 "false"
7618    Goto Done
7619
7620    Win9x:
7621    StrCpy $R0 "true"
7622
7623    Done:
7624    Pop $R2
7625    Pop $R1
7626    Exch $R0
7627  FunctionEnd
7628!macroend
7629
7630/**
7631 * Retrieve if present or generate and store a 64 bit hash of an install path
7632 * using the City Hash algorithm.  On return the resulting id is saved in the
7633 * $AppUserModelID variable declared by inserting this macro. InitHashAppModelId
7634 * will attempt to load from HKLM/_REG_PATH first, then HKCU/_REG_PATH. If found
7635 * in either it will return the hash it finds. If not found it will generate a
7636 * new hash and attempt to store the hash in HKLM/_REG_PATH, then HKCU/_REG_PATH.
7637 * Subsequent calls will then retreive the stored hash value. On any failure,
7638 * $AppUserModelID will be set to an empty string.
7639 *
7640 * Registry format: root/_REG_PATH/"_EXE_PATH" = "hash"
7641 *
7642 * @param   _EXE_PATH
7643 *          The main application executable path
7644 * @param   _REG_PATH
7645 *          The HKLM/HKCU agnostic registry path where the key hash should
7646 *          be stored. ex: "Software\Mozilla\Firefox\TaskBarIDs"
7647 * @result  (Var) $AppUserModelID contains the app model id.
7648 */
7649!macro InitHashAppModelId
7650  !ifndef ${_MOZFUNC_UN}InitHashAppModelId
7651    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
7652    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
7653    !undef _MOZFUNC_UN
7654    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
7655    !undef _MOZFUNC_UN_TMP
7656
7657    !ifndef InitHashAppModelId
7658      Var AppUserModelID
7659    !endif
7660
7661    !verbose push
7662    !verbose ${_MOZFUNC_VERBOSE}
7663    !define ${_MOZFUNC_UN}InitHashAppModelId "!insertmacro ${_MOZFUNC_UN}InitHashAppModelIdCall"
7664
7665    Function ${_MOZFUNC_UN}InitHashAppModelId
7666      ; stack: apppath, regpath
7667      Exch $R9 ; stack: $R9, regpath | $R9 = apppath
7668      Exch 1   ; stack: regpath, $R9
7669      Exch $R8 ; stack: $R8, $R9   | $R8 = regpath
7670      Push $R7
7671
7672      ${If} ${AtLeastWin7}
7673        ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9
7674        ; Always create a new AppUserModelID and overwrite the existing one
7675        ; for the current installation path.
7676        CityHash::GetCityHash64 "$R9"
7677        Pop $AppUserModelID
7678        ${If} $AppUserModelID == "error"
7679          GoTo end
7680        ${EndIf}
7681        ClearErrors
7682        WriteRegStr HKLM "$R8" "$R9" "$AppUserModelID"
7683        ${If} ${Errors}
7684          ClearErrors
7685          WriteRegStr HKCU "$R8" "$R9" "$AppUserModelID"
7686          ${If} ${Errors}
7687            StrCpy $AppUserModelID "error"
7688          ${EndIf}
7689        ${EndIf}
7690      ${EndIf}
7691
7692      end:
7693      ${If} "$AppUserModelID" == "error"
7694        StrCpy $AppUserModelID ""
7695      ${EndIf}
7696
7697      ClearErrors
7698      Pop $R7
7699      Exch $R8
7700      Exch 1
7701      Exch $R9
7702    FunctionEnd
7703
7704    !verbose pop
7705  !endif
7706!macroend
7707
7708!macro InitHashAppModelIdCall _EXE_PATH _REG_PATH
7709  !verbose push
7710  !verbose ${_MOZFUNC_VERBOSE}
7711  Push "${_REG_PATH}"
7712  Push "${_EXE_PATH}"
7713  Call InitHashAppModelId
7714  !verbose pop
7715!macroend
7716
7717!macro un.InitHashAppModelIdCall _EXE_PATH _REG_PATH
7718  !verbose push
7719  !verbose ${_MOZFUNC_VERBOSE}
7720  Push "${_REG_PATH}"
7721  Push "${_EXE_PATH}"
7722  Call un.InitHashAppModelId
7723  !verbose pop
7724!macroend
7725
7726!macro un.InitHashAppModelId
7727  !ifndef un.InitHashAppModelId
7728    !verbose push
7729    !verbose ${_MOZFUNC_VERBOSE}
7730    !undef _MOZFUNC_UN
7731    !define _MOZFUNC_UN "un."
7732
7733    !insertmacro InitHashAppModelId
7734
7735    !undef _MOZFUNC_UN
7736    !define _MOZFUNC_UN
7737    !verbose pop
7738  !endif
7739!macroend
7740
7741/**
7742 * Try to locate the default profile of this install from AppUserModelID
7743 * using installs.ini.
7744 * FIXME This could instead use the Install<AUMID> entries in profiles.ini?
7745 *
7746 * - `SetShellVarContext current` must be called before this macro so
7747 *   $APPDATA gets the current user's data.
7748 * - InitHashAppModelId must have been called before this macro to set
7749 *   $AppUserModelID
7750 *
7751 * @result: Path of the profile directory (not checked for existence),
7752 *          or "" if not found, left on top of the stack.
7753 */
7754!macro FindInstallSpecificProfileMaybeUn _MOZFUNC_UN
7755  Push $R0
7756  Push $0
7757  Push $1
7758  Push $2
7759
7760  StrCpy $R0 ""
7761  ; Look for an install-specific profile, which might be listed as
7762  ; either a relative or an absolute path (installs.ini doesn't say which).
7763  ${If} ${FileExists} "$APPDATA\Mozilla\Firefox\installs.ini"
7764    ClearErrors
7765    ReadINIStr $1 "$APPDATA\Mozilla\Firefox\installs.ini" "$AppUserModelID" "Default"
7766    ${IfNot} ${Errors}
7767      ${${_MOZFUNC_UN}GetLongPath} "$APPDATA\Mozilla\Firefox\$1" $2
7768      ${If} ${FileExists} $2
7769        StrCpy $R0 $2
7770      ${Else}
7771        ${${_MOZFUNC_UN}GetLongPath} "$1" $2
7772        ${If} ${FileExists} $2
7773          StrCpy $R0 $2
7774        ${EndIf}
7775      ${EndIf}
7776    ${EndIf}
7777  ${EndIf}
7778
7779  Pop $2
7780  Pop $1
7781  Pop $0
7782  Exch $R0
7783!macroend
7784!define FindInstallSpecificProfile "!insertmacro FindInstallSpecificProfileMaybeUn ''"
7785!define un.FindInstallSpecificProfile "!insertmacro FindInstallSpecificProfileMaybeUn un."
7786
7787/**
7788 * Copy the post-signing data, which was left alongside the installer
7789 * by the self-extractor stub, into the global location for this data.
7790 *
7791 * If the post-signing data file doesn't exist, or is empty, "0" is
7792 * pushed on the stack, and nothing is copied.
7793 * Otherwise the first line of the post-signing data (including newline,
7794 * if any) is pushed on the stack.
7795 */
7796!macro CopyPostSigningData
7797  !ifndef CopyPostSigningData
7798    !verbose push
7799    !verbose ${_MOZFUNC_VERBOSE}
7800    !define CopyPostSigningData "Call CopyPostSigningData"
7801
7802    Function CopyPostSigningData
7803      Push $0   ; Stack: old $0
7804      Push $1   ; Stack: $1, old $0
7805
7806      ${LineRead} "$EXEDIR\postSigningData" "1" $0
7807      ${If} ${Errors}
7808        ClearErrors
7809        StrCpy $0 "0"
7810      ${Else}
7811        ${GetLocalAppDataFolder} $1
7812        CreateDirectory "$1\Mozilla\Firefox"
7813        CopyFiles /SILENT "$EXEDIR\postSigningData" "$1\Mozilla\Firefox"
7814      ${Endif}
7815
7816      Pop $1    ; Stack: old $0
7817      Exch $0   ; Stack: postSigningData
7818    FunctionEnd
7819
7820    !verbose pop
7821  !endif
7822!macroend
7823
7824################################################################################
7825# Helpers for taskbar progress
7826
7827!ifndef CLSCTX_INPROC_SERVER
7828  !define CLSCTX_INPROC_SERVER  1
7829!endif
7830
7831!define CLSID_ITaskbarList {56fdf344-fd6d-11d0-958a-006097c9a090}
7832!define IID_ITaskbarList3 {ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf}
7833!define ITaskbarList3->SetProgressValue $ITaskbarList3->9
7834!define ITaskbarList3->SetProgressState $ITaskbarList3->10
7835
7836/**
7837 * Creates a single uninitialized object of the ITaskbarList class with a
7838 * reference to the ITaskbarList3 interface. This object can be used to set
7839 * progress and state on the installer's taskbar icon using the helper macros
7840 * in this section.
7841 */
7842!macro ITBL3Create
7843
7844  !ifndef ${_MOZFUNC_UN}ITBL3Create
7845    Var ITaskbarList3
7846
7847    !verbose push
7848    !verbose ${_MOZFUNC_VERBOSE}
7849    !define ${_MOZFUNC_UN}ITBL3Create "!insertmacro ${_MOZFUNC_UN}ITBL3CreateCall"
7850
7851    Function ${_MOZFUNC_UN}ITBL3Create
7852      ; Setting to 0 allows the helper macros to detect when the object was not
7853      ; created.
7854      StrCpy $ITaskbarList3 0
7855      ; Don't create when running silently.
7856      ${Unless} ${Silent}
7857        ; This is only supported on Win 7 and above.
7858        ${If} ${AtLeastWin7}
7859          System::Call "ole32::CoCreateInstance(g '${CLSID_ITaskbarList}', \
7860                                                i 0, \
7861                                                i ${CLSCTX_INPROC_SERVER}, \
7862                                                g '${IID_ITaskbarList3}', \
7863                                                *i .s)"
7864          Pop $ITaskbarList3
7865        ${EndIf}
7866      ${EndUnless}
7867    FunctionEnd
7868
7869    !verbose pop
7870  !endif
7871!macroend
7872
7873!macro ITBL3CreateCall
7874  !verbose push
7875  !verbose ${_MOZFUNC_VERBOSE}
7876  Call ITBL3Create
7877  !verbose pop
7878!macroend
7879
7880!macro un.ITBL3CreateCall _PATH_TO_IMAGE
7881  !verbose push
7882  !verbose ${_MOZFUNC_VERBOSE}
7883  Call un.ITBL3Create
7884  !verbose pop
7885!macroend
7886
7887!macro un.ITBL3Create
7888  !ifndef un.ITBL3Create
7889    !verbose push
7890    !verbose ${_MOZFUNC_VERBOSE}
7891    !undef _MOZFUNC_UN
7892    !define _MOZFUNC_UN "un."
7893
7894    !insertmacro ITBL3Create
7895
7896    !undef _MOZFUNC_UN
7897    !define _MOZFUNC_UN
7898    !verbose pop
7899  !endif
7900!macroend
7901
7902/**
7903 * Sets the percentage completed on the taskbar process icon progress indicator.
7904 *
7905 * @param   _COMPLETED
7906 *          The proportion of the operation that has been completed in relation
7907 *          to _TOTAL.
7908 * @param   _TOTAL
7909 *          The value _COMPLETED will have when the operation has completed.
7910 *
7911 * $R8 = _COMPLETED
7912 * $R9 = _TOTAL
7913 */
7914!macro ITBL3SetProgressValueCall _COMPLETED _TOTAL
7915  Push ${_COMPLETED}
7916  Push ${_TOTAL}
7917  ${CallArtificialFunction} ITBL3SetProgressValue_
7918!macroend
7919
7920!define ITBL3SetProgressValue "!insertmacro ITBL3SetProgressValueCall"
7921!define un.ITBL3SetProgressValue "!insertmacro ITBL3SetProgressValueCall"
7922
7923!macro ITBL3SetProgressValue_
7924  Exch $R9
7925  Exch 1
7926  Exch $R8
7927  ${If} $ITaskbarList3 <> 0
7928    System::Call "${ITaskbarList3->SetProgressValue}(i$HWNDPARENT, l$R8, l$R9)"
7929  ${EndIf}
7930  Exch $R8
7931  Exch 1
7932  Exch $R9
7933!macroend
7934
7935; Normal state / no progress bar
7936!define TBPF_NOPROGRESS       0x00000000
7937; Marquee style progress bar
7938!define TBPF_INDETERMINATE    0x00000001
7939; Standard progress bar
7940!define TBPF_NORMAL           0x00000002
7941; Red taskbar button to indicate an error occurred
7942!define TBPF_ERROR            0x00000004
7943; Yellow taskbar button to indicate user attention (input) is required to
7944; resume progress
7945!define TBPF_PAUSED           0x00000008
7946
7947/**
7948 * Sets the state on the taskbar process icon progress indicator.
7949 *
7950 * @param   _STATE
7951 *          The state to set on the taskbar icon progress indicator. Only one of
7952 *          the states defined above should be specified.
7953 *
7954 * $R9 = _STATE
7955 */
7956!macro ITBL3SetProgressStateCall _STATE
7957  Push ${_STATE}
7958  ${CallArtificialFunction} ITBL3SetProgressState_
7959!macroend
7960
7961!define ITBL3SetProgressState "!insertmacro ITBL3SetProgressStateCall"
7962!define un.ITBL3SetProgressState "!insertmacro ITBL3SetProgressStateCall"
7963
7964!macro ITBL3SetProgressState_
7965  Exch $R9
7966  ${If} $ITaskbarList3 <> 0
7967    System::Call "${ITaskbarList3->SetProgressState}(i$HWNDPARENT, i$R9)"
7968  ${EndIf}
7969  Exch $R9
7970!macroend
7971
7972################################################################################
7973# Helpers for the new user interface
7974
7975!ifndef MAXDWORD
7976  !define MAXDWORD 0xffffffff
7977!endif
7978
7979!ifndef DT_WORDBREAK
7980  !define DT_WORDBREAK 0x0010
7981!endif
7982!ifndef DT_SINGLELINE
7983  !define DT_SINGLELINE 0x0020
7984!endif
7985!ifndef DT_NOCLIP
7986  !define DT_NOCLIP 0x0100
7987!endif
7988!ifndef DT_CALCRECT
7989  !define DT_CALCRECT 0x0400
7990!endif
7991!ifndef DT_EDITCONTROL
7992  !define DT_EDITCONTROL 0x2000
7993!endif
7994!ifndef DT_RTLREADING
7995  !define DT_RTLREADING 0x00020000
7996!endif
7997!ifndef DT_NOFULLWIDTHCHARBREAK
7998  !define DT_NOFULLWIDTHCHARBREAK 0x00080000
7999!endif
8000
8001!define /ifndef GWL_STYLE -16
8002!define /ifndef GWL_EXSTYLE -20
8003
8004!ifndef WS_EX_NOINHERITLAYOUT
8005  !define WS_EX_NOINHERITLAYOUT 0x00100000
8006!endif
8007
8008!ifndef PBS_MARQUEE
8009  !define PBS_MARQUEE 0x08
8010!endif
8011
8012!ifndef PBM_SETRANGE32
8013  !define PBM_SETRANGE32 0x406
8014!endif
8015!ifndef PBM_GETRANGE
8016  !define PBM_GETRANGE 0x407
8017!endif
8018
8019!ifndef SHACF_FILESYSTEM
8020  !define SHACF_FILESYSTEM 1
8021!endif
8022
8023!define MOZ_LOADTRANSPARENT ${LR_LOADFROMFILE}|${LR_LOADTRANSPARENT}|${LR_LOADMAP3DCOLORS}
8024
8025; Extend nsDialogs.nsh to support creating centered labels if it is already
8026; included
8027!ifmacrodef __NSD_DefineControl
8028!insertmacro __NSD_DefineControl LabelCenter
8029!define __NSD_LabelCenter_CLASS STATIC
8030!define __NSD_LabelCenter_STYLE ${DEFAULT_STYLES}|${SS_NOTIFY}|${SS_CENTER}
8031!define __NSD_LabelCenter_EXSTYLE ${WS_EX_TRANSPARENT}
8032!endif
8033
8034/**
8035 * Draws an image file (BMP, GIF, or JPG) onto a bitmap control, with scaling.
8036 * Adapted from https://stackoverflow.com/a/13405711/1508094
8037 *
8038 * @param CONTROL bitmap control created by NSD_CreateBitmap
8039 * @param IMAGE path to image file to draw to the bitmap
8040 * @param HANDLE output bitmap handle which must be freed via NSD_FreeImage
8041 *               after nsDialogs::Show has been called
8042 */
8043!macro __SetStretchedImageOLE CONTROL IMAGE HANDLE
8044  !ifndef IID_IPicture
8045    !define IID_IPicture {7BF80980-BF32-101A-8BBB-00AA00300CAB}
8046  !endif
8047  !ifndef SRCCOPY
8048    !define SRCCOPY 0xCC0020
8049  !endif
8050  !ifndef HALFTONE
8051    !define HALFTONE 4
8052  !endif
8053  !ifndef IMAGE_BITMAP
8054    !define IMAGE_BITMAP 0
8055  !endif
8056
8057  Push $0 ; HANDLE
8058  Push $1 ; memory DC
8059  Push $2 ; IPicture created from IMAGE
8060  Push $3 ; HBITMAP obtained from $2
8061  Push $4 ; BITMAPINFO obtained from $3
8062  Push $5 ; width of IMAGE
8063  Push $6 ; height of IMAGE
8064  Push $7 ; width of CONTROL
8065  Push $8 ; height of CONTROL
8066  Push $R0 ; CONTROL
8067
8068  StrCpy $R0 ${CONTROL} ; in case ${CONTROL} is $0
8069  StrCpy $7 ""
8070  StrCpy $8 ""
8071
8072  System::Call '*(i, i, i, i) i.s'
8073  Pop $0
8074
8075  ${If} $0 <> 0
8076    System::Call 'user32::GetClientRect(i R0, i r0)'
8077    System::Call '*$0(i, i, i .s, i .s)'
8078    System::Free $0
8079    Pop $7
8080    Pop $8
8081  ${EndIf}
8082
8083  ${If} $7 > 0
8084  ${AndIf} $8 > 0
8085    System::Call 'oleaut32::OleLoadPicturePath(w"${IMAGE}",i0,i0,i0,g"${IID_IPicture}",*i.r2)i.r1'
8086    ${If} $1 = 0
8087      System::Call 'user32::GetDC(i0)i.s'
8088      System::Call 'gdi32::CreateCompatibleDC(iss)i.r1'
8089      System::Call 'gdi32::CreateCompatibleBitmap(iss,ir7,ir8)i.r0'
8090      System::Call 'user32::ReleaseDC(i0,is)'
8091      System::Call '$2->3(*i.r3)i.r4' ; IPicture->get_Handle
8092      ${If} $4 = 0
8093        System::Call 'gdi32::SetStretchBltMode(ir1,i${HALFTONE})'
8094        System::Call '*(&i40,&i1024)i.r4' ; BITMAP / BITMAPINFO
8095        System::Call 'gdi32::GetObject(ir3,i24,ir4)'
8096        System::Call 'gdi32::SelectObject(ir1,ir0)i.s'
8097        System::Call '*$4(i40,i.r5,i.r6,i0,i,i.s)' ; Grab size and bits-ptr AND init as BITMAPINFOHEADER
8098        System::Call 'gdi32::GetDIBits(ir1,ir3,i0,i0,i0,ir4,i0)' ; init BITMAPINFOHEADER
8099        System::Call 'gdi32::GetDIBits(ir1,ir3,i0,i0,i0,ir4,i0)' ; init BITMAPINFO
8100        System::Call 'gdi32::StretchDIBits(ir1,i0,i0,ir7,ir8,i0,i0,ir5,ir6,is,ir4,i0,i${SRCCOPY})'
8101        System::Call 'gdi32::SelectObject(ir1,is)'
8102        System::Free $4
8103        SendMessage $R0 ${STM_SETIMAGE} ${IMAGE_BITMAP} $0
8104      ${EndIf}
8105      System::Call 'gdi32::DeleteDC(ir1)'
8106      System::Call '$2->2()' ; IPicture->release()
8107    ${EndIf}
8108  ${EndIf}
8109
8110  Pop $R0
8111  Pop $8
8112  Pop $7
8113  Pop $6
8114  Pop $5
8115  Pop $4
8116  Pop $3
8117  Pop $2
8118  Pop $1
8119  Exch $0
8120  Pop ${HANDLE}
8121!macroend
8122!define SetStretchedImageOLE "!insertmacro __SetStretchedImageOLE"
8123
8124/**
8125 * Display a task dialog box with custom strings and button labels.
8126 *
8127 * The task dialog is highly customizable. The specific style being used here
8128 * is similar to a MessageBox except that the button text is customizable.
8129 * MessageBox-style buttons are used instead of command link buttons; this can
8130 * be made configurable if command buttons are needed.
8131 *
8132 * See https://msdn.microsoft.com/en-us/library/windows/desktop/bb760544.aspx
8133 * for the TaskDialogIndirect function's documentation, and links to definitions
8134 * of the TASKDIALOGCONFIG and TASKDIALOG_BUTTON structures it uses.
8135 *
8136 * @param INSTRUCTION  Dialog header string; use empty string if unneeded
8137 * @param CONTENT      Secondary message string; use empty string if unneeded
8138 * @param BUTTON1      Text for the first button, the one selected by default
8139 * @param BUTTON2      Text for the second button
8140 *
8141 * @return One of the following values will be left on the stack:
8142 *         1001 if the first button was clicked
8143 *         1002 if the second button was clicked
8144 *         2 (IDCANCEL) if the dialog was closed
8145 *         0 on error
8146 */
8147!macro _ShowTaskDialog INSTRUCTION CONTENT BUTTON1 BUTTON2
8148  !ifndef SIZEOF_TASKDIALOGCONFIG_32BIT
8149    !define SIZEOF_TASKDIALOGCONFIG_32BIT 96
8150  !endif
8151  !ifndef TDF_ALLOW_DIALOG_CANCELLATION
8152    !define TDF_ALLOW_DIALOG_CANCELLATION 0x0008
8153  !endif
8154  !ifndef TDF_RTL_LAYOUT
8155    !define TDF_RTL_LAYOUT 0x02000
8156  !endif
8157  !ifndef TD_WARNING_ICON
8158    !define TD_WARNING_ICON 0x0FFFF
8159  !endif
8160
8161  Push $0 ; return value
8162  Push $1 ; TASKDIALOGCONFIG struct
8163  Push $2 ; TASKDIALOG_BUTTON array
8164  Push $3 ; dwFlags member of the TASKDIALOGCONFIG
8165
8166  StrCpy $3 ${TDF_ALLOW_DIALOG_CANCELLATION}
8167  !ifdef ${AB_CD}_rtl
8168    IntOp $3 $3 | ${TDF_RTL_LAYOUT}
8169  !endif
8170
8171  ; Build an array of two TASKDIALOG_BUTTON structs
8172  System::Call "*(i 1001, \
8173                  w '${BUTTON1}', \
8174                  i 1002, \
8175                  w '${BUTTON2}' \
8176                  ) p.r2"
8177  ; Build a TASKDIALOGCONFIG struct
8178  System::Call "*(i ${SIZEOF_TASKDIALOGCONFIG_32BIT}, \
8179                  p $HWNDPARENT, \
8180                  p 0, \
8181                  i $3, \
8182                  i 0, \
8183                  w '$(INSTALLER_WIN_CAPTION)', \
8184                  p ${TD_WARNING_ICON}, \
8185                  w '${INSTRUCTION}', \
8186                  w '${CONTENT}', \
8187                  i 2, \
8188                  p r2, \
8189                  i 1001, \
8190                  i 0, \
8191                  p 0, \
8192                  i 0, \
8193                  p 0, \
8194                  p 0, \
8195                  p 0, \
8196                  p 0, \
8197                  p 0, \
8198                  p 0, \
8199                  p 0, \
8200                  p 0, \
8201                  i 0 \
8202                  ) p.r1"
8203  System::Call "comctl32::TaskDialogIndirect(p r1, *i 0 r0, p 0, p 0)"
8204  System::Free $1
8205  System::Free $2
8206
8207  Pop $3
8208  Pop $2
8209  Pop $1
8210  Exch $0
8211!macroend
8212!define ShowTaskDialog "!insertmacro _ShowTaskDialog"
8213
8214/**
8215 * Removes a single style from a control.
8216 *
8217 * _HANDLE the handle of the control
8218 * _STYLE  the style to remove
8219 */
8220!macro _RemoveStyle _HANDLE _STYLE
8221  Push $0
8222
8223  System::Call 'user32::GetWindowLongW(i ${_HANDLE}, i ${GWL_STYLE}) i .r0'
8224  IntOp $0 $0 | ${_STYLE}
8225  IntOp $0 $0 - ${_STYLE}
8226  System::Call 'user32::SetWindowLongW(i ${_HANDLE}, i ${GWL_STYLE}, i r0)'
8227
8228  Pop $0
8229!macroend
8230!define RemoveStyle "!insertmacro _RemoveStyle"
8231
8232/**
8233 * Adds a single extended style to a control.
8234 *
8235 * _HANDLE  the handle of the control
8236 * _EXSTYLE the extended style to add
8237 */
8238!macro _AddExStyle _HANDLE _EXSTYLE
8239  Push $0
8240
8241  System::Call 'user32::GetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}) i .r0'
8242  IntOp $0 $0 | ${_EXSTYLE}
8243  System::Call 'user32::SetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}, i r0)'
8244
8245  Pop $0
8246!macroend
8247!define AddExStyle "!insertmacro _AddExStyle"
8248
8249/**
8250 * Removes a single extended style from a control.
8251 *
8252 * _HANDLE  the handle of the control
8253 * _EXSTYLE the extended style to remove
8254 */
8255!macro _RemoveExStyle _HANDLE _EXSTYLE
8256  Push $0
8257
8258  System::Call 'user32::GetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}) i .r0'
8259  IntOp $0 $0 | ${_EXSTYLE}
8260  IntOp $0 $0 - ${_EXSTYLE}
8261  System::Call 'user32::SetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}, i r0)'
8262
8263  Pop $0
8264!macroend
8265!define RemoveExStyle "!insertmacro _RemoveExStyle"
8266
8267/**
8268 * Set the necessary styles to configure the given window as right-to-left
8269 *
8270 * _HANDLE the handle of the control to configure
8271 */
8272!macro _MakeWindowRTL _HANDLE
8273  !define /ifndef WS_EX_RIGHT 0x00001000
8274  !define /ifndef WS_EX_LEFT 0x00000000
8275  !define /ifndef WS_EX_RTLREADING 0x00002000
8276  !define /ifndef WS_EX_LTRREADING 0x00000000
8277  !define /ifndef WS_EX_LAYOUTRTL 0x00400000
8278
8279  ${AddExStyle} ${_HANDLE} ${WS_EX_LAYOUTRTL}
8280  ${RemoveExStyle} ${_HANDLE} ${WS_EX_RTLREADING}
8281  ${RemoveExStyle} ${_HANDLE} ${WS_EX_RIGHT}
8282  ${AddExStyle} ${_HANDLE} ${WS_EX_LEFT}|${WS_EX_LTRREADING}
8283!macroend
8284!define MakeWindowRTL "!insertmacro _MakeWindowRTL"
8285
8286/**
8287 * Gets the extent of the specified text in pixels for sizing a control.
8288 *
8289 * _TEXT       the text to get the text extent for
8290 * _FONT       the font to use when getting the text extent
8291 * _RES_WIDTH  return value - control width for the text
8292 * _RES_HEIGHT return value - control height for the text
8293 */
8294!macro GetTextExtentCall _TEXT _FONT _RES_WIDTH _RES_HEIGHT
8295  Push "${_TEXT}"
8296  Push "${_FONT}"
8297  ${CallArtificialFunction} GetTextExtent_
8298  Pop ${_RES_WIDTH}
8299  Pop ${_RES_HEIGHT}
8300!macroend
8301
8302!define GetTextExtent "!insertmacro GetTextExtentCall"
8303!define un.GetTextExtent "!insertmacro GetTextExtentCall"
8304
8305!macro GetTextExtent_
8306  Exch $0 ; font
8307  Exch 1
8308  Exch $1 ; text
8309  Push $2
8310  Push $3
8311  Push $4
8312  Push $5
8313  Push $6
8314  Push $7
8315
8316  ; Reuse the existing NSIS control which is used for BrandingText instead of
8317  ; creating a new control.
8318  GetDlgItem $2 $HWNDPARENT 1028
8319
8320  System::Call 'user32::GetDC(i r2) i .r3'
8321  System::Call 'gdi32::SelectObject(i r3, i r0)'
8322
8323  StrLen $4 "$1"
8324
8325  System::Call '*(i, i) i .r5'
8326  System::Call 'gdi32::GetTextExtentPoint32W(i r3, t$\"$1$\", i r4, i r5)'
8327  System::Call '*$5(i .r6, i .r7)'
8328  System::Free $5
8329
8330  System::Call 'user32::ReleaseDC(i r2, i r3)'
8331
8332  StrCpy $1 $7
8333  StrCpy $0 $6
8334
8335  Pop $7
8336  Pop $6
8337  Pop $5
8338  Pop $4
8339  Pop $3
8340  Pop $2
8341  Exch $1 ; return height
8342  Exch 1
8343  Exch $0 ; return width
8344!macroend
8345
8346/**
8347 * Gets the width and the height of a control in pixels.
8348 *
8349 * _HANDLE     the handle of the control
8350 * _RES_WIDTH  return value - control width for the text
8351 * _RES_HEIGHT return value - control height for the text
8352 */
8353!macro GetDlgItemWidthHeightCall _HANDLE _RES_WIDTH _RES_HEIGHT
8354  Push "${_HANDLE}"
8355  ${CallArtificialFunction} GetDlgItemWidthHeight_
8356  Pop ${_RES_WIDTH}
8357  Pop ${_RES_HEIGHT}
8358!macroend
8359
8360!define GetDlgItemWidthHeight "!insertmacro GetDlgItemWidthHeightCall"
8361!define un.GetDlgItemWidthHeight "!insertmacro GetDlgItemWidthHeightCall"
8362
8363!macro GetDlgItemWidthHeight_
8364  Exch $0 ; handle for the control
8365  Push $1
8366  Push $2
8367
8368  System::Call '*(i, i, i, i) i .r2'
8369  ; The left and top values will always be 0 so the right and bottom values
8370  ; will be the width and height.
8371  System::Call 'user32::GetClientRect(i r0, i r2)'
8372  System::Call '*$2(i, i, i .r0, i .r1)'
8373  System::Free $2
8374
8375  Pop $2
8376  Exch $1 ; return height
8377  Exch 1
8378  Exch $0 ; return width
8379!macroend
8380
8381/**
8382 * Gets the number of pixels from the beginning of the dialog to the end of a
8383 * control in a RTL friendly manner.
8384 *
8385 * _HANDLE the handle of the control
8386 * _RES_PX return value - pixels from the beginning of the dialog to the end of
8387 *         the control
8388 */
8389!macro GetDlgItemEndPXCall _HANDLE _RES_PX
8390  Push "${_HANDLE}"
8391  ${CallArtificialFunction} GetDlgItemEndPX_
8392  Pop ${_RES_PX}
8393!macroend
8394
8395!define GetDlgItemEndPX "!insertmacro GetDlgItemEndPXCall"
8396!define un.GetDlgItemEndPX "!insertmacro GetDlgItemEndPXCall"
8397
8398!macro GetDlgItemEndPX_
8399  Exch $0 ; handle of the control
8400  Push $1
8401  Push $2
8402
8403  ; #32770 is the dialog class
8404  FindWindow $1 "#32770" "" $HWNDPARENT
8405  System::Call '*(i, i, i, i) i .r2'
8406  System::Call 'user32::GetWindowRect(i r0, i r2)'
8407  System::Call 'user32::MapWindowPoints(i 0, i r1,i r2, i 2)'
8408  System::Call '*$2(i, i, i .r0, i)'
8409  System::Free $2
8410
8411  Pop $2
8412  Pop $1
8413  Exch $0 ; pixels from the beginning of the dialog to the end of the control
8414!macroend
8415
8416/**
8417 * Gets the number of pixels from the top of a dialog to the bottom of a control
8418 *
8419 * _CONTROL the handle of the control
8420 * _RES_PX  return value - pixels from the top of the dialog to the bottom
8421 *          of the control
8422 */
8423!macro GetDlgItemBottomPXCall _CONTROL _RES_PX
8424  Push "${_CONTROL}"
8425  ${CallArtificialFunction} GetDlgItemBottomPX_
8426  Pop ${_RES_PX}
8427!macroend
8428
8429!define GetDlgItemBottomPX "!insertmacro GetDlgItemBottomPXCall"
8430!define un.GetDlgItemBottomPX "!insertmacro GetDlgItemBottomPXCall"
8431
8432!macro GetDlgItemBottomPX_
8433  Exch $0 ; handle of the control
8434  Push $1
8435  Push $2
8436
8437  ; #32770 is the dialog class
8438  FindWindow $1 "#32770" "" $HWNDPARENT
8439  System::Call '*(i, i, i, i) i .r2'
8440  System::Call 'user32::GetWindowRect(i r0, i r2)'
8441  System::Call 'user32::MapWindowPoints(i 0, i r1, i r2, i 2)'
8442  System::Call '*$2(i, i, i, i .r0)'
8443  System::Free $2
8444
8445  Pop $2
8446  Pop $1
8447  Exch $0 ; pixels from the top of the dialog to the bottom of the control
8448!macroend
8449
8450/**
8451 * Gets the width and height for sizing a control that has the specified text.
8452 * The control's height and width will be dynamically determined for the maximum
8453 * width specified.
8454 *
8455 * _TEXT       the text
8456 * _FONT       the font to use when getting the width and height
8457 * _MAX_WIDTH  the maximum width for the control in pixels
8458 * _RES_WIDTH  return value - control width for the text in pixels.
8459 *             This might be larger than _MAX_WIDTH if that constraint couldn't
8460 *             be satisfied, e.g. a single word that couldn't be broken up is
8461 *             longer than _MAX_WIDTH by itself.
8462 * _RES_HEIGHT return value - control height for the text in pixels
8463 */
8464!macro GetTextWidthHeight
8465
8466  !ifndef ${_MOZFUNC_UN}GetTextWidthHeight
8467    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
8468    !insertmacro ${_MOZFUNC_UN_TMP}WordFind
8469    !undef _MOZFUNC_UN
8470    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
8471    !undef _MOZFUNC_UN_TMP
8472
8473    !verbose push
8474    !verbose ${_MOZFUNC_VERBOSE}
8475    !define ${_MOZFUNC_UN}GetTextWidthHeight "!insertmacro ${_MOZFUNC_UN}GetTextWidthHeightCall"
8476
8477    Function ${_MOZFUNC_UN}GetTextWidthHeight
8478      ; Stack contents after each instruction (top of the stack on the left):
8479      ;          _MAX_WIDTH _FONT _TEXT
8480      Exch $0  ; $0 _FONT _TEXT
8481      Exch 1   ; _FONT $0 _TEXT
8482      Exch $1  ; $1 $0 _TEXT
8483      Exch 2   ; _TEXT $0 $1
8484      Exch $2  ; $2 $0 $1
8485      ; That's all the parameters, now save our scratch registers.
8486      Push $3  ; handle to a temporary control for drawing the text into
8487      Push $4  ; DC handle
8488      Push $5  ; string length of the text argument
8489      Push $6  ; RECT struct to call DrawText with
8490      Push $7  ; width returned from DrawText
8491      Push $8  ; height returned from DrawText
8492      Push $9  ; flags to pass to DrawText
8493
8494      StrCpy $9 "${DT_NOCLIP}|${DT_CALCRECT}|${DT_WORDBREAK}"
8495      !ifdef ${AB_CD}_rtl
8496        StrCpy $9 "$9|${DT_RTLREADING}"
8497      !endif
8498
8499      ; Reuse the existing NSIS control which is used for BrandingText instead
8500      ; of creating a new control.
8501      GetDlgItem $3 $HWNDPARENT 1028
8502
8503      System::Call 'user32::GetDC(i r3) i .r4'
8504      System::Call 'gdi32::SelectObject(i r4, i r1)'
8505
8506      StrLen $5 "$2" ; text length
8507      System::Call '*(i, i, i r0, i) i .r6'
8508
8509      System::Call 'user32::DrawTextW(i r4, t $\"$2$\", i r5, i r6, i r9)'
8510      System::Call '*$6(i, i, i .r7, i .r8)'
8511      System::Free $6
8512
8513      System::Call 'user32::ReleaseDC(i r3, i r4)'
8514
8515      StrCpy $1 $8
8516      StrCpy $0 $7
8517
8518      ; Restore the values that were in our scratch registers.
8519      Pop $9
8520      Pop $8
8521      Pop $7
8522      Pop $6
8523      Pop $5
8524      Pop $4
8525      Pop $3
8526      ; Restore our parameter registers and return our results.
8527      ; Stack contents after each instruction (top of the stack on the left):
8528      ;         $2 $0 $1
8529      Pop $2  ; $0 $1
8530      Exch 1  ; $1 $0
8531      Exch $1 ; _RES_HEIGHT $0
8532      Exch 1  ; $0 _RES_HEIGHT
8533      Exch $0 ; _RES_WIDTH _RES_HEIGHT
8534    FunctionEnd
8535
8536    !verbose pop
8537  !endif
8538!macroend
8539
8540!macro GetTextWidthHeightCall _TEXT _FONT _MAX_WIDTH _RES_WIDTH _RES_HEIGHT
8541  !verbose push
8542  !verbose ${_MOZFUNC_VERBOSE}
8543  Push "${_TEXT}"
8544  Push "${_FONT}"
8545  Push "${_MAX_WIDTH}"
8546  Call GetTextWidthHeight
8547  Pop ${_RES_WIDTH}
8548  Pop ${_RES_HEIGHT}
8549  !verbose pop
8550!macroend
8551
8552!macro un.GetTextWidthHeightCall _TEXT _FONT _MAX_WIDTH _RES_WIDTH _RES_HEIGHT
8553  !verbose push
8554  !verbose ${_MOZFUNC_VERBOSE}
8555  Push "${_TEXT}"
8556  Push "${_FONT}"
8557  Push "${_MAX_WIDTH}"
8558  Call un.GetTextWidthHeight
8559  Pop ${_RES_WIDTH}
8560  Pop ${_RES_HEIGHT}
8561  !verbose pop
8562!macroend
8563
8564!macro un.GetTextWidthHeight
8565  !ifndef un.GetTextWidthHeight
8566    !verbose push
8567    !verbose ${_MOZFUNC_VERBOSE}
8568    !undef _MOZFUNC_UN
8569    !define _MOZFUNC_UN "un."
8570
8571    !insertmacro GetTextWidthHeight
8572
8573    !undef _MOZFUNC_UN
8574    !define _MOZFUNC_UN
8575    !verbose pop
8576  !endif
8577!macroend
8578
8579/**
8580 * Convert a number of dialog units to a number of pixels.
8581 *
8582 * _DU    Number of dialog units to convert
8583 * _AXIS  Which axis you want to convert a value along, X or Y
8584 * _RV    Register or variable to return the number of pixels in
8585 */
8586!macro _DialogUnitsToPixels _DU _AXIS _RV
8587  Push $0
8588  Push $1
8589
8590  ; The dialog units value might be a string ending with a 'u',
8591  ; so convert it to a number.
8592  IntOp $0 "${_DU}" + 0
8593
8594  !if ${_AXIS} == 'Y'
8595    System::Call '*(i 0, i 0, i 0, i r0) i .r1'
8596    System::Call 'user32::MapDialogRect(p $HWNDPARENT, p r1)'
8597    System::Call '*$1(i, i, i, i . r0)'
8598  !else if ${_AXIS} == 'X'
8599    System::Call '*(i 0, i 0, i r0, i 0) i .r1'
8600    System::Call 'user32::MapDialogRect(p $HWNDPARENT, p r1)'
8601    System::Call '*$1(i, i, i . r0, i)'
8602  !else
8603    !error "Invalid axis ${_AXIS} passed to DialogUnitsToPixels; please use X or Y"
8604  !endif
8605  System::Free $1
8606
8607  Pop $1
8608  Exch $0
8609  Pop ${_RV}
8610!macroend
8611!define DialogUnitsToPixels "!insertmacro _DialogUnitsToPixels"
8612
8613/**
8614 * Convert a given left coordinate for a dialog control to flip the control to
8615 * the other side of the dialog if we're using an RTL locale.
8616 *
8617 * _LEFT_DU   Number of dialog units to convert
8618 * _WIDTH     Width of the control in either pixels or DU's
8619 *            If the string has a 'u' on the end, it will be interpreted as
8620 *            dialog units, otherwise it will be interpreted as pixels.
8621 * _RV        Register or variable to return converted coordinate, in pixels
8622 */
8623!macro _ConvertLeftCoordForRTLCall _LEFT_DU _WIDTH _RV
8624  Push "${_LEFT_DU}"
8625  Push "${_WIDTH}"
8626  ${CallArtificialFunction} _ConvertLeftCoordForRTL
8627  Pop ${_RV}
8628!macroend
8629
8630!define ConvertLeftCoordForRTL "!insertmacro _ConvertLeftCoordForRTLCall"
8631!define un.ConvertLeftCoordForRTL "!insertmacro _ConvertLeftCoordForRTLCall"
8632
8633!macro _ConvertLeftCoordForRTL
8634  ; Stack contents after each instruction (top of the stack on the left):
8635  ;         _WIDTH _LEFT_DU
8636  Exch $0 ; $0 _LEFT_DU
8637  Exch 1  ; _LEFT_DU $0
8638  Exch $1 ; $1 $0
8639  ; That's all the parameters, now save our scratch registers.
8640  Push $2 ; width of the entire dialog, in pixels
8641  Push $3 ; _LEFT_DU converted to pixels
8642  Push $4 ; temp string search result
8643
8644  !ifndef ${AB_CD}_rtl
8645    StrCpy $0 "$1"
8646  !else
8647    ${GetDlgItemWidthHeight} $HWNDPARENT $2 $3
8648    ${DialogUnitsToPixels} $1 X $3
8649
8650    ClearErrors
8651    ${${_MOZFUNC_UN}WordFind} "$0" "u" "E+1{" $4
8652    ${IfNot} ${Errors}
8653      ${DialogUnitsToPixels} $4 X $0
8654    ${EndIf}
8655
8656    IntOp $1 $2 - $3
8657    IntOp $1 $1 - $0
8658    StrCpy $0 $1
8659  !endif
8660
8661  ; Restore the values that were in our scratch registers.
8662  Pop $4
8663  Pop $3
8664  Pop $2
8665  ; Restore our parameter registers and return our result.
8666  ; Stack contents after each instruction (top of the stack on the left):
8667  ;         $1 $0
8668  Pop $1  ; $0
8669  Exch $0 ; _RV
8670!macroend
8671
8672/**
8673 * Gets the elapsed time in seconds between two values in milliseconds stored as
8674 * an int64. The caller will typically get the millisecond values using
8675 * GetTickCount with a long return value as follows.
8676 * System::Call "kernel32::GetTickCount()l .s"
8677 * Pop $varname
8678 *
8679 * _START_TICK_COUNT
8680 * _FINISH_TICK_COUNT
8681 * _RES_ELAPSED_SECONDS return value - elapsed time between _START_TICK_COUNT
8682 *                      and _FINISH_TICK_COUNT in seconds.
8683 */
8684!macro GetSecondsElapsedCall _START_TICK_COUNT _FINISH_TICK_COUNT _RES_ELAPSED_SECONDS
8685  Push "${_START_TICK_COUNT}"
8686  Push "${_FINISH_TICK_COUNT}"
8687  ${CallArtificialFunction} GetSecondsElapsed_
8688  Pop ${_RES_ELAPSED_SECONDS}
8689!macroend
8690
8691!define GetSecondsElapsed "!insertmacro GetSecondsElapsedCall"
8692!define un.GetSecondsElapsed "!insertmacro GetSecondsElapsedCall"
8693
8694!macro GetSecondsElapsed_
8695  Exch $0 ; finish tick count
8696  Exch 1
8697  Exch $1 ; start tick count
8698
8699  System::Int64Op $0 - $1
8700  Pop $0
8701  ; Discard the top bits of the int64 by bitmasking with MAXDWORD
8702  System::Int64Op $0 & ${MAXDWORD}
8703  Pop $0
8704
8705  ; Convert from milliseconds to seconds
8706  System::Int64Op $0 / 1000
8707  Pop $0
8708
8709  Pop $1
8710  Exch $0 ; return elapsed seconds
8711!macroend
8712
8713/**
8714 * Create a process to execute a command line. If it is successfully created,
8715 * wait on it with WaitForInputIdle, to avoid exiting the current process too
8716 * early (exiting early can cause the created process's windows to be opened in
8717 * the background).
8718 *
8719 * CMDLINE Is the command line to execute, like the argument to Exec
8720 */
8721!define ExecAndWaitForInputIdle "!insertmacro ExecAndWaitForInputIdle_"
8722!define CREATE_DEFAULT_ERROR_MODE 0x04000000
8723!macro ExecAndWaitForInputIdle_ CMDLINE
8724  ; derived from https://stackoverflow.com/a/13960786/3444805 by Anders Kjersem
8725  Push $0
8726  Push $1
8727  Push $2
8728
8729  ; Command line
8730  StrCpy $0 "${CMDLINE}"
8731
8732  ; STARTUPINFO
8733  System::Alloc 68
8734  Pop $1
8735  ; fill in STARTUPINFO.cb (first field) with sizeof(STARTUPINFO)
8736  System::Call "*$1(i 68)"
8737
8738  ; PROCESS_INFORMATION
8739  System::Call "*(i, i, i, i) i . r2"
8740
8741  ; CREATE_DEFAULT_ERROR_MODE follows NSIS myCreateProcess used in Exec
8742  System::Call "kernel32::CreateProcessW(i 0, t r0, i 0, i 0, i 0, i ${CREATE_DEFAULT_ERROR_MODE}, i 0, i 0, i r1, i r2) i . r0"
8743
8744  System::Free $1
8745  ${If} $0 <> 0
8746    System::Call "*$2(i . r0, i . r1)"
8747    ; $0: hProcess, $1: hThread
8748    System::Call "user32::WaitForInputIdle(i $0, i 10000)"
8749    System::Call "kernel32::CloseHandle(i $0)"
8750    System::Call "kernel32::CloseHandle(i $1)"
8751  ${EndIf}
8752  System::Free $2
8753
8754  Pop $2
8755  Pop $1
8756  Pop $0
8757!macroend
8758
8759Function WriteRegQWORD
8760          ; Stack contents:
8761          ; VALUE, VALUE_NAME, SUBKEY, ROOTKEY
8762  Exch $3 ; $3, VALUE_NAME, SUBKEY, ROOTKEY
8763  Exch 1  ; VALUE_NAME, $3, SUBKEY, ROOTKEY
8764  Exch $2 ; $2, $3, SUBKEY, ROOTKEY
8765  Exch 2  ; SUBKEY, $3, $2, ROOTKEY
8766  Exch $1 ; $1, $3, $2, ROOTKEY
8767  Exch 3  ; ROOTKEY, $3, $2, $1
8768  Exch $0 ; $0, $3, $2, $1
8769  System::Call "advapi32::RegSetKeyValueW(p r0, w r1, w r2, i 11, *l r3, i 8) i.r0"
8770  ${IfNot} $0 = 0
8771    SetErrors
8772  ${EndIf}
8773  Pop $0
8774  Pop $3
8775  Pop $2
8776  Pop $1
8777FunctionEnd
8778!macro WriteRegQWORD ROOTKEY SUBKEY VALUE_NAME VALUE
8779  ${If} "${ROOTKEY}" == "HKCR"
8780    Push 0x80000000
8781  ${ElseIf} "${ROOTKEY}" == "HKCU"
8782    Push 0x80000001
8783  ${ElseIf} "${ROOTKEY}" == "HKLM"
8784    Push 0x80000002
8785  ${Endif}
8786  Push "${SUBKEY}"
8787  Push "${VALUE_NAME}"
8788  System::Int64Op ${VALUE} + 0 ; The result is pushed on the stack
8789  Call WriteRegQWORD
8790!macroend
8791!define WriteRegQWORD "!insertmacro WriteRegQWORD"
8792
8793Function ReadRegQWORD
8794          ; Stack contents:
8795          ; VALUE_NAME, SUBKEY, ROOTKEY
8796  Exch $2 ; $2, SUBKEY, ROOTKEY
8797  Exch 1  ; SUBKEY, $2, ROOTKEY
8798  Exch $1 ; $1, $2, ROOTKEY
8799  Exch 2  ; ROOTKEY, $2, $1
8800  Exch $0 ; $0, $2, $1
8801  System::Call "advapi32::RegGetValueW(p r0, w r1, w r2, i 0x48, p 0, *l s, *i 8) i.r0"
8802  ${IfNot} $0 = 0
8803    SetErrors
8804  ${EndIf}
8805          ; VALUE, $0, $2, $1
8806  Exch 3  ; $1, $0, $2, VALUE
8807  Pop $1  ; $0, $2, VALUE
8808  Pop $0  ; $2, VALUE
8809  Pop $2  ; VALUE
8810FunctionEnd
8811!macro ReadRegQWORD DEST ROOTKEY SUBKEY VALUE_NAME
8812  ${If} "${ROOTKEY}" == "HKCR"
8813    Push 0x80000000
8814  ${ElseIf} "${ROOTKEY}" == "HKCU"
8815    Push 0x80000001
8816  ${ElseIf} "${ROOTKEY}" == "HKLM"
8817    Push 0x80000002
8818  ${Endif}
8819  Push "${SUBKEY}"
8820  Push "${VALUE_NAME}"
8821  Call ReadRegQWORD
8822  Pop ${DEST}
8823!macroend
8824!define ReadRegQWORD "!insertmacro ReadRegQWORD"
8825
8826