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          ; The update directory is shared across all users of this
3698          ; installation, and it contains a number of things. Which files we
3699          ; want to keep and which we want to delete depends on if we are
3700          ; installing or uninstalling.
3701          ; If we are installing, we want to clear out any in-progress updates.
3702          ; Otherwise we could potentially install an old, pending update when
3703          ; Firefox first launches. The updates themselves live in the "updates"
3704          ; subdirectory, and the update metadata lives in active-update.xml.
3705          ; If we are uninstalling, we want to clear out the updates, the
3706          ; update history, and the per-installation update configuration data.
3707          ; In this case, we can just delete the whole update directory.
3708          !if "${_MOZFUNC_UN}" == "un."
3709            ${If} ${FileExists} "$R0"
3710              RmDir /r "$R0"
3711            ${EndIf}
3712          !else
3713            ${If} ${FileExists} "$R0\updates"
3714              RmDir /r "$R0\updates"
3715            ${EndIf}
3716            Delete "$R0\active-update.xml"
3717          !endif
3718
3719          ; Also remove the secure log files that our updater may have created
3720          ; inside the maintenance service path. There are several files named
3721          ; with the install hash and an extension indicating the kind of file.
3722          ; so use a wildcard to delete them all.
3723          Delete "$PROGRAMFILES32\Mozilla Maintenance Service\UpdateLogs\$R1.*"
3724
3725          ; If the UpdateLogs directory is now empty, then delete it.
3726          ; The Maintenance Service uninstaller should do this, but it may not
3727          ; be up to date enough because of bug 1665193, so doing this here as
3728          ; well lets us make sure it really happens.
3729          RmDir "$PROGRAMFILES32\Mozilla Maintenance Service\UpdateLogs"
3730        ${EndIf}
3731      ${EndIf}
3732
3733      ClearErrors
3734
3735      Pop $R0
3736      Pop $R1
3737      Pop $R2
3738      Pop $R3
3739      Pop $R4
3740      Pop $R5
3741      Pop $R6
3742      Exch $R7
3743      Exch 1
3744      Exch $R8
3745    FunctionEnd
3746
3747    !verbose pop
3748  !endif
3749!macroend
3750
3751!macro CleanUpdateDirectoriesCall _OLD_REL_PATH _NEW_REL_PATH
3752  !verbose push
3753  !verbose ${_MOZFUNC_VERBOSE}
3754  Push "${_OLD_REL_PATH}"
3755  Push "${_NEW_REL_PATH}"
3756  Call CleanUpdateDirectories
3757  !verbose pop
3758!macroend
3759
3760!macro un.CleanUpdateDirectoriesCall _OLD_REL_PATH _NEW_REL_PATH
3761  !verbose push
3762  !verbose ${_MOZFUNC_VERBOSE}
3763  Push "${_OLD_REL_PATH}"
3764  Push "${_NEW_REL_PATH}"
3765  Call un.CleanUpdateDirectories
3766  !verbose pop
3767!macroend
3768
3769!macro un.CleanUpdateDirectories
3770  !ifndef un.CleanUpdateDirectories
3771    !verbose push
3772    !verbose ${_MOZFUNC_VERBOSE}
3773    !undef _MOZFUNC_UN
3774    !define _MOZFUNC_UN "un."
3775
3776    !insertmacro CleanUpdateDirectories
3777
3778    !undef _MOZFUNC_UN
3779    !define _MOZFUNC_UN
3780    !verbose pop
3781  !endif
3782!macroend
3783
3784/**
3785 * Create the update directory and sets the permissions correctly
3786 *
3787 * @param   ROOT_DIR_NAME
3788 *          The name of the update directory to be created in the common
3789 *          application directory. For example, if ROOT_DIR_NAME is "Mozilla",
3790 *          the created directory will be "C:\ProgramData\Mozilla".
3791 *
3792 * $R0 = Used for checking errors
3793 * $R1 = The common application directory path
3794 * $R9 = An error message to be returned on the stack
3795 */
3796!macro CreateUpdateDir ROOT_DIR_NAME
3797  Push $R9
3798  Push $R0
3799  Push $R1
3800
3801  ; The update directory is in the Program Data directory
3802  ; (currently C:\ProgramData).
3803  ; This system call gets that directory path. The arguments are:
3804  ;   A null ptr for hwnd
3805  ;   $R1 for the output string
3806  ;   CSIDL_COMMON_APPDATA == 0x0023 == 35 for the csidl indicating which dir to get
3807  ;   true for fCreate (i.e. Do create the folder if it doesn't exist)
3808  ; We could use %APPDATA% for this instead, but that requires state: the shell
3809  ; var context would need to be saved, set, and reset. It is easier just to use
3810  ; the system call.
3811  System::Call "Shell32::SHGetSpecialFolderPathW(p 0, t.R1, i 35, i 1)"
3812  StrCpy $R1 "$R1\${ROOT_DIR_NAME}"
3813
3814  ClearErrors
3815  ${IfNot} ${FileExists} "$R1"
3816    CreateDirectory "$R1"
3817    ${If} ${Errors}
3818      StrCpy $R9 "Unable to create directory: $R1"
3819      GoTo end
3820    ${EndIf}
3821  ${EndIf}
3822
3823  ; Grant Full Access to the Builtin User group
3824  AccessControl::SetOnFile "$R1" "(BU)" "FullAccess"
3825  Pop $R0
3826  ${If} $R0 == error
3827    Pop $R9  ; Get AccessControl's Error Message
3828    SetErrors
3829    GoTo end
3830  ${EndIf}
3831
3832  ; Grant Full Access to the Builtin Administrator group
3833  AccessControl::SetOnFile "$R1" "(BA)" "FullAccess"
3834  Pop $R0
3835  ${If} $R0 == error
3836    Pop $R9  ; Get AccessControl's Error Message
3837    SetErrors
3838    GoTo end
3839  ${EndIf}
3840
3841  ; Grant Full Access to the SYSTEM user
3842  AccessControl::SetOnFile "$R1" "(SY)" "FullAccess"
3843  Pop $R0
3844  ${If} $R0 == error
3845    Pop $R9  ; Get AccessControl's Error Message
3846    SetErrors
3847    GoTo end
3848  ${EndIf}
3849
3850  ; Remove inherited permissions
3851  AccessControl::DisableFileInheritance "$R1"
3852  Pop $R0
3853  ${If} $R0 == error
3854    Pop $R9  ; Get AccessControl's Error Message
3855    SetErrors
3856    GoTo end
3857  ${EndIf}
3858
3859end:
3860  Pop $R1
3861  Pop $R0
3862  ${If} ${Errors}
3863    Exch $R9
3864  ${Else}
3865    Pop $R9
3866  ${EndIf}
3867!macroend
3868!define CreateUpdateDir "!insertmacro CreateUpdateDir"
3869
3870/**
3871 * Deletes all relative profiles specified in an application's profiles.ini and
3872 * performs various other cleanup.
3873 *
3874 * @param   _REL_PROFILE_PATH
3875 *          The relative path to the profile directory.
3876 *
3877 * $R6 = value of IsRelative read from profiles.ini
3878 * $R7 = value of Path to profile read from profiles.ini
3879 * $R8 = counter for reading profiles (e.g. Profile0, Profile1, etc.)
3880 * $R9 = _REL_PROFILE_PATH
3881 */
3882!macro DeleteRelativeProfiles
3883
3884  !ifndef ${_MOZFUNC_UN}DeleteRelativeProfiles
3885    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
3886    !insertmacro ${_MOZFUNC_UN_TMP}WordReplace
3887    !undef _MOZFUNC_UN
3888    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
3889    !undef _MOZFUNC_UN_TMP
3890
3891    !verbose push
3892    !verbose ${_MOZFUNC_VERBOSE}
3893    !define ${_MOZFUNC_UN}DeleteRelativeProfiles "!insertmacro ${_MOZFUNC_UN}DeleteRelativeProfilesCall"
3894
3895    Function ${_MOZFUNC_UN}DeleteRelativeProfiles
3896      Exch $R9
3897      Push $R8
3898      Push $R7
3899      Push $R6
3900
3901      SetShellVarContext current
3902      StrCpy $R8 -1
3903
3904      loop:
3905      IntOp $R8 $R8 + 1  ; Increment the counter.
3906      ReadINIStr $R7 "$APPDATA\$R9\profiles.ini" "Profile$R8" "Path"
3907      IfErrors end +1
3908
3909      ; Only remove relative profiles
3910      ReadINIStr $R6 "$APPDATA\$R9\profiles.ini" "Profile$R8" "IsRelative"
3911      StrCmp "$R6" "1" +1 loop
3912
3913      ; Relative paths in profiles.ini use / as a separator
3914      ${${_MOZFUNC_UN}WordReplace} "$R7" "/" "\" "+" $R7
3915
3916      IfFileExists "$LOCALAPPDATA\$R9\$R7" +1 +2
3917      RmDir /r "$LOCALAPPDATA\$R9\$R7"
3918      IfFileExists "$APPDATA\$R9\$R7" +1 +2
3919      RmDir /r "$APPDATA\$R9\$R7"
3920      GoTo loop
3921
3922      end:
3923      ; Remove profiles directory under LOCALAPPDATA (e.g. cache, etc.) since
3924      ; they are at times abandoned.
3925      RmDir /r "$LOCALAPPDATA\$R9\Profiles"
3926      RmDir /r "$APPDATA\$R9\Crash Reports"
3927      Delete "$APPDATA\$R9\profiles.ini"
3928      Delete "$APPDATA\$R9\console.log"
3929      Delete "$APPDATA\$R9\pluginreg.dat"
3930      RmDir "$APPDATA\$R9\Profiles"
3931      RmDir "$APPDATA\$R9"
3932
3933      Pop $R6
3934      Pop $R7
3935      Pop $R8
3936      Exch $R9
3937    FunctionEnd
3938
3939    !verbose pop
3940  !endif
3941!macroend
3942
3943!macro DeleteRelativeProfilesCall _REL_PROFILE_PATH
3944  !verbose push
3945  !verbose ${_MOZFUNC_VERBOSE}
3946  Push "${_REL_PROFILE_PATH}"
3947  Call DeleteRelativeProfiles
3948  !verbose pop
3949!macroend
3950
3951!macro un.DeleteRelativeProfilesCall _REL_PROFILE_PATH
3952  !verbose push
3953  !verbose ${_MOZFUNC_VERBOSE}
3954  Push "${_REL_PROFILE_PATH}"
3955  Call un.DeleteRelativeProfiles
3956  !verbose pop
3957!macroend
3958
3959!macro un.DeleteRelativeProfiles
3960  !ifndef un.DeleteRelativeProfiles
3961    !verbose push
3962    !verbose ${_MOZFUNC_VERBOSE}
3963    !undef _MOZFUNC_UN
3964    !define _MOZFUNC_UN "un."
3965
3966    !insertmacro DeleteRelativeProfiles
3967
3968    !undef _MOZFUNC_UN
3969    !define _MOZFUNC_UN
3970    !verbose pop
3971  !endif
3972!macroend
3973
3974/**
3975 * Deletes shortcuts and Start Menu directories under Programs as specified by
3976 * the shortcuts log ini file and on Windows 7 unpins TaskBar and Start Menu
3977 * shortcuts. The shortcuts will not be deleted if the shortcut target isn't for
3978 * this install location which is determined by the shortcut having a target of
3979 * $INSTDIR\${FileMainEXE}. The context (All Users or Current User) of the
3980 * $DESKTOP and $SMPROGRAMS constants depends on the
3981 * SetShellVarContext setting and must be set by the caller of this macro. There
3982 * is no All Users context for $QUICKLAUNCH but this will not cause a problem
3983 * since the macro will just continue past the $QUICKLAUNCH shortcut deletion
3984 * section on subsequent calls.
3985 *
3986 * The ini file sections must have the following format (the order of the
3987 * sections in the ini file is not important):
3988 * [SMPROGRAMS]
3989 * ; RelativePath is the directory relative from the Start Menu
3990 * ; Programs directory.
3991 * RelativePath=Mozilla App
3992 * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so
3993 * ; on. There must not be a break in the sequence of the numbers.
3994 * Shortcut1=Mozilla App.lnk
3995 * Shortcut2=Mozilla App (Safe Mode).lnk
3996 * [DESKTOP]
3997 * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so
3998 * ; on. There must not be a break in the sequence of the numbers.
3999 * Shortcut1=Mozilla App.lnk
4000 * Shortcut2=Mozilla App (Safe Mode).lnk
4001 * [QUICKLAUNCH]
4002 * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so
4003 * ; on. There must not be a break in the sequence of the numbers for the
4004 * ; suffix.
4005 * Shortcut1=Mozilla App.lnk
4006 * Shortcut2=Mozilla App (Safe Mode).lnk
4007 * [STARTMENU]
4008 * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so
4009 * ; on. There must not be a break in the sequence of the numbers for the
4010 * ; suffix.
4011 * Shortcut1=Mozilla App.lnk
4012 * Shortcut2=Mozilla App (Safe Mode).lnk
4013 *
4014 * $R4 = counter for appending to Shortcut for enumerating the ini file entries
4015 * $R5 = return value from ShellLink::GetShortCutTarget and
4016 *       ApplicationID::UninstallPinnedItem
4017 * $R6 = find handle and the long path to the Start Menu Programs directory
4018 *       (e.g. $SMPROGRAMS)
4019 * $R7 = path to the $QUICKLAUNCH\User Pinned directory and the return value
4020 *       from ReadINIStr for the relative path to the applications directory
4021 *       under the Start Menu Programs directory and the long path to this
4022 *       directory
4023 * $R8 = return filename from FindFirst / FindNext and the return value from
4024 *       ReadINIStr for enumerating shortcuts
4025 * $R9 = long path to the shortcuts log ini file
4026 */
4027!macro DeleteShortcuts
4028
4029  !ifndef ${_MOZFUNC_UN}DeleteShortcuts
4030    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
4031    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
4032    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
4033    !undef _MOZFUNC_UN
4034    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
4035    !undef _MOZFUNC_UN_TMP
4036
4037    !verbose push
4038    !verbose ${_MOZFUNC_VERBOSE}
4039    !define ${_MOZFUNC_UN}DeleteShortcuts "!insertmacro ${_MOZFUNC_UN}DeleteShortcutsCall"
4040
4041    Function ${_MOZFUNC_UN}DeleteShortcuts
4042      Push $R9
4043      Push $R8
4044      Push $R7
4045      Push $R6
4046      Push $R5
4047      Push $R4
4048
4049      ${If} ${AtLeastWin7}
4050        ; Since shortcuts that are pinned can later be removed without removing
4051        ; the pinned shortcut unpin the pinned shortcuts for the application's
4052        ; main exe using the pinned shortcuts themselves.
4053        StrCpy $R7 "$QUICKLAUNCH\User Pinned"
4054
4055        ${If} ${FileExists} "$R7\TaskBar"
4056          ; Delete TaskBar pinned shortcuts for the application's main exe
4057          FindFirst $R6 $R8 "$R7\TaskBar\*.lnk"
4058          ${Do}
4059            ${If} ${FileExists} "$R7\TaskBar\$R8"
4060              ShellLink::GetShortCutTarget "$R7\TaskBar\$R8"
4061              Pop $R5
4062              ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
4063              ${If} "$R5" == "$INSTDIR\${FileMainEXE}"
4064                ApplicationID::UninstallPinnedItem "$R7\TaskBar\$R8"
4065                Pop $R5
4066              ${EndIf}
4067            ${EndIf}
4068            ClearErrors
4069            FindNext $R6 $R8
4070            ${If} ${Errors}
4071              ${ExitDo}
4072            ${EndIf}
4073          ${Loop}
4074          FindClose $R6
4075        ${EndIf}
4076
4077        ${If} ${FileExists} "$R7\StartMenu"
4078          ; Delete Start Menu pinned shortcuts for the application's main exe
4079          FindFirst $R6 $R8 "$R7\StartMenu\*.lnk"
4080          ${Do}
4081            ${If} ${FileExists} "$R7\StartMenu\$R8"
4082              ShellLink::GetShortCutTarget "$R7\StartMenu\$R8"
4083              Pop $R5
4084              ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
4085              ${If} "$R5" == "$INSTDIR\${FileMainEXE}"
4086                  ApplicationID::UninstallPinnedItem "$R7\StartMenu\$R8"
4087                  Pop $R5
4088              ${EndIf}
4089            ${EndIf}
4090            ClearErrors
4091            FindNext $R6 $R8
4092            ${If} ${Errors}
4093              ${ExitDo}
4094            ${EndIf}
4095          ${Loop}
4096          FindClose $R6
4097        ${EndIf}
4098      ${EndIf}
4099
4100      ; Don't call ApplicationID::UninstallPinnedItem since pinned items for
4101      ; this application were removed above and removing them below will remove
4102      ; the association of side by side installations.
4103      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" $R9
4104      ${If} ${FileExists} "$R9"
4105        ; Delete Start Menu shortcuts for this application
4106        StrCpy $R4 -1
4107        ${Do}
4108          IntOp $R4 $R4 + 1 ; Increment the counter
4109          ClearErrors
4110          ReadINIStr $R8 "$R9" "STARTMENU" "Shortcut$R4"
4111          ${If} ${Errors}
4112            ${ExitDo}
4113          ${EndIf}
4114
4115          ${If} ${FileExists} "$SMPROGRAMS\$R8"
4116            ShellLink::GetShortCutTarget "$SMPROGRAMS\$R8"
4117            Pop $R5
4118            ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
4119            ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
4120              Delete "$SMPROGRAMS\$R8"
4121            ${EndIf}
4122          ${EndIf}
4123        ${Loop}
4124        ; There might also be a shortcut with a different name created by a
4125        ; previous version of the installer.
4126        ${If} ${FileExists} "$SMPROGRAMS\${BrandFullName}.lnk"
4127          ShellLink::GetShortCutTarget "$SMPROGRAMS\${BrandFullName}.lnk"
4128          Pop $R5
4129          ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
4130          ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
4131            Delete "$SMPROGRAMS\${BrandFullName}.lnk"
4132          ${EndIf}
4133        ${EndIf}
4134
4135        ; Delete Quick Launch shortcuts for this application
4136        StrCpy $R4 -1
4137        ${Do}
4138          IntOp $R4 $R4 + 1 ; Increment the counter
4139          ClearErrors
4140          ReadINIStr $R8 "$R9" "QUICKLAUNCH" "Shortcut$R4"
4141          ${If} ${Errors}
4142            ${ExitDo}
4143          ${EndIf}
4144
4145          ${If} ${FileExists} "$QUICKLAUNCH\$R8"
4146            ShellLink::GetShortCutTarget "$QUICKLAUNCH\$R8"
4147            Pop $R5
4148            ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
4149            ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
4150              Delete "$QUICKLAUNCH\$R8"
4151            ${EndIf}
4152          ${EndIf}
4153        ${Loop}
4154        ; There might also be a shortcut with a different name created by a
4155        ; previous version of the installer.
4156        ${If} ${FileExists} "$QUICKLAUNCH\${BrandFullName}.lnk"
4157          ShellLink::GetShortCutTarget "$QUICKLAUNCH\${BrandFullName}.lnk"
4158          Pop $R5
4159          ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
4160          ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
4161            Delete "$QUICKLAUNCH\${BrandFullName}.lnk"
4162          ${EndIf}
4163        ${EndIf}
4164
4165        ; Delete Desktop shortcuts for this application
4166        StrCpy $R4 -1
4167        ${Do}
4168          IntOp $R4 $R4 + 1 ; Increment the counter
4169          ClearErrors
4170          ReadINIStr $R8 "$R9" "DESKTOP" "Shortcut$R4"
4171          ${If} ${Errors}
4172            ${ExitDo}
4173          ${EndIf}
4174
4175          ${If} ${FileExists} "$DESKTOP\$R8"
4176            ShellLink::GetShortCutTarget "$DESKTOP\$R8"
4177            Pop $R5
4178            ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
4179            ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
4180              Delete "$DESKTOP\$R8"
4181            ${EndIf}
4182          ${EndIf}
4183        ${Loop}
4184        ; There might also be a shortcut with a different name created by a
4185        ; previous version of the installer.
4186        ${If} ${FileExists} "$DESKTOP\${BrandFullName}.lnk"
4187          ShellLink::GetShortCutTarget "$DESKTOP\${BrandFullName}.lnk"
4188          Pop $R5
4189          ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
4190          ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
4191            Delete "$DESKTOP\${BrandFullName}.lnk"
4192          ${EndIf}
4193        ${EndIf}
4194
4195        ${${_MOZFUNC_UN}GetLongPath} "$SMPROGRAMS" $R6
4196
4197        ; Delete Start Menu Programs shortcuts for this application
4198        ClearErrors
4199        ReadINIStr $R7 "$R9" "SMPROGRAMS" "RelativePathToDir"
4200        ${${_MOZFUNC_UN}GetLongPath} "$R6\$R7" $R7
4201        ${Unless} "$R7" == ""
4202          StrCpy $R4 -1
4203          ${Do}
4204            IntOp $R4 $R4 + 1 ; Increment the counter
4205            ClearErrors
4206            ReadINIStr $R8 "$R9" "SMPROGRAMS" "Shortcut$R4"
4207            ${If} ${Errors}
4208              ${ExitDo}
4209            ${EndIf}
4210
4211            ${If} ${FileExists} "$R7\$R8"
4212              ShellLink::GetShortCutTarget "$R7\$R8"
4213              Pop $R5
4214              ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5
4215              ${If} "$INSTDIR\${FileMainEXE}" == "$R5"
4216                Delete "$R7\$R8"
4217              ${EndIf}
4218            ${EndIf}
4219          ${Loop}
4220
4221          ; Delete Start Menu Programs directories for this application
4222          ${Do}
4223            ClearErrors
4224            ${If} "$R6" == "$R7"
4225              ${ExitDo}
4226            ${EndIf}
4227            RmDir "$R7"
4228            ${If} ${Errors}
4229              ${ExitDo}
4230            ${EndIf}
4231            ${${_MOZFUNC_UN}GetParent} "$R7" $R7
4232          ${Loop}
4233        ${EndUnless}
4234      ${EndIf}
4235
4236      ClearErrors
4237
4238      Pop $R4
4239      Pop $R5
4240      Pop $R6
4241      Pop $R7
4242      Pop $R8
4243      Pop $R9
4244    FunctionEnd
4245
4246    !verbose pop
4247  !endif
4248!macroend
4249
4250!macro DeleteShortcutsCall
4251  !verbose push
4252  !verbose ${_MOZFUNC_VERBOSE}
4253  Call DeleteShortcuts
4254  !verbose pop
4255!macroend
4256
4257!macro un.DeleteShortcutsCall
4258  !verbose push
4259  !verbose ${_MOZFUNC_VERBOSE}
4260  Call un.DeleteShortcuts
4261  !verbose pop
4262!macroend
4263
4264!macro un.DeleteShortcuts
4265  !ifndef un.DeleteShortcuts
4266    !verbose push
4267    !verbose ${_MOZFUNC_VERBOSE}
4268    !undef _MOZFUNC_UN
4269    !define _MOZFUNC_UN "un."
4270
4271    !insertmacro DeleteShortcuts
4272
4273    !undef _MOZFUNC_UN
4274    !define _MOZFUNC_UN
4275    !verbose pop
4276  !endif
4277!macroend
4278
4279
4280################################################################################
4281# Macros for parsing and updating the uninstall.log
4282
4283/**
4284 * Updates the uninstall.log with new files added by software update.
4285 *
4286 * When modifying this macro be aware that LineFind uses all registers except
4287 * $R0-$R3 and TextCompareNoDetails uses all registers except $R0-$R9 so be
4288 * cautious. Callers of this macro are not affected.
4289 */
4290!macro UpdateUninstallLog
4291
4292  !ifndef UpdateUninstallLog
4293    !insertmacro FileJoin
4294    !insertmacro LineFind
4295    !insertmacro TextCompareNoDetails
4296    !insertmacro TrimNewLines
4297
4298    !verbose push
4299    !verbose ${_MOZFUNC_VERBOSE}
4300    !define UpdateUninstallLog "!insertmacro UpdateUninstallLogCall"
4301
4302    Function UpdateUninstallLog
4303      Push $R3
4304      Push $R2
4305      Push $R1
4306      Push $R0
4307
4308      ClearErrors
4309
4310      GetFullPathName $R3 "$INSTDIR\uninstall"
4311      ${If} ${FileExists} "$R3\uninstall.update"
4312        ${LineFind} "$R3\uninstall.update" "" "1:-1" "CleanupUpdateLog"
4313
4314        GetTempFileName $R2 "$R3"
4315        FileOpen $R1 "$R2" w
4316        ${TextCompareNoDetails} "$R3\uninstall.update" "$R3\uninstall.log" "SlowDiff" "CreateUpdateDiff"
4317        FileClose $R1
4318
4319        IfErrors +2 0
4320        ${FileJoin} "$R3\uninstall.log" "$R2" "$R3\uninstall.log"
4321
4322        ${DeleteFile} "$R2"
4323      ${EndIf}
4324
4325      ClearErrors
4326
4327      Pop $R0
4328      Pop $R1
4329      Pop $R2
4330      Pop $R3
4331    FunctionEnd
4332
4333    ; This callback MUST use labels vs. relative line numbers.
4334    Function CleanupUpdateLog
4335      StrCpy $R2 "$R9" 12
4336      StrCmp "$R2" "EXECUTE ADD " +1 skip
4337      StrCpy $R9 "$R9" "" 12
4338
4339      Push $R6
4340      Push $R5
4341      Push $R4
4342      StrCpy $R4 ""         ; Initialize to an empty string.
4343      StrCpy $R6 -1         ; Set the counter to -1 so it will start at 0.
4344
4345      loop:
4346      IntOp $R6 $R6 + 1     ; Increment the counter.
4347      StrCpy $R5 $R9 1 $R6  ; Starting from the counter copy the next char.
4348      StrCmp $R5 "" copy    ; Are there no more chars?
4349      StrCmp $R5 "/" +1 +2  ; Is the char a /?
4350      StrCpy $R5 "\"        ; Replace the char with a \.
4351
4352      StrCpy $R4 "$R4$R5"
4353      GoTo loop
4354
4355      copy:
4356      StrCpy $R9 "File: \$R4"
4357      Pop $R6
4358      Pop $R5
4359      Pop $R4
4360      GoTo end
4361
4362      skip:
4363      StrCpy $0 "SkipWrite"
4364
4365      end:
4366      Push $0
4367    FunctionEnd
4368
4369    Function CreateUpdateDiff
4370      ${TrimNewLines} "$9" $9
4371      ${If} $9 != ""
4372        FileWrite $R1 "$9$\r$\n"
4373      ${EndIf}
4374
4375      Push 0
4376    FunctionEnd
4377
4378    !verbose pop
4379  !endif
4380!macroend
4381
4382!macro UpdateUninstallLogCall
4383  !verbose push
4384  !verbose ${_MOZFUNC_VERBOSE}
4385  Call UpdateUninstallLog
4386  !verbose pop
4387!macroend
4388
4389/**
4390 * Copies files from a source directory to a destination directory with logging
4391 * to the uninstall.log. If any destination files are in use a reboot will be
4392 * necessary to complete the installation and the reboot flag (see IfRebootFlag
4393 * in the NSIS documentation).
4394 *
4395 * @param   _PATH_TO_SOURCE
4396 *          Source path to copy the files from. This must not end with a \.
4397 *
4398 * @param   _PATH_TO_DESTINATION
4399 *          Destination path to copy the files to. This must not end with a \.
4400 *
4401 * @param   _PREFIX_ERROR_CREATEDIR
4402 *          Prefix for the directory creation error message. The directory path
4403 *          will be inserted below this string.
4404 *
4405 * @param   _SUFFIX_ERROR_CREATEDIR
4406 *          Suffix for the directory creation error message. The directory path
4407 *          will be inserted above this string.
4408 *
4409 * $0  = destination file's parent directory used in the create_dir label
4410 * $R0 = copied value from $R6 (e.g. _PATH_TO_SOURCE)
4411 * $R1 = copied value from $R7 (e.g. _PATH_TO_DESTINATION)
4412 * $R2 = string length of the path to source
4413 * $R3 = relative path from the path to source
4414 * $R4 = copied value from $R8 (e.g. _PREFIX_ERROR_CREATEDIR)
4415 * $R5 = copied value from $R9 (e.g. _SUFFIX_ERROR_CREATEDIR)
4416 * note: the LocateNoDetails macro uses these registers so we copy the values
4417 *       to other registers.
4418 * $R6 = initially _PATH_TO_SOURCE and then set to "size" ($R6="" if directory,
4419 *       $R6="0" if file with /S=)"path\name" in callback
4420 * $R7 = initially _PATH_TO_DESTINATION and then set to "name" in callback
4421 * $R8 = initially _PREFIX_ERROR_CREATEDIR and then set to "path" in callback
4422 * $R9 = initially _SUFFIX_ERROR_CREATEDIR and then set to "path\name" in
4423 *       callback
4424 */
4425!macro CopyFilesFromDir
4426
4427  !ifndef CopyFilesFromDir
4428    !insertmacro LocateNoDetails
4429    !insertmacro OnEndCommon
4430    !insertmacro WordReplace
4431
4432    !verbose push
4433    !verbose ${_MOZFUNC_VERBOSE}
4434    !define CopyFilesFromDir "!insertmacro CopyFilesFromDirCall"
4435
4436    Function CopyFilesFromDir
4437      Exch $R9
4438      Exch 1
4439      Exch $R8
4440      Exch 2
4441      Exch $R7
4442      Exch 3
4443      Exch $R6
4444      Push $R5
4445      Push $R4
4446      Push $R3
4447      Push $R2
4448      Push $R1
4449      Push $R0
4450      Push $0
4451
4452      StrCpy $R0 "$R6"
4453      StrCpy $R1 "$R7"
4454      StrCpy $R4 "$R8"
4455      StrCpy $R5 "$R9"
4456
4457      StrLen $R2 "$R0"
4458
4459      ${LocateNoDetails} "$R0" "/L=FD" "CopyFileCallback"
4460
4461      Pop $0
4462      Pop $R0
4463      Pop $R1
4464      Pop $R2
4465      Pop $R3
4466      Pop $R4
4467      Pop $R5
4468      Exch $R6
4469      Exch 3
4470      Exch $R7
4471      Exch 2
4472      Exch $R8
4473      Exch 1
4474      Exch $R9
4475    FunctionEnd
4476
4477    Function CopyFileCallback
4478      StrCpy $R3 $R8 "" $R2 ; $R3 always begins with a \.
4479
4480      retry:
4481      ClearErrors
4482      StrCmp $R6 "" +1 copy_file
4483      IfFileExists "$R1$R3\$R7" end +1
4484      StrCpy $0 "$R1$R3\$R7"
4485
4486      create_dir:
4487      ClearErrors
4488      CreateDirectory "$0"
4489      IfFileExists "$0" +1 err_create_dir  ; protect against looping.
4490      ${LogMsg} "Created Directory: $0"
4491      StrCmp $R6 "" end copy_file
4492
4493      err_create_dir:
4494      ${LogMsg} "** ERROR Creating Directory: $0 **"
4495      MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$R4$\r$\n$\r$\n$0$\r$\n$\r$\n$R5" IDRETRY retry
4496      ${OnEndCommon}
4497      Quit
4498
4499      copy_file:
4500      StrCpy $0 "$R1$R3"
4501      StrCmp "$0" "$INSTDIR" +2 +1
4502      IfFileExists "$0" +1 create_dir
4503
4504      ClearErrors
4505      ${DeleteFile} "$R1$R3\$R7"
4506      IfErrors +1 dest_clear
4507      ClearErrors
4508      Rename "$R1$R3\$R7" "$R1$R3\$R7.moz-delete"
4509      IfErrors +1 reboot_delete
4510
4511      ; file will replace destination file on reboot
4512      Rename "$R9" "$R9.moz-upgrade"
4513      CopyFiles /SILENT "$R9.moz-upgrade" "$R1$R3"
4514      Rename /REBOOTOK "$R1$R3\$R7.moz-upgrade" "$R1$R3\$R7"
4515      ${LogMsg} "Copied File: $R1$R3\$R7.moz-upgrade"
4516      ${LogMsg} "Delayed Install File (Reboot Required): $R1$R3\$R7"
4517      GoTo log_uninstall
4518
4519      ; file will be deleted on reboot
4520      reboot_delete:
4521      CopyFiles /SILENT $R9 "$R1$R3"
4522      Delete /REBOOTOK "$R1$R3\$R7.moz-delete"
4523      ${LogMsg} "Installed File: $R1$R3\$R7"
4524      ${LogMsg} "Delayed Delete File (Reboot Required): $R1$R3\$R7.moz-delete"
4525      GoTo log_uninstall
4526
4527      ; destination file doesn't exist - coast is clear
4528      dest_clear:
4529      CopyFiles /SILENT $R9 "$R1$R3"
4530      ${LogMsg} "Installed File: $R1$R3\$R7"
4531
4532      log_uninstall:
4533      ; If the file is installed into the installation directory remove the
4534      ; installation directory's path from the file path when writing to the
4535      ; uninstall.log so it will be a relative path. This allows the same
4536      ; helper.exe to be used with zip builds if we supply an uninstall.log.
4537      ${WordReplace} "$R1$R3\$R7" "$INSTDIR" "" "+" $R3
4538      ${LogUninstall} "File: $R3"
4539
4540      end:
4541      Push 0
4542    FunctionEnd
4543
4544    !verbose pop
4545  !endif
4546!macroend
4547
4548!macro CopyFilesFromDirCall _PATH_TO_SOURCE _PATH_TO_DESTINATION \
4549                            _PREFIX_ERROR_CREATEDIR _SUFFIX_ERROR_CREATEDIR
4550  !verbose push
4551  !verbose ${_MOZFUNC_VERBOSE}
4552  Push "${_PATH_TO_SOURCE}"
4553  Push "${_PATH_TO_DESTINATION}"
4554  Push "${_PREFIX_ERROR_CREATEDIR}"
4555  Push "${_SUFFIX_ERROR_CREATEDIR}"
4556  Call CopyFilesFromDir
4557  !verbose pop
4558!macroend
4559
4560/**
4561 * Parses the uninstall.log on install to first remove a previous installation's
4562 * files and then their directories if empty prior to installing.
4563 *
4564 * When modifying this macro be aware that LineFind uses all registers except
4565 * $R0-$R3 so be cautious. Callers of this macro are not affected.
4566 */
4567!macro OnInstallUninstall
4568
4569  !ifndef OnInstallUninstall
4570    !insertmacro GetParent
4571    !insertmacro LineFind
4572    !insertmacro TrimNewLines
4573
4574    !verbose push
4575    !verbose ${_MOZFUNC_VERBOSE}
4576    !define OnInstallUninstall "!insertmacro OnInstallUninstallCall"
4577
4578    Function OnInstallUninstall
4579      Push $R9
4580      Push $R8
4581      Push $R7
4582      Push $R6
4583      Push $R5
4584      Push $R4
4585      Push $R3
4586      Push $R2
4587      Push $R1
4588      Push $R0
4589      Push $TmpVal
4590
4591      IfFileExists "$INSTDIR\uninstall\uninstall.log" +1 end
4592
4593      ${LogHeader} "Removing Previous Installation"
4594
4595      ; Copy the uninstall log file to a temporary file
4596      GetTempFileName $TmpVal
4597      CopyFiles /SILENT /FILESONLY "$INSTDIR\uninstall\uninstall.log" "$TmpVal"
4598
4599      ; Delete files
4600      ${LineFind} "$TmpVal" "/NUL" "1:-1" "RemoveFilesCallback"
4601
4602      ; Remove empty directories
4603      ${LineFind} "$TmpVal" "/NUL" "1:-1" "RemoveDirsCallback"
4604
4605      ; Delete the temporary uninstall log file
4606      Delete /REBOOTOK "$TmpVal"
4607
4608      ; Delete the uninstall log file
4609      Delete "$INSTDIR\uninstall\uninstall.log"
4610
4611      end:
4612      ClearErrors
4613
4614      Pop $TmpVal
4615      Pop $R0
4616      Pop $R1
4617      Pop $R2
4618      Pop $R3
4619      Pop $R4
4620      Pop $R5
4621      Pop $R6
4622      Pop $R7
4623      Pop $R8
4624      Pop $R9
4625    FunctionEnd
4626
4627    Function RemoveFilesCallback
4628      ${TrimNewLines} "$R9" $R9
4629      StrCpy $R1 "$R9" 5       ; Copy the first five chars
4630
4631      StrCmp "$R1" "File:" +1 end
4632      StrCpy $R9 "$R9" "" 6    ; Copy string starting after the 6th char
4633      StrCpy $R0 "$R9" 1       ; Copy the first char
4634
4635      StrCmp "$R0" "\" +1 end  ; If this isn't a relative path goto end
4636      StrCmp "$R9" "\install.log" end +1 ; Skip the install.log
4637      StrCmp "$R9" "\MapiProxy_InUse.dll" end +1 ; Skip the MapiProxy_InUse.dll
4638      StrCmp "$R9" "\mozMapi32_InUse.dll" end +1 ; Skip the mozMapi32_InUse.dll
4639
4640      StrCpy $R1 "$INSTDIR$R9" ; Copy the install dir path and suffix it with the string
4641      IfFileExists "$R1" +1 end
4642
4643      ClearErrors
4644      Delete "$R1"
4645      ${Unless} ${Errors}
4646        ${LogMsg} "Deleted File: $R1"
4647        Goto end
4648      ${EndUnless}
4649
4650      ClearErrors
4651      Rename "$R1" "$R1.moz-delete"
4652      ${Unless} ${Errors}
4653        Delete /REBOOTOK "$R1.moz-delete"
4654        ${LogMsg} "Delayed Delete File (Reboot Required): $R1.moz-delete"
4655        GoTo end
4656      ${EndUnless}
4657
4658      ; Check if the file exists in the source. If it does the new file will
4659      ; replace the existing file when the system is rebooted. If it doesn't
4660      ; the file will be deleted when the system is rebooted.
4661      ${Unless} ${FileExists} "$EXEDIR\core$R9"
4662      ${AndUnless}  ${FileExists} "$EXEDIR\optional$R9"
4663        Delete /REBOOTOK "$R1"
4664        ${LogMsg} "Delayed Delete File (Reboot Required): $R1"
4665      ${EndUnless}
4666
4667      end:
4668      ClearErrors
4669
4670      Push 0
4671    FunctionEnd
4672
4673    ; Using locate will leave file handles open to some of the directories
4674    ; which will prevent the deletion of these directories. This parses the
4675    ; uninstall.log and uses the file entries to find / remove empty
4676    ; directories.
4677    Function RemoveDirsCallback
4678      ${TrimNewLines} "$R9" $R9
4679      StrCpy $R0 "$R9" 5          ; Copy the first five chars
4680      StrCmp "$R0" "File:" +1 end
4681
4682      StrCpy $R9 "$R9" "" 6       ; Copy string starting after the 6th char
4683      StrCpy $R0 "$R9" 1          ; Copy the first char
4684
4685      StrCpy $R1 "$INSTDIR$R9"    ; Copy the install dir path and suffix it with the string
4686      StrCmp "$R0" "\" loop end   ; If this isn't a relative path goto end
4687
4688      loop:
4689      ${GetParent} "$R1" $R1         ; Get the parent directory for the path
4690      StrCmp "$R1" "$INSTDIR" end +1 ; If the directory is the install dir goto end
4691
4692      IfFileExists "$R1" +1 loop  ; Only try to remove the dir if it exists
4693      ClearErrors
4694      RmDir "$R1"     ; Remove the dir
4695      IfErrors end +1  ; If we fail there is no use trying to remove its parent dir
4696      ${LogMsg} "Deleted Directory: $R1"
4697      GoTo loop
4698
4699      end:
4700      ClearErrors
4701
4702      Push 0
4703    FunctionEnd
4704
4705    !verbose pop
4706  !endif
4707!macroend
4708
4709!macro OnInstallUninstallCall
4710  !verbose push
4711  !verbose ${_MOZFUNC_VERBOSE}
4712  Call OnInstallUninstall
4713  !verbose pop
4714!macroend
4715
4716/**
4717 * Parses the precomplete file to remove an installation's files and
4718 * directories.
4719 *
4720 * @param   _CALLBACK
4721 *          The function address of a callback function for progress or "false"
4722 *          if there is no callback function.
4723 *
4724 * $R3 = false if all files were deleted or moved to the tobedeleted directory.
4725 *       true if file(s) could not be moved to the tobedeleted directory.
4726 * $R4 = Path to temporary precomplete file.
4727 * $R5 = File handle for the temporary precomplete file.
4728 * $R6 = String returned from FileRead.
4729 * $R7 = First seven characters of the string returned from FileRead.
4730 * $R8 = Temporary file path used to rename files that are in use.
4731 * $R9 = _CALLBACK
4732 */
4733!macro RemovePrecompleteEntries
4734
4735  !ifndef ${_MOZFUNC_UN}RemovePrecompleteEntries
4736    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
4737    !insertmacro ${_MOZFUNC_UN_TMP}GetParent
4738    !insertmacro ${_MOZFUNC_UN_TMP}TrimNewLines
4739    !insertmacro ${_MOZFUNC_UN_TMP}WordReplace
4740    !undef _MOZFUNC_UN
4741    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
4742    !undef _MOZFUNC_UN_TMP
4743
4744    !verbose push
4745    !verbose ${_MOZFUNC_VERBOSE}
4746    !define ${_MOZFUNC_UN}RemovePrecompleteEntries "!insertmacro ${_MOZFUNC_UN}RemovePrecompleteEntriesCall"
4747
4748    Function ${_MOZFUNC_UN}RemovePrecompleteEntries
4749      Exch $R9
4750      Push $R8
4751      Push $R7
4752      Push $R6
4753      Push $R5
4754      Push $R4
4755      Push $R3
4756
4757      ${If} ${FileExists} "$INSTDIR\precomplete"
4758        StrCpy $R3 "false"
4759
4760        RmDir /r "$INSTDIR\${TO_BE_DELETED}"
4761        CreateDirectory "$INSTDIR\${TO_BE_DELETED}"
4762        GetTempFileName $R4 "$INSTDIR\${TO_BE_DELETED}"
4763        Delete "$R4"
4764        Rename "$INSTDIR\precomplete" "$R4"
4765
4766        ClearErrors
4767        ; Rename and then remove files
4768        FileOpen $R5 "$R4" r
4769        ${Do}
4770          FileRead $R5 $R6
4771          ${If} ${Errors}
4772            ${Break}
4773          ${EndIf}
4774
4775          ${${_MOZFUNC_UN}TrimNewLines} "$R6" $R6
4776          ; Replace all occurrences of "/" with "\".
4777          ${${_MOZFUNC_UN}WordReplace} "$R6" "/" "\" "+" $R6
4778
4779          ; Copy the first 7 chars
4780          StrCpy $R7 "$R6" 7
4781          ${If} "$R7" == "remove "
4782            ; Copy the string starting after the 8th char
4783            StrCpy $R6 "$R6" "" 8
4784            ; Copy all but the last char to remove the double quote.
4785            StrCpy $R6 "$R6" -1
4786            ${If} ${FileExists} "$INSTDIR\$R6"
4787              ${Unless} "$R9" == "false"
4788                Call $R9
4789              ${EndUnless}
4790
4791              ClearErrors
4792              Delete "$INSTDIR\$R6"
4793              ${If} ${Errors}
4794                GetTempFileName $R8 "$INSTDIR\${TO_BE_DELETED}"
4795                Delete "$R8"
4796                ClearErrors
4797                Rename "$INSTDIR\$R6" "$R8"
4798                ${Unless} ${Errors}
4799                  Delete /REBOOTOK "$R8"
4800
4801                  ClearErrors
4802                ${EndUnless}
4803!ifdef __UNINSTALL__
4804                ${If} ${Errors}
4805                  Delete /REBOOTOK "$INSTDIR\$R6"
4806                  StrCpy $R3 "true"
4807                  ClearErrors
4808                ${EndIf}
4809!endif
4810              ${EndIf}
4811            ${EndIf}
4812          ${ElseIf} "$R7" == "rmdir $\""
4813            ; Copy the string starting after the 7th char.
4814            StrCpy $R6 "$R6" "" 7
4815            ; Copy all but the last two chars to remove the slash and the double quote.
4816            StrCpy $R6 "$R6" -2
4817            ${If} ${FileExists} "$INSTDIR\$R6"
4818              ; Ignore directory removal errors
4819              RmDir "$INSTDIR\$R6"
4820              ClearErrors
4821            ${EndIf}
4822          ${EndIf}
4823        ${Loop}
4824        FileClose $R5
4825
4826        ; Delete the temporary precomplete file
4827        Delete /REBOOTOK "$R4"
4828
4829        RmDir /r /REBOOTOK "$INSTDIR\${TO_BE_DELETED}"
4830
4831        ${If} ${RebootFlag}
4832        ${AndIf} "$R3" == "false"
4833          ; Clear the reboot flag if all files were deleted or moved to the
4834          ; tobedeleted directory.
4835          SetRebootFlag false
4836        ${EndIf}
4837      ${EndIf}
4838
4839      ClearErrors
4840
4841      Pop $R3
4842      Pop $R4
4843      Pop $R5
4844      Pop $R6
4845      Pop $R7
4846      Pop $R8
4847      Exch $R9
4848    FunctionEnd
4849
4850    !verbose pop
4851  !endif
4852!macroend
4853
4854!macro RemovePrecompleteEntriesCall _CALLBACK
4855  !verbose push
4856  Push "${_CALLBACK}"
4857  !verbose ${_MOZFUNC_VERBOSE}
4858  Call RemovePrecompleteEntries
4859  !verbose pop
4860!macroend
4861
4862!macro un.RemovePrecompleteEntriesCall _CALLBACK
4863  !verbose push
4864  !verbose ${_MOZFUNC_VERBOSE}
4865  Push "${_CALLBACK}"
4866  Call un.RemovePrecompleteEntries
4867  !verbose pop
4868!macroend
4869
4870!macro un.RemovePrecompleteEntries
4871  !ifndef un.RemovePrecompleteEntries
4872    !verbose push
4873    !verbose ${_MOZFUNC_VERBOSE}
4874    !undef _MOZFUNC_UN
4875    !define _MOZFUNC_UN "un."
4876
4877    !insertmacro RemovePrecompleteEntries
4878
4879    !undef _MOZFUNC_UN
4880    !define _MOZFUNC_UN
4881    !verbose pop
4882  !endif
4883!macroend
4884
4885/**
4886 * Parses the uninstall.log to unregister dll's, remove files, and remove
4887 * empty directories for this installation.
4888 *
4889 * When modifying this macro be aware that LineFind uses all registers except
4890 * $R0-$R3 so be cautious. Callers of this macro are not affected.
4891 */
4892!macro un.ParseUninstallLog
4893
4894  !ifndef un.ParseUninstallLog
4895    !insertmacro un.GetParent
4896    !insertmacro un.LineFind
4897    !insertmacro un.TrimNewLines
4898
4899    !verbose push
4900    !verbose ${_MOZFUNC_VERBOSE}
4901    !define un.ParseUninstallLog "!insertmacro un.ParseUninstallLogCall"
4902
4903    Function un.ParseUninstallLog
4904      Push $R9
4905      Push $R8
4906      Push $R7
4907      Push $R6
4908      Push $R5
4909      Push $R4
4910      Push $R3
4911      Push $R2
4912      Push $R1
4913      Push $R0
4914      Push $TmpVal
4915
4916      IfFileExists "$INSTDIR\uninstall\uninstall.log" +1 end
4917
4918      ; Copy the uninstall log file to a temporary file
4919      GetTempFileName $TmpVal
4920      CopyFiles /SILENT /FILESONLY "$INSTDIR\uninstall\uninstall.log" "$TmpVal"
4921
4922      ; Unregister DLL's
4923      ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.UnRegDLLsCallback"
4924
4925      ; Delete files
4926      ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.RemoveFilesCallback"
4927
4928      ; Remove empty directories
4929      ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.RemoveDirsCallback"
4930
4931      ; Delete the temporary uninstall log file
4932      Delete /REBOOTOK "$TmpVal"
4933
4934      end:
4935
4936      Pop $TmpVal
4937      Pop $R0
4938      Pop $R1
4939      Pop $R2
4940      Pop $R3
4941      Pop $R4
4942      Pop $R5
4943      Pop $R6
4944      Pop $R7
4945      Pop $R8
4946      Pop $R9
4947    FunctionEnd
4948
4949    Function un.RemoveFilesCallback
4950      ${un.TrimNewLines} "$R9" $R9
4951      StrCpy $R1 "$R9" 5
4952
4953      StrCmp "$R1" "File:" +1 end
4954      StrCpy $R9 "$R9" "" 6
4955      StrCpy $R0 "$R9" 1
4956
4957      StrCpy $R1 "$INSTDIR$R9"
4958      StrCmp "$R0" "\" +2 +1
4959      StrCpy $R1 "$R9"
4960
4961      IfFileExists "$R1" +1 end
4962      Delete "$R1"
4963      IfErrors +1 end
4964      ClearErrors
4965      Rename "$R1" "$R1.moz-delete"
4966      IfErrors +1 +3
4967      Delete /REBOOTOK "$R1"
4968      GoTo end
4969
4970      Delete /REBOOTOK "$R1.moz-delete"
4971
4972      end:
4973      ClearErrors
4974
4975      Push 0
4976    FunctionEnd
4977
4978    Function un.UnRegDLLsCallback
4979      ${un.TrimNewLines} "$R9" $R9
4980      StrCpy $R1 "$R9" 7
4981
4982      StrCmp $R1 "DLLReg:" +1 end
4983      StrCpy $R9 "$R9" "" 8
4984      StrCpy $R0 "$R9" 1
4985
4986      StrCpy $R1 "$INSTDIR$R9"
4987      StrCmp $R0 "\" +2 +1
4988      StrCpy $R1 "$R9"
4989
4990      ${UnregisterDLL} $R1
4991
4992      end:
4993      ClearErrors
4994
4995      Push 0
4996    FunctionEnd
4997
4998    ; Using locate will leave file handles open to some of the directories
4999    ; which will prevent the deletion of these directories. This parses the
5000    ; uninstall.log and uses the file entries to find / remove empty
5001    ; directories.
5002    Function un.RemoveDirsCallback
5003      ${un.TrimNewLines} "$R9" $R9
5004      StrCpy $R0 "$R9" 5          ; Copy the first five chars
5005      StrCmp "$R0" "File:" +1 end
5006
5007      StrCpy $R9 "$R9" "" 6       ; Copy string starting after the 6th char
5008      StrCpy $R0 "$R9" 1          ; Copy the first char
5009
5010      StrCpy $R1 "$INSTDIR$R9"    ; Copy the install dir path and suffix it with the string
5011      StrCmp "$R0" "\" loop       ; If this is a relative path goto the loop
5012      StrCpy $R1 "$R9"            ; Already a full path so copy the string
5013
5014      loop:
5015      ${un.GetParent} "$R1" $R1   ; Get the parent directory for the path
5016      StrCmp "$R1" "$INSTDIR" end ; If the directory is the install dir goto end
5017
5018      ; We only try to remove empty directories but the Desktop, StartMenu, and
5019      ; QuickLaunch directories can be empty so guard against removing them.
5020      SetShellVarContext all          ; Set context to all users
5021      StrCmp "$R1" "$DESKTOP" end     ; All users desktop
5022      StrCmp "$R1" "$STARTMENU" end   ; All users start menu
5023
5024      SetShellVarContext current      ; Set context to all users
5025      StrCmp "$R1" "$DESKTOP" end     ; Current user desktop
5026      StrCmp "$R1" "$STARTMENU" end   ; Current user start menu
5027      StrCmp "$R1" "$QUICKLAUNCH" end ; Current user quick launch
5028
5029      IfFileExists "$R1" +1 +3  ; Only try to remove the dir if it exists
5030      ClearErrors
5031      RmDir "$R1"    ; Remove the dir
5032      IfErrors end   ; If we fail there is no use trying to remove its parent dir
5033
5034      StrCmp "$R0" "\" loop end  ; Only loop when the path is relative to the install dir
5035
5036      end:
5037      ClearErrors
5038
5039      Push 0
5040    FunctionEnd
5041
5042    !verbose pop
5043  !endif
5044!macroend
5045
5046!macro un.ParseUninstallLogCall
5047  !verbose push
5048  !verbose ${_MOZFUNC_VERBOSE}
5049  Call un.ParseUninstallLog
5050  !verbose pop
5051!macroend
5052
5053/**
5054 * Finds a valid Start Menu shortcut in the uninstall log and returns the
5055 * relative path from the Start Menu's Programs directory to the shortcut's
5056 * directory.
5057 *
5058 * When modifying this macro be aware that LineFind uses all registers except
5059 * $R0-$R3 so be cautious. Callers of this macro are not affected.
5060 *
5061 * @return  _REL_PATH_TO_DIR
5062 *          The relative path to the application's Start Menu directory from the
5063 *          Start Menu's Programs directory.
5064 */
5065!macro FindSMProgramsDir
5066
5067  !ifndef FindSMProgramsDir
5068    !insertmacro GetParent
5069    !insertmacro LineFind
5070    !insertmacro TrimNewLines
5071
5072    !verbose push
5073    !verbose ${_MOZFUNC_VERBOSE}
5074    !define FindSMProgramsDir "!insertmacro FindSMProgramsDirCall"
5075
5076    Function FindSMProgramsDir
5077      Exch $R3
5078      Push $R2
5079      Push $R1
5080      Push $R0
5081
5082      StrCpy $R3 ""
5083      ${If} ${FileExists} "$INSTDIR\uninstall\uninstall.log"
5084        ${LineFind} "$INSTDIR\uninstall\uninstall.log" "/NUL" "1:-1" "FindSMProgramsDirRelPath"
5085      ${EndIf}
5086      ClearErrors
5087
5088      Pop $R0
5089      Pop $R1
5090      Pop $R2
5091      Exch $R3
5092    FunctionEnd
5093
5094    ; This callback MUST use labels vs. relative line numbers.
5095    Function FindSMProgramsDirRelPath
5096      Push 0
5097      ${TrimNewLines} "$R9" $R9
5098      StrCpy $R4 "$R9" 5
5099
5100      StrCmp "$R4" "File:" +1 end_FindSMProgramsDirRelPath
5101      StrCpy $R9 "$R9" "" 6
5102      StrCpy $R4 "$R9" 1
5103
5104      StrCmp "$R4" "\" end_FindSMProgramsDirRelPath +1
5105
5106      SetShellVarContext all
5107      ${GetLongPath} "$SMPROGRAMS" $R4
5108      StrLen $R2 "$R4"
5109      StrCpy $R1 "$R9" $R2
5110      StrCmp "$R1" "$R4" +1 end_FindSMProgramsDirRelPath
5111      IfFileExists "$R9" +1 end_FindSMProgramsDirRelPath
5112      ShellLink::GetShortCutTarget "$R9"
5113      Pop $R0
5114      StrCmp "$INSTDIR\${FileMainEXE}" "$R0" +1 end_FindSMProgramsDirRelPath
5115      ${GetParent} "$R9" $R3
5116      IntOp $R2 $R2 + 1
5117      StrCpy $R3 "$R3" "" $R2
5118
5119      Pop $R4             ; Remove the previously pushed 0 from the stack and
5120      push "StopLineFind" ; push StopLineFind to stop finding more lines.
5121
5122      end_FindSMProgramsDirRelPath:
5123      ClearErrors
5124
5125    FunctionEnd
5126
5127    !verbose pop
5128  !endif
5129!macroend
5130
5131!macro FindSMProgramsDirCall _REL_PATH_TO_DIR
5132  !verbose push
5133  !verbose ${_MOZFUNC_VERBOSE}
5134  Call FindSMProgramsDir
5135  Pop ${_REL_PATH_TO_DIR}
5136  !verbose pop
5137!macroend
5138
5139
5140################################################################################
5141# Macros for custom branding
5142
5143/**
5144 * Sets BrandFullName and / or BrandShortName to values provided in the specified
5145 * ini file and defaults to BrandShortName and BrandFullName as defined in
5146 * branding.nsi when the associated ini file entry is not specified.
5147 *
5148 * ini file format:
5149 * [Branding]
5150 * BrandFullName=Custom Full Name
5151 * BrandShortName=Custom Short Name
5152 *
5153 * @param   _PATH_TO_INI
5154 *          Path to the ini file.
5155 *
5156 * $R6 = return value from ReadINIStr
5157 * $R7 = stores BrandShortName
5158 * $R8 = stores BrandFullName
5159 * $R9 = _PATH_TO_INI
5160 */
5161!macro SetBrandNameVars
5162
5163  !ifndef ${_MOZFUNC_UN}SetBrandNameVars
5164    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
5165    !insertmacro ${_MOZFUNC_UN_TMP}WordReplace
5166    !undef _MOZFUNC_UN
5167    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
5168    !undef _MOZFUNC_UN_TMP
5169
5170    ; Prevent declaring vars twice when the SetBrandNameVars macro is
5171    ; inserted into both the installer and uninstaller.
5172    !ifndef SetBrandNameVars
5173      Var BrandFullName
5174      Var BrandFullNameDA
5175      Var BrandShortName
5176      Var BrandProductName
5177    !endif
5178
5179    !verbose push
5180    !verbose ${_MOZFUNC_VERBOSE}
5181    !define ${_MOZFUNC_UN}SetBrandNameVars "!insertmacro ${_MOZFUNC_UN}SetBrandNameVarsCall"
5182
5183    Function ${_MOZFUNC_UN}SetBrandNameVars
5184      Exch $R9
5185      Push $R8
5186      Push $R7
5187      Push $R6
5188      Push $R5
5189
5190      StrCpy $R8 "${BrandFullName}"
5191      StrCpy $R7 "${BrandShortName}"
5192      StrCpy $R6 "${BrandProductName}"
5193
5194      IfFileExists "$R9" +1 finish
5195
5196      ClearErrors
5197      ReadINIStr $R5 $R9 "Branding" "BrandFullName"
5198      IfErrors +2 +1
5199      StrCpy $R8 "$R5"
5200
5201      ClearErrors
5202      ReadINIStr $R5 $R9 "Branding" "BrandShortName"
5203      IfErrors +2 +1
5204      StrCpy $R7 "$R5"
5205
5206      ClearErrors
5207      ReadINIStr $R5 $R9 "Branding" "BrandProductName"
5208      IfErrors +2 +1
5209      StrCpy $R6 "$R5"
5210
5211      finish:
5212      StrCpy $BrandFullName "$R8"
5213      ${${_MOZFUNC_UN}WordReplace} "$R8" "&" "&&" "+" $R8
5214      StrCpy $BrandFullNameDA "$R8"
5215      StrCpy $BrandShortName "$R7"
5216      StrCpy $BrandProductName "$R6"
5217
5218      Pop $R5
5219      Pop $R6
5220      Pop $R7
5221      Pop $R8
5222      Exch $R9
5223    FunctionEnd
5224
5225    !verbose pop
5226  !endif
5227!macroend
5228
5229!macro SetBrandNameVarsCall _PATH_TO_INI
5230  !verbose push
5231  !verbose ${_MOZFUNC_VERBOSE}
5232  Push "${_PATH_TO_INI}"
5233  Call SetBrandNameVars
5234  !verbose pop
5235!macroend
5236
5237!macro un.SetBrandNameVarsCall _PATH_TO_INI
5238  !verbose push
5239  !verbose ${_MOZFUNC_VERBOSE}
5240  Push "${_PATH_TO_INI}"
5241  Call un.SetBrandNameVars
5242  !verbose pop
5243!macroend
5244
5245!macro un.SetBrandNameVars
5246  !ifndef un.SetBrandNameVars
5247    !verbose push
5248    !verbose ${_MOZFUNC_VERBOSE}
5249    !undef _MOZFUNC_UN
5250    !define _MOZFUNC_UN "un."
5251
5252    !insertmacro SetBrandNameVars
5253
5254    !undef _MOZFUNC_UN
5255    !define _MOZFUNC_UN
5256    !verbose pop
5257  !endif
5258!macroend
5259
5260/**
5261 * Replaces the wizard's header image with the one specified.
5262 *
5263 * @param   _PATH_TO_IMAGE
5264 *          Fully qualified path to the bitmap to use for the header image.
5265 *
5266 * $R8 = hwnd for the control returned from GetDlgItem.
5267 * $R9 = _PATH_TO_IMAGE
5268 */
5269!macro ChangeMUIHeaderImage
5270
5271  !ifndef ${_MOZFUNC_UN}ChangeMUIHeaderImage
5272    Var hHeaderBitmap
5273
5274    !verbose push
5275    !verbose ${_MOZFUNC_VERBOSE}
5276    !define ${_MOZFUNC_UN}ChangeMUIHeaderImage "!insertmacro ${_MOZFUNC_UN}ChangeMUIHeaderImageCall"
5277
5278    Function ${_MOZFUNC_UN}ChangeMUIHeaderImage
5279      Exch $R9
5280      Push $R8
5281
5282      GetDlgItem $R8 $HWNDPARENT 1046
5283      ${SetStretchedImageOLE} $R8 "$R9" $hHeaderBitmap
5284      ; There is no way to specify a show function for a custom page so hide
5285      ; and then show the control to force the bitmap to redraw.
5286      ShowWindow $R8 ${SW_HIDE}
5287      ShowWindow $R8 ${SW_SHOW}
5288
5289      Pop $R8
5290      Exch $R9
5291    FunctionEnd
5292
5293    !verbose pop
5294  !endif
5295!macroend
5296
5297!macro ChangeMUIHeaderImageCall _PATH_TO_IMAGE
5298  !verbose push
5299  !verbose ${_MOZFUNC_VERBOSE}
5300  Push "${_PATH_TO_IMAGE}"
5301  Call ChangeMUIHeaderImage
5302  !verbose pop
5303!macroend
5304
5305!macro un.ChangeMUIHeaderImageCall _PATH_TO_IMAGE
5306  !verbose push
5307  !verbose ${_MOZFUNC_VERBOSE}
5308  Push "${_PATH_TO_IMAGE}"
5309  Call un.ChangeMUIHeaderImage
5310  !verbose pop
5311!macroend
5312
5313!macro un.ChangeMUIHeaderImage
5314  !ifndef un.ChangeMUIHeaderImage
5315    !verbose push
5316    !verbose ${_MOZFUNC_VERBOSE}
5317    !undef _MOZFUNC_UN
5318    !define _MOZFUNC_UN "un."
5319
5320    !insertmacro ChangeMUIHeaderImage
5321
5322    !undef _MOZFUNC_UN
5323    !define _MOZFUNC_UN
5324    !verbose pop
5325  !endif
5326!macroend
5327
5328/**
5329 * Replaces the sidebar image on the wizard's welcome and finish pages.
5330 *
5331 * @param   _PATH_TO_IMAGE
5332 *          Fully qualified path to the bitmap to use for the header image.
5333 *
5334 * $R8 = hwnd for the bitmap control
5335 * $R9 = _PATH_TO_IMAGE
5336 */
5337!macro ChangeMUISidebarImage
5338
5339  !ifndef ${_MOZFUNC_UN}ChangeMUISidebarImage
5340    Var hSidebarBitmap
5341
5342    !verbose push
5343    !verbose ${_MOZFUNC_VERBOSE}
5344    !define ${_MOZFUNC_UN}ChangeMUISidebarImage "!insertmacro ${_MOZFUNC_UN}ChangeMUISidebarImageCall"
5345
5346    Function ${_MOZFUNC_UN}ChangeMUISidebarImage
5347      Exch $R9
5348      Push $R8
5349
5350      ; Make sure we're not about to leak an existing handle.
5351      ${If} $hSidebarBitmap <> 0
5352        System::Call "gdi32::DeleteObject(p $hSidebarBitmap)"
5353        StrCpy $hSidebarBitmap 0
5354      ${EndIf}
5355      ; The controls on the welcome and finish pages aren't in the dialog
5356      ; template, they're always created manually from the INI file, so we need
5357      ; to query it to find the right HWND.
5358      ReadINIStr $R8 "$PLUGINSDIR\ioSpecial.ini" "Field 1" "HWND"
5359      ${SetStretchedImageOLE} $R8 "$R9" $hSidebarBitmap
5360
5361      Pop $R8
5362      Exch $R9
5363    FunctionEnd
5364
5365    !verbose pop
5366  !endif
5367!macroend
5368
5369!macro ChangeMUISidebarImageCall _PATH_TO_IMAGE
5370  !verbose push
5371  !verbose ${_MOZFUNC_VERBOSE}
5372  Push "${_PATH_TO_IMAGE}"
5373  Call ChangeMUISidebarImage
5374  !verbose pop
5375!macroend
5376
5377!macro un.ChangeMUISidebarImageCall _PATH_TO_IMAGE
5378  !verbose push
5379  !verbose ${_MOZFUNC_VERBOSE}
5380  Push "${_PATH_TO_IMAGE}"
5381  Call un.ChangeMUISidebarImage
5382  !verbose pop
5383!macroend
5384
5385!macro un.ChangeMUISidebarImage
5386  !ifndef un.ChangeMUISidebarImage
5387    !verbose push
5388    !verbose ${_MOZFUNC_VERBOSE}
5389    !undef _MOZFUNC_UN
5390    !define _MOZFUNC_UN "un."
5391
5392    !insertmacro ChangeMUISidebarImage
5393
5394    !undef _MOZFUNC_UN
5395    !define _MOZFUNC_UN
5396    !verbose pop
5397  !endif
5398!macroend
5399
5400################################################################################
5401# User interface callback helper defines and macros
5402
5403/* Install type defines */
5404!ifndef INSTALLTYPE_BASIC
5405  !define INSTALLTYPE_BASIC     1
5406!endif
5407
5408!ifndef INSTALLTYPE_CUSTOM
5409  !define INSTALLTYPE_CUSTOM    2
5410!endif
5411
5412/**
5413 * Checks whether to display the current page (e.g. if not performing a custom
5414 * install don't display the custom pages).
5415 */
5416!macro CheckCustomCommon
5417
5418  !ifndef CheckCustomCommon
5419    !verbose push
5420    !verbose ${_MOZFUNC_VERBOSE}
5421    !define CheckCustomCommon "!insertmacro CheckCustomCommonCall"
5422
5423    Function CheckCustomCommon
5424
5425      ; Abort if not a custom install
5426      IntCmp $InstallType ${INSTALLTYPE_CUSTOM} +2 +1 +1
5427      Abort
5428
5429    FunctionEnd
5430
5431    !verbose pop
5432  !endif
5433!macroend
5434
5435!macro CheckCustomCommonCall
5436  !verbose push
5437  !verbose ${_MOZFUNC_VERBOSE}
5438  Call CheckCustomCommon
5439  !verbose pop
5440!macroend
5441
5442/**
5443 * Unloads dll's and releases references when the installer and uninstaller
5444 * exit.
5445 */
5446!macro OnEndCommon
5447
5448  !ifndef ${_MOZFUNC_UN}OnEndCommon
5449    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
5450    !insertmacro ${_MOZFUNC_UN_TMP}UnloadUAC
5451    !undef _MOZFUNC_UN
5452    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
5453    !undef _MOZFUNC_UN_TMP
5454
5455    !verbose push
5456    !verbose ${_MOZFUNC_VERBOSE}
5457    !define ${_MOZFUNC_UN}OnEndCommon "!insertmacro ${_MOZFUNC_UN}OnEndCommonCall"
5458
5459    Function ${_MOZFUNC_UN}OnEndCommon
5460
5461      ${${_MOZFUNC_UN}UnloadUAC}
5462      StrCmp $hHeaderBitmap "" +3 +1
5463      System::Call "gdi32::DeleteObject(i s)" $hHeaderBitmap
5464      StrCpy $hHeaderBitmap ""
5465      ; If ChangeMUISidebarImage was called, then we also need to clean up the
5466      ; GDI bitmap handle that it would have created.
5467      !ifdef ${_MOZFUNC_UN}ChangeMUISidebarImage
5468        StrCmp $hSidebarBitmap "" +3 +1
5469        System::Call "gdi32::DeleteObject(i s)" $hSidebarBitmap
5470        StrCpy $hSidebarBitmap ""
5471      !endif
5472
5473      System::Free 0
5474
5475    FunctionEnd
5476
5477    !verbose pop
5478  !endif
5479!macroend
5480
5481!macro OnEndCommonCall
5482  !verbose push
5483  !verbose ${_MOZFUNC_VERBOSE}
5484  Call OnEndCommon
5485  !verbose pop
5486!macroend
5487
5488!macro un.OnEndCommonCall
5489  !verbose push
5490  !verbose ${_MOZFUNC_VERBOSE}
5491  Call un.OnEndCommon
5492  !verbose pop
5493!macroend
5494
5495!macro un.OnEndCommon
5496  !ifndef un.OnEndCommon
5497    !verbose push
5498    !verbose ${_MOZFUNC_VERBOSE}
5499    !undef _MOZFUNC_UN
5500    !define _MOZFUNC_UN "un."
5501
5502    !insertmacro OnEndCommon
5503
5504    !undef _MOZFUNC_UN
5505    !define _MOZFUNC_UN
5506    !verbose pop
5507  !endif
5508!macroend
5509
5510/**
5511 * Reads a flag option from the command line and sets a variable with its state,
5512 * if the option is present on the command line.
5513 *
5514 * @param   FULL_COMMAND_LINE
5515 *          The entire installer command line, such as from ${GetParameters}
5516 * @param   OPTION
5517 *          Name of the option to look for
5518 * @param   OUTPUT
5519 *          Variable/register to write the output to. Will be set to "0" if the
5520 *          option was present with the value "false", will be set to "1" if the
5521 *          option was present with another value, and will be untouched if the
5522 *          option was not on the command line at all.
5523 */
5524!macro InstallGetOption FULL_COMMAND_LINE OPTION OUTPUT
5525  Push $0
5526  ClearErrors
5527  ${GetOptions} ${FULL_COMMAND_LINE} "/${OPTION}" $0
5528  ${IfNot} ${Errors}
5529    ; Any valid command-line option triggers a silent installation.
5530    SetSilent silent
5531
5532    ${If} $0 == "=false"
5533      StrCpy ${OUTPUT} "0"
5534    ${Else}
5535      StrCpy ${OUTPUT} "1"
5536    ${EndIf}
5537  ${EndIf}
5538  Pop $0
5539!macroend
5540!define InstallGetOption "!insertmacro InstallGetOption"
5541
5542/**
5543 * Called from the installer's .onInit function not to be confused with the
5544 * uninstaller's .onInit or the uninstaller's un.onInit functions.
5545 *
5546 * @param   _WARN_UNSUPPORTED_MSG
5547 *          Message displayed when the Windows version is not supported.
5548 *
5549 * $R4 = keeps track of whether a custom install path was specified on either
5550 *       the command line or in an INI file
5551 * $R5 = return value from the GetSize macro
5552 * $R6 = general string values, return value from GetTempFileName, return
5553 *       value from the GetSize macro
5554 * $R7 = full path to the configuration ini file
5555 * $R8 = used for OS Version and Service Pack detection and the return value
5556 *       from the GetParameters macro
5557 * $R9 = _WARN_UNSUPPORTED_MSG
5558 */
5559!macro InstallOnInitCommon
5560
5561  !ifndef InstallOnInitCommon
5562    !insertmacro ElevateUAC
5563    !insertmacro GetOptions
5564    !insertmacro GetParameters
5565    !insertmacro GetSize
5566
5567    !verbose push
5568    !verbose ${_MOZFUNC_VERBOSE}
5569    !define InstallOnInitCommon "!insertmacro InstallOnInitCommonCall"
5570
5571    Function InstallOnInitCommon
5572      Exch $R9
5573      Push $R8
5574      Push $R7
5575      Push $R6
5576      Push $R5
5577      Push $R4
5578
5579      ; Don't install on systems that don't support SSE2. The parameter value of
5580      ; 10 is for PF_XMMI64_INSTRUCTIONS_AVAILABLE which will check whether the
5581      ; SSE2 instruction set is available.
5582      System::Call "kernel32::IsProcessorFeaturePresent(i 10)i .R8"
5583      ${If} "$R8" == "0"
5584        MessageBox MB_OK|MB_ICONSTOP "$R9"
5585        ; Nothing initialized so no need to call OnEndCommon
5586        Quit
5587      ${EndIf}
5588
5589      ; Windows NT 6.0 (Vista/Server 2008) and lower are not supported.
5590      ${Unless} ${AtLeastWin7}
5591        MessageBox MB_OK|MB_ICONSTOP "$R9"
5592        ; Nothing initialized so no need to call OnEndCommon
5593        Quit
5594      ${EndUnless}
5595
5596      !ifdef HAVE_64BIT_BUILD
5597        SetRegView 64
5598      !endif
5599
5600      StrCpy $R4 0 ; will be set to 1 if a custom install path is set
5601
5602      ${GetParameters} $R8
5603      ${If} $R8 != ""
5604        ; Default install type
5605        StrCpy $InstallType ${INSTALLTYPE_BASIC}
5606
5607        ${Unless} ${Silent}
5608          ; NSIS should check for /S for us, but we've had issues with it such
5609          ; as bug 506867 in the past, so we'll check for it ourselves also.
5610          ClearErrors
5611          ${GetOptions} "$R8" "/S" $R7
5612          ${Unless} ${Errors}
5613            SetSilent silent
5614          ${Else}
5615            ; NSIS dropped support for the deprecated -ms argument, but we don't
5616            ; want to break backcompat, so we'll check for it here too.
5617            ClearErrors
5618            ${GetOptions} "$R8" "-ms" $R7
5619            ${Unless} ${Errors}
5620              SetSilent silent
5621            ${EndUnless}
5622          ${EndUnless}
5623        ${EndUnless}
5624
5625        ; Support for specifying an installation configuration file.
5626        ClearErrors
5627        ${GetOptions} "$R8" "/INI=" $R7
5628        ${Unless} ${Errors}
5629          ; The configuration file must also exist
5630          ${If} ${FileExists} "$R7"
5631            ; Any valid command-line option triggers a silent installation.
5632            SetSilent silent
5633
5634            ReadINIStr $R8 $R7 "Install" "InstallDirectoryName"
5635            ${If} $R8 != ""
5636              StrCpy $R4 1
5637              !ifdef HAVE_64BIT_BUILD
5638                StrCpy $INSTDIR "$PROGRAMFILES64\$R8"
5639              !else
5640                StrCpy $INSTDIR "$PROGRAMFILES32\$R8"
5641              !endif
5642            ${Else}
5643              ReadINIStr $R8 $R7 "Install" "InstallDirectoryPath"
5644              ${If} $R8 != ""
5645                StrCpy $R4 1
5646                StrCpy $INSTDIR "$R8"
5647              ${EndIf}
5648            ${EndIf}
5649
5650            ReadINIStr $R8 $R7 "Install" "QuickLaunchShortcut"
5651            ${If} $R8 == "false"
5652              StrCpy $AddQuickLaunchSC "0"
5653            ${Else}
5654              StrCpy $AddQuickLaunchSC "1"
5655            ${EndIf}
5656
5657            ReadINIStr $R8 $R7 "Install" "DesktopShortcut"
5658            ${If} $R8 == "false"
5659              StrCpy $AddDesktopSC "0"
5660            ${Else}
5661              StrCpy $AddDesktopSC "1"
5662            ${EndIf}
5663
5664            ReadINIStr $R8 $R7 "Install" "StartMenuShortcuts"
5665            ${If} $R8 == "false"
5666              StrCpy $AddStartMenuSC "0"
5667            ${Else}
5668              StrCpy $AddStartMenuSC "1"
5669            ${EndIf}
5670
5671            ; We still accept the plural version for backwards compatibility,
5672            ; but the singular version takes priority.
5673            ClearErrors
5674            ReadINIStr $R8 $R7 "Install" "StartMenuShortcut"
5675            ${If} $R8 == "false"
5676              StrCpy $AddStartMenuSC "0"
5677            ${ElseIfNot} ${Errors}
5678              StrCpy $AddStartMenuSC "1"
5679            ${EndIf}
5680
5681            ReadINIStr $R8 $R7 "Install" "TaskbarShortcut"
5682            ${If} $R8 == "false"
5683              StrCpy $AddTaskbarSC "0"
5684            ${Else}
5685              StrCpy $AddTaskbarSC "1"
5686            ${EndIf}
5687
5688            ReadINIStr $R8 $R7 "Install" "MaintenanceService"
5689            ${If} $R8 == "false"
5690              StrCpy $InstallMaintenanceService "0"
5691            ${Else}
5692              StrCpy $InstallMaintenanceService "1"
5693            ${EndIf}
5694
5695            ReadINIStr $R8 $R7 "Install" "RegisterDefaultAgent"
5696            ${If} $R8 == "false"
5697              StrCpy $RegisterDefaultAgent "0"
5698            ${Else}
5699              StrCpy $RegisterDefaultAgent "1"
5700            ${EndIf}
5701
5702            !ifdef MOZ_OPTIONAL_EXTENSIONS
5703              ReadINIStr $R8 $R7 "Install" "OptionalExtensions"
5704              ${If} $R8 == "false"
5705                StrCpy $InstallOptionalExtensions "0"
5706              ${Else}
5707                StrCpy $InstallOptionalExtensions "1"
5708              ${EndIf}
5709            !endif
5710
5711            !ifndef NO_STARTMENU_DIR
5712              ReadINIStr $R8 $R7 "Install" "StartMenuDirectoryName"
5713              ${If} $R8 != ""
5714                StrCpy $StartMenuDir "$R8"
5715              ${EndIf}
5716            !endif
5717          ${EndIf}
5718        ${EndUnless}
5719
5720        ; Check for individual command line parameters after evaluating the INI
5721        ; file, because these should override the INI entires.
5722        ${GetParameters} $R8
5723        ${GetOptions} $R8 "/InstallDirectoryName=" $R7
5724        ${If} $R7 != ""
5725          StrCpy $R4 1
5726          !ifdef HAVE_64BIT_BUILD
5727            StrCpy $INSTDIR "$PROGRAMFILES64\$R7"
5728          !else
5729            StrCpy $INSTDIR "$PROGRAMFILES32\$R7"
5730          !endif
5731        ${Else}
5732          ${GetOptions} $R8 "/InstallDirectoryPath=" $R7
5733          ${If} $R7 != ""
5734            StrCpy $R4 1
5735            StrCpy $INSTDIR "$R7"
5736          ${EndIf}
5737        ${EndIf}
5738
5739        ${InstallGetOption} $R8 "QuickLaunchShortcut" $AddQuickLaunchSC
5740        ${InstallGetOption} $R8 "DesktopShortcut" $AddDesktopSC
5741        ${InstallGetOption} $R8 "StartMenuShortcuts" $AddStartMenuSC
5742        ; We still accept the plural version for backwards compatibility,
5743        ; but the singular version takes priority.
5744        ${InstallGetOption} $R8 "StartMenuShortcut" $AddStartMenuSC
5745        ${InstallGetOption} $R8 "TaskbarShortcut" $AddTaskbarSC
5746        ${InstallGetOption} $R8 "MaintenanceService" $InstallMaintenanceService
5747        ${InstallGetOption} $R8 "RegisterDefaultAgent" $RegisterDefaultAgent
5748        !ifdef MOZ_OPTIONAL_EXTENSIONS
5749          ${InstallGetOption} $R8 "OptionalExtensions" $InstallOptionalExtensions
5750        !endif
5751
5752        ; Installing the service always requires elevated privileges.
5753        ${If} $InstallMaintenanceService == "1"
5754          ${ElevateUAC}
5755        ${EndIf}
5756      ${EndIf}
5757
5758      ${If} $R4 == 1
5759        ; Any valid command-line option triggers a silent installation.
5760        SetSilent silent
5761
5762        ; Quit if we are unable to create the installation directory or we are
5763        ; unable to write to a file in the installation directory.
5764        ClearErrors
5765        ${If} ${FileExists} "$INSTDIR"
5766          GetTempFileName $R6 "$INSTDIR"
5767          FileOpen $R5 "$R6" w
5768          FileWrite $R5 "Write Access Test"
5769          FileClose $R5
5770          Delete $R6
5771          ${If} ${Errors}
5772            ; Attempt to elevate and then try again.
5773            ${ElevateUAC}
5774            GetTempFileName $R6 "$INSTDIR"
5775            FileOpen $R5 "$R6" w
5776            FileWrite $R5 "Write Access Test"
5777            FileClose $R5
5778            Delete $R6
5779            ${If} ${Errors}
5780              ; Nothing initialized so no need to call OnEndCommon
5781              Quit
5782            ${EndIf}
5783          ${EndIf}
5784        ${Else}
5785          CreateDirectory "$INSTDIR"
5786          ${If} ${Errors}
5787            ; Attempt to elevate and then try again.
5788            ${ElevateUAC}
5789            CreateDirectory "$INSTDIR"
5790            ${If} ${Errors}
5791              ; Nothing initialized so no need to call OnEndCommon
5792              Quit
5793            ${EndIf}
5794          ${EndIf}
5795        ${EndIf}
5796      ${Else}
5797        ; If we weren't given a custom path parameter, then try to elevate now.
5798        ; We'll check the user's permission level later on to determine the
5799        ; default install path (which will be the real install path for /S).
5800        ; If an INI file is used, we try to elevate down that path when needed.
5801        ${ElevateUAC}
5802      ${EndIf}
5803
5804      Pop $R4
5805      Pop $R5
5806      Pop $R6
5807      Pop $R7
5808      Pop $R8
5809      Exch $R9
5810    FunctionEnd
5811
5812    !verbose pop
5813  !endif
5814!macroend
5815
5816!macro InstallOnInitCommonCall _WARN_UNSUPPORTED_MSG
5817  !verbose push
5818  !verbose ${_MOZFUNC_VERBOSE}
5819  Push "${_WARN_UNSUPPORTED_MSG}"
5820  Call InstallOnInitCommon
5821  !verbose pop
5822!macroend
5823
5824/**
5825 * Called from the uninstaller's .onInit function not to be confused with the
5826 * installer's .onInit or the uninstaller's un.onInit functions.
5827 */
5828!macro UninstallOnInitCommon
5829
5830  !ifndef UninstallOnInitCommon
5831    !insertmacro ElevateUAC
5832    !insertmacro GetLongPath
5833    !insertmacro GetOptions
5834    !insertmacro GetParameters
5835    !insertmacro GetParent
5836    !insertmacro UnloadUAC
5837    !insertmacro UpdateShortcutAppModelIDs
5838    !insertmacro UpdateUninstallLog
5839
5840    !verbose push
5841    !verbose ${_MOZFUNC_VERBOSE}
5842    !define UninstallOnInitCommon "!insertmacro UninstallOnInitCommonCall"
5843
5844    Function UninstallOnInitCommon
5845      ; Prevents breaking apps that don't use SetBrandNameVars
5846      !ifdef SetBrandNameVars
5847        ${SetBrandNameVars} "$EXEDIR\distribution\setup.ini"
5848      !endif
5849
5850      ; Prevent launching the application when a reboot is required and this
5851      ; executable is the main application executable
5852      IfFileExists "$EXEDIR\${FileMainEXE}.moz-upgrade" +1 +4
5853      MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UPGRADE)" IDNO +2
5854      Reboot
5855      Quit ; Nothing initialized so no need to call OnEndCommon
5856
5857      ${GetParent} "$EXEDIR" $INSTDIR
5858      ${GetLongPath} "$INSTDIR" $INSTDIR
5859      IfFileExists "$INSTDIR\${FileMainEXE}" +2 +1
5860      Quit ; Nothing initialized so no need to call OnEndCommon
5861
5862!ifmacrodef InitHashAppModelId
5863      ; setup the application model id registration value
5864      !ifdef AppName
5865      ${InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs"
5866      !endif
5867!endif
5868
5869      ; Prevents breaking apps that don't use SetBrandNameVars
5870      !ifdef SetBrandNameVars
5871        ${SetBrandNameVars} "$INSTDIR\distribution\setup.ini"
5872      !endif
5873
5874      ; Application update uses a directory named tobedeleted in the $INSTDIR to
5875      ; delete files on OS reboot when they are in use. Try to delete this
5876      ; directory if it exists.
5877      ${If} ${FileExists} "$INSTDIR\${TO_BE_DELETED}"
5878        RmDir /r "$INSTDIR\${TO_BE_DELETED}"
5879      ${EndIf}
5880
5881      ; Prevent all operations (e.g. set as default, postupdate, etc.) when a
5882      ; reboot is required and the executable launched is helper.exe
5883      IfFileExists "$INSTDIR\${FileMainEXE}.moz-upgrade" +1 +4
5884      MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UPGRADE)" IDNO +2
5885      Reboot
5886      Quit ; Nothing initialized so no need to call OnEndCommon
5887
5888      !ifdef HAVE_64BIT_BUILD
5889        SetRegView 64
5890      !endif
5891
5892      ${GetParameters} $R0
5893
5894      ${Unless} ${Silent}
5895        ; Manually check for /S in the command line due to Bug 506867
5896        ClearErrors
5897        ${GetOptions} "$R0" "/S" $R2
5898        ${Unless} ${Errors}
5899          SetSilent silent
5900        ${Else}
5901          ; Support for the deprecated -ms command line argument.
5902          ClearErrors
5903          ${GetOptions} "$R0" "-ms" $R2
5904          ${Unless} ${Errors}
5905            SetSilent silent
5906          ${EndUnless}
5907        ${EndUnless}
5908      ${EndUnless}
5909
5910      StrCmp "$R0" "" continue +1
5911
5912      ; Require elevation if the user can elevate
5913      hideshortcuts:
5914      ClearErrors
5915      ${GetOptions} "$R0" "/HideShortcuts" $R2
5916      IfErrors showshortcuts +1
5917!ifndef NONADMIN_ELEVATE
5918      ${ElevateUAC}
5919!endif
5920      ${HideShortcuts}
5921      GoTo finish
5922
5923      ; Require elevation if the user can elevate
5924      showshortcuts:
5925      ClearErrors
5926      ${GetOptions} "$R0" "/ShowShortcuts" $R2
5927      IfErrors defaultappuser +1
5928!ifndef NONADMIN_ELEVATE
5929      ${ElevateUAC}
5930!endif
5931      ${ShowShortcuts}
5932      GoTo finish
5933
5934      ; Require elevation if the the StartMenuInternet registry keys require
5935      ; updating and the user can elevate
5936      defaultappuser:
5937      ClearErrors
5938      ${GetOptions} "$R0" "/SetAsDefaultAppUser" $R2
5939      IfErrors defaultappglobal +1
5940      ${SetAsDefaultAppUser}
5941      GoTo finish
5942
5943      ; Require elevation if the user can elevate
5944      defaultappglobal:
5945      ClearErrors
5946      ${GetOptions} "$R0" "/SetAsDefaultAppGlobal" $R2
5947      IfErrors postupdate +1
5948      ${ElevateUAC}
5949      ${SetAsDefaultAppGlobal}
5950      GoTo finish
5951
5952      ; Do not attempt to elevate. The application launching this executable is
5953      ; responsible for elevation if it is required.
5954      postupdate:
5955      ${WordReplace} "$R0" "$\"" "" "+" $R0
5956      ClearErrors
5957      ${GetOptions} "$R0" "/PostUpdate" $R2
5958      IfErrors continue +1
5959      ; If the uninstall.log does not exist don't perform post update
5960      ; operations. This prevents updating the registry for zip builds.
5961      IfFileExists "$EXEDIR\uninstall.log" +2 +1
5962      Quit ; Nothing initialized so no need to call OnEndCommon
5963      ${PostUpdate}
5964      ClearErrors
5965      ${GetOptions} "$R0" "/UninstallLog=" $R2
5966      IfErrors updateuninstalllog +1
5967      StrCmp "$R2" "" finish +1
5968      GetFullPathName $R3 "$R2"
5969      IfFileExists "$R3" +1 finish
5970      Delete "$INSTDIR\uninstall\*wizard*"
5971      Delete "$INSTDIR\uninstall\uninstall.log"
5972      CopyFiles /SILENT /FILESONLY "$R3" "$INSTDIR\uninstall\"
5973      ${GetParent} "$R3" $R4
5974      Delete "$R3"
5975      RmDir "$R4"
5976      GoTo finish
5977
5978      ; Do not attempt to elevate. The application launching this executable is
5979      ; responsible for elevation if it is required.
5980      updateuninstalllog:
5981      ${UpdateUninstallLog}
5982
5983      finish:
5984      ${UnloadUAC}
5985      ${RefreshShellIcons}
5986      Quit ; Nothing initialized so no need to call OnEndCommon
5987
5988      continue:
5989
5990      ; If the uninstall.log does not exist don't perform uninstall
5991      ; operations. This prevents running the uninstaller for zip builds.
5992      IfFileExists "$INSTDIR\uninstall\uninstall.log" +2 +1
5993      Quit ; Nothing initialized so no need to call OnEndCommon
5994
5995      ; When silent, try to avoid elevation if we have a chance to succeed.  We
5996      ; can succeed when we can write to (hence delete from) the install
5997      ; directory and when we can clean up all registry entries.  Now, the
5998      ; installer when elevated writes privileged registry entries for the use
5999      ; of the Maintenance Service, even when the service is not and will not be
6000      ; installed.  (In fact, even when a service installed in the future will
6001      ; never update the installation, for example due to not being in a
6002      ; privileged location.)  In practice this means we can only truly silently
6003      ; remove an unelevated install: an elevated installer writing to an
6004      ; unprivileged install directory will still write privileged registry
6005      ; entries, requiring an elevated uninstaller to completely clean up.
6006      ;
6007      ; This avoids a wrinkle, whereby an uninstaller which runs unelevated will
6008      ; never itself launch the Maintenance Service uninstaller, because it will
6009      ; fail to remove its own service registration (removing the relevant
6010      ; registry key would require elevation).  Therefore the check for the
6011      ; service being unused will fail, which will prevent running the service
6012      ; uninstaller.  That's both subtle and possibly leaves the service
6013      ; registration hanging around, which might be a security risk.
6014      ;
6015      ; That is why we look for a privileged service registration for this
6016      ; installation when deciding to elevate, and elevate unconditionally if we
6017      ; find one, regardless of the result of the write check that would avoid
6018      ; elevation.
6019
6020      ; The reason for requiring elevation, or "" for not required.
6021      StrCpy $R4 ""
6022
6023      ${IfNot} ${Silent}
6024        ; In normal operation, require elevation if the user can elevate so that
6025        ; we are most likely to succeed.
6026        StrCpy $R4 "not silent"
6027      ${EndIf}
6028
6029      GetTempFileName $R6 "$INSTDIR"
6030      FileOpen $R5 "$R6" w
6031      FileWrite $R5 "Write Access Test"
6032      FileClose $R5
6033      Delete $R6
6034      ${If} ${Errors}
6035        StrCpy $R4 "write"
6036      ${EndIf}
6037
6038      !ifdef MOZ_MAINTENANCE_SERVICE
6039        ; We don't necessarily have $MaintCertKey, so use temporary registers.
6040        ServicesHelper::PathToUniqueRegistryPath "$INSTDIR"
6041        Pop $R5
6042
6043        ${If} $R5 != ""
6044          ; Always use the 64bit registry for certs on 64bit systems.
6045          ${If} ${RunningX64}
6046          ${OrIf} ${IsNativeARM64}
6047            SetRegView 64
6048          ${EndIf}
6049
6050          EnumRegKey $R6 HKLM $R5 0
6051          ClearErrors
6052
6053          ${If} ${RunningX64}
6054          ${OrIf} ${IsNativeARM64}
6055            SetRegView lastused
6056          ${EndIf}
6057
6058          ${IfNot} "$R6" == ""
6059            StrCpy $R4 "mms"
6060          ${EndIf}
6061        ${EndIf}
6062      !endif
6063
6064      ${If} "$R4" != ""
6065        ; In the future, we might not try to elevate to remain truly silent.  Or
6066        ; we might add a command line arguments to specify behaviour.  One
6067        ; reason to not do that immediately is that we have no great way to
6068        ; signal that we exited without taking action.
6069        ${ElevateUAC}
6070      ${EndIf}
6071
6072      ; Now we've elevated, try the write access test again.
6073      ClearErrors
6074      GetTempFileName $R6 "$INSTDIR"
6075      FileOpen $R5 "$R6" w
6076      FileWrite $R5 "Write Access Test"
6077      FileClose $R5
6078      Delete $R6
6079      ${If} ${Errors}
6080        ; Nothing initialized so no need to call OnEndCommon
6081        Quit
6082      ${EndIf}
6083
6084      !ifdef MOZ_MAINTENANCE_SERVICE
6085        ; And verify that if we need to, we're going to clean up the registry
6086        ; correctly.
6087        ${If} "$R4" == "mms"
6088          WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" "Write Test"
6089          ${If} ${Errors}
6090            ; Nothing initialized so no need to call OnEndCommon
6091            Quit
6092          ${Endif}
6093          DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
6094        ${EndIf}
6095      !endif
6096
6097      ; If we made it this far then this installer is being used as an uninstaller.
6098      WriteUninstaller "$EXEDIR\uninstaller.exe"
6099
6100      ${If} ${Silent}
6101        StrCpy $R1 "$\"$EXEDIR\uninstaller.exe$\" /S"
6102      ${Else}
6103        StrCpy $R1 "$\"$EXEDIR\uninstaller.exe$\""
6104      ${EndIf}
6105
6106      ; When the uninstaller is launched it copies itself to the temp directory
6107      ; so it won't be in use so it can delete itself.
6108      ExecWait $R1
6109      ${DeleteFile} "$EXEDIR\uninstaller.exe"
6110      ${UnloadUAC}
6111      SetErrorLevel 0
6112      Quit ; Nothing initialized so no need to call OnEndCommon
6113
6114    FunctionEnd
6115
6116    !verbose pop
6117  !endif
6118!macroend
6119
6120!macro UninstallOnInitCommonCall
6121  !verbose push
6122  !verbose ${_MOZFUNC_VERBOSE}
6123  Call UninstallOnInitCommon
6124  !verbose pop
6125!macroend
6126
6127/**
6128 * Called from the uninstaller's un.onInit function not to be confused with the
6129 * installer's .onInit or the uninstaller's .onInit functions.
6130 */
6131!macro un.UninstallUnOnInitCommon
6132
6133  !ifndef un.UninstallUnOnInitCommon
6134    !insertmacro un.GetLongPath
6135    !insertmacro un.GetParent
6136    !insertmacro un.SetBrandNameVars
6137
6138    !verbose push
6139    !verbose ${_MOZFUNC_VERBOSE}
6140    !define un.UninstallUnOnInitCommon "!insertmacro un.UninstallUnOnInitCommonCall"
6141
6142    Function un.UninstallUnOnInitCommon
6143      ${un.GetParent} "$INSTDIR" $INSTDIR
6144      ${un.GetLongPath} "$INSTDIR" $INSTDIR
6145      ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}"
6146        Abort
6147      ${EndUnless}
6148
6149      !ifdef HAVE_64BIT_BUILD
6150        SetRegView 64
6151      !endif
6152
6153      ; Prevents breaking apps that don't use SetBrandNameVars
6154      !ifdef un.SetBrandNameVars
6155        ${un.SetBrandNameVars} "$INSTDIR\distribution\setup.ini"
6156      !endif
6157
6158      ; Initialize $hHeaderBitmap to prevent redundant changing of the bitmap if
6159      ; the user clicks the back button
6160      StrCpy $hHeaderBitmap ""
6161    FunctionEnd
6162
6163    !verbose pop
6164  !endif
6165!macroend
6166
6167!macro un.UninstallUnOnInitCommonCall
6168  !verbose push
6169  !verbose ${_MOZFUNC_VERBOSE}
6170  Call un.UninstallUnOnInitCommon
6171  !verbose pop
6172!macroend
6173
6174/**
6175 * Called from the MUI leaveOptions function to set the value of $INSTDIR.
6176 */
6177!macro LeaveOptionsCommon
6178
6179  !ifndef LeaveOptionsCommon
6180    !insertmacro CanWriteToInstallDir
6181    !insertmacro GetLongPath
6182
6183!ifndef NO_INSTDIR_FROM_REG
6184    !insertmacro GetSingleInstallPath
6185!endif
6186
6187    !verbose push
6188    !verbose ${_MOZFUNC_VERBOSE}
6189    !define LeaveOptionsCommon "!insertmacro LeaveOptionsCommonCall"
6190
6191    Function LeaveOptionsCommon
6192      Push $R9
6193
6194      StrCpy $R9 "false"
6195
6196!ifndef NO_INSTDIR_FROM_REG
6197      SetShellVarContext all      ; Set SHCTX to HKLM
6198
6199      ${If} ${IsNativeAMD64}
6200      ${OrIf} ${IsNativeARM64}
6201        SetRegView 64
6202        ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
6203        SetRegView lastused
6204      ${EndIf}
6205
6206      StrCmp "$R9" "false" +1 finish_get_install_dir
6207
6208      SetRegView 32
6209      ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
6210      SetRegView lastused
6211
6212      StrCmp "$R9" "false" +1 finish_get_install_dir
6213
6214      SetShellVarContext current  ; Set SHCTX to HKCU
6215      ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
6216
6217      finish_get_install_dir:
6218      StrCmp "$R9" "false" +2 +1
6219      StrCpy $INSTDIR "$R9"
6220!endif
6221
6222      ; If the user doesn't have write access to the installation directory set
6223      ; the installation directory to a subdirectory of the All Users application
6224      ; directory and if the user can't write to that location set the installation
6225      ; directory to a subdirectory of the users local application directory
6226      ; (e.g. non-roaming).
6227      ${CanWriteToInstallDir} $R9
6228      StrCmp "$R9" "false" +1 finish_check_install_dir
6229
6230      SetShellVarContext all      ; Set SHCTX to All Users
6231      StrCpy $INSTDIR "$APPDATA\${BrandFullName}\"
6232      ${CanWriteToInstallDir} $R9
6233      StrCmp "$R9" "false" +2 +1
6234      StrCpy $INSTDIR "$LOCALAPPDATA\${BrandFullName}\"
6235
6236      finish_check_install_dir:
6237      IfFileExists "$INSTDIR" +3 +1
6238      Pop $R9
6239      Return
6240
6241      ; Always display the long path if the path already exists.
6242      ${GetLongPath} "$INSTDIR" $INSTDIR
6243
6244      ; The call to GetLongPath returns a long path without a trailing
6245      ; back-slash. Append a \ to the path to prevent the directory
6246      ; name from being appended when using the NSIS create new folder.
6247      ; http://www.nullsoft.com/free/nsis/makensis.htm#InstallDir
6248      StrCpy $INSTDIR "$INSTDIR\"
6249
6250      Pop $R9
6251    FunctionEnd
6252
6253    !verbose pop
6254  !endif
6255!macroend
6256
6257!macro LeaveOptionsCommonCall
6258  !verbose push
6259  !verbose ${_MOZFUNC_VERBOSE}
6260  Call LeaveOptionsCommon
6261  !verbose pop
6262!macroend
6263
6264/**
6265 * Called from the MUI preDirectory function to verify there is enough disk
6266 * space for the installation and the installation directory is writable.
6267 *
6268 * $R9 = returned value from CheckDiskSpace and CanWriteToInstallDir macros
6269 */
6270!macro PreDirectoryCommon
6271
6272  !ifndef PreDirectoryCommon
6273    !insertmacro CanWriteToInstallDir
6274    !insertmacro CheckDiskSpace
6275
6276    !verbose push
6277    !verbose ${_MOZFUNC_VERBOSE}
6278    !define PreDirectoryCommon "!insertmacro PreDirectoryCommonCall"
6279
6280    Function PreDirectoryCommon
6281      Push $R9
6282
6283      IntCmp $InstallType ${INSTALLTYPE_CUSTOM} end +1 +1
6284      ${CanWriteToInstallDir} $R9
6285      StrCmp "$R9" "false" end +1
6286      ${CheckDiskSpace} $R9
6287      StrCmp "$R9" "false" end +1
6288      Abort
6289
6290      end:
6291
6292      Pop $R9
6293    FunctionEnd
6294
6295    !verbose pop
6296  !endif
6297!macroend
6298
6299!macro PreDirectoryCommonCall
6300  !verbose push
6301  !verbose ${_MOZFUNC_VERBOSE}
6302  Call PreDirectoryCommon
6303  !verbose pop
6304!macroend
6305
6306/**
6307 * Called from the MUI leaveDirectory function
6308 *
6309 * @param   _WARN_DISK_SPACE
6310 *          Message displayed when there isn't enough disk space to perform the
6311 *          installation.
6312 * @param   _WARN_WRITE_ACCESS
6313 *          Message displayed when the installer does not have write access to
6314 *          $INSTDIR.
6315 *
6316 * $R7 = returned value from CheckDiskSpace and CanWriteToInstallDir macros
6317 * $R8 = _WARN_DISK_SPACE
6318 * $R9 = _WARN_WRITE_ACCESS
6319 */
6320!macro LeaveDirectoryCommon
6321
6322  !ifndef LeaveDirectoryCommon
6323    !insertmacro CheckDiskSpace
6324    !insertmacro CanWriteToInstallDir
6325
6326    !verbose push
6327    !verbose ${_MOZFUNC_VERBOSE}
6328    !define LeaveDirectoryCommon "!insertmacro LeaveDirectoryCommonCall"
6329
6330    Function LeaveDirectoryCommon
6331      Exch $R9
6332      Exch 1
6333      Exch $R8
6334      Push $R7
6335
6336      ${CanWriteToInstallDir} $R7
6337      ${If} $R7 == "false"
6338        MessageBox MB_OK|MB_ICONEXCLAMATION "$R9"
6339        Abort
6340      ${EndIf}
6341
6342      ${CheckDiskSpace} $R7
6343      ${If} $R7 == "false"
6344        MessageBox MB_OK|MB_ICONEXCLAMATION "$R8"
6345        Abort
6346      ${EndIf}
6347
6348      Pop $R7
6349      Exch $R8
6350      Exch 1
6351      Exch $R9
6352    FunctionEnd
6353
6354    !verbose pop
6355  !endif
6356!macroend
6357
6358!macro LeaveDirectoryCommonCall _WARN_DISK_SPACE _WARN_WRITE_ACCESS
6359  !verbose push
6360  Push "${_WARN_DISK_SPACE}"
6361  Push "${_WARN_WRITE_ACCESS}"
6362  !verbose ${_MOZFUNC_VERBOSE}
6363  Call LeaveDirectoryCommon
6364  !verbose pop
6365!macroend
6366
6367
6368################################################################################
6369# Install Section common macros.
6370
6371/**
6372 * Performs common cleanup operations prior to the actual installation.
6373 * This macro should be called first when installation starts.
6374 */
6375!macro InstallStartCleanupCommon
6376
6377  !ifndef InstallStartCleanupCommon
6378    !insertmacro CleanVirtualStore
6379    !insertmacro EndUninstallLog
6380    !insertmacro OnInstallUninstall
6381
6382    !verbose push
6383    !verbose ${_MOZFUNC_VERBOSE}
6384    !define InstallStartCleanupCommon "!insertmacro InstallStartCleanupCommonCall"
6385
6386    Function InstallStartCleanupCommon
6387
6388      ; Remove files not removed by parsing the uninstall.log
6389      Delete "$INSTDIR\install_wizard.log"
6390      Delete "$INSTDIR\install_status.log"
6391
6392      RmDir /r "$INSTDIR\updates"
6393      Delete "$INSTDIR\updates.xml"
6394      Delete "$INSTDIR\active-update.xml"
6395
6396      ; Remove files from the uninstall directory.
6397      ${If} ${FileExists} "$INSTDIR\uninstall"
6398        Delete "$INSTDIR\uninstall\*wizard*"
6399        Delete "$INSTDIR\uninstall\uninstall.ini"
6400        Delete "$INSTDIR\uninstall\cleanup.log"
6401        Delete "$INSTDIR\uninstall\uninstall.update"
6402        ${OnInstallUninstall}
6403      ${EndIf}
6404
6405      ; Since we write to the uninstall.log in this directory during the
6406      ; installation create the directory if it doesn't already exist.
6407      IfFileExists "$INSTDIR\uninstall" +2 +1
6408      CreateDirectory "$INSTDIR\uninstall"
6409
6410      ; Application update uses a directory named tobedeleted in the $INSTDIR to
6411      ; delete files on OS reboot when they are in use. Try to delete this
6412      ; directory if it exists.
6413      ${If} ${FileExists} "$INSTDIR\${TO_BE_DELETED}"
6414        RmDir /r "$INSTDIR\${TO_BE_DELETED}"
6415      ${EndIf}
6416
6417      ; Remove files that may be left behind by the application in the
6418      ; VirtualStore directory.
6419      ${CleanVirtualStore}
6420    FunctionEnd
6421
6422    !verbose pop
6423  !endif
6424!macroend
6425
6426!macro InstallStartCleanupCommonCall
6427  !verbose push
6428  !verbose ${_MOZFUNC_VERBOSE}
6429  Call InstallStartCleanupCommon
6430  !verbose pop
6431!macroend
6432
6433/**
6434 * Performs common cleanup operations after the actual installation.
6435 * This macro should be called last during the installation.
6436 */
6437!macro InstallEndCleanupCommon
6438
6439  !ifndef InstallEndCleanupCommon
6440    !insertmacro EndUninstallLog
6441
6442    !verbose push
6443    !verbose ${_MOZFUNC_VERBOSE}
6444    !define InstallEndCleanupCommon "!insertmacro InstallEndCleanupCommonCall"
6445
6446    Function InstallEndCleanupCommon
6447
6448      ; Close the file handle to the uninstall.log
6449      ${EndUninstallLog}
6450
6451    FunctionEnd
6452
6453    !verbose pop
6454  !endif
6455!macroend
6456
6457!macro InstallEndCleanupCommonCall
6458  !verbose push
6459  !verbose ${_MOZFUNC_VERBOSE}
6460  Call InstallEndCleanupCommon
6461  !verbose pop
6462!macroend
6463
6464
6465################################################################################
6466# UAC Related Macros
6467
6468/**
6469 * Provides UAC elevation support (requires the UAC plugin).
6470 *
6471 * $0 = return values from calls to the UAC plugin (always uses $0)
6472 * $R9 = return values from GetParameters and GetOptions macros
6473 */
6474!macro ElevateUAC
6475
6476  !ifndef ${_MOZFUNC_UN}ElevateUAC
6477    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
6478    !insertmacro ${_MOZFUNC_UN_TMP}GetOptions
6479    !insertmacro ${_MOZFUNC_UN_TMP}GetParameters
6480    !undef _MOZFUNC_UN
6481    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
6482    !undef _MOZFUNC_UN_TMP
6483
6484    !verbose push
6485    !verbose ${_MOZFUNC_VERBOSE}
6486    !define ${_MOZFUNC_UN}ElevateUAC "!insertmacro ${_MOZFUNC_UN}ElevateUACCall"
6487
6488    Function ${_MOZFUNC_UN}ElevateUAC
6489      Push $R9
6490      Push $0
6491
6492!ifndef NONADMIN_ELEVATE
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
6498        ${If} "$0" == "1"
6499          UAC::GetElevationType
6500          ; If the user account has a split token
6501          ${If} "$0" == "3"
6502            UAC::RunElevated
6503            UAC::Unload
6504            ; Nothing besides UAC initialized so no need to call OnEndCommon
6505            Quit
6506          ${EndIf}
6507        ${EndIf}
6508      ${Else}
6509        ${GetParameters} $R9
6510        ${If} $R9 != ""
6511          ClearErrors
6512          ${GetOptions} "$R9" "/UAC:" $0
6513          ; If the command line contains /UAC then we need to initialize
6514          ; the UAC plugin to use UAC::ExecCodeSegment to execute code in
6515          ; the non-elevated context.
6516          ${Unless} ${Errors}
6517            UAC::RunElevated
6518          ${EndUnless}
6519        ${EndIf}
6520      ${EndIf}
6521!else
6522      UAC::IsAdmin
6523      ; If the user is not an admin already
6524      ${If} "$0" != "1"
6525        UAC::SupportsUAC
6526        ; If the system supports UAC require that the user elevate
6527        ${If} "$0" == "1"
6528          UAC::GetElevationType
6529          ; If the user account has a split token
6530          ${If} "$0" == "3"
6531            UAC::RunElevated
6532            ${If} "$0" == "0" ; Was elevation successful
6533              UAC::Unload
6534              ; Nothing besides UAC initialized so no need to call OnEndCommon
6535              Quit
6536            ${EndIf}
6537            ; Unload UAC since the elevation request was not successful and
6538            ; install anyway.
6539            UAC::Unload
6540          ${EndIf}
6541        ${Else}
6542          ; Check if UAC is enabled. If the user has turned UAC on or off
6543          ; without rebooting this value will be incorrect. This is an
6544          ; edgecase that we have to live with when trying to allow
6545          ; installing when the user doesn't have privileges such as a public
6546          ; computer while trying to also achieve UAC elevation. When this
6547          ; happens the user will be presented with the runas dialog if the
6548          ; value is 1 and won't be presented with the UAC dialog when the
6549          ; value is 0.
6550          ReadRegDWord $R9 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "EnableLUA"
6551          ${If} "$R9" == "1"
6552            ; This will display the UAC version of the runas dialog which
6553            ; requires a password for an existing user account.
6554            UAC::RunElevated
6555            ${If} "$0" == "0" ; Was elevation successful
6556              UAC::Unload
6557              ; Nothing besides UAC initialized so no need to call OnEndCommon
6558              Quit
6559            ${EndIf}
6560            ; Unload UAC since the elevation request was not successful and
6561            ; install anyway.
6562            UAC::Unload
6563          ${EndIf}
6564        ${EndIf}
6565      ${Else}
6566        ClearErrors
6567        ${${_MOZFUNC_UN}GetParameters} $R9
6568        ${${_MOZFUNC_UN}GetOptions} "$R9" "/UAC:" $R9
6569        ; If the command line contains /UAC then we need to initialize the UAC
6570        ; plugin to use UAC::ExecCodeSegment to execute code in the
6571        ; non-elevated context.
6572        ${Unless} ${Errors}
6573          UAC::RunElevated
6574        ${EndUnless}
6575      ${EndIf}
6576!endif
6577
6578      ClearErrors
6579
6580      Pop $0
6581      Pop $R9
6582    FunctionEnd
6583
6584    !verbose pop
6585  !endif
6586!macroend
6587
6588!macro ElevateUACCall
6589  !verbose push
6590  !verbose ${_MOZFUNC_VERBOSE}
6591  Call ElevateUAC
6592  !verbose pop
6593!macroend
6594
6595!macro un.ElevateUACCall
6596  !verbose push
6597  !verbose ${_MOZFUNC_VERBOSE}
6598  Call un.ElevateUAC
6599  !verbose pop
6600!macroend
6601
6602!macro un.ElevateUAC
6603  !ifndef un.ElevateUAC
6604    !verbose push
6605    !verbose ${_MOZFUNC_VERBOSE}
6606    !undef _MOZFUNC_UN
6607    !define _MOZFUNC_UN "un."
6608
6609    !insertmacro ElevateUAC
6610
6611    !undef _MOZFUNC_UN
6612    !define _MOZFUNC_UN
6613    !verbose pop
6614  !endif
6615!macroend
6616
6617/**
6618 * Unloads the UAC plugin so the NSIS plugins can be removed when the installer
6619 * and uninstaller exit.
6620 *
6621 * $R9 = return values from GetParameters and GetOptions macros
6622 */
6623!macro UnloadUAC
6624
6625  !ifndef ${_MOZFUNC_UN}UnloadUAC
6626    !define _MOZFUNC_UN_TMP_UnloadUAC ${_MOZFUNC_UN}
6627    !insertmacro ${_MOZFUNC_UN_TMP_UnloadUAC}GetOptions
6628    !insertmacro ${_MOZFUNC_UN_TMP_UnloadUAC}GetParameters
6629    !undef _MOZFUNC_UN
6630    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP_UnloadUAC}
6631    !undef _MOZFUNC_UN_TMP_UnloadUAC
6632
6633    !verbose push
6634    !verbose ${_MOZFUNC_VERBOSE}
6635    !define ${_MOZFUNC_UN}UnloadUAC "!insertmacro ${_MOZFUNC_UN}UnloadUACCall"
6636
6637    Function ${_MOZFUNC_UN}UnloadUAC
6638      Push $R9
6639
6640      ClearErrors
6641      ${${_MOZFUNC_UN}GetParameters} $R9
6642      ${${_MOZFUNC_UN}GetOptions} "$R9" "/UAC:" $R9
6643      ; If the command line contains /UAC then we need to unload the UAC plugin
6644      IfErrors +2 +1
6645      UAC::Unload
6646
6647      ClearErrors
6648
6649      Pop $R9
6650    FunctionEnd
6651
6652    !verbose pop
6653  !endif
6654!macroend
6655
6656!macro UnloadUACCall
6657  !verbose push
6658  !verbose ${_MOZFUNC_VERBOSE}
6659  Call UnloadUAC
6660  !verbose pop
6661!macroend
6662
6663!macro un.UnloadUACCall
6664  !verbose push
6665  !verbose ${_MOZFUNC_VERBOSE}
6666  Call un.UnloadUAC
6667  !verbose pop
6668!macroend
6669
6670!macro un.UnloadUAC
6671  !ifndef un.UnloadUAC
6672    !verbose push
6673    !verbose ${_MOZFUNC_VERBOSE}
6674    !undef _MOZFUNC_UN
6675    !define _MOZFUNC_UN "un."
6676
6677    !insertmacro UnloadUAC
6678
6679    !undef _MOZFUNC_UN
6680    !define _MOZFUNC_UN
6681    !verbose pop
6682  !endif
6683!macroend
6684
6685
6686################################################################################
6687# Macros for uninstall.log and install.log logging
6688#
6689# Since these are used by other macros they should be inserted first. All of
6690# these macros can be easily inserted using the _LoggingCommon macro.
6691
6692/**
6693 * Adds all logging macros in the correct order in one fell swoop as well as
6694 * the vars for the install.log and uninstall.log file handles.
6695 */
6696!macro _LoggingCommon
6697  Var /GLOBAL fhInstallLog
6698  Var /GLOBAL fhUninstallLog
6699  !insertmacro StartInstallLog
6700  !insertmacro EndInstallLog
6701  !insertmacro StartUninstallLog
6702  !insertmacro EndUninstallLog
6703!macroend
6704!define _LoggingCommon "!insertmacro _LoggingCommon"
6705
6706/**
6707 * Creates a file named install.log in the install directory (e.g. $INSTDIR)
6708 * and adds the installation started message to the install.log for this
6709 * installation. This also adds the fhInstallLog and fhUninstallLog vars used
6710 * for logging.
6711 *
6712 * $fhInstallLog = filehandle for $INSTDIR\install.log
6713 *
6714 * @param   _APP_NAME
6715 *          Typically the BrandFullName
6716 * @param   _AB_CD
6717 *          The locale identifier
6718 * @param   _APP_VERSION
6719 *          The application version
6720 * @param   _GRE_VERSION
6721 *          The Gecko Runtime Engine version
6722 *
6723 * $R6 = _APP_NAME
6724 * $R7 = _AB_CD
6725 * $R8 = _APP_VERSION
6726 * $R9 = _GRE_VERSION
6727 */
6728!macro StartInstallLog
6729
6730  !ifndef StartInstallLog
6731    !insertmacro GetTime
6732
6733    !verbose push
6734    !verbose ${_MOZFUNC_VERBOSE}
6735    !define StartInstallLog "!insertmacro StartInstallLogCall"
6736
6737    Function StartInstallLog
6738      Exch $R9
6739      Exch 1
6740      Exch $R8
6741      Exch 2
6742      Exch $R7
6743      Exch 3
6744      Exch $R6
6745      Push $R5
6746      Push $R4
6747      Push $R3
6748      Push $R2
6749      Push $R1
6750      Push $R0
6751      Push $9
6752
6753      ${DeleteFile} "$INSTDIR\install.log"
6754      FileOpen $fhInstallLog "$INSTDIR\install.log" w
6755      FileWriteWord $fhInstallLog "65279"
6756
6757      ${GetTime} "" "L" $9 $R0 $R1 $R2 $R3 $R4 $R5
6758      FileWriteUTF16LE $fhInstallLog "$R6 Installation Started: $R1-$R0-$9 $R3:$R4:$R5"
6759      ${WriteLogSeparator}
6760
6761      ${LogHeader} "Installation Details"
6762      ${LogMsg} "Install Dir: $INSTDIR"
6763      ${LogMsg} "Locale     : $R7"
6764      ${LogMsg} "App Version: $R8"
6765      ${LogMsg} "GRE Version: $R9"
6766
6767      ${If} ${IsWin7}
6768        ${LogMsg} "OS Name    : Windows 7"
6769      ${ElseIf} ${IsWin8}
6770        ${LogMsg} "OS Name    : Windows 8"
6771      ${ElseIf} ${IsWin8.1}
6772        ${LogMsg} "OS Name    : Windows 8.1"
6773      ${ElseIf} ${IsWin10}
6774        ${LogMsg} "OS Name    : Windows 10"
6775      ${ElseIf} ${AtLeastWin10}
6776        ${LogMsg} "OS Name    : Above Windows 10"
6777      ${Else}
6778        ${LogMsg} "OS Name    : Unable to detect"
6779      ${EndIf}
6780
6781      ${LogMsg} "Target CPU : ${ARCH}"
6782
6783      Pop $9
6784      Pop $R0
6785      Pop $R1
6786      Pop $R2
6787      Pop $R3
6788      Pop $R4
6789      Pop $R5
6790      Exch $R6
6791      Exch 3
6792      Exch $R7
6793      Exch 2
6794      Exch $R8
6795      Exch 1
6796      Exch $R9
6797    FunctionEnd
6798
6799    !verbose pop
6800  !endif
6801!macroend
6802
6803!macro StartInstallLogCall _APP_NAME _AB_CD _APP_VERSION _GRE_VERSION
6804  !verbose push
6805  !verbose ${_MOZFUNC_VERBOSE}
6806  Push "${_APP_NAME}"
6807  Push "${_AB_CD}"
6808  Push "${_APP_VERSION}"
6809  Push "${_GRE_VERSION}"
6810  Call StartInstallLog
6811  !verbose pop
6812!macroend
6813
6814/**
6815 * Writes the installation finished message to the install.log and closes the
6816 * file handles to the install.log and uninstall.log
6817 *
6818 * @param   _APP_NAME
6819 *
6820 * $R9 = _APP_NAME
6821 */
6822!macro EndInstallLog
6823
6824  !ifndef EndInstallLog
6825    !insertmacro GetTime
6826
6827    !verbose push
6828    !verbose ${_MOZFUNC_VERBOSE}
6829    !define EndInstallLog "!insertmacro EndInstallLogCall"
6830
6831    Function EndInstallLog
6832      Exch $R9
6833      Push $R8
6834      Push $R7
6835      Push $R6
6836      Push $R5
6837      Push $R4
6838      Push $R3
6839      Push $R2
6840
6841      ${WriteLogSeparator}
6842      ${GetTime} "" "L" $R2 $R3 $R4 $R5 $R6 $R7 $R8
6843      FileWriteUTF16LE $fhInstallLog "$R9 Installation Finished: $R4-$R3-$R2 $R6:$R7:$R8$\r$\n"
6844      FileClose $fhInstallLog
6845
6846      Pop $R2
6847      Pop $R3
6848      Pop $R4
6849      Pop $R5
6850      Pop $R6
6851      Pop $R7
6852      Pop $R8
6853      Exch $R9
6854    FunctionEnd
6855
6856    !verbose pop
6857  !endif
6858!macroend
6859
6860!macro EndInstallLogCall _APP_NAME
6861  !verbose push
6862  !verbose ${_MOZFUNC_VERBOSE}
6863  Push "${_APP_NAME}"
6864  Call EndInstallLog
6865  !verbose pop
6866!macroend
6867
6868/**
6869 * Opens the file handle to the uninstall.log.
6870 *
6871 * $fhUninstallLog = filehandle for $INSTDIR\uninstall\uninstall.log
6872 */
6873!macro StartUninstallLog
6874
6875  !ifndef StartUninstallLog
6876    !verbose push
6877    !verbose ${_MOZFUNC_VERBOSE}
6878    !define StartUninstallLog "!insertmacro StartUninstallLogCall"
6879
6880    Function StartUninstallLog
6881      FileOpen $fhUninstallLog "$INSTDIR\uninstall\uninstall.log" w
6882    FunctionEnd
6883
6884    !verbose pop
6885  !endif
6886!macroend
6887
6888!macro StartUninstallLogCall
6889  !verbose push
6890  !verbose ${_MOZFUNC_VERBOSE}
6891  Call StartUninstallLog
6892  !verbose pop
6893!macroend
6894
6895/**
6896 * Closes the file handle to the uninstall.log.
6897 */
6898!macro EndUninstallLog
6899
6900  !ifndef EndUninstallLog
6901
6902    !verbose push
6903    !verbose ${_MOZFUNC_VERBOSE}
6904    !define EndUninstallLog "!insertmacro EndUninstallLogCall"
6905
6906    Function EndUninstallLog
6907      FileClose $fhUninstallLog
6908    FunctionEnd
6909
6910    !verbose pop
6911  !endif
6912!macroend
6913
6914!macro EndUninstallLogCall
6915  !verbose push
6916  !verbose ${_MOZFUNC_VERBOSE}
6917  Call EndUninstallLog
6918  !verbose pop
6919!macroend
6920
6921/**
6922 * Adds a section header to the human readable log.
6923 *
6924 * @param   _HEADER
6925 *          The header text to write to the log.
6926 */
6927!macro LogHeader _HEADER
6928  ${WriteLogSeparator}
6929  FileWriteUTF16LE $fhInstallLog "${_HEADER}"
6930  ${WriteLogSeparator}
6931!macroend
6932!define LogHeader "!insertmacro LogHeader"
6933
6934/**
6935 * Adds a section message to the human readable log.
6936 *
6937 * @param   _MSG
6938 *          The message text to write to the log.
6939 */
6940!macro LogMsg _MSG
6941  FileWriteUTF16LE $fhInstallLog "  ${_MSG}$\r$\n"
6942!macroend
6943!define LogMsg "!insertmacro LogMsg"
6944
6945/**
6946 * Adds an uninstall entry to the uninstall log.
6947 *
6948 * @param   _MSG
6949 *          The message text to write to the log.
6950 */
6951!macro LogUninstall _MSG
6952  FileWrite $fhUninstallLog "${_MSG}$\r$\n"
6953!macroend
6954!define LogUninstall "!insertmacro LogUninstall"
6955
6956/**
6957 * Adds a section divider to the human readable log.
6958 */
6959!macro WriteLogSeparator
6960  FileWriteUTF16LE $fhInstallLog "$\r$\n----------------------------------------\
6961                                  ---------------------------------------$\r$\n"
6962!macroend
6963!define WriteLogSeparator "!insertmacro WriteLogSeparator"
6964
6965
6966################################################################################
6967# Macros for managing the shortcuts log ini file
6968
6969/**
6970 * Adds the most commonly used shortcut logging macros for the installer in one
6971 * fell swoop.
6972 */
6973!macro _LoggingShortcutsCommon
6974  !insertmacro LogDesktopShortcut
6975  !insertmacro LogQuickLaunchShortcut
6976  !insertmacro LogSMProgramsShortcut
6977!macroend
6978!define _LoggingShortcutsCommon "!insertmacro _LoggingShortcutsCommon"
6979
6980/**
6981 * Creates the shortcuts log ini file with a UTF-16LE BOM if it doesn't exist.
6982 */
6983!macro initShortcutsLog
6984  Push $R9
6985
6986  IfFileExists "$INSTDIR\uninstall\${SHORTCUTS_LOG}" +4 +1
6987  FileOpen $R9 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" w
6988  FileWriteWord $R9 "65279"
6989  FileClose $R9
6990
6991  Pop $R9
6992!macroend
6993!define initShortcutsLog "!insertmacro initShortcutsLog"
6994
6995/**
6996 * Adds shortcut entries to the shortcuts log ini file. This macro is primarily
6997 * a helper used by the LogDesktopShortcut, LogQuickLaunchShortcut, and
6998 * LogSMProgramsShortcut macros but it can be used by other code if desired. If
6999 * the value already exists the the value is not written to the file.
7000 *
7001 * @param   _SECTION_NAME
7002 *          The section name to write to in the shortcut log ini file
7003 * @param   _FILE_NAME
7004 *          The shortcut's file name
7005 *
7006 * $R6 = return value from ReadIniStr for the shortcut file name
7007 * $R7 = counter for supporting multiple shortcuts in the same location
7008 * $R8 = _SECTION_NAME
7009 * $R9 = _FILE_NAME
7010 */
7011!macro LogShortcut
7012
7013  !ifndef LogShortcut
7014    !verbose push
7015    !verbose ${_MOZFUNC_VERBOSE}
7016    !define LogShortcut "!insertmacro LogShortcutCall"
7017
7018    Function LogShortcut
7019      Exch $R9
7020      Exch 1
7021      Exch $R8
7022      Push $R7
7023      Push $R6
7024
7025      ClearErrors
7026
7027      !insertmacro initShortcutsLog
7028
7029      StrCpy $R6 ""
7030      StrCpy $R7 -1
7031
7032      StrCmp "$R6" "$R9" +5 +1 ; if the shortcut already exists don't add it
7033      IntOp $R7 $R7 + 1 ; increment the counter
7034      ReadIniStr $R6 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "$R8" "Shortcut$R7"
7035      IfErrors +1 -3
7036      WriteINIStr "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "$R8" "Shortcut$R7" "$R9"
7037
7038      ClearErrors
7039
7040      Pop $R6
7041      Pop $R7
7042      Exch $R8
7043      Exch 1
7044      Exch $R9
7045    FunctionEnd
7046
7047    !verbose pop
7048  !endif
7049!macroend
7050
7051!macro LogShortcutCall _SECTION_NAME _FILE_NAME
7052  !verbose push
7053  !verbose ${_MOZFUNC_VERBOSE}
7054  Push "${_SECTION_NAME}"
7055  Push "${_FILE_NAME}"
7056  Call LogShortcut
7057  !verbose pop
7058!macroend
7059
7060/**
7061 * Adds a Desktop shortcut entry to the shortcuts log ini file.
7062 *
7063 * @param   _FILE_NAME
7064 *          The shortcut file name (e.g. shortcut.lnk)
7065 */
7066!macro LogDesktopShortcut
7067
7068  !ifndef LogDesktopShortcut
7069    !insertmacro LogShortcut
7070
7071    !verbose push
7072    !verbose ${_MOZFUNC_VERBOSE}
7073    !define LogDesktopShortcut "!insertmacro LogDesktopShortcutCall"
7074
7075    Function LogDesktopShortcut
7076      Call LogShortcut
7077    FunctionEnd
7078
7079    !verbose pop
7080  !endif
7081!macroend
7082
7083!macro LogDesktopShortcutCall _FILE_NAME
7084  !verbose push
7085  !verbose ${_MOZFUNC_VERBOSE}
7086  Push "DESKTOP"
7087  Push "${_FILE_NAME}"
7088  Call LogDesktopShortcut
7089  !verbose pop
7090!macroend
7091
7092/**
7093 * Adds a QuickLaunch shortcut entry to the shortcuts log ini file.
7094 *
7095 * @param   _FILE_NAME
7096 *          The shortcut file name (e.g. shortcut.lnk)
7097 */
7098!macro LogQuickLaunchShortcut
7099
7100  !ifndef LogQuickLaunchShortcut
7101    !insertmacro LogShortcut
7102
7103    !verbose push
7104    !verbose ${_MOZFUNC_VERBOSE}
7105    !define LogQuickLaunchShortcut "!insertmacro LogQuickLaunchShortcutCall"
7106
7107    Function LogQuickLaunchShortcut
7108      Call LogShortcut
7109    FunctionEnd
7110
7111    !verbose pop
7112  !endif
7113!macroend
7114
7115!macro LogQuickLaunchShortcutCall _FILE_NAME
7116  !verbose push
7117  !verbose ${_MOZFUNC_VERBOSE}
7118  Push "QUICKLAUNCH"
7119  Push "${_FILE_NAME}"
7120  Call LogQuickLaunchShortcut
7121  !verbose pop
7122!macroend
7123
7124/**
7125 * Adds a Start Menu shortcut entry to the shortcuts log ini file.
7126 *
7127 * @param   _FILE_NAME
7128 *          The shortcut file name (e.g. shortcut.lnk)
7129 */
7130!macro LogStartMenuShortcut
7131
7132  !ifndef LogStartMenuShortcut
7133    !insertmacro LogShortcut
7134
7135    !verbose push
7136    !verbose ${_MOZFUNC_VERBOSE}
7137    !define LogStartMenuShortcut "!insertmacro LogStartMenuShortcutCall"
7138
7139    Function LogStartMenuShortcut
7140      Call LogShortcut
7141    FunctionEnd
7142
7143    !verbose pop
7144  !endif
7145!macroend
7146
7147!macro LogStartMenuShortcutCall _FILE_NAME
7148  !verbose push
7149  !verbose ${_MOZFUNC_VERBOSE}
7150  Push "STARTMENU"
7151  Push "${_FILE_NAME}"
7152  Call LogStartMenuShortcut
7153  !verbose pop
7154!macroend
7155
7156/**
7157 * Adds a Start Menu Programs shortcut entry to the shortcuts log ini file.
7158 *
7159 * @param   _FILE_NAME
7160 *          The shortcut file name (e.g. shortcut.lnk)
7161 */
7162!macro LogSMProgramsShortcut
7163
7164  !ifndef LogSMProgramsShortcut
7165    !insertmacro LogShortcut
7166
7167    !verbose push
7168    !verbose ${_MOZFUNC_VERBOSE}
7169    !define LogSMProgramsShortcut "!insertmacro LogSMProgramsShortcutCall"
7170
7171    Function LogSMProgramsShortcut
7172      Call LogShortcut
7173    FunctionEnd
7174
7175    !verbose pop
7176  !endif
7177!macroend
7178
7179!macro LogSMProgramsShortcutCall _FILE_NAME
7180  !verbose push
7181  !verbose ${_MOZFUNC_VERBOSE}
7182  Push "SMPROGRAMS"
7183  Push "${_FILE_NAME}"
7184  Call LogSMProgramsShortcut
7185  !verbose pop
7186!macroend
7187
7188/**
7189 * Adds the relative path from the Start Menu Programs directory for the
7190 * application's Start Menu directory if it is different from the existing value
7191 * to the shortcuts log ini file.
7192 *
7193 * @param   _REL_PATH_TO_DIR
7194 *          The relative path from the Start Menu Programs directory to the
7195 *          program's directory.
7196 *
7197 * $R9 = _REL_PATH_TO_DIR
7198 */
7199!macro LogSMProgramsDirRelPath _REL_PATH_TO_DIR
7200  Push $R9
7201
7202  !insertmacro initShortcutsLog
7203
7204  ReadINIStr $R9 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" "RelativePathToDir"
7205  StrCmp "$R9" "${_REL_PATH_TO_DIR}" +2 +1
7206  WriteINIStr "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" "RelativePathToDir" "${_REL_PATH_TO_DIR}"
7207
7208  Pop $R9
7209!macroend
7210!define LogSMProgramsDirRelPath "!insertmacro LogSMProgramsDirRelPath"
7211
7212/**
7213 * Copies the value for the relative path from the Start Menu programs directory
7214 * (e.g. $SMPROGRAMS) to the Start Menu directory as it is stored in the
7215 * shortcuts log ini file to the variable specified in the first parameter.
7216 */
7217!macro GetSMProgramsDirRelPath _VAR
7218  ReadINIStr ${_VAR} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" \
7219             "RelativePathToDir"
7220!macroend
7221!define GetSMProgramsDirRelPath "!insertmacro GetSMProgramsDirRelPath"
7222
7223/**
7224 * Copies the shortcuts log ini file path to the variable specified in the
7225 * first parameter.
7226 */
7227!macro GetShortcutsLogPath _VAR
7228  StrCpy ${_VAR} "$INSTDIR\uninstall\${SHORTCUTS_LOG}"
7229!macroend
7230!define GetShortcutsLogPath "!insertmacro GetShortcutsLogPath"
7231
7232/**
7233 * Deletes the shortcuts log ini file.
7234 */
7235!macro DeleteShortcutsLogFile
7236  ${DeleteFile} "$INSTDIR\uninstall\${SHORTCUTS_LOG}"
7237!macroend
7238!define DeleteShortcutsLogFile "!insertmacro DeleteShortcutsLogFile"
7239
7240
7241################################################################################
7242# Macros for managing specific Windows version features
7243
7244/**
7245 * Sets the permitted layered service provider (LSP) categories
7246 * for the application. Consumers should call this after an
7247 * installation log section has completed since this macro will log the results
7248 * to the installation log along with a header.
7249 *
7250 * !IMPORTANT - When calling this macro from an uninstaller do not specify a
7251 *              parameter. The paramter is hardcoded with 0x00000000 to remove
7252 *              the LSP category for the application when performing an
7253 *              uninstall.
7254 *
7255 * @param   _LSP_CATEGORIES
7256 *          The permitted LSP categories for the application. When called by an
7257 *          uninstaller this will always be 0x00000000.
7258 *
7259 * $R5 = error code popped from the stack for the WSCSetApplicationCategory call
7260 * $R6 = return value from the WSCSetApplicationCategory call
7261 * $R7 = string length for the long path to the main application executable
7262 * $R8 = long path to the main application executable
7263 * $R9 = _LSP_CATEGORIES
7264 */
7265!macro SetAppLSPCategories
7266
7267  !ifndef ${_MOZFUNC_UN}SetAppLSPCategories
7268    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
7269    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
7270    !undef _MOZFUNC_UN
7271    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
7272    !undef _MOZFUNC_UN_TMP
7273
7274    !verbose push
7275    !verbose ${_MOZFUNC_VERBOSE}
7276    !define ${_MOZFUNC_UN}SetAppLSPCategories "!insertmacro ${_MOZFUNC_UN}SetAppLSPCategoriesCall"
7277
7278    Function ${_MOZFUNC_UN}SetAppLSPCategories
7279      Exch $R9
7280      Push $R8
7281      Push $R7
7282      Push $R6
7283      Push $R5
7284
7285      ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR\${FileMainEXE}" $R8
7286      StrLen $R7 "$R8"
7287
7288      ; Remove existing categories by setting the permitted categories to
7289      ; 0x00000000 since new categories are ANDed with existing categories. If
7290      ; the param value stored in $R9 is 0x00000000 then skip the removal since
7291      ; the categories  will be removed by the second call to
7292      ; WSCSetApplicationCategory.
7293      StrCmp "$R9" "0x00000000" +2 +1
7294      System::Call "Ws2_32::WSCSetApplicationCategory(w R8, i R7, w n, i 0,\
7295                                                      i 0x00000000, i n, *i) i"
7296
7297      ; Set the permitted LSP categories
7298      System::Call "Ws2_32::WSCSetApplicationCategory(w R8, i R7, w n, i 0,\
7299                                                      i R9, i n, *i .s) i.R6"
7300      Pop $R5
7301
7302!ifndef NO_LOG
7303      ${LogHeader} "Setting Permitted LSP Categories"
7304      StrCmp "$R6" 0 +3 +1
7305      ${LogMsg} "** ERROR Setting LSP Categories: $R5 **"
7306      GoTo +2
7307      ${LogMsg} "Permitted LSP Categories: $R9"
7308!endif
7309
7310      ClearErrors
7311
7312      Pop $R5
7313      Pop $R6
7314      Pop $R7
7315      Pop $R8
7316      Exch $R9
7317    FunctionEnd
7318
7319    !verbose pop
7320  !endif
7321!macroend
7322
7323!macro SetAppLSPCategoriesCall _LSP_CATEGORIES
7324  !verbose push
7325  !verbose ${_MOZFUNC_VERBOSE}
7326  Push "${_LSP_CATEGORIES}"
7327  Call SetAppLSPCategories
7328  !verbose pop
7329!macroend
7330
7331!macro un.SetAppLSPCategoriesCall
7332  !verbose push
7333  !verbose ${_MOZFUNC_VERBOSE}
7334  Push "0x00000000"
7335  Call un.SetAppLSPCategories
7336  !verbose pop
7337!macroend
7338
7339!macro un.SetAppLSPCategories
7340  !ifndef un.SetAppLSPCategories
7341    !verbose push
7342    !verbose ${_MOZFUNC_VERBOSE}
7343    !undef _MOZFUNC_UN
7344    !define _MOZFUNC_UN "un."
7345
7346    !insertmacro SetAppLSPCategories
7347
7348    !undef _MOZFUNC_UN
7349    !define _MOZFUNC_UN
7350    !verbose pop
7351  !endif
7352!macroend
7353
7354/**
7355 * Checks if any pinned TaskBar lnk files point to the executable's path passed
7356 * to the macro.
7357 *
7358 * @param   _EXE_PATH
7359 *          The executable path
7360 * @return  _RESULT
7361 *          false if no pinned shotcuts were found for this install location.
7362 *          true if pinned shotcuts were found for this install location.
7363 *
7364 * $R5 = stores whether a TaskBar lnk file has been found for the executable
7365 * $R6 = long path returned from GetShortCutTarget and GetLongPath
7366 * $R7 = file name returned from FindFirst and FindNext
7367 * $R8 = find handle for FindFirst and FindNext
7368 * $R9 = _EXE_PATH and _RESULT
7369 */
7370!macro IsPinnedToTaskBar
7371
7372  !ifndef IsPinnedToTaskBar
7373    !insertmacro GetLongPath
7374
7375    !verbose push
7376    !verbose ${_MOZFUNC_VERBOSE}
7377    !define IsPinnedToTaskBar "!insertmacro IsPinnedToTaskBarCall"
7378
7379    Function IsPinnedToTaskBar
7380      Exch $R9
7381      Push $R8
7382      Push $R7
7383      Push $R6
7384      Push $R5
7385
7386      StrCpy $R5 "false"
7387
7388      ${If} ${AtLeastWin7}
7389      ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar"
7390        FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\TaskBar\*.lnk"
7391        ${Do}
7392          ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar\$R7"
7393            ShellLink::GetShortCutTarget "$QUICKLAUNCH\User Pinned\TaskBar\$R7"
7394            Pop $R6
7395            ${GetLongPath} "$R6" $R6
7396            ${If} "$R6" == "$R9"
7397              StrCpy $R5 "true"
7398              ${ExitDo}
7399            ${EndIf}
7400          ${EndIf}
7401          ClearErrors
7402          FindNext $R8 $R7
7403          ${If} ${Errors}
7404            ${ExitDo}
7405          ${EndIf}
7406        ${Loop}
7407        FindClose $R8
7408      ${EndIf}
7409
7410      ClearErrors
7411
7412      StrCpy $R9 $R5
7413
7414      Pop $R5
7415      Pop $R6
7416      Pop $R7
7417      Pop $R8
7418      Exch $R9
7419    FunctionEnd
7420
7421    !verbose pop
7422  !endif
7423!macroend
7424
7425!macro IsPinnedToTaskBarCall _EXE_PATH _RESULT
7426  !verbose push
7427  !verbose ${_MOZFUNC_VERBOSE}
7428  Push "${_EXE_PATH}"
7429  Call IsPinnedToTaskBar
7430  Pop ${_RESULT}
7431  !verbose pop
7432!macroend
7433
7434/**
7435 * Checks if any pinned Start Menu lnk files point to the executable's path
7436 * passed to the macro.
7437 *
7438 * @param   _EXE_PATH
7439 *          The executable path
7440 * @return  _RESULT
7441 *          false if no pinned shotcuts were found for this install location.
7442 *          true if pinned shotcuts were found for this install location.
7443 *
7444 * $R5 = stores whether a Start Menu lnk file has been found for the executable
7445 * $R6 = long path returned from GetShortCutTarget and GetLongPath
7446 * $R7 = file name returned from FindFirst and FindNext
7447 * $R8 = find handle for FindFirst and FindNext
7448 * $R9 = _EXE_PATH and _RESULT
7449 */
7450!macro IsPinnedToStartMenu
7451
7452  !ifndef IsPinnedToStartMenu
7453    !insertmacro GetLongPath
7454
7455    !verbose push
7456    !verbose ${_MOZFUNC_VERBOSE}
7457    !define IsPinnedToStartMenu "!insertmacro IsPinnedToStartMenuCall"
7458
7459    Function IsPinnedToStartMenu
7460      Exch $R9
7461      Push $R8
7462      Push $R7
7463      Push $R6
7464      Push $R5
7465
7466      StrCpy $R5 "false"
7467
7468      ${If} ${AtLeastWin7}
7469      ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu"
7470        FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\StartMenu\*.lnk"
7471        ${Do}
7472          ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu\$R7"
7473            ShellLink::GetShortCutTarget "$QUICKLAUNCH\User Pinned\StartMenu\$R7"
7474            Pop $R6
7475            ${GetLongPath} "$R6" $R6
7476            ${If} "$R6" == "$R9"
7477              StrCpy $R5 "true"
7478              ${ExitDo}
7479            ${EndIf}
7480          ${EndIf}
7481          ClearErrors
7482          FindNext $R8 $R7
7483          ${If} ${Errors}
7484            ${ExitDo}
7485          ${EndIf}
7486        ${Loop}
7487        FindClose $R8
7488      ${EndIf}
7489
7490      ClearErrors
7491
7492      StrCpy $R9 $R5
7493
7494      Pop $R5
7495      Pop $R6
7496      Pop $R7
7497      Pop $R8
7498      Exch $R9
7499    FunctionEnd
7500
7501    !verbose pop
7502  !endif
7503!macroend
7504
7505!macro IsPinnedToStartMenuCall _EXE_PATH _RESULT
7506  !verbose push
7507  !verbose ${_MOZFUNC_VERBOSE}
7508  Push "${_EXE_PATH}"
7509  Call IsPinnedToStartMenu
7510  Pop ${_RESULT}
7511  !verbose pop
7512!macroend
7513
7514/**
7515 * Gets the number of pinned shortcut lnk files pinned to the Task Bar.
7516 *
7517 * @return  _RESULT
7518 *          number of pinned shortcut lnk files.
7519 *
7520 * $R7 = file name returned from FindFirst and FindNext
7521 * $R8 = find handle for FindFirst and FindNext
7522 * $R9 = _RESULT
7523 */
7524!macro PinnedToTaskBarLnkCount
7525
7526  !ifndef PinnedToTaskBarLnkCount
7527    !insertmacro GetLongPath
7528
7529    !verbose push
7530    !verbose ${_MOZFUNC_VERBOSE}
7531    !define PinnedToTaskBarLnkCount "!insertmacro PinnedToTaskBarLnkCountCall"
7532
7533    Function PinnedToTaskBarLnkCount
7534      Push $R9
7535      Push $R8
7536      Push $R7
7537
7538      StrCpy $R9 0
7539
7540      ${If} ${AtLeastWin7}
7541      ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar"
7542        FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\TaskBar\*.lnk"
7543        ${Do}
7544          ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar\$R7"
7545            IntOp $R9 $R9 + 1
7546          ${EndIf}
7547          ClearErrors
7548          FindNext $R8 $R7
7549          ${If} ${Errors}
7550            ${ExitDo}
7551          ${EndIf}
7552        ${Loop}
7553        FindClose $R8
7554      ${EndIf}
7555
7556      ClearErrors
7557
7558      Pop $R7
7559      Pop $R8
7560      Exch $R9
7561    FunctionEnd
7562
7563    !verbose pop
7564  !endif
7565!macroend
7566
7567!macro PinnedToTaskBarLnkCountCall _RESULT
7568  !verbose push
7569  !verbose ${_MOZFUNC_VERBOSE}
7570  Call PinnedToTaskBarLnkCount
7571  Pop ${_RESULT}
7572  !verbose pop
7573!macroend
7574
7575/**
7576 * Gets the number of pinned shortcut lnk files pinned to the Start Menu.
7577 *
7578 * @return  _RESULT
7579 *          number of pinned shortcut lnk files.
7580 *
7581 * $R7 = file name returned from FindFirst and FindNext
7582 * $R8 = find handle for FindFirst and FindNext
7583 * $R9 = _RESULT
7584 */
7585!macro PinnedToStartMenuLnkCount
7586
7587  !ifndef PinnedToStartMenuLnkCount
7588    !insertmacro GetLongPath
7589
7590    !verbose push
7591    !verbose ${_MOZFUNC_VERBOSE}
7592    !define PinnedToStartMenuLnkCount "!insertmacro PinnedToStartMenuLnkCountCall"
7593
7594    Function PinnedToStartMenuLnkCount
7595      Push $R9
7596      Push $R8
7597      Push $R7
7598
7599      StrCpy $R9 0
7600
7601      ${If} ${AtLeastWin7}
7602      ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu"
7603        FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\StartMenu\*.lnk"
7604        ${Do}
7605          ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu\$R7"
7606            IntOp $R9 $R9 + 1
7607          ${EndIf}
7608          ClearErrors
7609          FindNext $R8 $R7
7610          ${If} ${Errors}
7611            ${ExitDo}
7612          ${EndIf}
7613        ${Loop}
7614        FindClose $R8
7615      ${EndIf}
7616
7617      ClearErrors
7618
7619      Pop $R7
7620      Pop $R8
7621      Exch $R9
7622    FunctionEnd
7623
7624    !verbose pop
7625  !endif
7626!macroend
7627
7628!macro PinnedToStartMenuLnkCountCall _RESULT
7629  !verbose push
7630  !verbose ${_MOZFUNC_VERBOSE}
7631  Call PinnedToStartMenuLnkCount
7632  Pop ${_RESULT}
7633  !verbose pop
7634!macroend
7635
7636/**
7637 * Update Start Menu / TaskBar lnk files that point to the executable's path
7638 * passed to the macro and all other shortcuts installed by the application with
7639 * the current application user model ID. Requires ApplicationID.
7640 *
7641 * NOTE: this does not update Desktop shortcut application user model ID due to
7642 *       bug 633728.
7643 *
7644 * @param   _EXE_PATH
7645 *          The main application executable path
7646 * @param   _APP_ID
7647 *          The application user model ID for the current install
7648 * @return  _RESULT
7649 *          false if no pinned shotcuts were found for this install location.
7650 *          true if pinned shotcuts were found for this install location.
7651 */
7652!macro UpdateShortcutAppModelIDs
7653
7654  !ifndef UpdateShortcutAppModelIDs
7655    !insertmacro GetLongPath
7656
7657    !verbose push
7658    !verbose ${_MOZFUNC_VERBOSE}
7659    !define UpdateShortcutAppModelIDs "!insertmacro UpdateShortcutAppModelIDsCall"
7660
7661    Function UpdateShortcutAppModelIDs
7662      ; stack: path, appid
7663      Exch $R9 ; stack: $R9, appid | $R9 = path
7664      Exch 1   ; stack: appid, $R9
7665      Exch $R8 ; stack: $R8, $R9   | $R8 = appid
7666      Push $R7 ; stack: $R7, $R8, $R9
7667      Push $R6
7668      Push $R5
7669      Push $R4
7670      Push $R3 ; stack: $R3, $R5, $R6, $R7, $R8, $R9
7671      Push $R2
7672
7673      ; $R9 = main application executable path
7674      ; $R8 = appid
7675      ; $R7 = path to the application's start menu programs directory
7676      ; $R6 = path to the shortcut log ini file
7677      ; $R5 = shortcut filename
7678      ; $R4 = GetShortCutTarget result
7679
7680      StrCpy $R3 "false"
7681
7682      ${If} ${AtLeastWin7}
7683        ; installed shortcuts
7684        ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" $R6
7685        ${If} ${FileExists} "$R6"
7686          ; Update the Start Menu shortcuts' App ID for this application
7687          StrCpy $R2 -1
7688          ${Do}
7689            IntOp $R2 $R2 + 1 ; Increment the counter
7690            ClearErrors
7691            ReadINIStr $R5 "$R6" "STARTMENU" "Shortcut$R2"
7692            ${If} ${Errors}
7693              ${ExitDo}
7694            ${EndIf}
7695
7696            ${If} ${FileExists} "$SMPROGRAMS\$R5"
7697              ShellLink::GetShortCutTarget "$SMPROGRAMS\$$R5"
7698              Pop $R4
7699              ${GetLongPath} "$R4" $R4
7700              ${If} "$R4" == "$R9" ; link path == install path
7701                ApplicationID::Set "$SMPROGRAMS\$R5" "$R8" "true"
7702                Pop $R4
7703              ${EndIf}
7704            ${EndIf}
7705          ${Loop}
7706
7707          ; Update the Quick Launch shortcuts' App ID for this application
7708          StrCpy $R2 -1
7709          ${Do}
7710            IntOp $R2 $R2 + 1 ; Increment the counter
7711            ClearErrors
7712            ReadINIStr $R5 "$R6" "QUICKLAUNCH" "Shortcut$R2"
7713            ${If} ${Errors}
7714              ${ExitDo}
7715            ${EndIf}
7716
7717            ${If} ${FileExists} "$QUICKLAUNCH\$R5"
7718              ShellLink::GetShortCutTarget "$QUICKLAUNCH\$R5"
7719              Pop $R4
7720              ${GetLongPath} "$R4" $R4
7721              ${If} "$R4" == "$R9" ; link path == install path
7722                ApplicationID::Set "$QUICKLAUNCH\$R5" "$R8" "true"
7723                Pop $R4
7724              ${EndIf}
7725            ${EndIf}
7726          ${Loop}
7727
7728          ; Update the Start Menu Programs shortcuts' App ID for this application
7729          ClearErrors
7730          ReadINIStr $R7 "$R6" "SMPROGRAMS" "RelativePathToDir"
7731          ${Unless} ${Errors}
7732            ${${_MOZFUNC_UN}GetLongPath} "$SMPROGRAMS\$R7" $R7
7733            ${Unless} "$R7" == ""
7734              StrCpy $R2 -1
7735              ${Do}
7736                IntOp $R2 $R2 + 1 ; Increment the counter
7737                ClearErrors
7738                ReadINIStr $R5 "$R6" "SMPROGRAMS" "Shortcut$R2"
7739                ${If} ${Errors}
7740                  ${ExitDo}
7741                ${EndIf}
7742
7743                ${If} ${FileExists} "$R7\$R5"
7744                  ShellLink::GetShortCutTarget "$R7\$R5"
7745                  Pop $R4
7746                  ${GetLongPath} "$R4" $R4
7747                  ${If} "$R4" == "$R9" ; link path == install path
7748                    ApplicationID::Set "$R7\$R5" "$R8" "true"
7749                    Pop $R4
7750                  ${EndIf}
7751                ${EndIf}
7752              ${Loop}
7753            ${EndUnless}
7754          ${EndUnless}
7755        ${EndIf}
7756
7757        StrCpy $R7 "$QUICKLAUNCH\User Pinned"
7758        StrCpy $R3 "false"
7759
7760        ; $R9 = main application executable path
7761        ; $R8 = appid
7762        ; $R7 = user pinned path
7763        ; $R6 = find handle
7764        ; $R5 = found filename
7765        ; $R4 = GetShortCutTarget result
7766
7767        ; TaskBar links
7768        FindFirst $R6 $R5 "$R7\TaskBar\*.lnk"
7769        ${Do}
7770          ${If} ${FileExists} "$R7\TaskBar\$R5"
7771            ShellLink::GetShortCutTarget "$R7\TaskBar\$R5"
7772            Pop $R4
7773            ${If} "$R4" == "$R9" ; link path == install path
7774              ApplicationID::Set "$R7\TaskBar\$R5" "$R8" "true"
7775              Pop $R4 ; pop Set result off the stack
7776              StrCpy $R3 "true"
7777            ${EndIf}
7778          ${EndIf}
7779          ClearErrors
7780          FindNext $R6 $R5
7781          ${If} ${Errors}
7782            ${ExitDo}
7783          ${EndIf}
7784        ${Loop}
7785        FindClose $R6
7786
7787        ; Start menu links
7788        FindFirst $R6 $R5 "$R7\StartMenu\*.lnk"
7789        ${Do}
7790          ${If} ${FileExists} "$R7\StartMenu\$R5"
7791            ShellLink::GetShortCutTarget "$R7\StartMenu\$R5"
7792            Pop $R4
7793            ${If} "$R4" == "$R9" ; link path == install path
7794              ApplicationID::Set "$R7\StartMenu\$R5" "$R8" "true"
7795              Pop $R4 ; pop Set result off the stack
7796              StrCpy $R3 "true"
7797            ${EndIf}
7798          ${EndIf}
7799          ClearErrors
7800          FindNext $R6 $R5
7801          ${If} ${Errors}
7802            ${ExitDo}
7803          ${EndIf}
7804        ${Loop}
7805        FindClose $R6
7806      ${EndIf}
7807
7808      ClearErrors
7809
7810      StrCpy $R9 $R3
7811
7812      Pop $R2
7813      Pop $R3  ; stack: $R4, $R5, $R6, $R7, $R8, $R9
7814      Pop $R4  ; stack: $R5, $R6, $R7, $R8, $R9
7815      Pop $R5  ; stack: $R6, $R7, $R8, $R9
7816      Pop $R6  ; stack: $R7, $R8, $R9
7817      Pop $R7  ; stack: $R8, $R9
7818      Exch $R8 ; stack: appid, $R9 | $R8 = old $R8
7819      Exch 1   ; stack: $R9, appid
7820      Exch $R9 ; stack: path, appid | $R9 = old $R9
7821    FunctionEnd
7822
7823    !verbose pop
7824  !endif
7825!macroend
7826
7827!macro UpdateShortcutAppModelIDsCall _EXE_PATH _APP_ID _RESULT
7828  !verbose push
7829  !verbose ${_MOZFUNC_VERBOSE}
7830  Push "${_APP_ID}"
7831  Push "${_EXE_PATH}"
7832  Call UpdateShortcutAppModelIDs
7833  Pop ${_RESULT}
7834  !verbose pop
7835!macroend
7836
7837!macro IsUserAdmin
7838  ; Copied from: http://nsis.sourceforge.net/IsUserAdmin
7839  Function IsUserAdmin
7840    Push $R0
7841    Push $R1
7842    Push $R2
7843
7844    ClearErrors
7845    UserInfo::GetName
7846    IfErrors Win9x
7847    Pop $R1
7848    UserInfo::GetAccountType
7849    Pop $R2
7850
7851    StrCmp $R2 "Admin" 0 Continue
7852    StrCpy $R0 "true"
7853    Goto Done
7854
7855    Continue:
7856
7857    StrCmp $R2 "" Win9x
7858    StrCpy $R0 "false"
7859    Goto Done
7860
7861    Win9x:
7862    StrCpy $R0 "true"
7863
7864    Done:
7865    Pop $R2
7866    Pop $R1
7867    Exch $R0
7868  FunctionEnd
7869!macroend
7870
7871/**
7872 * Retrieve if present or generate and store a 64 bit hash of an install path
7873 * using the City Hash algorithm.  On return the resulting id is saved in the
7874 * $AppUserModelID variable declared by inserting this macro. InitHashAppModelId
7875 * will attempt to load from HKLM/_REG_PATH first, then HKCU/_REG_PATH. If found
7876 * in either it will return the hash it finds. If not found it will generate a
7877 * new hash and attempt to store the hash in HKLM/_REG_PATH, then HKCU/_REG_PATH.
7878 * Subsequent calls will then retreive the stored hash value. On any failure,
7879 * $AppUserModelID will be set to an empty string.
7880 *
7881 * Registry format: root/_REG_PATH/"_EXE_PATH" = "hash"
7882 *
7883 * @param   _EXE_PATH
7884 *          The main application executable path
7885 * @param   _REG_PATH
7886 *          The HKLM/HKCU agnostic registry path where the key hash should
7887 *          be stored. ex: "Software\Mozilla\Firefox\TaskBarIDs"
7888 * @result  (Var) $AppUserModelID contains the app model id.
7889 */
7890!macro InitHashAppModelId
7891  !ifndef ${_MOZFUNC_UN}InitHashAppModelId
7892    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
7893    !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath
7894    !undef _MOZFUNC_UN
7895    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
7896    !undef _MOZFUNC_UN_TMP
7897
7898    !ifndef InitHashAppModelId
7899      Var AppUserModelID
7900    !endif
7901
7902    !verbose push
7903    !verbose ${_MOZFUNC_VERBOSE}
7904    !define ${_MOZFUNC_UN}InitHashAppModelId "!insertmacro ${_MOZFUNC_UN}InitHashAppModelIdCall"
7905
7906    Function ${_MOZFUNC_UN}InitHashAppModelId
7907      ; stack: apppath, regpath
7908      Exch $R9 ; stack: $R9, regpath | $R9 = apppath
7909      Exch 1   ; stack: regpath, $R9
7910      Exch $R8 ; stack: $R8, $R9   | $R8 = regpath
7911      Push $R7
7912
7913      ${If} ${AtLeastWin7}
7914        ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9
7915        ; Always create a new AppUserModelID and overwrite the existing one
7916        ; for the current installation path.
7917        CityHash::GetCityHash64 "$R9"
7918        Pop $AppUserModelID
7919        ${If} $AppUserModelID == "error"
7920          GoTo end
7921        ${EndIf}
7922        ClearErrors
7923        WriteRegStr HKLM "$R8" "$R9" "$AppUserModelID"
7924        ${If} ${Errors}
7925          ClearErrors
7926          WriteRegStr HKCU "$R8" "$R9" "$AppUserModelID"
7927          ${If} ${Errors}
7928            StrCpy $AppUserModelID "error"
7929          ${EndIf}
7930        ${EndIf}
7931      ${EndIf}
7932
7933      end:
7934      ${If} "$AppUserModelID" == "error"
7935        StrCpy $AppUserModelID ""
7936      ${EndIf}
7937
7938      ClearErrors
7939      Pop $R7
7940      Exch $R8
7941      Exch 1
7942      Exch $R9
7943    FunctionEnd
7944
7945    !verbose pop
7946  !endif
7947!macroend
7948
7949!macro InitHashAppModelIdCall _EXE_PATH _REG_PATH
7950  !verbose push
7951  !verbose ${_MOZFUNC_VERBOSE}
7952  Push "${_REG_PATH}"
7953  Push "${_EXE_PATH}"
7954  Call InitHashAppModelId
7955  !verbose pop
7956!macroend
7957
7958!macro un.InitHashAppModelIdCall _EXE_PATH _REG_PATH
7959  !verbose push
7960  !verbose ${_MOZFUNC_VERBOSE}
7961  Push "${_REG_PATH}"
7962  Push "${_EXE_PATH}"
7963  Call un.InitHashAppModelId
7964  !verbose pop
7965!macroend
7966
7967!macro un.InitHashAppModelId
7968  !ifndef un.InitHashAppModelId
7969    !verbose push
7970    !verbose ${_MOZFUNC_VERBOSE}
7971    !undef _MOZFUNC_UN
7972    !define _MOZFUNC_UN "un."
7973
7974    !insertmacro InitHashAppModelId
7975
7976    !undef _MOZFUNC_UN
7977    !define _MOZFUNC_UN
7978    !verbose pop
7979  !endif
7980!macroend
7981
7982/**
7983 * Try to locate the default profile of this install from AppUserModelID
7984 * using installs.ini.
7985 * FIXME This could instead use the Install<AUMID> entries in profiles.ini?
7986 *
7987 * - `SetShellVarContext current` must be called before this macro so
7988 *   $APPDATA gets the current user's data.
7989 * - InitHashAppModelId must have been called before this macro to set
7990 *   $AppUserModelID
7991 *
7992 * @result: Path of the profile directory (not checked for existence),
7993 *          or "" if not found, left on top of the stack.
7994 */
7995!macro FindInstallSpecificProfileMaybeUn _MOZFUNC_UN
7996  Push $R0
7997  Push $0
7998  Push $1
7999  Push $2
8000
8001  StrCpy $R0 ""
8002  ; Look for an install-specific profile, which might be listed as
8003  ; either a relative or an absolute path (installs.ini doesn't say which).
8004  ${If} ${FileExists} "$APPDATA\Mozilla\Firefox\installs.ini"
8005    ClearErrors
8006    ReadINIStr $1 "$APPDATA\Mozilla\Firefox\installs.ini" "$AppUserModelID" "Default"
8007    ${IfNot} ${Errors}
8008      ${${_MOZFUNC_UN}GetLongPath} "$APPDATA\Mozilla\Firefox\$1" $2
8009      ${If} ${FileExists} $2
8010        StrCpy $R0 $2
8011      ${Else}
8012        ${${_MOZFUNC_UN}GetLongPath} "$1" $2
8013        ${If} ${FileExists} $2
8014          StrCpy $R0 $2
8015        ${EndIf}
8016      ${EndIf}
8017    ${EndIf}
8018  ${EndIf}
8019
8020  Pop $2
8021  Pop $1
8022  Pop $0
8023  Exch $R0
8024!macroend
8025!define FindInstallSpecificProfile "!insertmacro FindInstallSpecificProfileMaybeUn ''"
8026!define un.FindInstallSpecificProfile "!insertmacro FindInstallSpecificProfileMaybeUn un."
8027
8028/**
8029 * Copy the post-signing data, which was left alongside the installer
8030 * by the self-extractor stub, into the global location for this data.
8031 *
8032 * If the post-signing data file doesn't exist, or is empty, "0" is
8033 * pushed on the stack, and nothing is copied.
8034 * Otherwise the first line of the post-signing data (including newline,
8035 * if any) is pushed on the stack.
8036 */
8037!macro CopyPostSigningData
8038  !ifndef CopyPostSigningData
8039    !verbose push
8040    !verbose ${_MOZFUNC_VERBOSE}
8041    !define CopyPostSigningData "Call CopyPostSigningData"
8042
8043    Function CopyPostSigningData
8044      Push $0   ; Stack: old $0
8045
8046      ${LineRead} "$EXEDIR\postSigningData" "1" $0
8047      ${If} ${Errors}
8048        ClearErrors
8049        StrCpy $0 "0"
8050      ${Else}
8051        CreateDirectory "$LOCALAPPDATA\Mozilla\Firefox"
8052        CopyFiles /SILENT "$EXEDIR\postSigningData" "$LOCALAPPDATA\Mozilla\Firefox"
8053      ${Endif}
8054
8055      Exch $0   ; Stack: postSigningData
8056    FunctionEnd
8057
8058    !verbose pop
8059  !endif
8060!macroend
8061
8062################################################################################
8063# Helpers for taskbar progress
8064
8065!ifndef CLSCTX_INPROC_SERVER
8066  !define CLSCTX_INPROC_SERVER  1
8067!endif
8068
8069!define CLSID_ITaskbarList {56fdf344-fd6d-11d0-958a-006097c9a090}
8070!define IID_ITaskbarList3 {ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf}
8071!define ITaskbarList3->SetProgressValue $ITaskbarList3->9
8072!define ITaskbarList3->SetProgressState $ITaskbarList3->10
8073
8074/**
8075 * Creates a single uninitialized object of the ITaskbarList class with a
8076 * reference to the ITaskbarList3 interface. This object can be used to set
8077 * progress and state on the installer's taskbar icon using the helper macros
8078 * in this section.
8079 */
8080!macro ITBL3Create
8081
8082  !ifndef ${_MOZFUNC_UN}ITBL3Create
8083    Var ITaskbarList3
8084
8085    !verbose push
8086    !verbose ${_MOZFUNC_VERBOSE}
8087    !define ${_MOZFUNC_UN}ITBL3Create "!insertmacro ${_MOZFUNC_UN}ITBL3CreateCall"
8088
8089    Function ${_MOZFUNC_UN}ITBL3Create
8090      ; Setting to 0 allows the helper macros to detect when the object was not
8091      ; created.
8092      StrCpy $ITaskbarList3 0
8093      ; Don't create when running silently.
8094      ${Unless} ${Silent}
8095        ; This is only supported on Win 7 and above.
8096        ${If} ${AtLeastWin7}
8097          System::Call "ole32::CoCreateInstance(g '${CLSID_ITaskbarList}', \
8098                                                i 0, \
8099                                                i ${CLSCTX_INPROC_SERVER}, \
8100                                                g '${IID_ITaskbarList3}', \
8101                                                *i .s)"
8102          Pop $ITaskbarList3
8103        ${EndIf}
8104      ${EndUnless}
8105    FunctionEnd
8106
8107    !verbose pop
8108  !endif
8109!macroend
8110
8111!macro ITBL3CreateCall
8112  !verbose push
8113  !verbose ${_MOZFUNC_VERBOSE}
8114  Call ITBL3Create
8115  !verbose pop
8116!macroend
8117
8118!macro un.ITBL3CreateCall _PATH_TO_IMAGE
8119  !verbose push
8120  !verbose ${_MOZFUNC_VERBOSE}
8121  Call un.ITBL3Create
8122  !verbose pop
8123!macroend
8124
8125!macro un.ITBL3Create
8126  !ifndef un.ITBL3Create
8127    !verbose push
8128    !verbose ${_MOZFUNC_VERBOSE}
8129    !undef _MOZFUNC_UN
8130    !define _MOZFUNC_UN "un."
8131
8132    !insertmacro ITBL3Create
8133
8134    !undef _MOZFUNC_UN
8135    !define _MOZFUNC_UN
8136    !verbose pop
8137  !endif
8138!macroend
8139
8140/**
8141 * Sets the percentage completed on the taskbar process icon progress indicator.
8142 *
8143 * @param   _COMPLETED
8144 *          The proportion of the operation that has been completed in relation
8145 *          to _TOTAL.
8146 * @param   _TOTAL
8147 *          The value _COMPLETED will have when the operation has completed.
8148 *
8149 * $R8 = _COMPLETED
8150 * $R9 = _TOTAL
8151 */
8152!macro ITBL3SetProgressValueCall _COMPLETED _TOTAL
8153  Push ${_COMPLETED}
8154  Push ${_TOTAL}
8155  ${CallArtificialFunction} ITBL3SetProgressValue_
8156!macroend
8157
8158!define ITBL3SetProgressValue "!insertmacro ITBL3SetProgressValueCall"
8159!define un.ITBL3SetProgressValue "!insertmacro ITBL3SetProgressValueCall"
8160
8161!macro ITBL3SetProgressValue_
8162  Exch $R9
8163  Exch 1
8164  Exch $R8
8165  ${If} $ITaskbarList3 <> 0
8166    System::Call "${ITaskbarList3->SetProgressValue}(i$HWNDPARENT, l$R8, l$R9)"
8167  ${EndIf}
8168  Exch $R8
8169  Exch 1
8170  Exch $R9
8171!macroend
8172
8173; Normal state / no progress bar
8174!define TBPF_NOPROGRESS       0x00000000
8175; Marquee style progress bar
8176!define TBPF_INDETERMINATE    0x00000001
8177; Standard progress bar
8178!define TBPF_NORMAL           0x00000002
8179; Red taskbar button to indicate an error occurred
8180!define TBPF_ERROR            0x00000004
8181; Yellow taskbar button to indicate user attention (input) is required to
8182; resume progress
8183!define TBPF_PAUSED           0x00000008
8184
8185/**
8186 * Sets the state on the taskbar process icon progress indicator.
8187 *
8188 * @param   _STATE
8189 *          The state to set on the taskbar icon progress indicator. Only one of
8190 *          the states defined above should be specified.
8191 *
8192 * $R9 = _STATE
8193 */
8194!macro ITBL3SetProgressStateCall _STATE
8195  Push ${_STATE}
8196  ${CallArtificialFunction} ITBL3SetProgressState_
8197!macroend
8198
8199!define ITBL3SetProgressState "!insertmacro ITBL3SetProgressStateCall"
8200!define un.ITBL3SetProgressState "!insertmacro ITBL3SetProgressStateCall"
8201
8202!macro ITBL3SetProgressState_
8203  Exch $R9
8204  ${If} $ITaskbarList3 <> 0
8205    System::Call "${ITaskbarList3->SetProgressState}(i$HWNDPARENT, i$R9)"
8206  ${EndIf}
8207  Exch $R9
8208!macroend
8209
8210################################################################################
8211# Helpers for the new user interface
8212
8213!ifndef MAXDWORD
8214  !define MAXDWORD 0xffffffff
8215!endif
8216
8217!ifndef DT_WORDBREAK
8218  !define DT_WORDBREAK 0x0010
8219!endif
8220!ifndef DT_SINGLELINE
8221  !define DT_SINGLELINE 0x0020
8222!endif
8223!ifndef DT_NOCLIP
8224  !define DT_NOCLIP 0x0100
8225!endif
8226!ifndef DT_CALCRECT
8227  !define DT_CALCRECT 0x0400
8228!endif
8229!ifndef DT_EDITCONTROL
8230  !define DT_EDITCONTROL 0x2000
8231!endif
8232!ifndef DT_RTLREADING
8233  !define DT_RTLREADING 0x00020000
8234!endif
8235!ifndef DT_NOFULLWIDTHCHARBREAK
8236  !define DT_NOFULLWIDTHCHARBREAK 0x00080000
8237!endif
8238
8239!define /ifndef GWL_STYLE -16
8240!define /ifndef GWL_EXSTYLE -20
8241
8242!ifndef WS_EX_NOINHERITLAYOUT
8243  !define WS_EX_NOINHERITLAYOUT 0x00100000
8244!endif
8245
8246!ifndef PBS_MARQUEE
8247  !define PBS_MARQUEE 0x08
8248!endif
8249
8250!ifndef PBM_SETRANGE32
8251  !define PBM_SETRANGE32 0x406
8252!endif
8253!ifndef PBM_GETRANGE
8254  !define PBM_GETRANGE 0x407
8255!endif
8256
8257!ifndef SHACF_FILESYSTEM
8258  !define SHACF_FILESYSTEM 1
8259!endif
8260
8261!define MOZ_LOADTRANSPARENT ${LR_LOADFROMFILE}|${LR_LOADTRANSPARENT}|${LR_LOADMAP3DCOLORS}
8262
8263; Extend nsDialogs.nsh to support creating centered labels if it is already
8264; included
8265!ifmacrodef __NSD_DefineControl
8266!insertmacro __NSD_DefineControl LabelCenter
8267!define __NSD_LabelCenter_CLASS STATIC
8268!define __NSD_LabelCenter_STYLE ${DEFAULT_STYLES}|${SS_NOTIFY}|${SS_CENTER}
8269!define __NSD_LabelCenter_EXSTYLE ${WS_EX_TRANSPARENT}
8270!endif
8271
8272/**
8273 * Draws an image file (BMP, GIF, or JPG) onto a bitmap control, with scaling.
8274 * Adapted from https://stackoverflow.com/a/13405711/1508094
8275 *
8276 * @param CONTROL bitmap control created by NSD_CreateBitmap
8277 * @param IMAGE path to image file to draw to the bitmap
8278 * @param HANDLE output bitmap handle which must be freed via NSD_FreeImage
8279 *               after nsDialogs::Show has been called
8280 */
8281!macro __SetStretchedImageOLE CONTROL IMAGE HANDLE
8282  !ifndef IID_IPicture
8283    !define IID_IPicture {7BF80980-BF32-101A-8BBB-00AA00300CAB}
8284  !endif
8285  !ifndef SRCCOPY
8286    !define SRCCOPY 0xCC0020
8287  !endif
8288  !ifndef HALFTONE
8289    !define HALFTONE 4
8290  !endif
8291  !ifndef IMAGE_BITMAP
8292    !define IMAGE_BITMAP 0
8293  !endif
8294
8295  Push $0 ; HANDLE
8296  Push $1 ; memory DC
8297  Push $2 ; IPicture created from IMAGE
8298  Push $3 ; HBITMAP obtained from $2
8299  Push $4 ; BITMAPINFO obtained from $3
8300  Push $5 ; width of IMAGE
8301  Push $6 ; height of IMAGE
8302  Push $7 ; width of CONTROL
8303  Push $8 ; height of CONTROL
8304  Push $R0 ; CONTROL
8305
8306  StrCpy $R0 ${CONTROL} ; in case ${CONTROL} is $0
8307  StrCpy $7 ""
8308  StrCpy $8 ""
8309
8310  System::Call '*(i, i, i, i) i.s'
8311  Pop $0
8312
8313  ${If} $0 <> 0
8314    System::Call 'user32::GetClientRect(i R0, i r0)'
8315    System::Call '*$0(i, i, i .s, i .s)'
8316    System::Free $0
8317    Pop $7
8318    Pop $8
8319  ${EndIf}
8320
8321  ${If} $7 > 0
8322  ${AndIf} $8 > 0
8323    System::Call 'oleaut32::OleLoadPicturePath(w"${IMAGE}",i0,i0,i0,g"${IID_IPicture}",*i.r2)i.r1'
8324    ${If} $1 = 0
8325      System::Call 'user32::GetDC(i0)i.s'
8326      System::Call 'gdi32::CreateCompatibleDC(iss)i.r1'
8327      System::Call 'gdi32::CreateCompatibleBitmap(iss,ir7,ir8)i.r0'
8328      System::Call 'user32::ReleaseDC(i0,is)'
8329      System::Call '$2->3(*i.r3)i.r4' ; IPicture->get_Handle
8330      ${If} $4 = 0
8331        System::Call 'gdi32::SetStretchBltMode(ir1,i${HALFTONE})'
8332        System::Call '*(&i40,&i1024)i.r4' ; BITMAP / BITMAPINFO
8333        System::Call 'gdi32::GetObject(ir3,i24,ir4)'
8334        System::Call 'gdi32::SelectObject(ir1,ir0)i.s'
8335        System::Call '*$4(i40,i.r5,i.r6,i0,i,i.s)' ; Grab size and bits-ptr AND init as BITMAPINFOHEADER
8336        System::Call 'gdi32::GetDIBits(ir1,ir3,i0,i0,i0,ir4,i0)' ; init BITMAPINFOHEADER
8337        System::Call 'gdi32::GetDIBits(ir1,ir3,i0,i0,i0,ir4,i0)' ; init BITMAPINFO
8338        System::Call 'gdi32::StretchDIBits(ir1,i0,i0,ir7,ir8,i0,i0,ir5,ir6,is,ir4,i0,i${SRCCOPY})'
8339        System::Call 'gdi32::SelectObject(ir1,is)'
8340        System::Free $4
8341        SendMessage $R0 ${STM_SETIMAGE} ${IMAGE_BITMAP} $0
8342      ${EndIf}
8343      System::Call 'gdi32::DeleteDC(ir1)'
8344      System::Call '$2->2()' ; IPicture->release()
8345    ${EndIf}
8346  ${EndIf}
8347
8348  Pop $R0
8349  Pop $8
8350  Pop $7
8351  Pop $6
8352  Pop $5
8353  Pop $4
8354  Pop $3
8355  Pop $2
8356  Pop $1
8357  Exch $0
8358  Pop ${HANDLE}
8359!macroend
8360!define SetStretchedImageOLE "!insertmacro __SetStretchedImageOLE"
8361
8362/**
8363 * Display a task dialog box with custom strings and button labels.
8364 *
8365 * The task dialog is highly customizable. The specific style being used here
8366 * is similar to a MessageBox except that the button text is customizable.
8367 * MessageBox-style buttons are used instead of command link buttons; this can
8368 * be made configurable if command buttons are needed.
8369 *
8370 * See https://msdn.microsoft.com/en-us/library/windows/desktop/bb760544.aspx
8371 * for the TaskDialogIndirect function's documentation, and links to definitions
8372 * of the TASKDIALOGCONFIG and TASKDIALOG_BUTTON structures it uses.
8373 *
8374 * @param INSTRUCTION  Dialog header string; use empty string if unneeded
8375 * @param CONTENT      Secondary message string; use empty string if unneeded
8376 * @param BUTTON1      Text for the first button, the one selected by default
8377 * @param BUTTON2      Text for the second button
8378 *
8379 * @return One of the following values will be left on the stack:
8380 *         1001 if the first button was clicked
8381 *         1002 if the second button was clicked
8382 *         2 (IDCANCEL) if the dialog was closed
8383 *         0 on error
8384 */
8385!macro _ShowTaskDialog INSTRUCTION CONTENT BUTTON1 BUTTON2
8386  !ifndef SIZEOF_TASKDIALOGCONFIG_32BIT
8387    !define SIZEOF_TASKDIALOGCONFIG_32BIT 96
8388  !endif
8389  !ifndef TDF_ALLOW_DIALOG_CANCELLATION
8390    !define TDF_ALLOW_DIALOG_CANCELLATION 0x0008
8391  !endif
8392  !ifndef TDF_RTL_LAYOUT
8393    !define TDF_RTL_LAYOUT 0x02000
8394  !endif
8395  !ifndef TD_WARNING_ICON
8396    !define TD_WARNING_ICON 0x0FFFF
8397  !endif
8398
8399  Push $0 ; return value
8400  Push $1 ; TASKDIALOGCONFIG struct
8401  Push $2 ; TASKDIALOG_BUTTON array
8402  Push $3 ; dwFlags member of the TASKDIALOGCONFIG
8403
8404  StrCpy $3 ${TDF_ALLOW_DIALOG_CANCELLATION}
8405  !ifdef ${AB_CD}_rtl
8406    IntOp $3 $3 | ${TDF_RTL_LAYOUT}
8407  !endif
8408
8409  ; Build an array of two TASKDIALOG_BUTTON structs
8410  System::Call "*(i 1001, \
8411                  w '${BUTTON1}', \
8412                  i 1002, \
8413                  w '${BUTTON2}' \
8414                  ) p.r2"
8415  ; Build a TASKDIALOGCONFIG struct
8416  System::Call "*(i ${SIZEOF_TASKDIALOGCONFIG_32BIT}, \
8417                  p $HWNDPARENT, \
8418                  p 0, \
8419                  i $3, \
8420                  i 0, \
8421                  w '$(INSTALLER_WIN_CAPTION)', \
8422                  p ${TD_WARNING_ICON}, \
8423                  w '${INSTRUCTION}', \
8424                  w '${CONTENT}', \
8425                  i 2, \
8426                  p r2, \
8427                  i 1001, \
8428                  i 0, \
8429                  p 0, \
8430                  i 0, \
8431                  p 0, \
8432                  p 0, \
8433                  p 0, \
8434                  p 0, \
8435                  p 0, \
8436                  p 0, \
8437                  p 0, \
8438                  p 0, \
8439                  i 0 \
8440                  ) p.r1"
8441  System::Call "comctl32::TaskDialogIndirect(p r1, *i 0 r0, p 0, p 0)"
8442  System::Free $1
8443  System::Free $2
8444
8445  Pop $3
8446  Pop $2
8447  Pop $1
8448  Exch $0
8449!macroend
8450!define ShowTaskDialog "!insertmacro _ShowTaskDialog"
8451
8452/**
8453 * Removes a single style from a control.
8454 *
8455 * _HANDLE the handle of the control
8456 * _STYLE  the style to remove
8457 */
8458!macro _RemoveStyle _HANDLE _STYLE
8459  Push $0
8460
8461  System::Call 'user32::GetWindowLongW(i ${_HANDLE}, i ${GWL_STYLE}) i .r0'
8462  IntOp $0 $0 | ${_STYLE}
8463  IntOp $0 $0 - ${_STYLE}
8464  System::Call 'user32::SetWindowLongW(i ${_HANDLE}, i ${GWL_STYLE}, i r0)'
8465
8466  Pop $0
8467!macroend
8468!define RemoveStyle "!insertmacro _RemoveStyle"
8469
8470/**
8471 * Adds a single extended style to a control.
8472 *
8473 * _HANDLE  the handle of the control
8474 * _EXSTYLE the extended style to add
8475 */
8476!macro _AddExStyle _HANDLE _EXSTYLE
8477  Push $0
8478
8479  System::Call 'user32::GetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}) i .r0'
8480  IntOp $0 $0 | ${_EXSTYLE}
8481  System::Call 'user32::SetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}, i r0)'
8482
8483  Pop $0
8484!macroend
8485!define AddExStyle "!insertmacro _AddExStyle"
8486
8487/**
8488 * Removes a single extended style from a control.
8489 *
8490 * _HANDLE  the handle of the control
8491 * _EXSTYLE the extended style to remove
8492 */
8493!macro _RemoveExStyle _HANDLE _EXSTYLE
8494  Push $0
8495
8496  System::Call 'user32::GetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}) i .r0'
8497  IntOp $0 $0 | ${_EXSTYLE}
8498  IntOp $0 $0 - ${_EXSTYLE}
8499  System::Call 'user32::SetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}, i r0)'
8500
8501  Pop $0
8502!macroend
8503!define RemoveExStyle "!insertmacro _RemoveExStyle"
8504
8505/**
8506 * Set the necessary styles to configure the given window as right-to-left
8507 *
8508 * _HANDLE the handle of the control to configure
8509 */
8510!macro _MakeWindowRTL _HANDLE
8511  !define /ifndef WS_EX_RIGHT 0x00001000
8512  !define /ifndef WS_EX_LEFT 0x00000000
8513  !define /ifndef WS_EX_RTLREADING 0x00002000
8514  !define /ifndef WS_EX_LTRREADING 0x00000000
8515  !define /ifndef WS_EX_LAYOUTRTL 0x00400000
8516
8517  ${AddExStyle} ${_HANDLE} ${WS_EX_LAYOUTRTL}
8518  ${RemoveExStyle} ${_HANDLE} ${WS_EX_RTLREADING}
8519  ${RemoveExStyle} ${_HANDLE} ${WS_EX_RIGHT}
8520  ${AddExStyle} ${_HANDLE} ${WS_EX_LEFT}|${WS_EX_LTRREADING}
8521!macroend
8522!define MakeWindowRTL "!insertmacro _MakeWindowRTL"
8523
8524/**
8525 * Gets the extent of the specified text in pixels for sizing a control.
8526 *
8527 * _TEXT       the text to get the text extent for
8528 * _FONT       the font to use when getting the text extent
8529 * _RES_WIDTH  return value - control width for the text
8530 * _RES_HEIGHT return value - control height for the text
8531 */
8532!macro GetTextExtentCall _TEXT _FONT _RES_WIDTH _RES_HEIGHT
8533  Push "${_TEXT}"
8534  Push "${_FONT}"
8535  ${CallArtificialFunction} GetTextExtent_
8536  Pop ${_RES_WIDTH}
8537  Pop ${_RES_HEIGHT}
8538!macroend
8539
8540!define GetTextExtent "!insertmacro GetTextExtentCall"
8541!define un.GetTextExtent "!insertmacro GetTextExtentCall"
8542
8543!macro GetTextExtent_
8544  Exch $0 ; font
8545  Exch 1
8546  Exch $1 ; text
8547  Push $2
8548  Push $3
8549  Push $4
8550  Push $5
8551  Push $6
8552  Push $7
8553
8554  ; Reuse the existing NSIS control which is used for BrandingText instead of
8555  ; creating a new control.
8556  GetDlgItem $2 $HWNDPARENT 1028
8557
8558  System::Call 'user32::GetDC(i r2) i .r3'
8559  System::Call 'gdi32::SelectObject(i r3, i r0)'
8560
8561  StrLen $4 "$1"
8562
8563  System::Call '*(i, i) i .r5'
8564  System::Call 'gdi32::GetTextExtentPoint32W(i r3, t$\"$1$\", i r4, i r5)'
8565  System::Call '*$5(i .r6, i .r7)'
8566  System::Free $5
8567
8568  System::Call 'user32::ReleaseDC(i r2, i r3)'
8569
8570  StrCpy $1 $7
8571  StrCpy $0 $6
8572
8573  Pop $7
8574  Pop $6
8575  Pop $5
8576  Pop $4
8577  Pop $3
8578  Pop $2
8579  Exch $1 ; return height
8580  Exch 1
8581  Exch $0 ; return width
8582!macroend
8583
8584/**
8585 * Gets the width and the height of a control in pixels.
8586 *
8587 * _HANDLE     the handle of the control
8588 * _RES_WIDTH  return value - control width for the text
8589 * _RES_HEIGHT return value - control height for the text
8590 */
8591!macro GetDlgItemWidthHeightCall _HANDLE _RES_WIDTH _RES_HEIGHT
8592  Push "${_HANDLE}"
8593  ${CallArtificialFunction} GetDlgItemWidthHeight_
8594  Pop ${_RES_WIDTH}
8595  Pop ${_RES_HEIGHT}
8596!macroend
8597
8598!define GetDlgItemWidthHeight "!insertmacro GetDlgItemWidthHeightCall"
8599!define un.GetDlgItemWidthHeight "!insertmacro GetDlgItemWidthHeightCall"
8600
8601!macro GetDlgItemWidthHeight_
8602  Exch $0 ; handle for the control
8603  Push $1
8604  Push $2
8605
8606  System::Call '*(i, i, i, i) i .r2'
8607  ; The left and top values will always be 0 so the right and bottom values
8608  ; will be the width and height.
8609  System::Call 'user32::GetClientRect(i r0, i r2)'
8610  System::Call '*$2(i, i, i .r0, i .r1)'
8611  System::Free $2
8612
8613  Pop $2
8614  Exch $1 ; return height
8615  Exch 1
8616  Exch $0 ; return width
8617!macroend
8618
8619/**
8620 * Gets the number of pixels from the beginning of the dialog to the end of a
8621 * control in a RTL friendly manner.
8622 *
8623 * _HANDLE the handle of the control
8624 * _RES_PX return value - pixels from the beginning of the dialog to the end of
8625 *         the control
8626 */
8627!macro GetDlgItemEndPXCall _HANDLE _RES_PX
8628  Push "${_HANDLE}"
8629  ${CallArtificialFunction} GetDlgItemEndPX_
8630  Pop ${_RES_PX}
8631!macroend
8632
8633!define GetDlgItemEndPX "!insertmacro GetDlgItemEndPXCall"
8634!define un.GetDlgItemEndPX "!insertmacro GetDlgItemEndPXCall"
8635
8636!macro GetDlgItemEndPX_
8637  Exch $0 ; handle of the control
8638  Push $1
8639  Push $2
8640
8641  ; #32770 is the dialog class
8642  FindWindow $1 "#32770" "" $HWNDPARENT
8643  System::Call '*(i, i, i, i) i .r2'
8644  System::Call 'user32::GetWindowRect(i r0, i r2)'
8645  System::Call 'user32::MapWindowPoints(i 0, i r1,i r2, i 2)'
8646  System::Call '*$2(i, i, i .r0, i)'
8647  System::Free $2
8648
8649  Pop $2
8650  Pop $1
8651  Exch $0 ; pixels from the beginning of the dialog to the end of the control
8652!macroend
8653
8654/**
8655 * Gets the number of pixels from the top of a dialog to the bottom of a control
8656 *
8657 * _CONTROL the handle of the control
8658 * _RES_PX  return value - pixels from the top of the dialog to the bottom
8659 *          of the control
8660 */
8661!macro GetDlgItemBottomPXCall _CONTROL _RES_PX
8662  Push "${_CONTROL}"
8663  ${CallArtificialFunction} GetDlgItemBottomPX_
8664  Pop ${_RES_PX}
8665!macroend
8666
8667!define GetDlgItemBottomPX "!insertmacro GetDlgItemBottomPXCall"
8668!define un.GetDlgItemBottomPX "!insertmacro GetDlgItemBottomPXCall"
8669
8670!macro GetDlgItemBottomPX_
8671  Exch $0 ; handle of the control
8672  Push $1
8673  Push $2
8674
8675  ; #32770 is the dialog class
8676  FindWindow $1 "#32770" "" $HWNDPARENT
8677  System::Call '*(i, i, i, i) i .r2'
8678  System::Call 'user32::GetWindowRect(i r0, i r2)'
8679  System::Call 'user32::MapWindowPoints(i 0, i r1, i r2, i 2)'
8680  System::Call '*$2(i, i, i, i .r0)'
8681  System::Free $2
8682
8683  Pop $2
8684  Pop $1
8685  Exch $0 ; pixels from the top of the dialog to the bottom of the control
8686!macroend
8687
8688/**
8689 * Gets the width and height for sizing a control that has the specified text.
8690 * The control's height and width will be dynamically determined for the maximum
8691 * width specified.
8692 *
8693 * _TEXT       the text
8694 * _FONT       the font to use when getting the width and height
8695 * _MAX_WIDTH  the maximum width for the control in pixels
8696 * _RES_WIDTH  return value - control width for the text in pixels.
8697 *             This might be larger than _MAX_WIDTH if that constraint couldn't
8698 *             be satisfied, e.g. a single word that couldn't be broken up is
8699 *             longer than _MAX_WIDTH by itself.
8700 * _RES_HEIGHT return value - control height for the text in pixels
8701 */
8702!macro GetTextWidthHeight
8703
8704  !ifndef ${_MOZFUNC_UN}GetTextWidthHeight
8705    !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN}
8706    !insertmacro ${_MOZFUNC_UN_TMP}WordFind
8707    !undef _MOZFUNC_UN
8708    !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP}
8709    !undef _MOZFUNC_UN_TMP
8710
8711    !verbose push
8712    !verbose ${_MOZFUNC_VERBOSE}
8713    !define ${_MOZFUNC_UN}GetTextWidthHeight "!insertmacro ${_MOZFUNC_UN}GetTextWidthHeightCall"
8714
8715    Function ${_MOZFUNC_UN}GetTextWidthHeight
8716      ; Stack contents after each instruction (top of the stack on the left):
8717      ;          _MAX_WIDTH _FONT _TEXT
8718      Exch $0  ; $0 _FONT _TEXT
8719      Exch 1   ; _FONT $0 _TEXT
8720      Exch $1  ; $1 $0 _TEXT
8721      Exch 2   ; _TEXT $0 $1
8722      Exch $2  ; $2 $0 $1
8723      ; That's all the parameters, now save our scratch registers.
8724      Push $3  ; handle to a temporary control for drawing the text into
8725      Push $4  ; DC handle
8726      Push $5  ; string length of the text argument
8727      Push $6  ; RECT struct to call DrawText with
8728      Push $7  ; width returned from DrawText
8729      Push $8  ; height returned from DrawText
8730      Push $9  ; flags to pass to DrawText
8731
8732      StrCpy $9 "${DT_NOCLIP}|${DT_CALCRECT}|${DT_WORDBREAK}"
8733      !ifdef ${AB_CD}_rtl
8734        StrCpy $9 "$9|${DT_RTLREADING}"
8735      !endif
8736
8737      ; Reuse the existing NSIS control which is used for BrandingText instead
8738      ; of creating a new control.
8739      GetDlgItem $3 $HWNDPARENT 1028
8740
8741      System::Call 'user32::GetDC(i r3) i .r4'
8742      System::Call 'gdi32::SelectObject(i r4, i r1)'
8743
8744      StrLen $5 "$2" ; text length
8745      System::Call '*(i, i, i r0, i) i .r6'
8746
8747      System::Call 'user32::DrawTextW(i r4, t $\"$2$\", i r5, i r6, i r9)'
8748      System::Call '*$6(i, i, i .r7, i .r8)'
8749      System::Free $6
8750
8751      System::Call 'user32::ReleaseDC(i r3, i r4)'
8752
8753      StrCpy $1 $8
8754      StrCpy $0 $7
8755
8756      ; Restore the values that were in our scratch registers.
8757      Pop $9
8758      Pop $8
8759      Pop $7
8760      Pop $6
8761      Pop $5
8762      Pop $4
8763      Pop $3
8764      ; Restore our parameter registers and return our results.
8765      ; Stack contents after each instruction (top of the stack on the left):
8766      ;         $2 $0 $1
8767      Pop $2  ; $0 $1
8768      Exch 1  ; $1 $0
8769      Exch $1 ; _RES_HEIGHT $0
8770      Exch 1  ; $0 _RES_HEIGHT
8771      Exch $0 ; _RES_WIDTH _RES_HEIGHT
8772    FunctionEnd
8773
8774    !verbose pop
8775  !endif
8776!macroend
8777
8778!macro GetTextWidthHeightCall _TEXT _FONT _MAX_WIDTH _RES_WIDTH _RES_HEIGHT
8779  !verbose push
8780  !verbose ${_MOZFUNC_VERBOSE}
8781  Push "${_TEXT}"
8782  Push "${_FONT}"
8783  Push "${_MAX_WIDTH}"
8784  Call GetTextWidthHeight
8785  Pop ${_RES_WIDTH}
8786  Pop ${_RES_HEIGHT}
8787  !verbose pop
8788!macroend
8789
8790!macro un.GetTextWidthHeightCall _TEXT _FONT _MAX_WIDTH _RES_WIDTH _RES_HEIGHT
8791  !verbose push
8792  !verbose ${_MOZFUNC_VERBOSE}
8793  Push "${_TEXT}"
8794  Push "${_FONT}"
8795  Push "${_MAX_WIDTH}"
8796  Call un.GetTextWidthHeight
8797  Pop ${_RES_WIDTH}
8798  Pop ${_RES_HEIGHT}
8799  !verbose pop
8800!macroend
8801
8802!macro un.GetTextWidthHeight
8803  !ifndef un.GetTextWidthHeight
8804    !verbose push
8805    !verbose ${_MOZFUNC_VERBOSE}
8806    !undef _MOZFUNC_UN
8807    !define _MOZFUNC_UN "un."
8808
8809    !insertmacro GetTextWidthHeight
8810
8811    !undef _MOZFUNC_UN
8812    !define _MOZFUNC_UN
8813    !verbose pop
8814  !endif
8815!macroend
8816
8817/**
8818 * Convert a number of dialog units to a number of pixels.
8819 *
8820 * _DU    Number of dialog units to convert
8821 * _AXIS  Which axis you want to convert a value along, X or Y
8822 * _RV    Register or variable to return the number of pixels in
8823 */
8824!macro _DialogUnitsToPixels _DU _AXIS _RV
8825  Push $0
8826  Push $1
8827
8828  ; The dialog units value might be a string ending with a 'u',
8829  ; so convert it to a number.
8830  IntOp $0 "${_DU}" + 0
8831
8832  !if ${_AXIS} == 'Y'
8833    System::Call '*(i 0, i 0, i 0, i r0) i .r1'
8834    System::Call 'user32::MapDialogRect(p $HWNDPARENT, p r1)'
8835    System::Call '*$1(i, i, i, i . r0)'
8836  !else if ${_AXIS} == 'X'
8837    System::Call '*(i 0, i 0, i r0, i 0) i .r1'
8838    System::Call 'user32::MapDialogRect(p $HWNDPARENT, p r1)'
8839    System::Call '*$1(i, i, i . r0, i)'
8840  !else
8841    !error "Invalid axis ${_AXIS} passed to DialogUnitsToPixels; please use X or Y"
8842  !endif
8843  System::Free $1
8844
8845  Pop $1
8846  Exch $0
8847  Pop ${_RV}
8848!macroend
8849!define DialogUnitsToPixels "!insertmacro _DialogUnitsToPixels"
8850
8851/**
8852 * Convert a given left coordinate for a dialog control to flip the control to
8853 * the other side of the dialog if we're using an RTL locale.
8854 *
8855 * _LEFT_DU   Number of dialog units to convert
8856 * _WIDTH     Width of the control in either pixels or DU's
8857 *            If the string has a 'u' on the end, it will be interpreted as
8858 *            dialog units, otherwise it will be interpreted as pixels.
8859 * _RV        Register or variable to return converted coordinate, in pixels
8860 */
8861!macro _ConvertLeftCoordForRTLCall _LEFT_DU _WIDTH _RV
8862  Push "${_LEFT_DU}"
8863  Push "${_WIDTH}"
8864  ${CallArtificialFunction} _ConvertLeftCoordForRTL
8865  Pop ${_RV}
8866!macroend
8867
8868!define ConvertLeftCoordForRTL "!insertmacro _ConvertLeftCoordForRTLCall"
8869!define un.ConvertLeftCoordForRTL "!insertmacro _ConvertLeftCoordForRTLCall"
8870
8871!macro _ConvertLeftCoordForRTL
8872  ; Stack contents after each instruction (top of the stack on the left):
8873  ;         _WIDTH _LEFT_DU
8874  Exch $0 ; $0 _LEFT_DU
8875  Exch 1  ; _LEFT_DU $0
8876  Exch $1 ; $1 $0
8877  ; That's all the parameters, now save our scratch registers.
8878  Push $2 ; width of the entire dialog, in pixels
8879  Push $3 ; _LEFT_DU converted to pixels
8880  Push $4 ; temp string search result
8881
8882  !ifndef ${AB_CD}_rtl
8883    StrCpy $0 "$1"
8884  !else
8885    ${GetDlgItemWidthHeight} $HWNDPARENT $2 $3
8886    ${DialogUnitsToPixels} $1 X $3
8887
8888    ClearErrors
8889    ${${_MOZFUNC_UN}WordFind} "$0" "u" "E+1{" $4
8890    ${IfNot} ${Errors}
8891      ${DialogUnitsToPixels} $4 X $0
8892    ${EndIf}
8893
8894    IntOp $1 $2 - $3
8895    IntOp $1 $1 - $0
8896    StrCpy $0 $1
8897  !endif
8898
8899  ; Restore the values that were in our scratch registers.
8900  Pop $4
8901  Pop $3
8902  Pop $2
8903  ; Restore our parameter registers and return our result.
8904  ; Stack contents after each instruction (top of the stack on the left):
8905  ;         $1 $0
8906  Pop $1  ; $0
8907  Exch $0 ; _RV
8908!macroend
8909
8910/**
8911 * Gets the elapsed time in seconds between two values in milliseconds stored as
8912 * an int64. The caller will typically get the millisecond values using
8913 * GetTickCount with a long return value as follows.
8914 * System::Call "kernel32::GetTickCount()l .s"
8915 * Pop $varname
8916 *
8917 * _START_TICK_COUNT
8918 * _FINISH_TICK_COUNT
8919 * _RES_ELAPSED_SECONDS return value - elapsed time between _START_TICK_COUNT
8920 *                      and _FINISH_TICK_COUNT in seconds.
8921 */
8922!macro GetSecondsElapsedCall _START_TICK_COUNT _FINISH_TICK_COUNT _RES_ELAPSED_SECONDS
8923  Push "${_START_TICK_COUNT}"
8924  Push "${_FINISH_TICK_COUNT}"
8925  ${CallArtificialFunction} GetSecondsElapsed_
8926  Pop ${_RES_ELAPSED_SECONDS}
8927!macroend
8928
8929!define GetSecondsElapsed "!insertmacro GetSecondsElapsedCall"
8930!define un.GetSecondsElapsed "!insertmacro GetSecondsElapsedCall"
8931
8932!macro GetSecondsElapsed_
8933  Exch $0 ; finish tick count
8934  Exch 1
8935  Exch $1 ; start tick count
8936
8937  System::Int64Op $0 - $1
8938  Pop $0
8939  ; Discard the top bits of the int64 by bitmasking with MAXDWORD
8940  System::Int64Op $0 & ${MAXDWORD}
8941  Pop $0
8942
8943  ; Convert from milliseconds to seconds
8944  System::Int64Op $0 / 1000
8945  Pop $0
8946
8947  Pop $1
8948  Exch $0 ; return elapsed seconds
8949!macroend
8950
8951/**
8952 * Create a process to execute a command line. If it is successfully created,
8953 * wait on it with WaitForInputIdle, to avoid exiting the current process too
8954 * early (exiting early can cause the created process's windows to be opened in
8955 * the background).
8956 *
8957 * CMDLINE Is the command line to execute, like the argument to Exec
8958 */
8959!define ExecAndWaitForInputIdle "!insertmacro ExecAndWaitForInputIdle_"
8960!define CREATE_DEFAULT_ERROR_MODE 0x04000000
8961!macro ExecAndWaitForInputIdle_ CMDLINE
8962  ; derived from https://stackoverflow.com/a/13960786/3444805 by Anders Kjersem
8963  Push $0
8964  Push $1
8965  Push $2
8966
8967  ; Command line
8968  StrCpy $0 "${CMDLINE}"
8969
8970  ; STARTUPINFO
8971  System::Alloc 68
8972  Pop $1
8973  ; fill in STARTUPINFO.cb (first field) with sizeof(STARTUPINFO)
8974  System::Call "*$1(i 68)"
8975
8976  ; PROCESS_INFORMATION
8977  System::Call "*(i, i, i, i) i . r2"
8978
8979  ; CREATE_DEFAULT_ERROR_MODE follows NSIS myCreateProcess used in Exec
8980  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"
8981
8982  System::Free $1
8983  ${If} $0 <> 0
8984    System::Call "*$2(i . r0, i . r1)"
8985    ; $0: hProcess, $1: hThread
8986    System::Call "user32::WaitForInputIdle(i $0, i 10000)"
8987    System::Call "kernel32::CloseHandle(i $0)"
8988    System::Call "kernel32::CloseHandle(i $1)"
8989  ${EndIf}
8990  System::Free $2
8991
8992  Pop $2
8993  Pop $1
8994  Pop $0
8995!macroend
8996
8997Function WriteRegQWORD
8998          ; Stack contents:
8999          ; VALUE, VALUE_NAME, SUBKEY, ROOTKEY
9000  Exch $3 ; $3, VALUE_NAME, SUBKEY, ROOTKEY
9001  Exch 1  ; VALUE_NAME, $3, SUBKEY, ROOTKEY
9002  Exch $2 ; $2, $3, SUBKEY, ROOTKEY
9003  Exch 2  ; SUBKEY, $3, $2, ROOTKEY
9004  Exch $1 ; $1, $3, $2, ROOTKEY
9005  Exch 3  ; ROOTKEY, $3, $2, $1
9006  Exch $0 ; $0, $3, $2, $1
9007  System::Call "advapi32::RegSetKeyValueW(p r0, w r1, w r2, i 11, *l r3, i 8) i.r0"
9008  ${IfNot} $0 = 0
9009    SetErrors
9010  ${EndIf}
9011  Pop $0
9012  Pop $3
9013  Pop $2
9014  Pop $1
9015FunctionEnd
9016!macro WriteRegQWORD ROOTKEY SUBKEY VALUE_NAME VALUE
9017  ${If} "${ROOTKEY}" == "HKCR"
9018    Push 0x80000000
9019  ${ElseIf} "${ROOTKEY}" == "HKCU"
9020    Push 0x80000001
9021  ${ElseIf} "${ROOTKEY}" == "HKLM"
9022    Push 0x80000002
9023  ${Endif}
9024  Push "${SUBKEY}"
9025  Push "${VALUE_NAME}"
9026  System::Int64Op ${VALUE} + 0 ; The result is pushed on the stack
9027  Call WriteRegQWORD
9028!macroend
9029!define WriteRegQWORD "!insertmacro WriteRegQWORD"
9030
9031Function ReadRegQWORD
9032          ; Stack contents:
9033          ; VALUE_NAME, SUBKEY, ROOTKEY
9034  Exch $2 ; $2, SUBKEY, ROOTKEY
9035  Exch 1  ; SUBKEY, $2, ROOTKEY
9036  Exch $1 ; $1, $2, ROOTKEY
9037  Exch 2  ; ROOTKEY, $2, $1
9038  Exch $0 ; $0, $2, $1
9039  System::Call "advapi32::RegGetValueW(p r0, w r1, w r2, i 0x48, p 0, *l s, *i 8) i.r0"
9040  ${IfNot} $0 = 0
9041    SetErrors
9042  ${EndIf}
9043          ; VALUE, $0, $2, $1
9044  Exch 3  ; $1, $0, $2, VALUE
9045  Pop $1  ; $0, $2, VALUE
9046  Pop $0  ; $2, VALUE
9047  Pop $2  ; VALUE
9048FunctionEnd
9049!macro ReadRegQWORD DEST ROOTKEY SUBKEY VALUE_NAME
9050  ${If} "${ROOTKEY}" == "HKCR"
9051    Push 0x80000000
9052  ${ElseIf} "${ROOTKEY}" == "HKCU"
9053    Push 0x80000001
9054  ${ElseIf} "${ROOTKEY}" == "HKLM"
9055    Push 0x80000002
9056  ${Endif}
9057  Push "${SUBKEY}"
9058  Push "${VALUE_NAME}"
9059  Call ReadRegQWORD
9060  Pop ${DEST}
9061!macroend
9062!define ReadRegQWORD "!insertmacro ReadRegQWORD"
9063
9064