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