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