# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. ################################################################################ # Helper defines and macros for toolkit applications /** * Avoid creating macros / functions that overwrite registers (see the * GetLongPath macro for one way to avoid this)! * * Before using the registers exchange the passed in params and save existing * register values to the stack. * * Exch $R9 ; exhange the original $R9 with the top of the stack * Exch 1 ; exchange the top of the stack with 1 below the top of the stack * Exch $R8 ; exchange the original $R8 with the top of the stack * Exch 2 ; exchange the top of the stack with 2 below the top of the stack * Exch $R7 ; exchange the original $R7 with the top of the stack * Push $R6 ; push the original $R6 onto the top of the stack * Push $R5 ; push the original $R5 onto the top of the stack * Push $R4 ; push the original $R4 onto the top of the stack * * * * ; Restore the values. * Pop $R4 ; restore the value for $R4 from the top of the stack * Pop $R5 ; restore the value for $R5 from the top of the stack * Pop $R6 ; restore the value for $R6 from the top of the stack * Exch $R7 ; exchange the new $R7 value with the top of the stack * Exch 2 ; exchange the top of the stack with 2 below the top of the stack * Exch $R8 ; exchange the new $R8 value with the top of the stack * Exch 1 ; exchange the top of the stack with 2 below the top of the stack * Exch $R9 ; exchange the new $R9 value with the top of the stack * * * When inserting macros in common.nsh from another macro in common.nsh that * can be used from the uninstaller _MOZFUNC_UN will be undefined when it is * inserted. Use the following to redefine _MOZFUNC_UN with its original value * (see the RegCleanMain macro for an example). * * !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} * !insertmacro ${_MOZFUNC_UN_TMP}FileJoin * !insertmacro ${_MOZFUNC_UN_TMP}LineFind * !insertmacro ${_MOZFUNC_UN_TMP}TextCompareNoDetails * !insertmacro ${_MOZFUNC_UN_TMP}TrimNewLines * !undef _MOZFUNC_UN * !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} * !undef _MOZFUNC_UN_TMP */ ; When including a file provided by NSIS check if its verbose macro is defined ; to prevent loading the file a second time. !ifmacrondef TEXTFUNC_VERBOSE !include TextFunc.nsh !endif !ifmacrondef FILEFUNC_VERBOSE !include FileFunc.nsh !endif !ifmacrondef LOGICLIB_VERBOSITY !include LogicLib.nsh !endif !ifndef WINMESSAGES_INCLUDED !include WinMessages.nsh !endif ; When including WinVer.nsh check if ___WINVER__NSH___ is defined to prevent ; loading the file a second time. !ifndef ___WINVER__NSH___ !include WinVer.nsh !endif ; When including x64.nsh check if ___X64__NSH___ is defined to prevent ; loading the file a second time. !ifndef ___X64__NSH___ !include x64.nsh !endif ; NSIS provided macros that we have overridden. !include overrides.nsh !define SHORTCUTS_LOG "shortcuts_log.ini" !define TO_BE_DELETED "tobedeleted" ; !define SHCNF_DWORD 0x0003 ; !define SHCNF_FLUSH 0x1000 !ifndef SHCNF_DWORDFLUSH !define SHCNF_DWORDFLUSH 0x1003 !endif !ifndef SHCNE_ASSOCCHANGED !define SHCNE_ASSOCCHANGED 0x08000000 !endif ################################################################################ # Macros for debugging /** * The following two macros assist with verifying that a macro doesn't * overwrite any registers. * * Usage: * ${debugSetRegisters} * * ${debugDisplayRegisters} */ /** * Sets all register values to their name to assist with verifying that a macro * doesn't overwrite any registers. */ !macro debugSetRegisters StrCpy $0 "$$0" StrCpy $1 "$$1" StrCpy $2 "$$2" StrCpy $3 "$$3" StrCpy $4 "$$4" StrCpy $5 "$$5" StrCpy $6 "$$6" StrCpy $7 "$$7" StrCpy $8 "$$8" StrCpy $9 "$$9" StrCpy $R0 "$$R0" StrCpy $R1 "$$R1" StrCpy $R2 "$$R2" StrCpy $R3 "$$R3" StrCpy $R4 "$$R4" StrCpy $R5 "$$R5" StrCpy $R6 "$$R6" StrCpy $R7 "$$R7" StrCpy $R8 "$$R8" StrCpy $R9 "$$R9" !macroend !define debugSetRegisters "!insertmacro debugSetRegisters" /** * Displays all register values to assist with verifying that a macro doesn't * overwrite any registers. */ !macro debugDisplayRegisters MessageBox MB_OK \ "Register Values:$\n\ $$0 = $0$\n$$1 = $1$\n$$2 = $2$\n$$3 = $3$\n$$4 = $4$\n\ $$5 = $5$\n$$6 = $6$\n$$7 = $7$\n$$8 = $8$\n$$9 = $9$\n\ $$R0 = $R0$\n$$R1 = $R1$\n$$R2 = $R2$\n$$R3 = $R3$\n$$R4 = $R4$\n\ $$R5 = $R5$\n$$R6 = $R6$\n$$R7 = $R7$\n$$R8 = $R8$\n$$R9 = $R9" !macroend !define debugDisplayRegisters "!insertmacro debugDisplayRegisters" ################################################################################ # Modern User Interface (MUI) override macros ; Removed macros in nsis 2.33u (ported from nsis 2.22) ; MUI_LANGUAGEFILE_DEFINE ; MUI_LANGUAGEFILE_LANGSTRING_PAGE ; MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE ; MUI_LANGUAGEFILE_LANGSTRING_DEFINE ; MUI_LANGUAGEFILE_UNLANGSTRING_PAGE !macro MOZ_MUI_LANGUAGEFILE_DEFINE DEFINE NAME !ifndef "${DEFINE}" !define "${DEFINE}" "${${NAME}}" !endif !undef "${NAME}" !macroend !macro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE PAGE NAME !ifdef MUI_${PAGE}PAGE LangString "${NAME}" 0 "${${NAME}}" !undef "${NAME}" !else !undef "${NAME}" !endif !macroend !macro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE PAGE NAME !ifdef MUI_${PAGE}PAGE | MUI_UN${PAGE}PAGE LangString "${NAME}" 0 "${${NAME}}" !undef "${NAME}" !else !undef "${NAME}" !endif !macroend !macro MOZ_MUI_LANGUAGEFILE_LANGSTRING_DEFINE DEFINE NAME !ifdef "${DEFINE}" LangString "${NAME}" 0 "${${NAME}}" !endif !undef "${NAME}" !macroend !macro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE PAGE NAME !ifdef MUI_UNINSTALLER !ifdef MUI_UN${PAGE}PAGE LangString "${NAME}" 0 "${${NAME}}" !undef "${NAME}" !else !undef "${NAME}" !endif !else !undef "${NAME}" !endif !macroend ; Modified version of the following MUI macros to support Mozilla localization. ; MUI_LANGUAGE ; MUI_LANGUAGEFILE_BEGIN ; MOZ_MUI_LANGUAGEFILE_END ; See /Contrib/Modern UI/System.nsh for more information !define MUI_INSTALLOPTIONS_READ "!insertmacro MUI_INSTALLOPTIONS_READ" !macro MOZ_MUI_LANGUAGE LANGUAGE !verbose push !verbose ${MUI_VERBOSE} !include "${LANGUAGE}.nsh" !verbose pop !macroend !macro MOZ_MUI_LANGUAGEFILE_BEGIN LANGUAGE !insertmacro MUI_INSERT !ifndef "MUI_LANGUAGEFILE_${LANGUAGE}_USED" !define "MUI_LANGUAGEFILE_${LANGUAGE}_USED" LoadLanguageFile "${LANGUAGE}.nlf" !else !error "Modern UI language file ${LANGUAGE} included twice!" !endif !macroend ; Custom version of MUI_LANGUAGEFILE_END. The macro to add the default MUI ; strings and the macros for several strings that are part of the NSIS MUI and ; not in our locale files have been commented out. !macro MOZ_MUI_LANGUAGEFILE_END # !include "${NSISDIR}\Contrib\Modern UI\Language files\Default.nsh" !ifdef MUI_LANGUAGEFILE_DEFAULT_USED !undef MUI_LANGUAGEFILE_DEFAULT_USED !warning "${LANGUAGE} Modern UI language file version doesn't match. Using default English texts for missing strings." !endif !insertmacro MOZ_MUI_LANGUAGEFILE_DEFINE "MUI_${LANGUAGE}_LANGNAME" "MUI_LANGNAME" !ifndef MUI_LANGDLL_PUSHLIST !define MUI_LANGDLL_PUSHLIST "'${MUI_${LANGUAGE}_LANGNAME}' ${LANG_${LANGUAGE}} " !else !ifdef MUI_LANGDLL_PUSHLIST_TEMP !undef MUI_LANGDLL_PUSHLIST_TEMP !endif !define MUI_LANGDLL_PUSHLIST_TEMP "${MUI_LANGDLL_PUSHLIST}" !undef MUI_LANGDLL_PUSHLIST !define MUI_LANGDLL_PUSHLIST "'${MUI_${LANGUAGE}_LANGNAME}' ${LANG_${LANGUAGE}} ${MUI_LANGDLL_PUSHLIST_TEMP}" !endif !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE WELCOME "MUI_TEXT_WELCOME_INFO_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE WELCOME "MUI_TEXT_WELCOME_INFO_TEXT" !ifdef MUI_TEXT_LICENSE_TITLE !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_TEXT_LICENSE_TITLE" !endif !ifdef MUI_TEXT_LICENSE_SUBTITLE !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_TEXT_LICENSE_SUBTITLE" !endif !ifdef MUI_INNERTEXT_LICENSE_TOP !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_TOP" !endif # !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_BOTTOM" !ifdef MUI_INNERTEXT_LICENSE_BOTTOM_CHECKBOX !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_BOTTOM_CHECKBOX" !endif !ifdef MUI_INNERTEXT_LICENSE_BOTTOM_RADIOBUTTONS !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_BOTTOM_RADIOBUTTONS" !endif !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE COMPONENTS "MUI_TEXT_COMPONENTS_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE COMPONENTS "MUI_TEXT_COMPONENTS_SUBTITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE COMPONENTS "MUI_INNERTEXT_COMPONENTS_DESCRIPTION_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE COMPONENTS "MUI_INNERTEXT_COMPONENTS_DESCRIPTION_INFO" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE DIRECTORY "MUI_TEXT_DIRECTORY_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE DIRECTORY "MUI_TEXT_DIRECTORY_SUBTITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_TEXT_STARTMENU_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_TEXT_STARTMENU_SUBTITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_INNERTEXT_STARTMENU_TOP" # !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_INNERTEXT_STARTMENU_CHECKBOX" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_INSTALLING_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_INSTALLING_SUBTITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_FINISH_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_FINISH_SUBTITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_ABORT_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_ABORT_SUBTITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_BUTTONTEXT_FINISH" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_INFO_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_INFO_TEXT" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_INFO_REBOOT" !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_REBOOTNOW" !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_REBOOTLATER" # !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_RUN" # !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_SHOWREADME" ; Support for using the existing MUI_TEXT_ABORTWARNING string !ifdef MOZ_MUI_CUSTOM_ABORT LangString MOZ_MUI_TEXT_ABORTWARNING 0 "${MUI_TEXT_ABORTWARNING}" !endif !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_DEFINE MUI_ABORTWARNING "MUI_TEXT_ABORTWARNING" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE WELCOME "MUI_UNTEXT_WELCOME_INFO_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE WELCOME "MUI_UNTEXT_WELCOME_INFO_TEXT" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE CONFIRM "MUI_UNTEXT_CONFIRM_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE CONFIRM "MUI_UNTEXT_CONFIRM_SUBTITLE" # !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNTEXT_LICENSE_TITLE" # !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNTEXT_LICENSE_SUBTITLE" # !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNINNERTEXT_LICENSE_BOTTOM" # !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNINNERTEXT_LICENSE_BOTTOM_CHECKBOX" # !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNINNERTEXT_LICENSE_BOTTOM_RADIOBUTTONS" # !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE COMPONENTS "MUI_UNTEXT_COMPONENTS_TITLE" # !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE COMPONENTS "MUI_UNTEXT_COMPONENTS_SUBTITLE" # !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE DIRECTORY "MUI_UNTEXT_DIRECTORY_TITLE" # !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE DIRECTORY "MUI_UNTEXT_DIRECTORY_SUBTITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_UNINSTALLING_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_UNINSTALLING_SUBTITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_FINISH_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_FINISH_SUBTITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_ABORT_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_ABORT_SUBTITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE FINISH "MUI_UNTEXT_FINISH_INFO_TITLE" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE FINISH "MUI_UNTEXT_FINISH_INFO_TEXT" !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE FINISH "MUI_UNTEXT_FINISH_INFO_REBOOT" !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_DEFINE MUI_UNABORTWARNING "MUI_UNTEXT_ABORTWARNING" !ifndef MUI_LANGDLL_LANGUAGES !define MUI_LANGDLL_LANGUAGES "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' " !define MUI_LANGDLL_LANGUAGES_CP "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' '${LANG_${LANGUAGE}_CP}' " !else !ifdef MUI_LANGDLL_LANGUAGES_TEMP !undef MUI_LANGDLL_LANGUAGES_TEMP !endif !define MUI_LANGDLL_LANGUAGES_TEMP "${MUI_LANGDLL_LANGUAGES}" !undef MUI_LANGDLL_LANGUAGES !ifdef MUI_LANGDLL_LANGUAGES_CP_TEMP !undef MUI_LANGDLL_LANGUAGES_CP_TEMP !endif !define MUI_LANGDLL_LANGUAGES_CP_TEMP "${MUI_LANGDLL_LANGUAGES_CP}" !undef MUI_LANGDLL_LANGUAGES_CP !define MUI_LANGDLL_LANGUAGES "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' ${MUI_LANGDLL_LANGUAGES_TEMP}" !define MUI_LANGDLL_LANGUAGES_CP "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' '${LANG_${LANGUAGE}_CP}' ${MUI_LANGDLL_LANGUAGES_CP_TEMP}" !endif !macroend /** * Creates an InstallOptions file with a UTF-16LE BOM and adds the RTL value * to the Settings section. * * @param _FILE * The name of the file to be created in $PLUGINSDIR. */ !macro InitInstallOptionsFile _FILE Push $R9 FileOpen $R9 "$PLUGINSDIR\${_FILE}" w FileWriteWord $R9 "65279" FileClose $R9 WriteIniStr "$PLUGINSDIR\${_FILE}" "Settings" "RTL" "$(^RTL)" Pop $R9 !macroend ################################################################################ # Macros for handling files in use /** * Checks for files in use in the $INSTDIR directory. To check files in * sub-directories this macro would need to be rewritten to create * sub-directories in the temporary directory used to backup the files that are * checked. * * Example usage: * * ; The first string to be pushed onto the stack MUST be "end" to indicate * ; that there are no more files in the $INSTDIR directory to check. * Push "end" * Push "freebl3.dll" * ; The last file pushed should be the app's main exe so if it is in use this * ; macro will return after the first check. * Push "${FileMainEXE}" * ${CheckForFilesInUse} $R9 * * !IMPORTANT - this macro uses the $R7, $R8, and $R9 registers and makes no * attempt to restore their original values. * * @return _RESULT * false if all of the files popped from the stack are not in use. * True if any of the files popped from the stack are in use. * $R7 = Temporary backup directory where the files will be copied to. * $R8 = value popped from the stack. This will either be a file name for a file * in the $INSTDIR directory or "end" to indicate that there are no * additional files to check. * $R9 = _RESULT */ !macro CheckForFilesInUse !ifndef ${_MOZFUNC_UN}CheckForFilesInUse !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}CheckForFilesInUse "!insertmacro ${_MOZFUNC_UN}CheckForFilesInUseCall" Function ${_MOZFUNC_UN}CheckForFilesInUse ; Create a temporary backup directory. GetTempFileName $R7 "$INSTDIR" Delete "$R7" SetOutPath "$R7" StrCpy $R9 "false" Pop $R8 ${While} $R8 != "end" ${Unless} ${FileExists} "$INSTDIR\$R8" Pop $R8 ; get next file to check before continuing ${Continue} ${EndUnless} ClearErrors CopyFiles /SILENT "$INSTDIR\$R8" "$R7\$R8" ; try to copy ${If} ${Errors} ; File is in use StrCpy $R9 "true" ${Break} ${EndIf} Delete "$INSTDIR\$R8" ; delete original ${If} ${Errors} ; File is in use StrCpy $R9 "true" Delete "$R7\$R8" ; delete temp copy ${Break} ${EndIf} Pop $R8 ; get next file to check ${EndWhile} ; clear stack ${While} $R8 != "end" Pop $R8 ${EndWhile} ; restore everything SetOutPath "$INSTDIR" CopyFiles /SILENT "$R7\*" "$INSTDIR\" RmDir /r "$R7" SetOutPath "$EXEDIR" ClearErrors Push $R9 FunctionEnd !verbose pop !endif !macroend !macro CheckForFilesInUseCall _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Call CheckForFilesInUse Pop ${_RESULT} !verbose pop !macroend !macro un.CheckForFilesInUseCall _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.CheckForFilesInUse Pop ${_RESULT} !verbose pop !macroend !macro un.CheckForFilesInUse !ifndef un.CheckForFilesInUse !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro CheckForFilesInUse !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend !macro GetCommonDirectory !ifndef ${_MOZFUNC_UN}GetCommonDirectory !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}GetCommonDirectory "!insertmacro ${_MOZFUNC_UN}GetCommonDirectoryCall" Function ${_MOZFUNC_UN}GetCommonDirectory Push $0 ; Save $0 ; This gets C:\ProgramData or the equivalent. ${GetCommonAppDataFolder} $0 ; Add our subdirectory, this is hardcoded as grandparent of the update directory in ; several other places. StrCpy $0 "$0\Mozilla-1de4eec8-1241-4177-a864-e594e8d1fb38" Exch $0 ; Restore original $0 and put our $0 on the stack. FunctionEnd !verbose pop !endif !macroend !macro GetCommonDirectoryCall _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Call GetCommonDirectory Pop ${_RESULT} !verbose pop !macroend !macro un.GetCommonDirectoryCall _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.GetCommonDirectory Pop ${_RESULT} !verbose pop !macroend !macro un.GetCommonDirectory !ifndef un.GetCommonDirectory !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro GetCommonDirectory !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * The macros below will automatically prepend un. to the function names when * they are defined (e.g. !define un.RegCleanMain). */ !verbose push !verbose 3 !ifndef _MOZFUNC_VERBOSE !define _MOZFUNC_VERBOSE 3 !endif !verbose ${_MOZFUNC_VERBOSE} !define MOZFUNC_VERBOSE "!insertmacro MOZFUNC_VERBOSE" !define _MOZFUNC_UN !define _MOZFUNC_S !verbose pop !macro MOZFUNC_VERBOSE _VERBOSE !verbose push !verbose 3 !undef _MOZFUNC_VERBOSE !define _MOZFUNC_VERBOSE ${_VERBOSE} !verbose pop !macroend /** * Displays a MessageBox and then calls abort to prevent continuing to the * next page when the specified Window Class is found. * * @param _WINDOW_CLASS * The Window Class to search for with FindWindow. * @param _MSG * The message text to display in the message box. * * $R7 = return value from FindWindow * $R8 = _WINDOW_CLASS * $R9 = _MSG */ !macro ManualCloseAppPrompt !ifndef ${_MOZFUNC_UN}ManualCloseAppPrompt !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}ManualCloseAppPrompt "!insertmacro ${_MOZFUNC_UN}ManualCloseAppPromptCall" Function ${_MOZFUNC_UN}ManualCloseAppPrompt Exch $R9 Exch 1 Exch $R8 Push $R7 FindWindow $R7 "$R8" ${If} $R7 <> 0 ; integer comparison MessageBox MB_OK|MB_ICONQUESTION "$R9" Abort ${EndIf} Pop $R7 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro ManualCloseAppPromptCall _WINDOW_CLASS _MSG !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_WINDOW_CLASS}" Push "${_MSG}" Call ManualCloseAppPrompt !verbose pop !macroend !macro un.ManualCloseAppPromptCall _WINDOW_CLASS _MSG !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_WINDOW_CLASS}" Push "${_MSG}" Call un.ManualCloseAppPrompt !verbose pop !macroend !macro un.ManualCloseAppPrompt !ifndef un.ManualCloseAppPrompt !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro ManualCloseAppPrompt !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend ################################################################################ # Macros for working with the registry /** * Writes a registry string using SHCTX and the supplied params and logs the * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. * * Define NO_LOG to prevent all logging when calling this from the uninstaller. * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * This will only be used for logging. * @param _KEY * The subkey in relation to the key root. * @param _NAME * The key value name to write to. * @param _STR * The string to write to the key value name. * @param _LOG_UNINSTALL * 0 = don't add to uninstall log, 1 = add to uninstall log. * * $R5 = _ROOT * $R6 = _KEY * $R7 = _NAME * $R8 = _STR * $R9 = _LOG_UNINSTALL */ !macro WriteRegStr2 !ifndef ${_MOZFUNC_UN}WriteRegStr2 !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}WriteRegStr2 "!insertmacro ${_MOZFUNC_UN}WriteRegStr2Call" Function ${_MOZFUNC_UN}WriteRegStr2 Exch $R9 Exch 1 Exch $R8 Exch 2 Exch $R7 Exch 3 Exch $R6 Exch 4 Exch $R5 ClearErrors WriteRegStr SHCTX "$R6" "$R7" "$R8" !ifndef NO_LOG ${If} ${Errors} ${LogMsg} "** ERROR Adding Registry String: $R5 | $R6 | $R7 | $R8 **" ${Else} ${If} $R9 == 1 ; add to the uninstall log? ${LogUninstall} "RegVal: $R5 | $R6 | $R7" ${EndIf} ${LogMsg} "Added Registry String: $R5 | $R6 | $R7 | $R8" ${EndIf} !endif Exch $R5 Exch 4 Exch $R6 Exch 3 Exch $R7 Exch 2 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro WriteRegStr2Call _ROOT _KEY _NAME _STR _LOG_UNINSTALL !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_ROOT}" Push "${_KEY}" Push "${_NAME}" Push "${_STR}" Push "${_LOG_UNINSTALL}" Call WriteRegStr2 !verbose pop !macroend !macro un.WriteRegStr2Call _ROOT _KEY _NAME _STR _LOG_UNINSTALL !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_ROOT}" Push "${_KEY}" Push "${_NAME}" Push "${_STR}" Push "${_LOG_UNINSTALL}" Call un.WriteRegStr2 !verbose pop !macroend !macro un.WriteRegStr2 !ifndef un.WriteRegStr2 !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro WriteRegStr2 !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Writes a registry dword using SHCTX and the supplied params and logs the * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. * * Define NO_LOG to prevent all logging when calling this from the uninstaller. * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * This will only be used for logging. * @param _KEY * The subkey in relation to the key root. * @param _NAME * The key value name to write to. * @param _DWORD * The dword to write to the key value name. * @param _LOG_UNINSTALL * 0 = don't add to uninstall log, 1 = add to uninstall log. * * $R5 = _ROOT * $R6 = _KEY * $R7 = _NAME * $R8 = _DWORD * $R9 = _LOG_UNINSTALL */ !macro WriteRegDWORD2 !ifndef ${_MOZFUNC_UN}WriteRegDWORD2 !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}WriteRegDWORD2 "!insertmacro ${_MOZFUNC_UN}WriteRegDWORD2Call" Function ${_MOZFUNC_UN}WriteRegDWORD2 Exch $R9 Exch 1 Exch $R8 Exch 2 Exch $R7 Exch 3 Exch $R6 Exch 4 Exch $R5 ClearErrors WriteRegDWORD SHCTX "$R6" "$R7" "$R8" !ifndef NO_LOG ${If} ${Errors} ${LogMsg} "** ERROR Adding Registry DWord: $R5 | $R6 | $R7 | $R8 **" ${Else} ${If} $R9 == 1 ; add to the uninstall log? ${LogUninstall} "RegVal: $R5 | $R6 | $R7" ${EndIf} ${LogMsg} "Added Registry DWord: $R5 | $R6 | $R7 | $R8" ${EndIf} !endif Exch $R5 Exch 4 Exch $R6 Exch 3 Exch $R7 Exch 2 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro WriteRegDWORD2Call _ROOT _KEY _NAME _DWORD _LOG_UNINSTALL !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_ROOT}" Push "${_KEY}" Push "${_NAME}" Push "${_DWORD}" Push "${_LOG_UNINSTALL}" Call WriteRegDWORD2 !verbose pop !macroend !macro un.WriteRegDWORD2Call _ROOT _KEY _NAME _DWORD _LOG_UNINSTALL !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_ROOT}" Push "${_KEY}" Push "${_NAME}" Push "${_DWORD}" Push "${_LOG_UNINSTALL}" Call un.WriteRegDWORD2 !verbose pop !macroend !macro un.WriteRegDWORD2 !ifndef un.WriteRegDWORD2 !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro WriteRegDWORD2 !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Writes a registry string to HKCR using the supplied params and logs the * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. * * Define NO_LOG to prevent all logging when calling this from the uninstaller. * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * This will only be used for logging. * @param _KEY * The subkey in relation to the key root. * @param _NAME * The key value name to write to. * @param _STR * The string to write to the key value name. * @param _LOG_UNINSTALL * 0 = don't add to uninstall log, 1 = add to uninstall log. * * $R5 = _ROOT * $R6 = _KEY * $R7 = _NAME * $R8 = _STR * $R9 = _LOG_UNINSTALL */ !macro WriteRegStrHKCR !ifndef ${_MOZFUNC_UN}WriteRegStrHKCR !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}WriteRegStrHKCR "!insertmacro ${_MOZFUNC_UN}WriteRegStrHKCRCall" Function ${_MOZFUNC_UN}WriteRegStrHKCR Exch $R9 Exch 1 Exch $R8 Exch 2 Exch $R7 Exch 3 Exch $R6 Exch 4 Exch $R5 ClearErrors WriteRegStr HKCR "$R6" "$R7" "$R8" !ifndef NO_LOG ${If} ${Errors} ${LogMsg} "** ERROR Adding Registry String: $R5 | $R6 | $R7 | $R8 **" ${Else} ${If} $R9 == 1 ; add to the uninstall log? ${LogUninstall} "RegVal: $R5 | $R6 | $R7" ${EndIf} ${LogMsg} "Added Registry String: $R5 | $R6 | $R7 | $R8" ${EndIf} !endif Exch $R5 Exch 4 Exch $R6 Exch 3 Exch $R7 Exch 2 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro WriteRegStrHKCRCall _ROOT _KEY _NAME _STR _LOG_UNINSTALL !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_ROOT}" Push "${_KEY}" Push "${_NAME}" Push "${_STR}" Push "${_LOG_UNINSTALL}" Call WriteRegStrHKCR !verbose pop !macroend !macro un.WriteRegStrHKCRCall _ROOT _KEY _NAME _STR _LOG_UNINSTALL !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_ROOT}" Push "${_KEY}" Push "${_NAME}" Push "${_STR}" Push "${_LOG_UNINSTALL}" Call un.WriteRegStrHKCR !verbose pop !macroend !macro un.WriteRegStrHKCR !ifndef un.WriteRegStrHKCR !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro WriteRegStrHKCR !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend !ifndef KEY_SET_VALUE !define KEY_SET_VALUE 0x0002 !endif !ifndef KEY_WOW64_64KEY !define KEY_WOW64_64KEY 0x0100 !endif !ifndef HAVE_64BIT_BUILD !define CREATE_KEY_SAM ${KEY_SET_VALUE} !else !define CREATE_KEY_SAM ${KEY_SET_VALUE}|${KEY_WOW64_64KEY} !endif /** * Creates a registry key. This will log the actions to the install and * uninstall logs. Alternatively you can set a registry value to create the key * and then delete the value. * * Define NO_LOG to prevent all logging when calling this from the uninstaller. * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * @param _KEY * The subkey in relation to the key root. * @param _LOG_UNINSTALL * 0 = don't add to uninstall log, 1 = add to uninstall log. * * $R4 = [out] handle to newly created registry key. If this is not a key * located in one of the predefined registry keys this must be closed * with RegCloseKey (this should not be needed unless someone decides to * do something extremely squirrelly with NSIS). * $R5 = return value from RegCreateKeyExW (represented by R5 in the system call). * $R6 = [in] hKey passed to RegCreateKeyExW. * $R7 = _ROOT * $R8 = _KEY * $R9 = _LOG_UNINSTALL */ !macro CreateRegKey !ifndef ${_MOZFUNC_UN}CreateRegKey !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}CreateRegKey "!insertmacro ${_MOZFUNC_UN}CreateRegKeyCall" Function ${_MOZFUNC_UN}CreateRegKey Exch $R9 Exch 1 Exch $R8 Exch 2 Exch $R7 Push $R6 Push $R5 Push $R4 StrCmp $R7 "HKCR" +1 +2 StrCpy $R6 "0x80000000" StrCmp $R7 "HKCU" +1 +2 StrCpy $R6 "0x80000001" StrCmp $R7 "HKLM" +1 +2 StrCpy $R6 "0x80000002" ; see definition of RegCreateKey System::Call "Advapi32::RegCreateKeyExW(i R6, w R8, i 0, i 0, i 0,\ i ${CREATE_KEY_SAM}, i 0, *i .R4,\ i 0) i .R5" !ifndef NO_LOG ; if $R5 is not 0 then there was an error creating the registry key. ${If} $R5 <> 0 ${LogMsg} "** ERROR Adding Registry Key: $R7 | $R8 **" ${Else} ${If} $R9 == 1 ; add to the uninstall log? ${LogUninstall} "RegKey: $R7 | $R8" ${EndIf} ${LogMsg} "Added Registry Key: $R7 | $R8" ${EndIf} !endif StrCmp $R5 0 +1 +2 System::Call "Advapi32::RegCloseKey(iR4)" Pop $R4 Pop $R5 Pop $R6 Exch $R7 Exch 2 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro CreateRegKeyCall _ROOT _KEY _LOG_UNINSTALL !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_ROOT}" Push "${_KEY}" Push "${_LOG_UNINSTALL}" Call CreateRegKey !verbose pop !macroend !macro un.CreateRegKeyCall _ROOT _KEY _LOG_UNINSTALL !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_ROOT}" Push "${_KEY}" Push "${_LOG_UNINSTALL}" Call un.CreateRegKey !verbose pop !macroend !macro un.CreateRegKey !ifndef un.CreateRegKey !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro CreateRegKey !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Helper for checking for the existence of a registry key. * SHCTX is the root key to search. * * @param _MAIN_KEY * Sub key to iterate for the key in question * @param _KEY * Key name to search for * @return _RESULT * 'true' / 'false' result */ !macro CheckIfRegistryKeyExists !ifndef CheckIfRegistryKeyExists !verbose push !verbose ${_MOZFUNC_VERBOSE} !define CheckIfRegistryKeyExists "!insertmacro CheckIfRegistryKeyExistsCall" Function CheckIfRegistryKeyExists ; stack: main key, key Exch $R9 ; main key, stack: old R9, key Exch 1 ; stack: key, old R9 Exch $R8 ; key, stack: old R8, old R9 Push $R7 Push $R6 Push $R5 StrCpy $R5 "false" StrCpy $R7 "0" # loop index ${Do} EnumRegKey $R6 SHCTX "$R9" "$R7" ${If} "$R6" == "$R8" StrCpy $R5 "true" ${Break} ${EndIf} IntOp $R7 $R7 + 1 ${LoopWhile} $R6 != "" ClearErrors StrCpy $R9 $R5 Pop $R5 Pop $R6 Pop $R7 ; stack: old R8, old R9 Pop $R8 ; stack: old R9 Exch $R9 ; stack: result FunctionEnd !verbose pop !endif !macroend !macro CheckIfRegistryKeyExistsCall _MAIN_KEY _KEY _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Push "${_MAIN_KEY}" Call CheckIfRegistryKeyExists Pop ${_RESULT} !verbose pop !macroend /** * Read the value of an installer pref that's been set by the product. * * @param _KEY ($R1) * Sub key containing all the installer prefs * Usually "Software\Mozilla\${AppName}" * @param _PREF ($R2) * Name of the pref to look up * @return _RESULT ($R3) * 'true' or 'false' (only boolean prefs are supported) * If no value exists for the requested pref, the result is 'false' */ !macro GetInstallerRegistryPref !ifndef ${_MOZFUNC_UN}GetInstallerRegistryPref !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}GetInstallerRegistryPref "!insertmacro GetInstallerRegistryPrefCall" Function ${_MOZFUNC_UN}GetInstallerRegistryPref ; stack: key, pref Exch $R1 ; key, stack: old R1, pref Exch 1 ; stack: pref, old R1 Exch $R2 ; pref, stack: old R2, old R1 Push $R3 StrCpy $R3 0 ; These prefs are always stored in the native registry. SetRegView 64 ClearErrors ReadRegDWORD $R3 HKCU "$R1\Installer\$AppUserModelID" "$R2" SetRegView lastused ${IfNot} ${Errors} ${AndIf} $R3 != 0 StrCpy $R1 "true" ${Else} StrCpy $R1 "false" ${EndIf} ; stack: old R3, old R2, old R1 Pop $R3 ; stack: old R2, old R1 Pop $R2 ; stack: old R1 Exch $R1 ; stack: result FunctionEnd !verbose pop !endif !macroend !macro GetInstallerRegistryPrefCall _KEY _PREF _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_PREF}" Push "${_KEY}" Call GetInstallerRegistryPref Pop ${_RESULT} !verbose pop !macroend !macro un.GetInstallerRegistryPrefCall _KEY _PREF _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_PREF}" Push "${_KEY}" Call un.GetInstallerRegistryPref Pop ${_RESULT} !verbose pop !macroend !macro un.GetInstallerRegistryPref !ifndef un.GetInstallerRegistryPref !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro GetInstallerRegistryPref !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend ################################################################################ # Macros for adding file and protocol handlers /** * Writes common registry values for a handler using SHCTX. * * @param _KEY * The subkey in relation to the key root. * @param _VALOPEN * The path and args to launch the application. * @param _VALICON * The path to the binary that contains the icon group for the default icon * followed by a comma and either the icon group's resource index or the icon * group's resource id prefixed with a minus sign * @param _DISPNAME * The display name for the handler. If emtpy no value will be set. * @param _ISPROTOCOL * Sets protocol handler specific registry values when "true". * Deletes protocol handler specific registry values when "delete". * Otherwise doesn't touch handler specific registry values. * @param _ISDDE * Sets DDE specific registry values when "true". * * $R3 = string value of the current registry key path. * $R4 = _KEY * $R5 = _VALOPEN * $R6 = _VALICON * $R7 = _DISPNAME * $R8 = _ISPROTOCOL * $R9 = _ISDDE */ !macro AddHandlerValues !ifndef ${_MOZFUNC_UN}AddHandlerValues !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}AddHandlerValues "!insertmacro ${_MOZFUNC_UN}AddHandlerValuesCall" Function ${_MOZFUNC_UN}AddHandlerValues Exch $R9 Exch 1 Exch $R8 Exch 2 Exch $R7 Exch 3 Exch $R6 Exch 4 Exch $R5 Exch 5 Exch $R4 Push $R3 StrCmp "$R7" "" +6 +1 ReadRegStr $R3 SHCTX "$R4" "FriendlyTypeName" StrCmp "$R3" "" +1 +3 WriteRegStr SHCTX "$R4" "" "$R7" WriteRegStr SHCTX "$R4" "FriendlyTypeName" "$R7" StrCmp "$R8" "true" +1 +2 WriteRegStr SHCTX "$R4" "URL Protocol" "" StrCmp "$R8" "delete" +1 +2 DeleteRegValue SHCTX "$R4" "URL Protocol" StrCpy $R3 "" ReadRegDWord $R3 SHCTX "$R4" "EditFlags" StrCmp $R3 "" +1 +3 ; Only add EditFlags if a value doesn't exist DeleteRegValue SHCTX "$R4" "EditFlags" WriteRegDWord SHCTX "$R4" "EditFlags" 0x00000002 StrCmp "$R6" "" +2 +1 WriteRegStr SHCTX "$R4\DefaultIcon" "" "$R6" StrCmp "$R5" "" +2 +1 WriteRegStr SHCTX "$R4\shell\open\command" "" "$R5" !ifdef DDEApplication StrCmp "$R9" "true" +1 +11 WriteRegStr SHCTX "$R4\shell\open\ddeexec" "" "$\"%1$\",,0,0,,,," WriteRegStr SHCTX "$R4\shell\open\ddeexec" "NoActivateHandler" "" WriteRegStr SHCTX "$R4\shell\open\ddeexec\Application" "" "${DDEApplication}" WriteRegStr SHCTX "$R4\shell\open\ddeexec\Topic" "" "WWW_OpenURL" ; The ifexec key may have been added by another application so try to ; delete it to prevent it from breaking this app's shell integration. ; Also, IE 6 and below doesn't remove this key when it sets itself as the ; default handler and if this key exists IE's shell integration breaks. DeleteRegKey HKLM "$R4\shell\open\ddeexec\ifexec" DeleteRegKey HKCU "$R4\shell\open\ddeexec\ifexec" !endif ClearErrors Pop $R3 Exch $R4 Exch 5 Exch $R5 Exch 4 Exch $R6 Exch 3 Exch $R7 Exch 2 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro AddHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL _ISDDE !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Push "${_VALOPEN}" Push "${_VALICON}" Push "${_DISPNAME}" Push "${_ISPROTOCOL}" Push "${_ISDDE}" Call AddHandlerValues !verbose pop !macroend !macro un.AddHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL _ISDDE !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Push "${_VALOPEN}" Push "${_VALICON}" Push "${_DISPNAME}" Push "${_ISPROTOCOL}" Push "${_ISDDE}" Call un.AddHandlerValues !verbose pop !macroend !macro un.AddHandlerValues !ifndef un.AddHandlerValues !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro AddHandlerValues !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Writes common registry values for a handler that DOES NOT use DDE using SHCTX. * * @param _KEY * The key name in relation to the HKCR root. SOFTWARE\Classes is * prefixed to this value when using SHCTX. * @param _VALOPEN * The path and args to launch the application. * @param _VALICON * The path to the binary that contains the icon group for the default icon * followed by a comma and either the icon group's resource index or the icon * group's resource id prefixed with a minus sign * @param _DISPNAME * The display name for the handler. If emtpy no value will be set. * @param _ISPROTOCOL * Sets protocol handler specific registry values when "true". * Deletes protocol handler specific registry values when "delete". * Otherwise doesn't touch handler specific registry values. * * $R3 = storage for SOFTWARE\Classes * $R4 = string value of the current registry key path. * $R5 = _KEY * $R6 = _VALOPEN * $R7 = _VALICON * $R8 = _DISPNAME * $R9 = _ISPROTOCOL */ !macro AddDisabledDDEHandlerValues !ifndef ${_MOZFUNC_UN}AddDisabledDDEHandlerValues !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}AddDisabledDDEHandlerValues "!insertmacro ${_MOZFUNC_UN}AddDisabledDDEHandlerValuesCall" Function ${_MOZFUNC_UN}AddDisabledDDEHandlerValues Exch $R9 ; _ISPROTOCOL Exch 1 Exch $R8 ; FriendlyTypeName Exch 2 Exch $R7 ; icon index Exch 3 Exch $R6 ; shell\open\command Exch 4 Exch $R5 ; reg key Push $R4 ; Push $R3 ; base reg class StrCpy $R3 "SOFTWARE\Classes" StrCmp "$R8" "" +6 +1 ReadRegStr $R4 SHCTX "$R5" "FriendlyTypeName" StrCmp "$R4" "" +1 +3 WriteRegStr SHCTX "$R3\$R5" "" "$R8" WriteRegStr SHCTX "$R3\$R5" "FriendlyTypeName" "$R8" StrCmp "$R9" "true" +1 +2 WriteRegStr SHCTX "$R3\$R5" "URL Protocol" "" StrCmp "$R9" "delete" +1 +2 DeleteRegValue SHCTX "$R3\$R5" "URL Protocol" StrCpy $R4 "" ReadRegDWord $R4 SHCTX "$R3\$R5" "EditFlags" StrCmp $R4 "" +1 +3 ; Only add EditFlags if a value doesn't exist DeleteRegValue SHCTX "$R3\$R5" "EditFlags" WriteRegDWord SHCTX "$R3\$R5" "EditFlags" 0x00000002 StrCmp "$R7" "" +2 +1 WriteRegStr SHCTX "$R3\$R5\DefaultIcon" "" "$R7" ; Main command handler for the app WriteRegStr SHCTX "$R3\$R5\shell" "" "open" WriteRegStr SHCTX "$R3\$R5\shell\open\command" "" "$R6" ; Drop support for DDE (bug 491947), and remove old dde entries if ; they exist. ; ; Note, changes in SHCTX should propegate to hkey classes root when ; current user or local machine entries are written. Windows will also ; attempt to propegate entries when a handler is used. CR entries are a ; combination of LM and CU, with CU taking priority. ; ; To disable dde, an empty shell/ddeexec key must be created in current ; user or local machine. Unfortunately, settings have various different ; behaviors depending on the windows version. The following code attempts ; to address these differences. ; ; IE does not configure ddeexec, so issues with left over ddeexec keys ; in LM are reduced. We configure an empty ddeexec key with an empty default ; string in CU to be sure. ; DeleteRegKey SHCTX "SOFTWARE\Classes\$R5\shell\open\ddeexec" WriteRegStr SHCTX "SOFTWARE\Classes\$R5\shell\open\ddeexec" "" "" ClearErrors Pop $R3 Pop $R4 Exch $R5 Exch 4 Exch $R6 Exch 3 Exch $R7 Exch 2 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro AddDisabledDDEHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Push "${_VALOPEN}" Push "${_VALICON}" Push "${_DISPNAME}" Push "${_ISPROTOCOL}" Call AddDisabledDDEHandlerValues !verbose pop !macroend !macro un.AddDisabledDDEHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Push "${_VALOPEN}" Push "${_VALICON}" Push "${_DISPNAME}" Push "${_ISPROTOCOL}" Call un.AddDisabledDDEHandlerValues !verbose pop !macroend !macro un.AddDisabledDDEHandlerValues !ifndef un.AddDisabledDDEHandlerValues !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro AddDisabledDDEHandlerValues !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend ################################################################################ # Macros for handling DLL registration !macro RegisterDLL DLL ; The x64 regsvr32.exe registers x86 DLL's properly so just use it ; when installing on an x64 systems even when installing an x86 application. ${If} ${RunningX64} ${OrIf} ${IsNativeARM64} ${DisableX64FSRedirection} ExecWait '"$SYSDIR\regsvr32.exe" /s "${DLL}"' ${EnableX64FSRedirection} ${Else} RegDLL "${DLL}" ${EndIf} !macroend !macro UnregisterDLL DLL ; The x64 regsvr32.exe registers x86 DLL's properly so just use it ; when installing on an x64 systems even when installing an x86 application. ${If} ${RunningX64} ${OrIf} ${IsNativeARM64} ${DisableX64FSRedirection} ExecWait '"$SYSDIR\regsvr32.exe" /s /u "${DLL}"' ${EnableX64FSRedirection} ${Else} UnRegDLL "${DLL}" ${EndIf} !macroend !define RegisterDLL "!insertmacro RegisterDLL" !define UnregisterDLL "!insertmacro UnregisterDLL" ################################################################################ # Macros for retrieving special folders /** * These macro get special folder paths directly, without depending on * SetShellVarContext. * * Usage: * ${GetProgramsFolder} $0 * ${GetLocalAppDataFolder} $0 * ${GetCommonAppDataFolder} $0 * */ !macro GetSpecialFolder _ID _RESULT ; This system call gets the directory path. The arguments are: ; A null ptr for hwnd ; t.s puts the output string on the NSIS stack ; id indicates which dir to get ; false for fCreate (i.e. Do not create the folder if it doesn't exist) System::Call "Shell32::SHGetSpecialFolderPathW(p 0, t.s, i ${_ID}, i 0)" Pop ${_RESULT} !macroend !define CSIDL_PROGRAMS 0x0002 !define CSIDL_LOCAL_APPDATA 0x001c !define CSIDL_COMMON_APPDATA 0x0023 ; Current User's Start Menu Programs !define GetProgramsFolder "!insertmacro GetSpecialFolder ${CSIDL_PROGRAMS}" ; Current User's Local App Data (e.g. C:\Users\\AppData\Local) !define GetLocalAppDataFolder "!insertmacro GetSpecialFolder ${CSIDL_LOCAL_APPDATA}" ; Common App Data (e.g. C:\ProgramData) !define GetCommonAppDataFolder "!insertmacro GetSpecialFolder ${CSIDL_COMMON_APPDATA}" ################################################################################ # Macros for retrieving existing install paths /** * Finds a second installation of the application so we can make informed * decisions about registry operations. This uses SHCTX to determine the * registry hive so you must call SetShellVarContext first. * * @param _KEY * The registry subkey (typically this will be Software\Mozilla). * @return _RESULT * false if a second install isn't found, path to the main exe if a * second install is found. * * $R3 = stores the long path to $INSTDIR * $R4 = counter for the outer loop's EnumRegKey * $R5 = return value from ReadRegStr and RemoveQuotesFromPath * $R6 = return value from GetParent * $R7 = return value from the loop's EnumRegKey * $R8 = storage for _KEY * $R9 = _KEY and _RESULT */ !macro GetSecondInstallPath !ifndef ${_MOZFUNC_UN}GetSecondInstallPath !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}GetParent !insertmacro ${_MOZFUNC_UN_TMP}RemoveQuotesFromPath !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}GetSecondInstallPath "!insertmacro ${_MOZFUNC_UN}GetSecondInstallPathCall" Function ${_MOZFUNC_UN}GetSecondInstallPath Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 Push $R3 ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R3 StrCpy $R4 0 ; set the counter for the loop to 0 StrCpy $R8 "$R9" ; Registry key path to search StrCpy $R9 "false" ; default return value loop: EnumRegKey $R7 SHCTX $R8 $R4 StrCmp $R7 "" end +1 ; if empty there are no more keys to enumerate IntOp $R4 $R4 + 1 ; increment the loop's counter ClearErrors ReadRegStr $R5 SHCTX "$R8\$R7\bin" "PathToExe" IfErrors loop ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R5" $R5 IfFileExists "$R5" +1 loop ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ${${_MOZFUNC_UN}GetParent} "$R5" $R6 StrCmp "$R6" "$R3" loop +1 StrCmp "$R6\${FileMainEXE}" "$R5" +1 loop StrCpy $R9 "$R5" end: ClearErrors Pop $R3 Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro GetSecondInstallPathCall _KEY _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Call GetSecondInstallPath Pop ${_RESULT} !verbose pop !macroend !macro un.GetSecondInstallPathCall _KEY _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Call un.GetSecondInstallPath Pop ${_RESULT} !verbose pop !macroend !macro un.GetSecondInstallPath !ifndef un.GetSecondInstallPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro GetSecondInstallPath !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Finds an existing installation path for the application based on the * application's executable name so we can default to using this path for the * install. If there is zero or more than one installation of the application * then we default to the default installation path. This uses SHCTX to * determine the registry hive to read from so you must call SetShellVarContext * first. * * @param _KEY * The registry subkey (typically this will be Software\Mozilla\App Name). * @return _RESULT * false if a single install location for this app name isn't found, * path to the install directory if a single install location is found. * * $R5 = counter for the loop's EnumRegKey * $R6 = return value from EnumRegKey * $R7 = return value from ReadRegStr * $R8 = storage for _KEY * $R9 = _KEY and _RESULT */ !macro GetSingleInstallPath !ifndef ${_MOZFUNC_UN}GetSingleInstallPath !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}GetParent !insertmacro ${_MOZFUNC_UN_TMP}RemoveQuotesFromPath !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}GetSingleInstallPath "!insertmacro ${_MOZFUNC_UN}GetSingleInstallPathCall" Function ${_MOZFUNC_UN}GetSingleInstallPath Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 StrCpy $R8 $R9 StrCpy $R9 "false" StrCpy $R5 0 ; set the counter for the loop to 0 loop: ClearErrors EnumRegKey $R6 SHCTX $R8 $R5 IfErrors cleanup StrCmp $R6 "" cleanup +1 ; if empty there are no more keys to enumerate IntOp $R5 $R5 + 1 ; increment the loop's counter ClearErrors ReadRegStr $R7 SHCTX "$R8\$R6\Main" "PathToExe" IfErrors loop ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R7" $R7 GetFullPathName $R7 "$R7" IfErrors loop StrCmp "$R9" "false" +1 +3 StrCpy $R9 "$R7" GoTo Loop StrCpy $R9 "false" cleanup: StrCmp $R9 "false" end +1 ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9 ${${_MOZFUNC_UN}GetParent} "$R9" $R9 end: ClearErrors Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro GetSingleInstallPathCall _KEY _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Call GetSingleInstallPath Pop ${_RESULT} !verbose pop !macroend !macro un.GetSingleInstallPathCall _KEY _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Call un.GetSingleInstallPath Pop ${_RESULT} !verbose pop !macroend !macro un.GetSingleInstallPath !ifndef un.GetSingleInstallPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro GetSingleInstallPath !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Find the first existing installation for the application. * This is similar to GetSingleInstallPath, except that it always returns the * first path it finds, instead of an error when more than one path exists. * * The shell context and the registry view should already have been set. * * @param _KEY * The registry subkey (typically Software\Mozilla\App Name). * @return _RESULT * path to the install directory of the first location found, or * the string "false" if no existing installation was found. * * $R5 = counter for the loop's EnumRegKey * $R6 = return value from EnumRegKey * $R7 = return value from ReadRegStr * $R8 = storage for _KEY * $R9 = _KEY and _RESULT */ !macro GetFirstInstallPath !ifndef ${_MOZFUNC_UN}GetFirstInstallPath !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}GetParent !insertmacro ${_MOZFUNC_UN_TMP}RemoveQuotesFromPath !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}GetFirstInstallPath "!insertmacro ${_MOZFUNC_UN}__GetFirstInstallPathCall" Function ${_MOZFUNC_UN}__GetFirstInstallPath Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 StrCpy $R8 $R9 StrCpy $R9 "false" StrCpy $R5 0 ${Do} ClearErrors EnumRegKey $R6 SHCTX $R8 $R5 ${If} ${Errors} ${OrIf} $R6 == "" ${Break} ${EndIf} IntOp $R5 $R5 + 1 ReadRegStr $R7 SHCTX "$R8\$R6\Main" "PathToExe" ${If} ${Errors} ${Continue} ${EndIf} ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R7" $R7 GetFullPathName $R7 "$R7" ${If} ${Errors} ${Continue} ${EndIf} StrCpy $R9 "$R7" ${Break} ${Loop} ${If} $R9 != "false" ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9 ${${_MOZFUNC_UN}GetParent} "$R9" $R9 ${EndIf} Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro __GetFirstInstallPathCall _KEY _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Call __GetFirstInstallPath Pop ${_RESULT} !verbose pop !macroend !macro un.__GetFirstInstallPathCall _KEY _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Call un.__GetFirstInstallPath Pop ${_RESULT} !verbose pop !macroend !macro un.__GetFirstInstallPath !ifndef un.__GetFirstInstallPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro __GetFirstInstallPath !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend ################################################################################ # Macros for working with the file system /** * Attempts to delete a file if it exists. This will fail if the file is in use. * * @param _FILE * The path to the file that is to be deleted. */ !macro DeleteFile _FILE ${If} ${FileExists} "${_FILE}" Delete "${_FILE}" ${EndIf} !macroend !define DeleteFile "!insertmacro DeleteFile" /** * Removes a directory if it exists and is empty. * * @param _DIR * The path to the directory that is to be removed. */ !macro RemoveDir _DIR ${If} ${FileExists} "${_DIR}" RmDir "${_DIR}" ${EndIf} !macroend !define RemoveDir "!insertmacro RemoveDir" /** * Checks whether it is possible to create and delete a directory and a file in * the install directory. Creation and deletion of files and directories are * checked since a user may have rights for one and not the other. If creation * and deletion of a file and a directory are successful this macro will return * true... if not, this it return false. * * @return _RESULT * true if files and directories can be created and deleted in the * install directory otherwise false. * * $R8 = temporary filename in the installation directory returned from * GetTempFileName. * $R9 = _RESULT */ !macro CanWriteToInstallDir !ifndef ${_MOZFUNC_UN}CanWriteToInstallDir !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}CanWriteToInstallDir "!insertmacro ${_MOZFUNC_UN}CanWriteToInstallDirCall" Function ${_MOZFUNC_UN}CanWriteToInstallDir Push $R9 Push $R8 StrCpy $R9 "true" ; IfFileExists returns false for $INSTDIR when $INSTDIR is the root of a ; UNC path so always try to create $INSTDIR CreateDirectory "$INSTDIR\" GetTempFileName $R8 "$INSTDIR\" ${Unless} ${FileExists} $R8 ; Can files be created? StrCpy $R9 "false" Goto done ${EndUnless} Delete $R8 ${If} ${FileExists} $R8 ; Can files be deleted? StrCpy $R9 "false" Goto done ${EndIf} CreateDirectory $R8 ${Unless} ${FileExists} $R8 ; Can directories be created? StrCpy $R9 "false" Goto done ${EndUnless} RmDir $R8 ${If} ${FileExists} $R8 ; Can directories be deleted? StrCpy $R9 "false" Goto done ${EndIf} done: RmDir "$INSTDIR\" ; Only remove $INSTDIR if it is empty ClearErrors Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro CanWriteToInstallDirCall _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Call CanWriteToInstallDir Pop ${_RESULT} !verbose pop !macroend !macro un.CanWriteToInstallDirCall _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.CanWriteToInstallDir Pop ${_RESULT} !verbose pop !macroend !macro un.CanWriteToInstallDir !ifndef un.CanWriteToInstallDir !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro CanWriteToInstallDir !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Checks whether there is sufficient free space available for the installation * directory using GetDiskFreeSpaceExW which respects disk quotas. This macro * will calculate the size of all sections that are selected, compare that with * the free space available, and if there is sufficient free space it will * return true... if not, it will return false. * * @return _RESULT * "true" if there is sufficient free space otherwise "false". * * $R5 = return value from SectionGetSize * $R6 = return value from SectionGetFlags * return value from an 'and' comparison of SectionGetFlags (1=selected) * return value for lpFreeBytesAvailable from GetDiskFreeSpaceExW * return value for System::Int64Op $R6 / 1024 * return value for System::Int64Op $R6 > $R8 * $R7 = the counter for enumerating the sections * the temporary file name for the directory created under $INSTDIR passed * to GetDiskFreeSpaceExW. * $R8 = sum in KB of all selected sections * $R9 = _RESULT */ !macro CheckDiskSpace !ifndef ${_MOZFUNC_UN}CheckDiskSpace !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}CheckDiskSpace "!insertmacro ${_MOZFUNC_UN}CheckDiskSpaceCall" Function ${_MOZFUNC_UN}CheckDiskSpace Push $R9 Push $R8 Push $R7 Push $R6 Push $R5 ClearErrors StrCpy $R9 "true" ; default return value StrCpy $R8 "0" ; sum in KB of all selected sections StrCpy $R7 "0" ; counter for enumerating sections ; Enumerate the sections and sum up the sizes of the sections that are ; selected. SectionGetFlags $R7 $R6 IfErrors +7 +1 IntOp $R6 ${SF_SELECTED} & $R6 IntCmp $R6 0 +3 +1 +1 SectionGetSize $R7 $R5 IntOp $R8 $R8 + $R5 IntOp $R7 $R7 + 1 GoTo -7 ; The directory passed to GetDiskFreeSpaceExW must exist for the call to ; succeed. Since the CanWriteToInstallDir macro is called prior to this ; macro the call to CreateDirectory will always succeed. ; IfFileExists returns false for $INSTDIR when $INSTDIR is the root of a ; UNC path so always try to create $INSTDIR CreateDirectory "$INSTDIR\" GetTempFileName $R7 "$INSTDIR\" Delete "$R7" CreateDirectory "$R7" System::Call 'kernel32::GetDiskFreeSpaceExW(w, *l, *l, *l) i(R7, .R6, ., .) .' ; Convert to KB for comparison with $R8 which is in KB System::Int64Op $R6 / 1024 Pop $R6 System::Int64Op $R6 > $R8 Pop $R6 IntCmp $R6 1 end +1 +1 StrCpy $R9 "false" end: RmDir "$R7" RmDir "$INSTDIR\" ; Only remove $INSTDIR if it is empty ClearErrors Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro CheckDiskSpaceCall _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Call CheckDiskSpace Pop ${_RESULT} !verbose pop !macroend !macro un.CheckDiskSpaceCall _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.CheckDiskSpace Pop ${_RESULT} !verbose pop !macroend !macro un.CheckDiskSpace !ifndef un.CheckDiskSpace !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro CheckDiskSpace !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Returns the path found within a passed in string. The path is quoted or not * with the exception of an unquoted non 8dot3 path without arguments that is * also not a DefaultIcon path, is a 8dot3 path or not, has command line * arguments, or is a registry DefaultIcon path (e.g. ,# where # * is the icon's resuorce id). The string does not need to be a valid path or * exist. It is up to the caller to pass in a string of one of the forms noted * above and to verify existence if necessary. * * Examples: * In: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE -flag "%1" * In: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE,0 * In: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE * In: "C:\PROGRA~1\MOZILL~1\FIREFOX.EXE" * In: "C:\PROGRA~1\MOZILL~1\FIREFOX.EXE" -flag "%1" * Out: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE * * In: "C:\Program Files\Mozilla Firefox\firefox.exe" -flag "%1" * In: C:\Program Files\Mozilla Firefox\firefox.exe,0 * In: "C:\Program Files\Mozilla Firefox\firefox.exe" * Out: C:\Program Files\Mozilla Firefox\firefox.exe * * @param _IN_PATH * The string containing the path. * @param _OUT_PATH * The register to store the path to. * * $R7 = counter for the outer loop's EnumRegKey * $R8 = return value from ReadRegStr * $R9 = _IN_PATH and _OUT_PATH */ !macro GetPathFromString !ifndef ${_MOZFUNC_UN}GetPathFromString !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}GetPathFromString "!insertmacro ${_MOZFUNC_UN}GetPathFromStringCall" Function ${_MOZFUNC_UN}GetPathFromString Exch $R9 Push $R8 Push $R7 StrCpy $R7 0 ; Set the counter to 0. ; Handle quoted paths with arguments. StrCpy $R8 $R9 1 ; Copy the first char. StrCmp $R8 '"' +2 +1 ; Is it a "? StrCmp $R8 "'" +1 +9 ; Is it a '? StrCpy $R9 $R9 "" 1 ; Remove the first char. IntOp $R7 $R7 + 1 ; Increment the counter. StrCpy $R8 $R9 1 $R7 ; Starting from the counter copy the next char. StrCmp $R8 "" end +1 ; Are there no more chars? StrCmp $R8 '"' +2 +1 ; Is it a " char? StrCmp $R8 "'" +1 -4 ; Is it a ' char? StrCpy $R9 $R9 $R7 ; Copy chars up to the counter. GoTo end ; Handle DefaultIcon paths. DefaultIcon paths are not quoted and end with ; a , and a number. IntOp $R7 $R7 - 1 ; Decrement the counter. StrCpy $R8 $R9 1 $R7 ; Copy one char from the end minus the counter. StrCmp $R8 '' +4 +1 ; Are there no more chars? StrCmp $R8 ',' +1 -3 ; Is it a , char? StrCpy $R9 $R9 $R7 ; Copy chars up to the end minus the counter. GoTo end ; Handle unquoted paths with arguments. An unquoted path with arguments ; must be an 8dot3 path. StrCpy $R7 -1 ; Set the counter to -1 so it will start at 0. IntOp $R7 $R7 + 1 ; Increment the counter. StrCpy $R8 $R9 1 $R7 ; Starting from the counter copy the next char. StrCmp $R8 "" end +1 ; Are there no more chars? StrCmp $R8 " " +1 -3 ; Is it a space char? StrCpy $R9 $R9 $R7 ; Copy chars up to the counter. end: ClearErrors Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro GetPathFromStringCall _IN_PATH _OUT_PATH !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_IN_PATH}" Call GetPathFromString Pop ${_OUT_PATH} !verbose pop !macroend !macro un.GetPathFromStringCall _IN_PATH _OUT_PATH !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_IN_PATH}" Call un.GetPathFromString Pop ${_OUT_PATH} !verbose pop !macroend !macro un.GetPathFromString !ifndef un.GetPathFromString !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro GetPathFromString !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Removes the quotes from each end of a string if present. * * @param _IN_PATH * The string containing the path. * @param _OUT_PATH * The register to store the long path. * * $R7 = storage for single character comparison * $R8 = storage for _IN_PATH * $R9 = _IN_PATH and _OUT_PATH */ !macro RemoveQuotesFromPath !ifndef ${_MOZFUNC_UN}RemoveQuotesFromPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}RemoveQuotesFromPath "!insertmacro ${_MOZFUNC_UN}RemoveQuotesFromPathCall" Function ${_MOZFUNC_UN}RemoveQuotesFromPath Exch $R9 Push $R8 Push $R7 StrCpy $R7 "$R9" 1 StrCmp $R7 "$\"" +1 +2 StrCpy $R9 "$R9" "" 1 StrCpy $R7 "$R9" "" -1 StrCmp $R7 "$\"" +1 +2 StrCpy $R9 "$R9" -1 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro RemoveQuotesFromPathCall _IN_PATH _OUT_PATH !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_IN_PATH}" Call RemoveQuotesFromPath Pop ${_OUT_PATH} !verbose pop !macroend !macro un.RemoveQuotesFromPathCall _IN_PATH _OUT_PATH !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_IN_PATH}" Call un.RemoveQuotesFromPath Pop ${_OUT_PATH} !verbose pop !macroend !macro un.RemoveQuotesFromPath !ifndef un.RemoveQuotesFromPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro RemoveQuotesFromPath !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Returns the long path for an existing file or directory. GetLongPathNameW * may not be available on Win95 if Microsoft Layer for Unicode is not * installed and GetFullPathName only returns a long path for the last file or * directory that doesn't end with a \ in the path that it is passed. If the * path does not exist on the file system this will return an empty string. To * provide a consistent result trailing back-slashes are always removed. * * Note: 1024 used by GetLongPathNameW is the maximum NSIS string length. * * @param _IN_PATH * The string containing the path. * @param _OUT_PATH * The register to store the long path. * * $R4 = counter value when the previous \ was found * $R5 = directory or file name found during loop * $R6 = return value from GetLongPathNameW and loop counter * $R7 = long path from GetLongPathNameW and single char from path for comparison * $R8 = storage for _IN_PATH * $R9 = _IN_PATH _OUT_PATH */ !macro GetLongPath !ifndef ${_MOZFUNC_UN}GetLongPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}GetLongPath "!insertmacro ${_MOZFUNC_UN}GetLongPathCall" Function ${_MOZFUNC_UN}GetLongPath Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 ClearErrors GetFullPathName $R8 "$R9" IfErrors end_GetLongPath +1 ; If the path doesn't exist return an empty string. ; Make the drive letter uppercase. StrCpy $R9 "$R8" 1 ; Copy the first char. StrCpy $R8 "$R8" "" 1 ; Copy everything after the first char. ; Convert the first char to uppercase. System::Call "User32::CharUpper(w R9 R9)i" StrCpy $R8 "$R9$R8" ; Copy the uppercase char and the rest of the chars. ; Do it the hard way. StrCpy $R4 0 ; Stores the position in the string of the last \ found. StrCpy $R6 -1 ; Set the counter to -1 so it will start at 0. loop_GetLongPath: IntOp $R6 $R6 + 1 ; Increment the counter. StrCpy $R7 $R8 1 $R6 ; Starting from the counter copy the next char. StrCmp $R7 "" +2 +1 ; Are there no more chars? StrCmp $R7 "\" +1 -3 ; Is it a \? ; Copy chars starting from the previously found \ to the counter. StrCpy $R5 $R8 $R6 $R4 ; If this is the first \ found we want to swap R9 with R5 so a \ will ; be appended to the drive letter and colon (e.g. C: will become C:\). StrCmp $R4 0 +1 +3 StrCpy $R9 $R5 StrCpy $R5 "" GetFullPathName $R9 "$R9\$R5" StrCmp $R7 "" end_GetLongPath +1 ; Are there no more chars? ; Store the counter for the current \ and prefix it for StrCpy operations. StrCpy $R4 "+$R6" IntOp $R6 $R6 + 1 ; Increment the counter so we skip over the \. StrCpy $R8 $R8 "" $R6 ; Copy chars starting from the counter to the end. StrCpy $R6 -1 ; Reset the counter to -1 so it will start over at 0. GoTo loop_GetLongPath end_GetLongPath: ; If there is a trailing slash remove it StrCmp $R9 "" +4 +1 StrCpy $R8 "$R9" "" -1 StrCmp $R8 "\" +1 +2 StrCpy $R9 "$R9" -1 ClearErrors Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro GetLongPathCall _IN_PATH _OUT_PATH !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_IN_PATH}" Call GetLongPath Pop ${_OUT_PATH} !verbose pop !macroend !macro un.GetLongPathCall _IN_PATH _OUT_PATH !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_IN_PATH}" Call un.GetLongPath Pop ${_OUT_PATH} !verbose pop !macroend !macro un.GetLongPath !ifndef un.GetLongPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro GetLongPath !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend ################################################################################ # Macros for cleaning up the registry and file system /** * Removes registry keys that reference this install location and for paths that * no longer exist. This uses SHCTX to determine the registry hive so you must * call SetShellVarContext first. * * @param _KEY * The registry subkey (typically this will be Software\Mozilla). * * $0 = loop counter * $1 = temporary value used for string searches * $R0 = on x64 systems set to 'false' at the beginning of the macro when * enumerating the x86 registry view and set to 'true' when enumerating * the x64 registry view. * $R1 = stores the long path to $INSTDIR * $R2 = return value from the stack from the GetParent and GetLongPath macros * $R3 = return value from the outer loop's EnumRegKey and ESR string * $R4 = return value from the inner loop's EnumRegKey * $R5 = return value from ReadRegStr * $R6 = counter for the outer loop's EnumRegKey * $R7 = counter for the inner loop's EnumRegKey * $R8 = return value from the stack from the RemoveQuotesFromPath macro * $R9 = _KEY */ !macro RegCleanMain !ifndef ${_MOZFUNC_UN}RegCleanMain !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetParent !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}RemoveQuotesFromPath !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}RegCleanMain "!insertmacro ${_MOZFUNC_UN}RegCleanMainCall" Function ${_MOZFUNC_UN}RegCleanMain Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 Push $R3 Push $R2 Push $R1 Push $R0 Push $0 Push $1 ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R1 StrCpy $R6 0 ; set the counter for the outer loop to 0 ${If} ${RunningX64} ${OrIf} ${IsNativeARM64} StrCpy $R0 "false" ; Set the registry to the 32 bit registry for 64 bit installations or to ; the 64 bit registry for 32 bit installations at the beginning so it can ; easily be set back to the correct registry view when finished. !ifdef HAVE_64BIT_BUILD SetRegView 32 !else SetRegView 64 !endif ${EndIf} outerloop: EnumRegKey $R3 SHCTX $R9 $R6 StrCmp $R3 "" end +1 ; if empty there are no more keys to enumerate IntOp $R6 $R6 + 1 ; increment the outer loop's counter ClearErrors ReadRegStr $R5 SHCTX "$R9\$R3\bin" "PathToExe" IfErrors 0 outercontinue StrCpy $R7 0 ; set the counter for the inner loop to 0 innerloop: EnumRegKey $R4 SHCTX "$R9\$R3" $R7 StrCmp $R4 "" outerloop +1 ; if empty there are no more keys to enumerate IntOp $R7 $R7 + 1 ; increment the inner loop's counter ClearErrors ReadRegStr $R5 SHCTX "$R9\$R3\$R4\Main" "PathToExe" IfErrors innerloop ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R5" $R8 ${${_MOZFUNC_UN}GetParent} "$R8" $R2 ${${_MOZFUNC_UN}GetLongPath} "$R2" $R2 IfFileExists "$R2" +1 innerloop StrCmp "$R2" "$R1" +1 innerloop ClearErrors DeleteRegKey SHCTX "$R9\$R3\$R4" IfErrors innerloop IntOp $R7 $R7 - 1 ; decrement the inner loop's counter when the key is deleted successfully. ClearErrors DeleteRegKey /ifempty SHCTX "$R9\$R3" IfErrors innerloop outerdecrement outercontinue: ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R5" $R8 ${${_MOZFUNC_UN}GetParent} "$R8" $R2 ${${_MOZFUNC_UN}GetLongPath} "$R2" $R2 IfFileExists "$R2" +1 outerloop StrCmp "$R2" "$R1" +1 outerloop ClearErrors DeleteRegKey SHCTX "$R9\$R3" IfErrors outerloop outerdecrement: IntOp $R6 $R6 - 1 ; decrement the outer loop's counter when the key is deleted successfully. GoTo outerloop end: ; Check if _KEY\${BrandFullNameInternal} refers to a key that's been ; removed, either just now by this function or earlier by something else, ; and if so either update it to a key that does exist or remove it if we ; can't find anything to update it to. ; We'll run this check twice, once looking for non-ESR keys and then again ; looking specifically for the separate ESR keys. StrCpy $R3 "" ${For} $0 0 1 ClearErrors ReadRegStr $R5 SHCTX "$R9\${BrandFullNameInternal}$R3" "CurrentVersion" ${IfNot} ${Errors} ReadRegStr $R5 SHCTX "$R9\${BrandFullNameInternal}\$R5" "" ${If} ${Errors} ; Key doesn't exist, update or remove CurrentVersion and default. StrCpy $R5 "" StrCpy $R6 0 EnumRegKey $R4 SHCTX "$R9\${BrandFullNameInternal}" $R6 ${While} $R4 != "" ClearErrors ${WordFind} "$R4" "esr" "E#" $1 ${If} $R3 == "" ; The key we're looking to update is a non-ESR, so we need to ; select only another non-ESR to update it with. ${If} ${Errors} StrCpy $R5 "$R4" ${Break} ${EndIf} ${Else} ; The key we're looking to update is an ESR, so we need to ; select only another ESR to update it with. ${IfNot} ${Errors} StrCpy $R5 "$R4" ${Break} ${EndIf} ${EndIf} IntOp $R6 $R6 + 1 EnumRegKey $R4 SHCTX "$R9\${BrandFullNameInternal}" $R6 ${EndWhile} ${If} $R5 == "" ; We didn't find an install to update the key with, so delete the ; CurrentVersion value and the entire key if it has no subkeys. DeleteRegValue SHCTX "$R9\${BrandFullNameInternal}$R3" "CurrentVersion" DeleteRegValue SHCTX "$R9\${BrandFullNameInternal}$R3" "" DeleteRegKey /ifempty SHCTX "$R9\${BrandFullNameInternal}$R3" ${Else} ; We do have another still-existing install, so update the key to ; that version. WriteRegStr SHCTX "$R9\${BrandFullNameInternal}$R3" \ "CurrentVersion" "$R5" ${WordFind} "$R5" " " "+1{" $R5 WriteRegStr SHCTX "$R9\${BrandFullNameInternal}$R3" "" "$R5" ${EndIf} ${EndIf} ; Else, the key referenced in CurrentVersion still exists, ; so there's nothing to update or remove. ${EndIf} ; Set up for the second iteration of the loop, where we'll be looking ; for the separate ESR keys. StrCpy $R3 " ESR" ${Next} ${If} ${RunningX64} ${OrIf} ${IsNativeARM64} ${If} "$R0" == "false" ; Set the registry to the correct view. !ifdef HAVE_64BIT_BUILD SetRegView 64 !else SetRegView 32 !endif StrCpy $R6 0 ; set the counter for the outer loop to 0 StrCpy $R0 "true" GoTo outerloop ${EndIf} ${EndIf} ClearErrors Pop $1 Pop $0 Pop $R0 Pop $R1 Pop $R2 Pop $R3 Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro RegCleanMainCall _KEY !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Call RegCleanMain !verbose pop !macroend !macro un.RegCleanMainCall _KEY !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Call un.RegCleanMain !verbose pop !macroend !macro un.RegCleanMain !ifndef un.RegCleanMain !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro RegCleanMain !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Removes registry keys that reference this install location and for paths that * no longer exist. * * @param _KEY ($R1) * The registry subkey * (typically this will be Software\Mozilla\${AppName}). */ !macro RegCleanPrefs !ifndef ${_MOZFUNC_UN}RegCleanPrefs !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}RegCleanPrefs "!insertmacro ${_MOZFUNC_UN}RegCleanPrefsCall" Function ${_MOZFUNC_UN}RegCleanPrefs Exch $R1 ; get _KEY from the stack ; These prefs are always stored in the native registry. SetRegView 64 ; Delete the installer prefs key for this installation, if one exists. DeleteRegKey HKCU "$R1\Installer\$AppUserModelID" ; If there aren't any more installer prefs keys, delete the parent key. DeleteRegKey /ifempty HKCU "$R1\Installer" SetRegView lastused Pop $R1 ; restore the previous $R1 FunctionEnd !verbose pop !endif !macroend !macro RegCleanPrefsCall _KEY !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Call RegCleanPrefs !verbose pop !macroend !macro un.RegCleanPrefsCall _KEY !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_KEY}" Call un.RegCleanPrefs !verbose pop !macroend !macro un.RegCleanPrefs !ifndef un.RegCleanPrefs !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro RegCleanPrefs !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Removes all registry keys from \Software\Windows\CurrentVersion\Uninstall * that reference this install location in both the 32 bit and 64 bit registry * view. This macro uses SHCTX to determine the registry hive so you must call * SetShellVarContext first. * * $R3 = on x64 systems set to 'false' at the beginning of the macro when * enumerating the x86 registry view and set to 'true' when enumerating * the x64 registry view. * $R4 = stores the long path to $INSTDIR * $R5 = return value from ReadRegStr * $R6 = string for the base reg key (e.g. Software\Microsoft\Windows\CurrentVersion\Uninstall) * $R7 = return value from EnumRegKey * $R8 = counter for EnumRegKey * $R9 = return value from the stack from the RemoveQuotesFromPath and GetLongPath macros */ !macro RegCleanUninstall !ifndef ${_MOZFUNC_UN}RegCleanUninstall !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}RemoveQuotesFromPath !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}RegCleanUninstall "!insertmacro ${_MOZFUNC_UN}RegCleanUninstallCall" Function ${_MOZFUNC_UN}RegCleanUninstall Push $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 Push $R3 ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R4 StrCpy $R6 "Software\Microsoft\Windows\CurrentVersion\Uninstall" StrCpy $R7 "" StrCpy $R8 0 ${If} ${RunningX64} ${OrIf} ${IsNativeARM64} StrCpy $R3 "false" ; Set the registry to the 32 bit registry for 64 bit installations or to ; the 64 bit registry for 32 bit installations at the beginning so it can ; easily be set back to the correct registry view when finished. !ifdef HAVE_64BIT_BUILD SetRegView 32 !else SetRegView 64 !endif ${EndIf} loop: EnumRegKey $R7 SHCTX $R6 $R8 StrCmp $R7 "" end +1 IntOp $R8 $R8 + 1 ; Increment the counter ClearErrors ReadRegStr $R5 SHCTX "$R6\$R7" "InstallLocation" IfErrors loop ${${_MOZFUNC_UN}RemoveQuotesFromPath} "$R5" $R9 ; Detect when the path is just a drive letter without a trailing ; backslash (e.g., "C:"), and add a backslash. If we don't, the Win32 ; calls in GetLongPath will interpret that syntax as a shorthand ; for the working directory, because that's the DOS 2.0 convention, ; and will return the path to that directory instead of just the drive. ; Back here, we would then successfully match that with our $INSTDIR, ; and end up deleting a registry key that isn't really ours. StrLen $R5 "$R9" ${If} $R5 == 2 StrCpy $R5 "$R9" 1 1 ${If} "$R5" == ":" StrCpy $R9 "$R9\" ${EndIf} ${EndIf} ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9 StrCmp "$R9" "$R4" +1 loop ClearErrors DeleteRegKey SHCTX "$R6\$R7" IfErrors loop +1 IntOp $R8 $R8 - 1 ; Decrement the counter on successful deletion GoTo loop end: ${If} ${RunningX64} ${OrIf} ${IsNativeARM64} ${If} "$R3" == "false" ; Set the registry to the correct view. !ifdef HAVE_64BIT_BUILD SetRegView 64 !else SetRegView 32 !endif StrCpy $R7 "" StrCpy $R8 0 StrCpy $R3 "true" GoTo loop ${EndIf} ${EndIf} ClearErrors Pop $R3 Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Pop $R9 FunctionEnd !verbose pop !endif !macroend !macro RegCleanUninstallCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call RegCleanUninstall !verbose pop !macroend !macro un.RegCleanUninstallCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.RegCleanUninstall !verbose pop !macroend !macro un.RegCleanUninstall !ifndef un.RegCleanUninstall !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro RegCleanUninstall !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Removes an application specific handler registry key under Software\Classes * for both HKCU and HKLM when its open command refers to this install * location or the install location doesn't exist. * * @param _HANDLER_NAME * The registry name for the handler. * * $R7 = stores the long path to the $INSTDIR * $R8 = stores the path to the open command's parent directory * $R9 = _HANDLER_NAME */ !macro RegCleanAppHandler !ifndef ${_MOZFUNC_UN}RegCleanAppHandler !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}GetParent !insertmacro ${_MOZFUNC_UN_TMP}GetPathFromString !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}RegCleanAppHandler "!insertmacro ${_MOZFUNC_UN}RegCleanAppHandlerCall" Function ${_MOZFUNC_UN}RegCleanAppHandler Exch $R9 Push $R8 Push $R7 ClearErrors ReadRegStr $R8 HKCU "Software\Classes\$R9\shell\open\command" "" IfErrors next +1 ${${_MOZFUNC_UN}GetPathFromString} "$R8" $R8 ${${_MOZFUNC_UN}GetParent} "$R8" $R8 IfFileExists "$R8" +3 +1 DeleteRegKey HKCU "Software\Classes\$R9" GoTo next ${${_MOZFUNC_UN}GetLongPath} "$R8" $R8 ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R7 StrCmp "$R7" "$R8" +1 next DeleteRegKey HKCU "Software\Classes\$R9" next: ReadRegStr $R8 HKLM "Software\Classes\$R9\shell\open\command" "" IfErrors end ${${_MOZFUNC_UN}GetPathFromString} "$R8" $R8 ${${_MOZFUNC_UN}GetParent} "$R8" $R8 IfFileExists "$R8" +3 +1 DeleteRegKey HKLM "Software\Classes\$R9" GoTo end ${${_MOZFUNC_UN}GetLongPath} "$R8" $R8 ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R7 StrCmp "$R7" "$R8" +1 end DeleteRegKey HKLM "Software\Classes\$R9" end: Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro RegCleanAppHandlerCall _HANDLER_NAME !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_HANDLER_NAME}" Call RegCleanAppHandler !verbose pop !macroend !macro un.RegCleanAppHandlerCall _HANDLER_NAME !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_HANDLER_NAME}" Call un.RegCleanAppHandler !verbose pop !macroend !macro un.RegCleanAppHandler !ifndef un.RegCleanAppHandler !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro RegCleanAppHandler !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Cleans up the registry for a protocol handler when its open command * refers to this install location. For HKCU the registry key is deleted * and for HKLM the values set by the application are deleted. * * @param _HANDLER_NAME * The registry name for the handler. * * $R7 = stores the long path to $INSTDIR * $R8 = stores the the long path to the open command's parent directory * $R9 = _HANDLER_NAME */ !macro un.RegCleanProtocolHandler !ifndef un.RegCleanProtocolHandler !insertmacro un.GetLongPath !insertmacro un.GetParent !insertmacro un.GetPathFromString !verbose push !verbose ${_MOZFUNC_VERBOSE} !define un.RegCleanProtocolHandler "!insertmacro un.RegCleanProtocolHandlerCall" Function un.RegCleanProtocolHandler Exch $R9 Push $R8 Push $R7 ReadRegStr $R8 HKCU "Software\Classes\$R9\shell\open\command" "" ${un.GetLongPath} "$INSTDIR" $R7 StrCmp "$R8" "" next +1 ${un.GetPathFromString} "$R8" $R8 ${un.GetParent} "$R8" $R8 ${un.GetLongPath} "$R8" $R8 StrCmp "$R7" "$R8" +1 next DeleteRegKey HKCU "Software\Classes\$R9" next: ReadRegStr $R8 HKLM "Software\Classes\$R9\shell\open\command" "" StrCmp "$R8" "" end +1 ${un.GetLongPath} "$INSTDIR" $R7 ${un.GetPathFromString} "$R8" $R8 ${un.GetParent} "$R8" $R8 ${un.GetLongPath} "$R8" $R8 StrCmp "$R7" "$R8" +1 end DeleteRegValue HKLM "Software\Classes\$R9\DefaultIcon" "" DeleteRegValue HKLM "Software\Classes\$R9\shell\open" "" DeleteRegValue HKLM "Software\Classes\$R9\shell\open\command" "" DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec" "" DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec\Application" "" DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec\Topic" "" end: Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro un.RegCleanProtocolHandlerCall _HANDLER_NAME !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_HANDLER_NAME}" Call un.RegCleanProtocolHandler !verbose pop !macroend /** * Cleans up the registry for a file handler when the passed in value equals * the default value for the file handler. For HKCU the registry key is deleted * and for HKLM the default value is deleted. * * @param _HANDLER_NAME * The registry name for the handler. * @param _DEFAULT_VALUE * The value to check for against the handler's default value. * * $R6 = stores the long path to $INSTDIR * $R7 = _DEFAULT_VALUE * $R9 = _HANDLER_NAME */ !macro RegCleanFileHandler !ifndef ${_MOZFUNC_UN}RegCleanFileHandler !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}GetParent !insertmacro ${_MOZFUNC_UN_TMP}GetPathFromString !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}RegCleanFileHandler "!insertmacro ${_MOZFUNC_UN}RegCleanFileHandlerCall" Function ${_MOZFUNC_UN}RegCleanFileHandler Exch $R9 Exch 1 Exch $R8 Push $R7 DeleteRegValue HKCU "Software\Classes\$R9\OpenWithProgids" $R8 EnumRegValue $R7 HKCU "Software\Classes\$R9\OpenWithProgids" 0 StrCmp "$R7" "" +1 +2 DeleteRegKey HKCU "Software\Classes\$R9\OpenWithProgids" ReadRegStr $R7 HKCU "Software\Classes\$R9" "" StrCmp "$R7" "$R8" +1 +2 DeleteRegKey HKCU "Software\Classes\$R9" DeleteRegValue HKLM "Software\Classes\$R9\OpenWithProgids" $R8 EnumRegValue $R7 HKLM "Software\Classes\$R9\OpenWithProgids" 0 StrCmp "$R7" "" +1 +2 DeleteRegKey HKLM "Software\Classes\$R9\OpenWithProgids" ReadRegStr $R7 HKLM "Software\Classes\$R9" "" StrCmp "$R7" "$R8" +1 +2 DeleteRegValue HKLM "Software\Classes\$R9" "" ClearErrors Pop $R7 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro RegCleanFileHandlerCall _HANDLER_NAME _DEFAULT_VALUE !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_DEFAULT_VALUE}" Push "${_HANDLER_NAME}" Call RegCleanFileHandler !verbose pop !macroend !macro un.RegCleanFileHandlerCall _HANDLER_NAME _DEFAULT_VALUE !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_DEFAULT_VALUE}" Push "${_HANDLER_NAME}" Call un.RegCleanFileHandler !verbose pop !macroend !macro un.RegCleanFileHandler !ifndef un.RegCleanFileHandler !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro RegCleanFileHandler !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Checks if a handler's open command points to this installation directory. * Uses SHCTX to determine the registry hive (e.g. HKLM or HKCU) to check. * * @param _HANDLER_NAME * The registry name for the handler. * @param _RESULT * true if it is the handler's open command points to this * installation directory and false if it does not. * * $R7 = stores the value of the open command and the path macros return values * $R8 = stores the handler's registry key name * $R9 = _DEFAULT_VALUE and _RESULT */ !macro IsHandlerForInstallDir !ifndef ${_MOZFUNC_UN}IsHandlerForInstallDir !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}GetParent !insertmacro ${_MOZFUNC_UN_TMP}GetPathFromString !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}IsHandlerForInstallDir "!insertmacro ${_MOZFUNC_UN}IsHandlerForInstallDirCall" Function ${_MOZFUNC_UN}IsHandlerForInstallDir Exch $R9 Push $R8 Push $R7 StrCpy $R8 "$R9" StrCpy $R9 "false" ReadRegStr $R7 SHCTX "Software\Classes\$R8\shell\open\command" "" ${If} $R7 != "" ${GetPathFromString} "$R7" $R7 ${GetParent} "$R7" $R7 ${GetLongPath} "$R7" $R7 ${If} $R7 == $INSTDIR StrCpy $R9 "true" ${EndIf} ${EndIf} ClearErrors Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro IsHandlerForInstallDirCall _HANDLER_NAME _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_HANDLER_NAME}" Call IsHandlerForInstallDir Pop "${_RESULT}" !verbose pop !macroend !macro un.IsHandlerForInstallDirCall _HANDLER_NAME _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_HANDLER_NAME}" Call un.IsHandlerForInstallDir Pop "${_RESULT}" !verbose pop !macroend !macro un.IsHandlerForInstallDir !ifndef un.IsHandlerForInstallDir !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro IsHandlerForInstallDir !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Removes the application's VirtualStore directory if present when the * installation directory is a sub-directory of the program files directory. * * $R3 = Local App Data dir * $R4 = $PROGRAMFILES/$PROGRAMFILES64 for CleanVirtualStore_Internal * $R5 = various path values. * $R6 = length of the long path to $PROGRAMFILES32 or $PROGRAMFILES64 * $R7 = long path to $PROGRAMFILES32 or $PROGRAMFILES64 * $R8 = length of the long path to $INSTDIR * $R9 = long path to $INSTDIR */ !macro CleanVirtualStore !ifndef ${_MOZFUNC_UN}CleanVirtualStore !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}CleanVirtualStore "!insertmacro ${_MOZFUNC_UN}CleanVirtualStoreCall" Function ${_MOZFUNC_UN}CleanVirtualStore Push $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 Push $R3 ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R9 ${If} "$R9" != "" StrLen $R8 "$R9" StrCpy $R4 $PROGRAMFILES32 Call ${_MOZFUNC_UN}CleanVirtualStore_Internal ${If} ${RunningX64} ${OrIf} ${IsNativeARM64} StrCpy $R4 $PROGRAMFILES64 Call ${_MOZFUNC_UN}CleanVirtualStore_Internal ${EndIf} ${EndIf} ClearErrors Pop $R3 Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Pop $R9 FunctionEnd Function ${_MOZFUNC_UN}CleanVirtualStore_Internal ${${_MOZFUNC_UN}GetLongPath} "" $R7 ${If} "$R7" != "" StrLen $R6 "$R7" ${If} $R8 < $R6 ; Copy from the start of $INSTDIR the length of $PROGRAMFILES64 StrCpy $R5 "$R9" $R6 ${If} "$R5" == "$R7" ; Remove the drive letter and colon from the $INSTDIR long path StrCpy $R5 "$R9" "" 2 ${GetLocalAppDataFolder} $R3 StrCpy $R5 "$R3\VirtualStore$R5" ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ${If} "$R5" != "" ${AndIf} ${FileExists} "$R5" RmDir /r "$R5" ${EndIf} ${EndIf} ${EndIf} ${EndIf} FunctionEnd !verbose pop !endif !macroend !macro CleanVirtualStoreCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call CleanVirtualStore !verbose pop !macroend !macro un.CleanVirtualStoreCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.CleanVirtualStore !verbose pop !macroend !macro un.CleanVirtualStore !ifndef un.CleanVirtualStore !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro CleanVirtualStore !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Cleans up some old logs in the Maintenance Service directory. * * @param _OLD_REL_PATH * The relative path to the profile directory from Local AppData. * Calculated for the old update directory not based on a hash. * * $R7 = _OLD_REL_PATH * $R1 = taskBar ID hash located in registry at SOFTWARE\_OLD_REL_PATH\TaskBarIDs * $R6 = long path to $INSTDIR */ !macro CleanMaintenanceServiceLogs !ifndef ${_MOZFUNC_UN}CleanMaintenanceServiceLogs !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}GetCommonDirectory !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}CleanMaintenanceServiceLogs "!insertmacro ${_MOZFUNC_UN}CleanMaintenanceServiceLogsCall" Function ${_MOZFUNC_UN}CleanMaintenanceServiceLogs Exch $R7 Push $R6 Push $R1 ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR" $R6 ${If} $R7 != "" ; _OLD_REL_PATH was passed ${AndIf} $R6 != "" ; We have the install dir path ; Get the taskbar ID hash for this installation path ReadRegStr $R1 HKLM "SOFTWARE\$R7\TaskBarIDs" $R6 ${If} $R1 == "" ReadRegStr $R1 HKCU "SOFTWARE\$R7\TaskBarIDs" $R6 ${EndIf} ${If} $R1 != "" ; Remove the secure log files that our updater may have created ; inside the maintenance service path. There are several files named ; with the install hash and an extension indicating the kind of file. ; so use a wildcard to delete them all. Delete "$PROGRAMFILES32\Mozilla Maintenance Service\UpdateLogs\$R1.*" ; If the UpdateLogs directory is now empty, then delete it. ; The Maintenance Service uninstaller should do this, but it may not ; be up to date enough because of bug 1665193, so doing this here as ; well lets us make sure it really happens. RmDir "$PROGRAMFILES32\Mozilla Maintenance Service\UpdateLogs" ${EndIf} ${EndIf} ClearErrors Pop $R1 Pop $R6 Exch $R7 FunctionEnd !verbose pop !endif !macroend !macro CleanMaintenanceServiceLogsCall _OLD_REL_PATH !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_OLD_REL_PATH}" Call CleanMaintenanceServiceLogs !verbose pop !macroend !macro un.CleanMaintenanceServiceLogsCall _OLD_REL_PATH !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_OLD_REL_PATH}" Call un.CleanMaintenanceServiceLogs !verbose pop !macroend !macro un.CleanMaintenanceServiceLogs !ifndef un.CleanMaintenanceServiceLogs !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro CleanMaintenanceServiceLogs !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Removes relevant shortcuts from a given shortcuts log. * * $R3 = return value from ShellLink::GetShortCutWorkingDirectory * $R4 = counter for appending to Shortcut for enumerating the ini file entries * $R5 = return value from ShellLink::GetShortCutTarget * $R6 = the long path to the Start Menu Programs directory (e.g. $SMPROGRAMS) * $R7 = the return value from ReadINIStr for the relative path to the applications * directory under the Start Menu Programs directory and the long path to this * directory * $R8 = the return value from ReadINIStr for enumerating shortcuts * $R9 = [in] long path to the shortcuts ini file */ !macro DeleteShortcutsFromLog !ifndef ${_MOZFUNC_UN}DeleteShortcutsFromLog !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}GetParent !insertmacro ${_MOZFUNC_UN_TMP}GetCommonDirectory !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}DeleteShortcutsFromLog "!insertmacro ${_MOZFUNC_UN}DeleteShortcutsFromLogCall" Function ${_MOZFUNC_UN}DeleteShortcutsFromLog Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 Push $R3 ${If} ${FileExists} "$R9" ; Delete Start Menu shortcuts for this application StrCpy $R4 -1 ${Do} IntOp $R4 $R4 + 1 ; Increment the counter ClearErrors ReadINIStr $R8 "$R9" "STARTMENU" "Shortcut$R4" ${If} ${Errors} ${ExitDo} ${EndIf} ${If} ${FileExists} "$SMPROGRAMS\$R8" ShellLink::GetShortCutTarget "$SMPROGRAMS\$R8" Pop $R5 ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ; Shortcuts created outside of the installer may ; have metadata set on them such that GetShortCutTarget ; returns the wrong path on 64-bit systems. ; GetShortCutWorkingDirectory is not _quite_ as good ; of a test (because it may be unset), but it's not ; subject to this bug, and is therefore the next best thing. ; https://phabricator.services.mozilla.com/D138197 ; contains some additional background on this. ShellLink::GetShortCutWorkingDirectory "$SMPROGRAMS\$R8" Pop $R3 ${If} "$INSTDIR\${FileMainEXE}" == "$R5" ${OrIf} "$INSTDIR" == "$R3" Delete "$SMPROGRAMS\$R8" ${EndIf} ${EndIf} ${Loop} ; There might also be a shortcut with a different name created by a ; previous version of the installer. ${If} ${FileExists} "$SMPROGRAMS\${BrandFullName}.lnk" ShellLink::GetShortCutTarget "$SMPROGRAMS\${BrandFullName}.lnk" Pop $R5 ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ShellLink::GetShortCutWorkingDirectory "$SMPROGRAMS\$R8" Pop $R3 ${If} "$INSTDIR\${FileMainEXE}" == "$R5" ${OrIf} "$INSTDIR" == "$R3" Delete "$SMPROGRAMS\${BrandFullName}.lnk" ${EndIf} ${EndIf} ; Delete Quick Launch shortcuts for this application StrCpy $R4 -1 ${Do} IntOp $R4 $R4 + 1 ; Increment the counter ClearErrors ReadINIStr $R8 "$R9" "QUICKLAUNCH" "Shortcut$R4" ${If} ${Errors} ${ExitDo} ${EndIf} ${If} ${FileExists} "$QUICKLAUNCH\$R8" ShellLink::GetShortCutTarget "$QUICKLAUNCH\$R8" Pop $R5 ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ShellLink::GetShortCutWorkingDirectory "$SMPROGRAMS\$R8" Pop $R3 ${If} "$INSTDIR\${FileMainEXE}" == "$R5" ${OrIf} "$INSTDIR" == "$R3" Delete "$QUICKLAUNCH\$R8" ${EndIf} ${EndIf} ${Loop} ; There might also be a shortcut with a different name created by a ; previous version of the installer. ${If} ${FileExists} "$QUICKLAUNCH\${BrandFullName}.lnk" ShellLink::GetShortCutTarget "$QUICKLAUNCH\${BrandFullName}.lnk" Pop $R5 ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ShellLink::GetShortCutWorkingDirectory "$SMPROGRAMS\$R8" Pop $R3 ${If} "$INSTDIR\${FileMainEXE}" == "$R5" ${OrIf} "$INSTDIR" == "$R3" Delete "$QUICKLAUNCH\${BrandFullName}.lnk" ${EndIf} ${EndIf} ; Delete Desktop shortcuts for this application StrCpy $R4 -1 ${Do} IntOp $R4 $R4 + 1 ; Increment the counter ClearErrors ReadINIStr $R8 "$R9" "DESKTOP" "Shortcut$R4" ${If} ${Errors} ${ExitDo} ${EndIf} ${If} ${FileExists} "$DESKTOP\$R8" ShellLink::GetShortCutTarget "$DESKTOP\$R8" Pop $R5 ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ShellLink::GetShortCutWorkingDirectory "$SMPROGRAMS\$R8" Pop $R3 ${If} "$INSTDIR\${FileMainEXE}" == "$R5" ${OrIf} "$INSTDIR" == "$R3" Delete "$DESKTOP\$R8" ${EndIf} ${EndIf} ${Loop} ; There might also be a shortcut with a different name created by a ; previous version of the installer. ${If} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" ShellLink::GetShortCutTarget "$DESKTOP\${BrandFullName}.lnk" Pop $R5 ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ; We don't bother checking working directory here because we know ; these shortcuts were only created by the installer, and thus ; not subject to the bug described above. ${If} "$INSTDIR\${FileMainEXE}" == "$R5" Delete "$DESKTOP\${BrandFullName}.lnk" ${EndIf} ${EndIf} ${${_MOZFUNC_UN}GetLongPath} "$SMPROGRAMS" $R6 ; Delete Start Menu Programs shortcuts for this application ClearErrors ReadINIStr $R7 "$R9" "SMPROGRAMS" "RelativePathToDir" ${${_MOZFUNC_UN}GetLongPath} "$R6\$R7" $R7 ${Unless} "$R7" == "" StrCpy $R4 -1 ${Do} IntOp $R4 $R4 + 1 ; Increment the counter ClearErrors ReadINIStr $R8 "$R9" "SMPROGRAMS" "Shortcut$R4" ${If} ${Errors} ${ExitDo} ${EndIf} ${If} ${FileExists} "$R7\$R8" ShellLink::GetShortCutTarget "$R7\$R8" Pop $R5 ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ${If} "$INSTDIR\${FileMainEXE}" == "$R5" Delete "$R7\$R8" ${EndIf} ${EndIf} ${Loop} ; Delete Start Menu Programs directories for this application ${Do} ClearErrors ${If} "$R6" == "$R7" ${ExitDo} ${EndIf} RmDir "$R7" ${If} ${Errors} ${ExitDo} ${EndIf} ${${_MOZFUNC_UN}GetParent} "$R7" $R7 ${Loop} ${EndUnless} ${EndIf} ClearErrors Pop $R3 Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro DeleteShortcutsFromLogCall _SHORTCUTS_LOG !verbose push !verbose ${_MOZFUNC_VERBOSE} Push ${_SHORTCUTS_LOG} Call DeleteShortcutsFromLog !verbose pop !macroend !macro un.DeleteShortcutsFromLogCall _SHORTCUTS_LOG !verbose push !verbose ${_MOZFUNC_VERBOSE} Push ${_SHORTCUTS_LOG} Call un.DeleteShortcutsFromLog !verbose pop !macroend !macro un.DeleteShortcutsFromLog !ifndef un.DeleteShortcutsFromLog !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro DeleteShortcutsFromLog !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Deletes shortcuts and Start Menu directories under Programs as specified by * the shortcuts log ini files and on Windows 7 unpins TaskBar and Start Menu * shortcuts. The shortcuts will not be deleted if the shortcut target isn't for * this install location which is determined by the shortcut having a target of * $INSTDIR\${FileMainEXE} _or_ the working directory of the shortcut being * equal to $INSTDIR. The context (All Users or Current User) of the * $DESKTOP and $SMPROGRAMS constants depends on the * SetShellVarContext setting and must be set by the caller of this macro. There * is no All Users context for $QUICKLAUNCH but this will not cause a problem * since the macro will just continue past the $QUICKLAUNCH shortcut deletion * section on subsequent calls. * * The meat of this is farmed out to DeleteShortcutsFromLog to facilitate * the processing of multiple shortcuts logs. * * The ini file sections must have the following format (the order of the * sections in the ini file is not important): * [SMPROGRAMS] -- this section is optional and largely irrelevant these days * ; RelativePath is the directory relative from the Start Menu * ; Programs directory. * RelativePath=Mozilla App * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so * ; on. There must not be a break in the sequence of the numbers. * Shortcut1=Mozilla App.lnk * Shortcut2=Mozilla App (Safe Mode).lnk * [DESKTOP] * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so * ; on. There must not be a break in the sequence of the numbers. * Shortcut1=Mozilla App.lnk * Shortcut2=Mozilla App (Safe Mode).lnk * [QUICKLAUNCH] * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so * ; on. There must not be a break in the sequence of the numbers for the * ; suffix. * Shortcut1=Mozilla App.lnk * Shortcut2=Mozilla App (Safe Mode).lnk * [STARTMENU] * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so * ; on. There must not be a break in the sequence of the numbers for the * ; suffix. * Shortcut1=Mozilla App.lnk * Shortcut2=Mozilla App (Safe Mode).lnk * * $R4 = return value from ShellLink::GetShortCutWorkingDirectory * $R5 = return value from ShellLink::GetShortCutTarget and * ApplicationID::UninstallPinnedItem * $R6 = find handle * $R7 = path to the $QUICKLAUNCH\User Pinned directory * $R8 = return filename from FindFirst / FindNext * $R9 = long path to the shortcut log ini file and path to the ProgramData * directory that the application stores additional shortcut logs in * (Typically c:\ProgramData\Mozilla-1de4eec8-1241-4177-a864-e594e8d1fb38) */ !macro DeleteShortcuts !ifndef ${_MOZFUNC_UN}DeleteShortcuts !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !insertmacro ${_MOZFUNC_UN_TMP}GetParent !insertmacro ${_MOZFUNC_UN_TMP}DeleteShortcutsFromLog !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}DeleteShortcuts "!insertmacro ${_MOZFUNC_UN}DeleteShortcutsCall" Function ${_MOZFUNC_UN}DeleteShortcuts Push $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 ; We call ApplicationID::UninstallPinnedItem once per shortcut here ; (and explicitly not in DeleteShortcutsFromLog). Calling it again later ; would remove the association of side by side installations. ${If} ${AtLeastWin7} ; Since shortcuts that are pinned can later be removed without removing ; the pinned shortcut unpin the pinned shortcuts for the application's ; main exe using the pinned shortcuts themselves. StrCpy $R7 "$QUICKLAUNCH\User Pinned" ${If} ${FileExists} "$R7\TaskBar" ; Delete TaskBar pinned shortcuts for the application's main exe FindFirst $R6 $R8 "$R7\TaskBar\*.lnk" ${Do} ${If} ${FileExists} "$R7\TaskBar\$R8" ShellLink::GetShortCutTarget "$R7\TaskBar\$R8" Pop $R5 ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ShellLink::GetShortCutWorkingDirectory "$SMPROGRAMS\$R8" Pop $R4 ${If} "$R5" == "$INSTDIR\${FileMainEXE}" ${OrIf} "$R4" == "$INSTDIR" ApplicationID::UninstallPinnedItem "$R7\TaskBar\$R8" Pop $R5 ${EndIf} ${EndIf} ClearErrors FindNext $R6 $R8 ${If} ${Errors} ${ExitDo} ${EndIf} ${Loop} FindClose $R6 ${EndIf} ${If} ${FileExists} "$R7\StartMenu" ; Delete Start Menu pinned shortcuts for the application's main exe FindFirst $R6 $R8 "$R7\StartMenu\*.lnk" ${Do} ${If} ${FileExists} "$R7\StartMenu\$R8" ShellLink::GetShortCutTarget "$R7\StartMenu\$R8" Pop $R5 ${${_MOZFUNC_UN}GetLongPath} "$R5" $R5 ShellLink::GetShortCutWorkingDirectory "$SMPROGRAMS\$R8" Pop $R4 ${If} "$R5" == "$INSTDIR\${FileMainEXE}" ${OrIf} "$R4" == "$INSTDIR" ApplicationID::UninstallPinnedItem "$R7\StartMenu\$R8" Pop $R5 ${EndIf} ${EndIf} ClearErrors FindNext $R6 $R8 ${If} ${Errors} ${ExitDo} ${EndIf} ${Loop} FindClose $R6 ${EndIf} ${EndIf} ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" $R9 ${${_MOZFUNC_UN}DeleteShortcutsFromLog} $R9 ${${_MOZFUNC_UN}GetCommonDirectory} $R9 ; Shortcut logs created by an application are in a different directory, ; and named after both the application and the user SID, eg: ; Firefox_S-1-5-21-1004336348-1177238915-682003330-512_shortcuts.ini FindFirst $R6 $R8 "$R9\*_shortcuts.ini" ${DoUntil} ${Errors} ${If} ${FileExists} "$R9\$R8" ${${_MOZFUNC_UN}DeleteShortcutsFromLog} "$R9\$R8" ${EndIf} ClearErrors FindNext $R6 $R8 ${Loop} ClearErrors Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Pop $R9 FunctionEnd !verbose pop !endif !macroend !macro DeleteShortcutsCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call DeleteShortcuts !verbose pop !macroend !macro un.DeleteShortcutsCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.DeleteShortcuts !verbose pop !macroend !macro un.DeleteShortcuts !ifndef un.DeleteShortcuts !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro DeleteShortcuts !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend ################################################################################ # Macros for parsing and updating the uninstall.log /** * Updates the uninstall.log with new files added by software update. * * When modifying this macro be aware that LineFind uses all registers except * $R0-$R3 and TextCompareNoDetails uses all registers except $R0-$R9 so be * cautious. Callers of this macro are not affected. */ !macro UpdateUninstallLog !ifndef UpdateUninstallLog !insertmacro FileJoin !insertmacro LineFind !insertmacro TextCompareNoDetails !insertmacro TrimNewLines !verbose push !verbose ${_MOZFUNC_VERBOSE} !define UpdateUninstallLog "!insertmacro UpdateUninstallLogCall" Function UpdateUninstallLog Push $R3 Push $R2 Push $R1 Push $R0 ClearErrors GetFullPathName $R3 "$INSTDIR\uninstall" ${If} ${FileExists} "$R3\uninstall.update" ${LineFind} "$R3\uninstall.update" "" "1:-1" "CleanupUpdateLog" GetTempFileName $R2 "$R3" FileOpen $R1 "$R2" w ${TextCompareNoDetails} "$R3\uninstall.update" "$R3\uninstall.log" "SlowDiff" "CreateUpdateDiff" FileClose $R1 IfErrors +2 0 ${FileJoin} "$R3\uninstall.log" "$R2" "$R3\uninstall.log" ${DeleteFile} "$R2" ${EndIf} ClearErrors Pop $R0 Pop $R1 Pop $R2 Pop $R3 FunctionEnd ; This callback MUST use labels vs. relative line numbers. Function CleanupUpdateLog StrCpy $R2 "$R9" 12 StrCmp "$R2" "EXECUTE ADD " +1 skip StrCpy $R9 "$R9" "" 12 Push $R6 Push $R5 Push $R4 StrCpy $R4 "" ; Initialize to an empty string. StrCpy $R6 -1 ; Set the counter to -1 so it will start at 0. loop: IntOp $R6 $R6 + 1 ; Increment the counter. StrCpy $R5 $R9 1 $R6 ; Starting from the counter copy the next char. StrCmp $R5 "" copy ; Are there no more chars? StrCmp $R5 "/" +1 +2 ; Is the char a /? StrCpy $R5 "\" ; Replace the char with a \. StrCpy $R4 "$R4$R5" GoTo loop copy: StrCpy $R9 "File: \$R4" Pop $R6 Pop $R5 Pop $R4 GoTo end skip: StrCpy $0 "SkipWrite" end: Push $0 FunctionEnd Function CreateUpdateDiff ${TrimNewLines} "$9" $9 ${If} $9 != "" FileWrite $R1 "$9$\r$\n" ${EndIf} Push 0 FunctionEnd !verbose pop !endif !macroend !macro UpdateUninstallLogCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call UpdateUninstallLog !verbose pop !macroend /** * Copies files from a source directory to a destination directory with logging * to the uninstall.log. If any destination files are in use a reboot will be * necessary to complete the installation and the reboot flag (see IfRebootFlag * in the NSIS documentation). * * @param _PATH_TO_SOURCE * Source path to copy the files from. This must not end with a \. * * @param _PATH_TO_DESTINATION * Destination path to copy the files to. This must not end with a \. * * @param _PREFIX_ERROR_CREATEDIR * Prefix for the directory creation error message. The directory path * will be inserted below this string. * * @param _SUFFIX_ERROR_CREATEDIR * Suffix for the directory creation error message. The directory path * will be inserted above this string. * * $0 = destination file's parent directory used in the create_dir label * $R0 = copied value from $R6 (e.g. _PATH_TO_SOURCE) * $R1 = copied value from $R7 (e.g. _PATH_TO_DESTINATION) * $R2 = string length of the path to source * $R3 = relative path from the path to source * $R4 = copied value from $R8 (e.g. _PREFIX_ERROR_CREATEDIR) * $R5 = copied value from $R9 (e.g. _SUFFIX_ERROR_CREATEDIR) * note: the LocateNoDetails macro uses these registers so we copy the values * to other registers. * $R6 = initially _PATH_TO_SOURCE and then set to "size" ($R6="" if directory, * $R6="0" if file with /S=)"path\name" in callback * $R7 = initially _PATH_TO_DESTINATION and then set to "name" in callback * $R8 = initially _PREFIX_ERROR_CREATEDIR and then set to "path" in callback * $R9 = initially _SUFFIX_ERROR_CREATEDIR and then set to "path\name" in * callback */ !macro CopyFilesFromDir !ifndef CopyFilesFromDir !insertmacro LocateNoDetails !insertmacro OnEndCommon !insertmacro WordReplace !verbose push !verbose ${_MOZFUNC_VERBOSE} !define CopyFilesFromDir "!insertmacro CopyFilesFromDirCall" Function CopyFilesFromDir Exch $R9 Exch 1 Exch $R8 Exch 2 Exch $R7 Exch 3 Exch $R6 Push $R5 Push $R4 Push $R3 Push $R2 Push $R1 Push $R0 Push $0 StrCpy $R0 "$R6" StrCpy $R1 "$R7" StrCpy $R4 "$R8" StrCpy $R5 "$R9" StrLen $R2 "$R0" ${LocateNoDetails} "$R0" "/L=FD" "CopyFileCallback" Pop $0 Pop $R0 Pop $R1 Pop $R2 Pop $R3 Pop $R4 Pop $R5 Exch $R6 Exch 3 Exch $R7 Exch 2 Exch $R8 Exch 1 Exch $R9 FunctionEnd Function CopyFileCallback StrCpy $R3 $R8 "" $R2 ; $R3 always begins with a \. retry: ClearErrors StrCmp $R6 "" +1 copy_file IfFileExists "$R1$R3\$R7" end +1 StrCpy $0 "$R1$R3\$R7" create_dir: ClearErrors CreateDirectory "$0" IfFileExists "$0" +1 err_create_dir ; protect against looping. ${LogMsg} "Created Directory: $0" StrCmp $R6 "" end copy_file err_create_dir: ${LogMsg} "** ERROR Creating Directory: $0 **" MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$R4$\r$\n$\r$\n$0$\r$\n$\r$\n$R5" IDRETRY retry ${OnEndCommon} Quit copy_file: StrCpy $0 "$R1$R3" StrCmp "$0" "$INSTDIR" +2 +1 IfFileExists "$0" +1 create_dir ClearErrors ${DeleteFile} "$R1$R3\$R7" IfErrors +1 dest_clear ClearErrors Rename "$R1$R3\$R7" "$R1$R3\$R7.moz-delete" IfErrors +1 reboot_delete ; file will replace destination file on reboot Rename "$R9" "$R9.moz-upgrade" CopyFiles /SILENT "$R9.moz-upgrade" "$R1$R3" Rename /REBOOTOK "$R1$R3\$R7.moz-upgrade" "$R1$R3\$R7" ${LogMsg} "Copied File: $R1$R3\$R7.moz-upgrade" ${LogMsg} "Delayed Install File (Reboot Required): $R1$R3\$R7" GoTo log_uninstall ; file will be deleted on reboot reboot_delete: CopyFiles /SILENT $R9 "$R1$R3" Delete /REBOOTOK "$R1$R3\$R7.moz-delete" ${LogMsg} "Installed File: $R1$R3\$R7" ${LogMsg} "Delayed Delete File (Reboot Required): $R1$R3\$R7.moz-delete" GoTo log_uninstall ; destination file doesn't exist - coast is clear dest_clear: CopyFiles /SILENT $R9 "$R1$R3" ${LogMsg} "Installed File: $R1$R3\$R7" log_uninstall: ; If the file is installed into the installation directory remove the ; installation directory's path from the file path when writing to the ; uninstall.log so it will be a relative path. This allows the same ; helper.exe to be used with zip builds if we supply an uninstall.log. ${WordReplace} "$R1$R3\$R7" "$INSTDIR" "" "+" $R3 ${LogUninstall} "File: $R3" end: Push 0 FunctionEnd !verbose pop !endif !macroend !macro CopyFilesFromDirCall _PATH_TO_SOURCE _PATH_TO_DESTINATION \ _PREFIX_ERROR_CREATEDIR _SUFFIX_ERROR_CREATEDIR !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_PATH_TO_SOURCE}" Push "${_PATH_TO_DESTINATION}" Push "${_PREFIX_ERROR_CREATEDIR}" Push "${_SUFFIX_ERROR_CREATEDIR}" Call CopyFilesFromDir !verbose pop !macroend /** * Parses the uninstall.log on install to first remove a previous installation's * files and then their directories if empty prior to installing. * * When modifying this macro be aware that LineFind uses all registers except * $R0-$R3 so be cautious. Callers of this macro are not affected. */ !macro OnInstallUninstall !ifndef OnInstallUninstall !insertmacro GetParent !insertmacro LineFind !insertmacro TrimNewLines !verbose push !verbose ${_MOZFUNC_VERBOSE} !define OnInstallUninstall "!insertmacro OnInstallUninstallCall" Function OnInstallUninstall Push $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 Push $R3 Push $R2 Push $R1 Push $R0 Push $TmpVal IfFileExists "$INSTDIR\uninstall\uninstall.log" +1 end ${LogHeader} "Removing Previous Installation" ; Copy the uninstall log file to a temporary file GetTempFileName $TmpVal CopyFiles /SILENT /FILESONLY "$INSTDIR\uninstall\uninstall.log" "$TmpVal" ; Delete files ${LineFind} "$TmpVal" "/NUL" "1:-1" "RemoveFilesCallback" ; Remove empty directories ${LineFind} "$TmpVal" "/NUL" "1:-1" "RemoveDirsCallback" ; Delete the temporary uninstall log file Delete /REBOOTOK "$TmpVal" ; Delete the uninstall log file Delete "$INSTDIR\uninstall\uninstall.log" end: ClearErrors Pop $TmpVal Pop $R0 Pop $R1 Pop $R2 Pop $R3 Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Pop $R9 FunctionEnd Function RemoveFilesCallback ${TrimNewLines} "$R9" $R9 StrCpy $R1 "$R9" 5 ; Copy the first five chars StrCmp "$R1" "File:" +1 end StrCpy $R9 "$R9" "" 6 ; Copy string starting after the 6th char StrCpy $R0 "$R9" 1 ; Copy the first char StrCmp "$R0" "\" +1 end ; If this isn't a relative path goto end StrCmp "$R9" "\install.log" end +1 ; Skip the install.log StrCmp "$R9" "\MapiProxy_InUse.dll" end +1 ; Skip the MapiProxy_InUse.dll StrCmp "$R9" "\mozMapi32_InUse.dll" end +1 ; Skip the mozMapi32_InUse.dll StrCpy $R1 "$INSTDIR$R9" ; Copy the install dir path and suffix it with the string IfFileExists "$R1" +1 end ClearErrors Delete "$R1" ${Unless} ${Errors} ${LogMsg} "Deleted File: $R1" Goto end ${EndUnless} ClearErrors Rename "$R1" "$R1.moz-delete" ${Unless} ${Errors} Delete /REBOOTOK "$R1.moz-delete" ${LogMsg} "Delayed Delete File (Reboot Required): $R1.moz-delete" GoTo end ${EndUnless} ; Check if the file exists in the source. If it does the new file will ; replace the existing file when the system is rebooted. If it doesn't ; the file will be deleted when the system is rebooted. ${Unless} ${FileExists} "$EXEDIR\core$R9" ${AndUnless} ${FileExists} "$EXEDIR\optional$R9" Delete /REBOOTOK "$R1" ${LogMsg} "Delayed Delete File (Reboot Required): $R1" ${EndUnless} end: ClearErrors Push 0 FunctionEnd ; Using locate will leave file handles open to some of the directories ; which will prevent the deletion of these directories. This parses the ; uninstall.log and uses the file entries to find / remove empty ; directories. Function RemoveDirsCallback ${TrimNewLines} "$R9" $R9 StrCpy $R0 "$R9" 5 ; Copy the first five chars StrCmp "$R0" "File:" +1 end StrCpy $R9 "$R9" "" 6 ; Copy string starting after the 6th char StrCpy $R0 "$R9" 1 ; Copy the first char StrCpy $R1 "$INSTDIR$R9" ; Copy the install dir path and suffix it with the string StrCmp "$R0" "\" loop end ; If this isn't a relative path goto end loop: ${GetParent} "$R1" $R1 ; Get the parent directory for the path StrCmp "$R1" "$INSTDIR" end +1 ; If the directory is the install dir goto end IfFileExists "$R1" +1 loop ; Only try to remove the dir if it exists ClearErrors RmDir "$R1" ; Remove the dir IfErrors end +1 ; If we fail there is no use trying to remove its parent dir ${LogMsg} "Deleted Directory: $R1" GoTo loop end: ClearErrors Push 0 FunctionEnd !verbose pop !endif !macroend !macro OnInstallUninstallCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call OnInstallUninstall !verbose pop !macroend /** * Parses the precomplete file to remove an installation's files and * directories. * * @param _CALLBACK * The function address of a callback function for progress or "false" * if there is no callback function. * * $R3 = false if all files were deleted or moved to the tobedeleted directory. * true if file(s) could not be moved to the tobedeleted directory. * $R4 = Path to temporary precomplete file. * $R5 = File handle for the temporary precomplete file. * $R6 = String returned from FileRead. * $R7 = First seven characters of the string returned from FileRead. * $R8 = Temporary file path used to rename files that are in use. * $R9 = _CALLBACK */ !macro RemovePrecompleteEntries !ifndef ${_MOZFUNC_UN}RemovePrecompleteEntries !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetParent !insertmacro ${_MOZFUNC_UN_TMP}TrimNewLines !insertmacro ${_MOZFUNC_UN_TMP}WordReplace !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}RemovePrecompleteEntries "!insertmacro ${_MOZFUNC_UN}RemovePrecompleteEntriesCall" Function ${_MOZFUNC_UN}RemovePrecompleteEntries Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 Push $R3 ${If} ${FileExists} "$INSTDIR\precomplete" StrCpy $R3 "false" RmDir /r "$INSTDIR\${TO_BE_DELETED}" CreateDirectory "$INSTDIR\${TO_BE_DELETED}" GetTempFileName $R4 "$INSTDIR\${TO_BE_DELETED}" Delete "$R4" Rename "$INSTDIR\precomplete" "$R4" ClearErrors ; Rename and then remove files FileOpen $R5 "$R4" r ${Do} FileRead $R5 $R6 ${If} ${Errors} ${Break} ${EndIf} ${${_MOZFUNC_UN}TrimNewLines} "$R6" $R6 ; Replace all occurrences of "/" with "\". ${${_MOZFUNC_UN}WordReplace} "$R6" "/" "\" "+" $R6 ; Copy the first 7 chars StrCpy $R7 "$R6" 7 ${If} "$R7" == "remove " ; Copy the string starting after the 8th char StrCpy $R6 "$R6" "" 8 ; Copy all but the last char to remove the double quote. StrCpy $R6 "$R6" -1 ${If} ${FileExists} "$INSTDIR\$R6" ${Unless} "$R9" == "false" Call $R9 ${EndUnless} ClearErrors Delete "$INSTDIR\$R6" ${If} ${Errors} GetTempFileName $R8 "$INSTDIR\${TO_BE_DELETED}" Delete "$R8" ClearErrors Rename "$INSTDIR\$R6" "$R8" ${Unless} ${Errors} Delete /REBOOTOK "$R8" ClearErrors ${EndUnless} !ifdef __UNINSTALL__ ${If} ${Errors} Delete /REBOOTOK "$INSTDIR\$R6" StrCpy $R3 "true" ClearErrors ${EndIf} !endif ${EndIf} ${EndIf} ${ElseIf} "$R7" == "rmdir $\"" ; Copy the string starting after the 7th char. StrCpy $R6 "$R6" "" 7 ; Copy all but the last two chars to remove the slash and the double quote. StrCpy $R6 "$R6" -2 ${If} ${FileExists} "$INSTDIR\$R6" ; Ignore directory removal errors RmDir "$INSTDIR\$R6" ClearErrors ${EndIf} ${EndIf} ${Loop} FileClose $R5 ; Delete the temporary precomplete file Delete /REBOOTOK "$R4" RmDir /r /REBOOTOK "$INSTDIR\${TO_BE_DELETED}" ${If} ${RebootFlag} ${AndIf} "$R3" == "false" ; Clear the reboot flag if all files were deleted or moved to the ; tobedeleted directory. SetRebootFlag false ${EndIf} ${EndIf} ClearErrors Pop $R3 Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro RemovePrecompleteEntriesCall _CALLBACK !verbose push Push "${_CALLBACK}" !verbose ${_MOZFUNC_VERBOSE} Call RemovePrecompleteEntries !verbose pop !macroend !macro un.RemovePrecompleteEntriesCall _CALLBACK !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_CALLBACK}" Call un.RemovePrecompleteEntries !verbose pop !macroend !macro un.RemovePrecompleteEntries !ifndef un.RemovePrecompleteEntries !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro RemovePrecompleteEntries !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Parses the uninstall.log to unregister dll's, remove files, and remove * empty directories for this installation. * * When modifying this macro be aware that LineFind uses all registers except * $R0-$R3 so be cautious. Callers of this macro are not affected. */ !macro un.ParseUninstallLog !ifndef un.ParseUninstallLog !insertmacro un.GetParent !insertmacro un.LineFind !insertmacro un.TrimNewLines !verbose push !verbose ${_MOZFUNC_VERBOSE} !define un.ParseUninstallLog "!insertmacro un.ParseUninstallLogCall" Function un.ParseUninstallLog Push $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 Push $R3 Push $R2 Push $R1 Push $R0 Push $TmpVal IfFileExists "$INSTDIR\uninstall\uninstall.log" +1 end ; Copy the uninstall log file to a temporary file GetTempFileName $TmpVal CopyFiles /SILENT /FILESONLY "$INSTDIR\uninstall\uninstall.log" "$TmpVal" ; Unregister DLL's ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.UnRegDLLsCallback" ; Delete files ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.RemoveFilesCallback" ; Remove empty directories ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.RemoveDirsCallback" ; Delete the temporary uninstall log file Delete /REBOOTOK "$TmpVal" end: Pop $TmpVal Pop $R0 Pop $R1 Pop $R2 Pop $R3 Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Pop $R9 FunctionEnd Function un.RemoveFilesCallback ${un.TrimNewLines} "$R9" $R9 StrCpy $R1 "$R9" 5 StrCmp "$R1" "File:" +1 end StrCpy $R9 "$R9" "" 6 StrCpy $R0 "$R9" 1 StrCpy $R1 "$INSTDIR$R9" StrCmp "$R0" "\" +2 +1 StrCpy $R1 "$R9" IfFileExists "$R1" +1 end Delete "$R1" IfErrors +1 end ClearErrors Rename "$R1" "$R1.moz-delete" IfErrors +1 +3 Delete /REBOOTOK "$R1" GoTo end Delete /REBOOTOK "$R1.moz-delete" end: ClearErrors Push 0 FunctionEnd Function un.UnRegDLLsCallback ${un.TrimNewLines} "$R9" $R9 StrCpy $R1 "$R9" 7 StrCmp $R1 "DLLReg:" +1 end StrCpy $R9 "$R9" "" 8 StrCpy $R0 "$R9" 1 StrCpy $R1 "$INSTDIR$R9" StrCmp $R0 "\" +2 +1 StrCpy $R1 "$R9" ${UnregisterDLL} $R1 end: ClearErrors Push 0 FunctionEnd ; Using locate will leave file handles open to some of the directories ; which will prevent the deletion of these directories. This parses the ; uninstall.log and uses the file entries to find / remove empty ; directories. Function un.RemoveDirsCallback ${un.TrimNewLines} "$R9" $R9 StrCpy $R0 "$R9" 5 ; Copy the first five chars StrCmp "$R0" "File:" +1 end StrCpy $R9 "$R9" "" 6 ; Copy string starting after the 6th char StrCpy $R0 "$R9" 1 ; Copy the first char StrCpy $R1 "$INSTDIR$R9" ; Copy the install dir path and suffix it with the string StrCmp "$R0" "\" loop ; If this is a relative path goto the loop StrCpy $R1 "$R9" ; Already a full path so copy the string loop: ${un.GetParent} "$R1" $R1 ; Get the parent directory for the path StrCmp "$R1" "$INSTDIR" end ; If the directory is the install dir goto end ; We only try to remove empty directories but the Desktop, StartMenu, and ; QuickLaunch directories can be empty so guard against removing them. SetShellVarContext all ; Set context to all users StrCmp "$R1" "$DESKTOP" end ; All users desktop StrCmp "$R1" "$STARTMENU" end ; All users start menu SetShellVarContext current ; Set context to all users StrCmp "$R1" "$DESKTOP" end ; Current user desktop StrCmp "$R1" "$STARTMENU" end ; Current user start menu StrCmp "$R1" "$QUICKLAUNCH" end ; Current user quick launch IfFileExists "$R1" +1 +3 ; Only try to remove the dir if it exists ClearErrors RmDir "$R1" ; Remove the dir IfErrors end ; If we fail there is no use trying to remove its parent dir StrCmp "$R0" "\" loop end ; Only loop when the path is relative to the install dir end: ClearErrors Push 0 FunctionEnd !verbose pop !endif !macroend !macro un.ParseUninstallLogCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.ParseUninstallLog !verbose pop !macroend /** * Finds a valid Start Menu shortcut in the uninstall log and returns the * relative path from the Start Menu's Programs directory to the shortcut's * directory. * * When modifying this macro be aware that LineFind uses all registers except * $R0-$R3 so be cautious. Callers of this macro are not affected. * * @return _REL_PATH_TO_DIR * The relative path to the application's Start Menu directory from the * Start Menu's Programs directory. */ !macro FindSMProgramsDir !ifndef FindSMProgramsDir !insertmacro GetParent !insertmacro LineFind !insertmacro TrimNewLines !verbose push !verbose ${_MOZFUNC_VERBOSE} !define FindSMProgramsDir "!insertmacro FindSMProgramsDirCall" Function FindSMProgramsDir Exch $R3 Push $R2 Push $R1 Push $R0 StrCpy $R3 "" ${If} ${FileExists} "$INSTDIR\uninstall\uninstall.log" ${LineFind} "$INSTDIR\uninstall\uninstall.log" "/NUL" "1:-1" "FindSMProgramsDirRelPath" ${EndIf} ClearErrors Pop $R0 Pop $R1 Pop $R2 Exch $R3 FunctionEnd ; This callback MUST use labels vs. relative line numbers. Function FindSMProgramsDirRelPath Push 0 ${TrimNewLines} "$R9" $R9 StrCpy $R4 "$R9" 5 StrCmp "$R4" "File:" +1 end_FindSMProgramsDirRelPath StrCpy $R9 "$R9" "" 6 StrCpy $R4 "$R9" 1 StrCmp "$R4" "\" end_FindSMProgramsDirRelPath +1 SetShellVarContext all ${GetLongPath} "$SMPROGRAMS" $R4 StrLen $R2 "$R4" StrCpy $R1 "$R9" $R2 StrCmp "$R1" "$R4" +1 end_FindSMProgramsDirRelPath IfFileExists "$R9" +1 end_FindSMProgramsDirRelPath ShellLink::GetShortCutTarget "$R9" Pop $R0 StrCmp "$INSTDIR\${FileMainEXE}" "$R0" +1 end_FindSMProgramsDirRelPath ${GetParent} "$R9" $R3 IntOp $R2 $R2 + 1 StrCpy $R3 "$R3" "" $R2 Pop $R4 ; Remove the previously pushed 0 from the stack and push "StopLineFind" ; push StopLineFind to stop finding more lines. end_FindSMProgramsDirRelPath: ClearErrors FunctionEnd !verbose pop !endif !macroend !macro FindSMProgramsDirCall _REL_PATH_TO_DIR !verbose push !verbose ${_MOZFUNC_VERBOSE} Call FindSMProgramsDir Pop ${_REL_PATH_TO_DIR} !verbose pop !macroend ################################################################################ # Macros for custom branding /** * Sets BrandFullName and / or BrandShortName to values provided in the specified * ini file and defaults to BrandShortName and BrandFullName as defined in * branding.nsi when the associated ini file entry is not specified. * * ini file format: * [Branding] * BrandFullName=Custom Full Name * BrandShortName=Custom Short Name * * @param _PATH_TO_INI * Path to the ini file. * * $R6 = return value from ReadINIStr * $R7 = stores BrandShortName * $R8 = stores BrandFullName * $R9 = _PATH_TO_INI */ !macro SetBrandNameVars !ifndef ${_MOZFUNC_UN}SetBrandNameVars !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}WordReplace !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP ; Prevent declaring vars twice when the SetBrandNameVars macro is ; inserted into both the installer and uninstaller. !ifndef SetBrandNameVars Var BrandFullName Var BrandFullNameDA Var BrandShortName Var BrandProductName !endif !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}SetBrandNameVars "!insertmacro ${_MOZFUNC_UN}SetBrandNameVarsCall" Function ${_MOZFUNC_UN}SetBrandNameVars Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 StrCpy $R8 "${BrandFullName}" StrCpy $R7 "${BrandShortName}" StrCpy $R6 "${BrandProductName}" IfFileExists "$R9" +1 finish ClearErrors ReadINIStr $R5 $R9 "Branding" "BrandFullName" IfErrors +2 +1 StrCpy $R8 "$R5" ClearErrors ReadINIStr $R5 $R9 "Branding" "BrandShortName" IfErrors +2 +1 StrCpy $R7 "$R5" ClearErrors ReadINIStr $R5 $R9 "Branding" "BrandProductName" IfErrors +2 +1 StrCpy $R6 "$R5" finish: StrCpy $BrandFullName "$R8" ${${_MOZFUNC_UN}WordReplace} "$R8" "&" "&&" "+" $R8 StrCpy $BrandFullNameDA "$R8" StrCpy $BrandShortName "$R7" StrCpy $BrandProductName "$R6" Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro SetBrandNameVarsCall _PATH_TO_INI !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_PATH_TO_INI}" Call SetBrandNameVars !verbose pop !macroend !macro un.SetBrandNameVarsCall _PATH_TO_INI !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_PATH_TO_INI}" Call un.SetBrandNameVars !verbose pop !macroend !macro un.SetBrandNameVars !ifndef un.SetBrandNameVars !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro SetBrandNameVars !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Replaces the wizard's header image with the one specified. * * @param _PATH_TO_IMAGE * Fully qualified path to the bitmap to use for the header image. * * $R8 = hwnd for the control returned from GetDlgItem. * $R9 = _PATH_TO_IMAGE */ !macro ChangeMUIHeaderImage !ifndef ${_MOZFUNC_UN}ChangeMUIHeaderImage Var hHeaderBitmap !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}ChangeMUIHeaderImage "!insertmacro ${_MOZFUNC_UN}ChangeMUIHeaderImageCall" Function ${_MOZFUNC_UN}ChangeMUIHeaderImage Exch $R9 Push $R8 GetDlgItem $R8 $HWNDPARENT 1046 ${SetStretchedImageOLE} $R8 "$R9" $hHeaderBitmap ; There is no way to specify a show function for a custom page so hide ; and then show the control to force the bitmap to redraw. ShowWindow $R8 ${SW_HIDE} ShowWindow $R8 ${SW_SHOW} Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro ChangeMUIHeaderImageCall _PATH_TO_IMAGE !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_PATH_TO_IMAGE}" Call ChangeMUIHeaderImage !verbose pop !macroend !macro un.ChangeMUIHeaderImageCall _PATH_TO_IMAGE !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_PATH_TO_IMAGE}" Call un.ChangeMUIHeaderImage !verbose pop !macroend !macro un.ChangeMUIHeaderImage !ifndef un.ChangeMUIHeaderImage !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro ChangeMUIHeaderImage !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Replaces the sidebar image on the wizard's welcome and finish pages. * * @param _PATH_TO_IMAGE * Fully qualified path to the bitmap to use for the header image. * * $R8 = hwnd for the bitmap control * $R9 = _PATH_TO_IMAGE */ !macro ChangeMUISidebarImage !ifndef ${_MOZFUNC_UN}ChangeMUISidebarImage Var hSidebarBitmap !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}ChangeMUISidebarImage "!insertmacro ${_MOZFUNC_UN}ChangeMUISidebarImageCall" Function ${_MOZFUNC_UN}ChangeMUISidebarImage Exch $R9 Push $R8 ; Make sure we're not about to leak an existing handle. ${If} $hSidebarBitmap <> 0 System::Call "gdi32::DeleteObject(p $hSidebarBitmap)" StrCpy $hSidebarBitmap 0 ${EndIf} ; The controls on the welcome and finish pages aren't in the dialog ; template, they're always created manually from the INI file, so we need ; to query it to find the right HWND. ReadINIStr $R8 "$PLUGINSDIR\ioSpecial.ini" "Field 1" "HWND" ${SetStretchedImageOLE} $R8 "$R9" $hSidebarBitmap Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro ChangeMUISidebarImageCall _PATH_TO_IMAGE !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_PATH_TO_IMAGE}" Call ChangeMUISidebarImage !verbose pop !macroend !macro un.ChangeMUISidebarImageCall _PATH_TO_IMAGE !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_PATH_TO_IMAGE}" Call un.ChangeMUISidebarImage !verbose pop !macroend !macro un.ChangeMUISidebarImage !ifndef un.ChangeMUISidebarImage !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro ChangeMUISidebarImage !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend ################################################################################ # User interface callback helper defines and macros /* Install type defines */ !ifndef INSTALLTYPE_BASIC !define INSTALLTYPE_BASIC 1 !endif !ifndef INSTALLTYPE_CUSTOM !define INSTALLTYPE_CUSTOM 2 !endif /** * Checks whether to display the current page (e.g. if not performing a custom * install don't display the custom pages). */ !macro CheckCustomCommon !ifndef CheckCustomCommon !verbose push !verbose ${_MOZFUNC_VERBOSE} !define CheckCustomCommon "!insertmacro CheckCustomCommonCall" Function CheckCustomCommon ; Abort if not a custom install IntCmp $InstallType ${INSTALLTYPE_CUSTOM} +2 +1 +1 Abort FunctionEnd !verbose pop !endif !macroend !macro CheckCustomCommonCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call CheckCustomCommon !verbose pop !macroend /** * Unloads dll's and releases references when the installer and uninstaller * exit. */ !macro OnEndCommon !ifndef ${_MOZFUNC_UN}OnEndCommon !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}UnloadUAC !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}OnEndCommon "!insertmacro ${_MOZFUNC_UN}OnEndCommonCall" Function ${_MOZFUNC_UN}OnEndCommon ${${_MOZFUNC_UN}UnloadUAC} StrCmp $hHeaderBitmap "" +3 +1 System::Call "gdi32::DeleteObject(i s)" $hHeaderBitmap StrCpy $hHeaderBitmap "" ; If ChangeMUISidebarImage was called, then we also need to clean up the ; GDI bitmap handle that it would have created. !ifdef ${_MOZFUNC_UN}ChangeMUISidebarImage StrCmp $hSidebarBitmap "" +3 +1 System::Call "gdi32::DeleteObject(i s)" $hSidebarBitmap StrCpy $hSidebarBitmap "" !endif System::Free 0 FunctionEnd !verbose pop !endif !macroend !macro OnEndCommonCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call OnEndCommon !verbose pop !macroend !macro un.OnEndCommonCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.OnEndCommon !verbose pop !macroend !macro un.OnEndCommon !ifndef un.OnEndCommon !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro OnEndCommon !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Reads a flag option from the command line and sets a variable with its state, * if the option is present on the command line. * * @param FULL_COMMAND_LINE * The entire installer command line, such as from ${GetParameters} * @param OPTION * Name of the option to look for * @param OUTPUT * Variable/register to write the output to. Will be set to "0" if the * option was present with the value "false", will be set to "1" if the * option was present with another value, and will be untouched if the * option was not on the command line at all. */ !macro InstallGetOption FULL_COMMAND_LINE OPTION OUTPUT Push $0 ClearErrors ${GetOptions} ${FULL_COMMAND_LINE} "/${OPTION}" $0 ${IfNot} ${Errors} ; Any valid command-line option triggers a silent installation. SetSilent silent ${If} $0 == "=false" StrCpy ${OUTPUT} "0" ${Else} StrCpy ${OUTPUT} "1" ${EndIf} ${EndIf} Pop $0 !macroend !define InstallGetOption "!insertmacro InstallGetOption" /** * Called from the installer's .onInit function not to be confused with the * uninstaller's .onInit or the uninstaller's un.onInit functions. * * @param _WARN_UNSUPPORTED_MSG * Message displayed when the Windows version is not supported. * * $R4 = keeps track of whether a custom install path was specified on either * the command line or in an INI file * $R5 = return value from the GetSize macro * $R6 = general string values, return value from GetTempFileName, return * value from the GetSize macro * $R7 = full path to the configuration ini file * $R8 = used for OS Version and Service Pack detection and the return value * from the GetParameters macro * $R9 = _WARN_UNSUPPORTED_MSG */ !macro InstallOnInitCommon !ifndef InstallOnInitCommon !insertmacro ElevateUAC !insertmacro GetOptions !insertmacro GetParameters !insertmacro GetSize !verbose push !verbose ${_MOZFUNC_VERBOSE} !define InstallOnInitCommon "!insertmacro InstallOnInitCommonCall" Function InstallOnInitCommon Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 ; Don't install on systems that don't support SSE2. The parameter value of ; 10 is for PF_XMMI64_INSTRUCTIONS_AVAILABLE which will check whether the ; SSE2 instruction set is available. System::Call "kernel32::IsProcessorFeaturePresent(i 10)i .R8" ${If} "$R8" == "0" MessageBox MB_OK|MB_ICONSTOP "$R9" ; Nothing initialized so no need to call OnEndCommon Quit ${EndIf} ; Windows NT 6.0 (Vista/Server 2008) and lower are not supported. ${Unless} ${AtLeastWin7} MessageBox MB_OK|MB_ICONSTOP "$R9" ; Nothing initialized so no need to call OnEndCommon Quit ${EndUnless} !ifdef HAVE_64BIT_BUILD SetRegView 64 !endif StrCpy $R4 0 ; will be set to 1 if a custom install path is set ${GetParameters} $R8 ${If} $R8 != "" ; Default install type StrCpy $InstallType ${INSTALLTYPE_BASIC} ${Unless} ${Silent} ; NSIS should check for /S for us, but we've had issues with it such ; as bug 506867 in the past, so we'll check for it ourselves also. ClearErrors ${GetOptions} "$R8" "/S" $R7 ${Unless} ${Errors} SetSilent silent ${Else} ; NSIS dropped support for the deprecated -ms argument, but we don't ; want to break backcompat, so we'll check for it here too. ClearErrors ${GetOptions} "$R8" "-ms" $R7 ${Unless} ${Errors} SetSilent silent ${EndUnless} ${EndUnless} ${EndUnless} ; Support for specifying an installation configuration file. ClearErrors ${GetOptions} "$R8" "/INI=" $R7 ${Unless} ${Errors} ; The configuration file must also exist ${If} ${FileExists} "$R7" ; Any valid command-line option triggers a silent installation. SetSilent silent ReadINIStr $R8 $R7 "Install" "InstallDirectoryName" ${If} $R8 != "" StrCpy $R4 1 !ifdef HAVE_64BIT_BUILD StrCpy $INSTDIR "$PROGRAMFILES64\$R8" !else StrCpy $INSTDIR "$PROGRAMFILES32\$R8" !endif ${Else} ReadINIStr $R8 $R7 "Install" "InstallDirectoryPath" ${If} $R8 != "" StrCpy $R4 1 StrCpy $INSTDIR "$R8" ${EndIf} ${EndIf} ReadINIStr $R8 $R7 "Install" "QuickLaunchShortcut" ${If} $R8 == "false" StrCpy $AddQuickLaunchSC "0" ${Else} StrCpy $AddQuickLaunchSC "1" ${EndIf} ReadINIStr $R8 $R7 "Install" "DesktopShortcut" ${If} $R8 == "false" StrCpy $AddDesktopSC "0" ${Else} StrCpy $AddDesktopSC "1" ${EndIf} ReadINIStr $R8 $R7 "Install" "StartMenuShortcuts" ${If} $R8 == "false" StrCpy $AddStartMenuSC "0" ${Else} StrCpy $AddStartMenuSC "1" ${EndIf} ; We still accept the plural version for backwards compatibility, ; but the singular version takes priority. ClearErrors ReadINIStr $R8 $R7 "Install" "StartMenuShortcut" ${If} $R8 == "false" StrCpy $AddStartMenuSC "0" ${ElseIfNot} ${Errors} StrCpy $AddStartMenuSC "1" ${EndIf} !ifdef MOZ_PRIVATE_BROWSING ReadINIStr $R8 $R7 "Install" "PrivateBrowsingShortcut" ${If} $R8 == "false" StrCpy $AddPrivateBrowsingSC "0" ${ElseIfNot} ${Errors} StrCpy $AddPrivateBrowsingSC "1" ${EndIf} !endif ReadINIStr $R8 $R7 "Install" "TaskbarShortcut" ${If} $R8 == "false" StrCpy $AddTaskbarSC "0" ${Else} StrCpy $AddTaskbarSC "1" ${EndIf} ReadINIStr $R8 $R7 "Install" "MaintenanceService" ${If} $R8 == "false" StrCpy $InstallMaintenanceService "0" ${Else} StrCpy $InstallMaintenanceService "1" ${EndIf} ReadINIStr $R8 $R7 "Install" "RegisterDefaultAgent" ${If} $R8 == "false" StrCpy $RegisterDefaultAgent "0" ${Else} StrCpy $RegisterDefaultAgent "1" ${EndIf} !ifdef MOZ_OPTIONAL_EXTENSIONS ReadINIStr $R8 $R7 "Install" "OptionalExtensions" ${If} $R8 == "false" StrCpy $InstallOptionalExtensions "0" ${Else} StrCpy $InstallOptionalExtensions "1" ${EndIf} !endif !ifndef NO_STARTMENU_DIR ReadINIStr $R8 $R7 "Install" "StartMenuDirectoryName" ${If} $R8 != "" StrCpy $StartMenuDir "$R8" ${EndIf} !endif ${EndIf} ${EndUnless} ; Check for individual command line parameters after evaluating the INI ; file, because these should override the INI entires. ${GetParameters} $R8 ${GetOptions} $R8 "/InstallDirectoryName=" $R7 ${If} $R7 != "" StrCpy $R4 1 !ifdef HAVE_64BIT_BUILD StrCpy $INSTDIR "$PROGRAMFILES64\$R7" !else StrCpy $INSTDIR "$PROGRAMFILES32\$R7" !endif ${Else} ${GetOptions} $R8 "/InstallDirectoryPath=" $R7 ${If} $R7 != "" StrCpy $R4 1 StrCpy $INSTDIR "$R7" ${EndIf} ${EndIf} ${InstallGetOption} $R8 "QuickLaunchShortcut" $AddQuickLaunchSC ${InstallGetOption} $R8 "DesktopShortcut" $AddDesktopSC ${InstallGetOption} $R8 "StartMenuShortcuts" $AddStartMenuSC ; We still accept the plural version for backwards compatibility, ; but the singular version takes priority. ${InstallGetOption} $R8 "StartMenuShortcut" $AddStartMenuSC !ifdef MOZ_PRIVATE_BROWSING ${InstallGetOption} $R8 "PrivateBrowsingShortcut" $AddPrivateBrowsingSC !endif ${InstallGetOption} $R8 "TaskbarShortcut" $AddTaskbarSC ${InstallGetOption} $R8 "MaintenanceService" $InstallMaintenanceService ${InstallGetOption} $R8 "RegisterDefaultAgent" $RegisterDefaultAgent !ifdef MOZ_OPTIONAL_EXTENSIONS ${InstallGetOption} $R8 "OptionalExtensions" $InstallOptionalExtensions !endif ; Installing the service always requires elevated privileges. ${If} $InstallMaintenanceService == "1" ${ElevateUAC} ${EndIf} ${EndIf} ${If} $R4 == 1 ; Any valid command-line option triggers a silent installation. SetSilent silent ; Quit if we are unable to create the installation directory or we are ; unable to write to a file in the installation directory. ClearErrors ${If} ${FileExists} "$INSTDIR" GetTempFileName $R6 "$INSTDIR" FileOpen $R5 "$R6" w FileWrite $R5 "Write Access Test" FileClose $R5 Delete $R6 ${If} ${Errors} ; Attempt to elevate and then try again. ${ElevateUAC} GetTempFileName $R6 "$INSTDIR" FileOpen $R5 "$R6" w FileWrite $R5 "Write Access Test" FileClose $R5 Delete $R6 ${If} ${Errors} ; Nothing initialized so no need to call OnEndCommon Quit ${EndIf} ${EndIf} ${Else} CreateDirectory "$INSTDIR" ${If} ${Errors} ; Attempt to elevate and then try again. ${ElevateUAC} CreateDirectory "$INSTDIR" ${If} ${Errors} ; Nothing initialized so no need to call OnEndCommon Quit ${EndIf} ${EndIf} ${EndIf} ${Else} ; If we weren't given a custom path parameter, then try to elevate now. ; We'll check the user's permission level later on to determine the ; default install path (which will be the real install path for /S). ; If an INI file is used, we try to elevate down that path when needed. ${ElevateUAC} ${EndIf} Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro InstallOnInitCommonCall _WARN_UNSUPPORTED_MSG !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_WARN_UNSUPPORTED_MSG}" Call InstallOnInitCommon !verbose pop !macroend /** * Called from the uninstaller's .onInit function not to be confused with the * installer's .onInit or the uninstaller's un.onInit functions. */ !macro UninstallOnInitCommon !ifndef UninstallOnInitCommon !insertmacro ElevateUAC !insertmacro GetLongPath !insertmacro GetOptions !insertmacro GetParameters !insertmacro GetParent !insertmacro UnloadUAC !insertmacro UpdateShortcutAppModelIDs !insertmacro UpdateUninstallLog !verbose push !verbose ${_MOZFUNC_VERBOSE} !define UninstallOnInitCommon "!insertmacro UninstallOnInitCommonCall" Function UninstallOnInitCommon ; Prevents breaking apps that don't use SetBrandNameVars !ifdef SetBrandNameVars ${SetBrandNameVars} "$EXEDIR\distribution\setup.ini" !endif ; Prevent launching the application when a reboot is required and this ; executable is the main application executable IfFileExists "$EXEDIR\${FileMainEXE}.moz-upgrade" +1 +4 MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UPGRADE)" IDNO +2 Reboot Quit ; Nothing initialized so no need to call OnEndCommon ${GetParent} "$EXEDIR" $INSTDIR ${GetLongPath} "$INSTDIR" $INSTDIR IfFileExists "$INSTDIR\${FileMainEXE}" +2 +1 Quit ; Nothing initialized so no need to call OnEndCommon !ifmacrodef InitHashAppModelId ; setup the application model id registration value !ifdef AppName ${InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs" !endif !endif ; Prevents breaking apps that don't use SetBrandNameVars !ifdef SetBrandNameVars ${SetBrandNameVars} "$INSTDIR\distribution\setup.ini" !endif ; Application update uses a directory named tobedeleted in the $INSTDIR to ; delete files on OS reboot when they are in use. Try to delete this ; directory if it exists. ${If} ${FileExists} "$INSTDIR\${TO_BE_DELETED}" RmDir /r "$INSTDIR\${TO_BE_DELETED}" ${EndIf} ; Prevent all operations (e.g. set as default, postupdate, etc.) when a ; reboot is required and the executable launched is helper.exe IfFileExists "$INSTDIR\${FileMainEXE}.moz-upgrade" +1 +4 MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UPGRADE)" IDNO +2 Reboot Quit ; Nothing initialized so no need to call OnEndCommon !ifdef HAVE_64BIT_BUILD SetRegView 64 !endif ${GetParameters} $R0 ${Unless} ${Silent} ; Manually check for /S in the command line due to Bug 506867 ClearErrors ${GetOptions} "$R0" "/S" $R2 ${Unless} ${Errors} SetSilent silent ${Else} ; Support for the deprecated -ms command line argument. ClearErrors ${GetOptions} "$R0" "-ms" $R2 ${Unless} ${Errors} SetSilent silent ${EndUnless} ${EndUnless} ${EndUnless} StrCmp "$R0" "" continue +1 ; Require elevation if the user can elevate hideshortcuts: ClearErrors ${GetOptions} "$R0" "/HideShortcuts" $R2 IfErrors showshortcuts +1 !ifndef NONADMIN_ELEVATE ${ElevateUAC} !endif ${HideShortcuts} GoTo finish ; Require elevation if the user can elevate showshortcuts: ClearErrors ${GetOptions} "$R0" "/ShowShortcuts" $R2 IfErrors defaultappuser +1 !ifndef NONADMIN_ELEVATE ${ElevateUAC} !endif ${ShowShortcuts} GoTo finish ; Require elevation if the the StartMenuInternet registry keys require ; updating and the user can elevate defaultappuser: ClearErrors ${GetOptions} "$R0" "/SetAsDefaultAppUser" $R2 IfErrors defaultappglobal +1 ${SetAsDefaultAppUser} GoTo finish ; Require elevation if the user can elevate defaultappglobal: ClearErrors ${GetOptions} "$R0" "/SetAsDefaultAppGlobal" $R2 IfErrors postupdate +1 ${ElevateUAC} ${SetAsDefaultAppGlobal} GoTo finish ; Do not attempt to elevate. The application launching this executable is ; responsible for elevation if it is required. postupdate: ${WordReplace} "$R0" "$\"" "" "+" $R0 ClearErrors ${GetOptions} "$R0" "/PostUpdate" $R2 IfErrors continue +1 ; If the uninstall.log does not exist don't perform post update ; operations. This prevents updating the registry for zip builds. IfFileExists "$EXEDIR\uninstall.log" +2 +1 Quit ; Nothing initialized so no need to call OnEndCommon ${PostUpdate} ClearErrors ${GetOptions} "$R0" "/UninstallLog=" $R2 IfErrors updateuninstalllog +1 StrCmp "$R2" "" finish +1 GetFullPathName $R3 "$R2" IfFileExists "$R3" +1 finish Delete "$INSTDIR\uninstall\*wizard*" Delete "$INSTDIR\uninstall\uninstall.log" CopyFiles /SILENT /FILESONLY "$R3" "$INSTDIR\uninstall\" ${GetParent} "$R3" $R4 Delete "$R3" RmDir "$R4" GoTo finish ; Do not attempt to elevate. The application launching this executable is ; responsible for elevation if it is required. updateuninstalllog: ${UpdateUninstallLog} finish: ${UnloadUAC} ${RefreshShellIcons} Quit ; Nothing initialized so no need to call OnEndCommon continue: ; If the uninstall.log does not exist don't perform uninstall ; operations. This prevents running the uninstaller for zip builds. IfFileExists "$INSTDIR\uninstall\uninstall.log" +2 +1 Quit ; Nothing initialized so no need to call OnEndCommon ; When silent, try to avoid elevation if we have a chance to succeed. We ; can succeed when we can write to (hence delete from) the install ; directory and when we can clean up all registry entries. Now, the ; installer when elevated writes privileged registry entries for the use ; of the Maintenance Service, even when the service is not and will not be ; installed. (In fact, even when a service installed in the future will ; never update the installation, for example due to not being in a ; privileged location.) In practice this means we can only truly silently ; remove an unelevated install: an elevated installer writing to an ; unprivileged install directory will still write privileged registry ; entries, requiring an elevated uninstaller to completely clean up. ; ; This avoids a wrinkle, whereby an uninstaller which runs unelevated will ; never itself launch the Maintenance Service uninstaller, because it will ; fail to remove its own service registration (removing the relevant ; registry key would require elevation). Therefore the check for the ; service being unused will fail, which will prevent running the service ; uninstaller. That's both subtle and possibly leaves the service ; registration hanging around, which might be a security risk. ; ; That is why we look for a privileged service registration for this ; installation when deciding to elevate, and elevate unconditionally if we ; find one, regardless of the result of the write check that would avoid ; elevation. ; The reason for requiring elevation, or "" for not required. StrCpy $R4 "" ${IfNot} ${Silent} ; In normal operation, require elevation if the user can elevate so that ; we are most likely to succeed. StrCpy $R4 "not silent" ${EndIf} GetTempFileName $R6 "$INSTDIR" FileOpen $R5 "$R6" w FileWrite $R5 "Write Access Test" FileClose $R5 Delete $R6 ${If} ${Errors} StrCpy $R4 "write" ${EndIf} !ifdef MOZ_MAINTENANCE_SERVICE ; We don't necessarily have $MaintCertKey, so use temporary registers. ServicesHelper::PathToUniqueRegistryPath "$INSTDIR" Pop $R5 ${If} $R5 != "" ; Always use the 64bit registry for certs on 64bit systems. ${If} ${RunningX64} ${OrIf} ${IsNativeARM64} SetRegView 64 ${EndIf} EnumRegKey $R6 HKLM $R5 0 ClearErrors ${If} ${RunningX64} ${OrIf} ${IsNativeARM64} SetRegView lastused ${EndIf} ${IfNot} "$R6" == "" StrCpy $R4 "mms" ${EndIf} ${EndIf} !endif ${If} "$R4" != "" ; In the future, we might not try to elevate to remain truly silent. Or ; we might add a command line arguments to specify behaviour. One ; reason to not do that immediately is that we have no great way to ; signal that we exited without taking action. ${ElevateUAC} ${EndIf} ; Now we've elevated, try the write access test again. ClearErrors GetTempFileName $R6 "$INSTDIR" FileOpen $R5 "$R6" w FileWrite $R5 "Write Access Test" FileClose $R5 Delete $R6 ${If} ${Errors} ; Nothing initialized so no need to call OnEndCommon Quit ${EndIf} !ifdef MOZ_MAINTENANCE_SERVICE ; And verify that if we need to, we're going to clean up the registry ; correctly. ${If} "$R4" == "mms" WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" "Write Test" ${If} ${Errors} ; Nothing initialized so no need to call OnEndCommon Quit ${Endif} DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" ${EndIf} !endif ; If we made it this far then this installer is being used as an uninstaller. WriteUninstaller "$EXEDIR\uninstaller.exe" ${If} ${Silent} StrCpy $R1 "$\"$EXEDIR\uninstaller.exe$\" /S" ${Else} StrCpy $R1 "$\"$EXEDIR\uninstaller.exe$\"" ${EndIf} ; When the uninstaller is launched it copies itself to the temp directory ; so it won't be in use so it can delete itself. ExecWait $R1 ${DeleteFile} "$EXEDIR\uninstaller.exe" ${UnloadUAC} SetErrorLevel 0 Quit ; Nothing initialized so no need to call OnEndCommon FunctionEnd !verbose pop !endif !macroend !macro UninstallOnInitCommonCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call UninstallOnInitCommon !verbose pop !macroend /** * Called from the uninstaller's un.onInit function not to be confused with the * installer's .onInit or the uninstaller's .onInit functions. */ !macro un.UninstallUnOnInitCommon !ifndef un.UninstallUnOnInitCommon !insertmacro un.GetLongPath !insertmacro un.GetParent !insertmacro un.SetBrandNameVars !verbose push !verbose ${_MOZFUNC_VERBOSE} !define un.UninstallUnOnInitCommon "!insertmacro un.UninstallUnOnInitCommonCall" Function un.UninstallUnOnInitCommon ${un.GetParent} "$INSTDIR" $INSTDIR ${un.GetLongPath} "$INSTDIR" $INSTDIR ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}" Abort ${EndUnless} !ifdef HAVE_64BIT_BUILD SetRegView 64 !endif ; Prevents breaking apps that don't use SetBrandNameVars !ifdef un.SetBrandNameVars ${un.SetBrandNameVars} "$INSTDIR\distribution\setup.ini" !endif ; Initialize $hHeaderBitmap to prevent redundant changing of the bitmap if ; the user clicks the back button StrCpy $hHeaderBitmap "" FunctionEnd !verbose pop !endif !macroend !macro un.UninstallUnOnInitCommonCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.UninstallUnOnInitCommon !verbose pop !macroend /** * Called from the MUI leaveOptions function to set the value of $INSTDIR. */ !macro LeaveOptionsCommon !ifndef LeaveOptionsCommon !insertmacro CanWriteToInstallDir !insertmacro GetLongPath !ifndef NO_INSTDIR_FROM_REG !insertmacro GetSingleInstallPath !endif !verbose push !verbose ${_MOZFUNC_VERBOSE} !define LeaveOptionsCommon "!insertmacro LeaveOptionsCommonCall" Function LeaveOptionsCommon Push $R9 StrCpy $R9 "false" !ifndef NO_INSTDIR_FROM_REG SetShellVarContext all ; Set SHCTX to HKLM ${If} ${IsNativeAMD64} ${OrIf} ${IsNativeARM64} SetRegView 64 ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9 SetRegView lastused ${EndIf} StrCmp "$R9" "false" +1 finish_get_install_dir SetRegView 32 ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9 SetRegView lastused StrCmp "$R9" "false" +1 finish_get_install_dir SetShellVarContext current ; Set SHCTX to HKCU ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9 finish_get_install_dir: StrCmp "$R9" "false" +2 +1 StrCpy $INSTDIR "$R9" !endif ; If the user doesn't have write access to the installation directory set ; the installation directory to a subdirectory of the user's local ; application directory (e.g. non-roaming). ${CanWriteToInstallDir} $R9 ${If} "$R9" == "false" ; NOTE: This SetShellVarContext isn't directly needed anymore, but to ; leave the state consistent with earlier code I'm leaving it here. SetShellVarContext all ; Set SHCTX to All Users ${GetLocalAppDataFolder} $R9 StrCpy $INSTDIR "$R9\${BrandFullName}\" ${CanWriteToInstallDir} $R9 ${EndIf} IfFileExists "$INSTDIR" +3 +1 Pop $R9 Return ; Always display the long path if the path already exists. ${GetLongPath} "$INSTDIR" $INSTDIR ; The call to GetLongPath returns a long path without a trailing ; back-slash. Append a \ to the path to prevent the directory ; name from being appended when using the NSIS create new folder. ; http://www.nullsoft.com/free/nsis/makensis.htm#InstallDir StrCpy $INSTDIR "$INSTDIR\" Pop $R9 FunctionEnd !verbose pop !endif !macroend !macro LeaveOptionsCommonCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call LeaveOptionsCommon !verbose pop !macroend /** * Called from the MUI preDirectory function to verify there is enough disk * space for the installation and the installation directory is writable. * * $R9 = returned value from CheckDiskSpace and CanWriteToInstallDir macros */ !macro PreDirectoryCommon !ifndef PreDirectoryCommon !insertmacro CanWriteToInstallDir !insertmacro CheckDiskSpace !verbose push !verbose ${_MOZFUNC_VERBOSE} !define PreDirectoryCommon "!insertmacro PreDirectoryCommonCall" Function PreDirectoryCommon Push $R9 IntCmp $InstallType ${INSTALLTYPE_CUSTOM} end +1 +1 ${CanWriteToInstallDir} $R9 StrCmp "$R9" "false" end +1 ${CheckDiskSpace} $R9 StrCmp "$R9" "false" end +1 Abort end: Pop $R9 FunctionEnd !verbose pop !endif !macroend !macro PreDirectoryCommonCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call PreDirectoryCommon !verbose pop !macroend /** * Called from the MUI leaveDirectory function * * @param _WARN_DISK_SPACE * Message displayed when there isn't enough disk space to perform the * installation. * @param _WARN_WRITE_ACCESS * Message displayed when the installer does not have write access to * $INSTDIR. * * $R7 = returned value from CheckDiskSpace and CanWriteToInstallDir macros * $R8 = _WARN_DISK_SPACE * $R9 = _WARN_WRITE_ACCESS */ !macro LeaveDirectoryCommon !ifndef LeaveDirectoryCommon !insertmacro CheckDiskSpace !insertmacro CanWriteToInstallDir !verbose push !verbose ${_MOZFUNC_VERBOSE} !define LeaveDirectoryCommon "!insertmacro LeaveDirectoryCommonCall" Function LeaveDirectoryCommon Exch $R9 Exch 1 Exch $R8 Push $R7 ${CanWriteToInstallDir} $R7 ${If} $R7 == "false" MessageBox MB_OK|MB_ICONEXCLAMATION "$R9" Abort ${EndIf} ${CheckDiskSpace} $R7 ${If} $R7 == "false" MessageBox MB_OK|MB_ICONEXCLAMATION "$R8" Abort ${EndIf} Pop $R7 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro LeaveDirectoryCommonCall _WARN_DISK_SPACE _WARN_WRITE_ACCESS !verbose push Push "${_WARN_DISK_SPACE}" Push "${_WARN_WRITE_ACCESS}" !verbose ${_MOZFUNC_VERBOSE} Call LeaveDirectoryCommon !verbose pop !macroend ################################################################################ # Install Section common macros. /** * Performs common cleanup operations prior to the actual installation. * This macro should be called first when installation starts. */ !macro InstallStartCleanupCommon !ifndef InstallStartCleanupCommon !insertmacro CleanVirtualStore !insertmacro EndUninstallLog !insertmacro OnInstallUninstall !verbose push !verbose ${_MOZFUNC_VERBOSE} !define InstallStartCleanupCommon "!insertmacro InstallStartCleanupCommonCall" Function InstallStartCleanupCommon ; Remove files not removed by parsing the uninstall.log Delete "$INSTDIR\install_wizard.log" Delete "$INSTDIR\install_status.log" RmDir /r "$INSTDIR\updates" Delete "$INSTDIR\updates.xml" Delete "$INSTDIR\active-update.xml" ; Remove files from the uninstall directory. ${If} ${FileExists} "$INSTDIR\uninstall" Delete "$INSTDIR\uninstall\*wizard*" Delete "$INSTDIR\uninstall\uninstall.ini" Delete "$INSTDIR\uninstall\cleanup.log" Delete "$INSTDIR\uninstall\uninstall.update" ${OnInstallUninstall} ${EndIf} ; Since we write to the uninstall.log in this directory during the ; installation create the directory if it doesn't already exist. IfFileExists "$INSTDIR\uninstall" +2 +1 CreateDirectory "$INSTDIR\uninstall" ; Application update uses a directory named tobedeleted in the $INSTDIR to ; delete files on OS reboot when they are in use. Try to delete this ; directory if it exists. ${If} ${FileExists} "$INSTDIR\${TO_BE_DELETED}" RmDir /r "$INSTDIR\${TO_BE_DELETED}" ${EndIf} ; Remove files that may be left behind by the application in the ; VirtualStore directory. ${CleanVirtualStore} FunctionEnd !verbose pop !endif !macroend !macro InstallStartCleanupCommonCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call InstallStartCleanupCommon !verbose pop !macroend /** * Performs common cleanup operations after the actual installation. * This macro should be called last during the installation. */ !macro InstallEndCleanupCommon !ifndef InstallEndCleanupCommon !insertmacro EndUninstallLog !verbose push !verbose ${_MOZFUNC_VERBOSE} !define InstallEndCleanupCommon "!insertmacro InstallEndCleanupCommonCall" Function InstallEndCleanupCommon ; Close the file handle to the uninstall.log ${EndUninstallLog} FunctionEnd !verbose pop !endif !macroend !macro InstallEndCleanupCommonCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call InstallEndCleanupCommon !verbose pop !macroend ################################################################################ # UAC Related Macros /** * Provides UAC elevation support (requires the UAC plugin). * * $0 = return values from calls to the UAC plugin (always uses $0) * $R9 = return values from GetParameters and GetOptions macros */ !macro ElevateUAC !ifndef ${_MOZFUNC_UN}ElevateUAC !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetOptions !insertmacro ${_MOZFUNC_UN_TMP}GetParameters !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}ElevateUAC "!insertmacro ${_MOZFUNC_UN}ElevateUACCall" Function ${_MOZFUNC_UN}ElevateUAC Push $R9 Push $0 !ifndef NONADMIN_ELEVATE UAC::IsAdmin ; If the user is not an admin already ${If} "$0" != "1" UAC::SupportsUAC ; If the system supports UAC ${If} "$0" == "1" UAC::GetElevationType ; If the user account has a split token ${If} "$0" == "3" UAC::RunElevated UAC::Unload ; Nothing besides UAC initialized so no need to call OnEndCommon Quit ${EndIf} ${EndIf} ${Else} ${GetParameters} $R9 ${If} $R9 != "" ClearErrors ${GetOptions} "$R9" "/UAC:" $0 ; If the command line contains /UAC then we need to initialize ; the UAC plugin to use UAC::ExecCodeSegment to execute code in ; the non-elevated context. ${Unless} ${Errors} UAC::RunElevated ${EndUnless} ${EndIf} ${EndIf} !else UAC::IsAdmin ; If the user is not an admin already ${If} "$0" != "1" UAC::SupportsUAC ; If the system supports UAC require that the user elevate ${If} "$0" == "1" UAC::GetElevationType ; If the user account has a split token ${If} "$0" == "3" UAC::RunElevated ${If} "$0" == "0" ; Was elevation successful UAC::Unload ; Nothing besides UAC initialized so no need to call OnEndCommon Quit ${EndIf} ; Unload UAC since the elevation request was not successful and ; install anyway. UAC::Unload ${EndIf} ${Else} ; Check if UAC is enabled. If the user has turned UAC on or off ; without rebooting this value will be incorrect. This is an ; edgecase that we have to live with when trying to allow ; installing when the user doesn't have privileges such as a public ; computer while trying to also achieve UAC elevation. When this ; happens the user will be presented with the runas dialog if the ; value is 1 and won't be presented with the UAC dialog when the ; value is 0. ReadRegDWord $R9 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "EnableLUA" ${If} "$R9" == "1" ; This will display the UAC version of the runas dialog which ; requires a password for an existing user account. UAC::RunElevated ${If} "$0" == "0" ; Was elevation successful UAC::Unload ; Nothing besides UAC initialized so no need to call OnEndCommon Quit ${EndIf} ; Unload UAC since the elevation request was not successful and ; install anyway. UAC::Unload ${EndIf} ${EndIf} ${Else} ClearErrors ${${_MOZFUNC_UN}GetParameters} $R9 ${${_MOZFUNC_UN}GetOptions} "$R9" "/UAC:" $R9 ; If the command line contains /UAC then we need to initialize the UAC ; plugin to use UAC::ExecCodeSegment to execute code in the ; non-elevated context. ${Unless} ${Errors} UAC::RunElevated ${EndUnless} ${EndIf} !endif ClearErrors Pop $0 Pop $R9 FunctionEnd !verbose pop !endif !macroend !macro ElevateUACCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call ElevateUAC !verbose pop !macroend !macro un.ElevateUACCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.ElevateUAC !verbose pop !macroend !macro un.ElevateUAC !ifndef un.ElevateUAC !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro ElevateUAC !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Unloads the UAC plugin so the NSIS plugins can be removed when the installer * and uninstaller exit. * * $R9 = return values from GetParameters and GetOptions macros */ !macro UnloadUAC !ifndef ${_MOZFUNC_UN}UnloadUAC !define _MOZFUNC_UN_TMP_UnloadUAC ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP_UnloadUAC}GetOptions !insertmacro ${_MOZFUNC_UN_TMP_UnloadUAC}GetParameters !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP_UnloadUAC} !undef _MOZFUNC_UN_TMP_UnloadUAC !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}UnloadUAC "!insertmacro ${_MOZFUNC_UN}UnloadUACCall" Function ${_MOZFUNC_UN}UnloadUAC Push $R9 ClearErrors ${${_MOZFUNC_UN}GetParameters} $R9 ${${_MOZFUNC_UN}GetOptions} "$R9" "/UAC:" $R9 ; If the command line contains /UAC then we need to unload the UAC plugin IfErrors +2 +1 UAC::Unload ClearErrors Pop $R9 FunctionEnd !verbose pop !endif !macroend !macro UnloadUACCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call UnloadUAC !verbose pop !macroend !macro un.UnloadUACCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.UnloadUAC !verbose pop !macroend !macro un.UnloadUAC !ifndef un.UnloadUAC !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro UnloadUAC !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend ################################################################################ # Macros for uninstall.log and install.log logging # # Since these are used by other macros they should be inserted first. All of # these macros can be easily inserted using the _LoggingCommon macro. /** * Adds all logging macros in the correct order in one fell swoop as well as * the vars for the install.log and uninstall.log file handles. */ !macro _LoggingCommon Var /GLOBAL fhInstallLog Var /GLOBAL fhUninstallLog !insertmacro StartInstallLog !insertmacro EndInstallLog !insertmacro StartUninstallLog !insertmacro EndUninstallLog !macroend !define _LoggingCommon "!insertmacro _LoggingCommon" /** * Creates a file named install.log in the install directory (e.g. $INSTDIR) * and adds the installation started message to the install.log for this * installation. This also adds the fhInstallLog and fhUninstallLog vars used * for logging. * * $fhInstallLog = filehandle for $INSTDIR\install.log * * @param _APP_NAME * Typically the BrandFullName * @param _AB_CD * The locale identifier * @param _APP_VERSION * The application version * @param _GRE_VERSION * The Gecko Runtime Engine version * * $R6 = _APP_NAME * $R7 = _AB_CD * $R8 = _APP_VERSION * $R9 = _GRE_VERSION */ !macro StartInstallLog !ifndef StartInstallLog !insertmacro GetTime !verbose push !verbose ${_MOZFUNC_VERBOSE} !define StartInstallLog "!insertmacro StartInstallLogCall" Function StartInstallLog Exch $R9 Exch 1 Exch $R8 Exch 2 Exch $R7 Exch 3 Exch $R6 Push $R5 Push $R4 Push $R3 Push $R2 Push $R1 Push $R0 Push $9 ${DeleteFile} "$INSTDIR\install.log" FileOpen $fhInstallLog "$INSTDIR\install.log" w FileWriteWord $fhInstallLog "65279" ${GetTime} "" "L" $9 $R0 $R1 $R2 $R3 $R4 $R5 FileWriteUTF16LE $fhInstallLog "$R6 Installation Started: $R1-$R0-$9 $R3:$R4:$R5" ${WriteLogSeparator} ${LogHeader} "Installation Details" ${LogMsg} "Install Dir: $INSTDIR" ${LogMsg} "Locale : $R7" ${LogMsg} "App Version: $R8" ${LogMsg} "GRE Version: $R9" ${If} ${IsWin7} ${LogMsg} "OS Name : Windows 7" ${ElseIf} ${IsWin8} ${LogMsg} "OS Name : Windows 8" ${ElseIf} ${IsWin8.1} ${LogMsg} "OS Name : Windows 8.1" ${ElseIf} ${IsWin10} ${LogMsg} "OS Name : Windows 10" ${ElseIf} ${AtLeastWin10} ${LogMsg} "OS Name : Above Windows 10" ${Else} ${LogMsg} "OS Name : Unable to detect" ${EndIf} ${LogMsg} "Target CPU : ${ARCH}" Pop $9 Pop $R0 Pop $R1 Pop $R2 Pop $R3 Pop $R4 Pop $R5 Exch $R6 Exch 3 Exch $R7 Exch 2 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro StartInstallLogCall _APP_NAME _AB_CD _APP_VERSION _GRE_VERSION !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_APP_NAME}" Push "${_AB_CD}" Push "${_APP_VERSION}" Push "${_GRE_VERSION}" Call StartInstallLog !verbose pop !macroend /** * Writes the installation finished message to the install.log and closes the * file handles to the install.log and uninstall.log * * @param _APP_NAME * * $R9 = _APP_NAME */ !macro EndInstallLog !ifndef EndInstallLog !insertmacro GetTime !verbose push !verbose ${_MOZFUNC_VERBOSE} !define EndInstallLog "!insertmacro EndInstallLogCall" Function EndInstallLog Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 Push $R4 Push $R3 Push $R2 ${WriteLogSeparator} ${GetTime} "" "L" $R2 $R3 $R4 $R5 $R6 $R7 $R8 FileWriteUTF16LE $fhInstallLog "$R9 Installation Finished: $R4-$R3-$R2 $R6:$R7:$R8$\r$\n" FileClose $fhInstallLog Pop $R2 Pop $R3 Pop $R4 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro EndInstallLogCall _APP_NAME !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_APP_NAME}" Call EndInstallLog !verbose pop !macroend /** * Opens the file handle to the uninstall.log. * * $fhUninstallLog = filehandle for $INSTDIR\uninstall\uninstall.log */ !macro StartUninstallLog !ifndef StartUninstallLog !verbose push !verbose ${_MOZFUNC_VERBOSE} !define StartUninstallLog "!insertmacro StartUninstallLogCall" Function StartUninstallLog FileOpen $fhUninstallLog "$INSTDIR\uninstall\uninstall.log" w FunctionEnd !verbose pop !endif !macroend !macro StartUninstallLogCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call StartUninstallLog !verbose pop !macroend /** * Closes the file handle to the uninstall.log. */ !macro EndUninstallLog !ifndef EndUninstallLog !verbose push !verbose ${_MOZFUNC_VERBOSE} !define EndUninstallLog "!insertmacro EndUninstallLogCall" Function EndUninstallLog FileClose $fhUninstallLog FunctionEnd !verbose pop !endif !macroend !macro EndUninstallLogCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call EndUninstallLog !verbose pop !macroend /** * Adds a section header to the human readable log. * * @param _HEADER * The header text to write to the log. */ !macro LogHeader _HEADER ${WriteLogSeparator} FileWriteUTF16LE $fhInstallLog "${_HEADER}" ${WriteLogSeparator} !macroend !define LogHeader "!insertmacro LogHeader" /** * Adds a section message to the human readable log. * * @param _MSG * The message text to write to the log. */ !macro LogMsg _MSG FileWriteUTF16LE $fhInstallLog " ${_MSG}$\r$\n" !macroend !define LogMsg "!insertmacro LogMsg" /** * Adds an uninstall entry to the uninstall log. * * @param _MSG * The message text to write to the log. */ !macro LogUninstall _MSG FileWrite $fhUninstallLog "${_MSG}$\r$\n" !macroend !define LogUninstall "!insertmacro LogUninstall" /** * Adds a section divider to the human readable log. */ !macro WriteLogSeparator FileWriteUTF16LE $fhInstallLog "$\r$\n----------------------------------------\ ---------------------------------------$\r$\n" !macroend !define WriteLogSeparator "!insertmacro WriteLogSeparator" ################################################################################ # Macros for managing the shortcuts log ini file /** * Adds the most commonly used shortcut logging macros for the installer in one * fell swoop. */ !macro _LoggingShortcutsCommon !insertmacro LogDesktopShortcut !insertmacro LogQuickLaunchShortcut !insertmacro LogSMProgramsShortcut !macroend !define _LoggingShortcutsCommon "!insertmacro _LoggingShortcutsCommon" /** * Creates the shortcuts log ini file with a UTF-16LE BOM if it doesn't exist. */ !macro initShortcutsLog Push $R9 IfFileExists "$INSTDIR\uninstall\${SHORTCUTS_LOG}" +4 +1 FileOpen $R9 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" w FileWriteWord $R9 "65279" FileClose $R9 Pop $R9 !macroend !define initShortcutsLog "!insertmacro initShortcutsLog" /** * Adds shortcut entries to the shortcuts log ini file. This macro is primarily * a helper used by the LogDesktopShortcut, LogQuickLaunchShortcut, and * LogSMProgramsShortcut macros but it can be used by other code if desired. If * the value already exists the the value is not written to the file. * * @param _SECTION_NAME * The section name to write to in the shortcut log ini file * @param _FILE_NAME * The shortcut's file name * * $R6 = return value from ReadIniStr for the shortcut file name * $R7 = counter for supporting multiple shortcuts in the same location * $R8 = _SECTION_NAME * $R9 = _FILE_NAME */ !macro LogShortcut !ifndef LogShortcut !verbose push !verbose ${_MOZFUNC_VERBOSE} !define LogShortcut "!insertmacro LogShortcutCall" Function LogShortcut Exch $R9 Exch 1 Exch $R8 Push $R7 Push $R6 ClearErrors !insertmacro initShortcutsLog StrCpy $R6 "" StrCpy $R7 -1 StrCmp "$R6" "$R9" +5 +1 ; if the shortcut already exists don't add it IntOp $R7 $R7 + 1 ; increment the counter ReadIniStr $R6 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "$R8" "Shortcut$R7" IfErrors +1 -3 WriteINIStr "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "$R8" "Shortcut$R7" "$R9" ClearErrors Pop $R6 Pop $R7 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro LogShortcutCall _SECTION_NAME _FILE_NAME !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_SECTION_NAME}" Push "${_FILE_NAME}" Call LogShortcut !verbose pop !macroend /** * Adds a Desktop shortcut entry to the shortcuts log ini file. * * @param _FILE_NAME * The shortcut file name (e.g. shortcut.lnk) */ !macro LogDesktopShortcut !ifndef LogDesktopShortcut !insertmacro LogShortcut !verbose push !verbose ${_MOZFUNC_VERBOSE} !define LogDesktopShortcut "!insertmacro LogDesktopShortcutCall" Function LogDesktopShortcut Call LogShortcut FunctionEnd !verbose pop !endif !macroend !macro LogDesktopShortcutCall _FILE_NAME !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "DESKTOP" Push "${_FILE_NAME}" Call LogDesktopShortcut !verbose pop !macroend /** * Adds a QuickLaunch shortcut entry to the shortcuts log ini file. * * @param _FILE_NAME * The shortcut file name (e.g. shortcut.lnk) */ !macro LogQuickLaunchShortcut !ifndef LogQuickLaunchShortcut !insertmacro LogShortcut !verbose push !verbose ${_MOZFUNC_VERBOSE} !define LogQuickLaunchShortcut "!insertmacro LogQuickLaunchShortcutCall" Function LogQuickLaunchShortcut Call LogShortcut FunctionEnd !verbose pop !endif !macroend !macro LogQuickLaunchShortcutCall _FILE_NAME !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "QUICKLAUNCH" Push "${_FILE_NAME}" Call LogQuickLaunchShortcut !verbose pop !macroend /** * Adds a Start Menu shortcut entry to the shortcuts log ini file. * * @param _FILE_NAME * The shortcut file name (e.g. shortcut.lnk) */ !macro LogStartMenuShortcut !ifndef LogStartMenuShortcut !insertmacro LogShortcut !verbose push !verbose ${_MOZFUNC_VERBOSE} !define LogStartMenuShortcut "!insertmacro LogStartMenuShortcutCall" Function LogStartMenuShortcut Call LogShortcut FunctionEnd !verbose pop !endif !macroend !macro LogStartMenuShortcutCall _FILE_NAME !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "STARTMENU" Push "${_FILE_NAME}" Call LogStartMenuShortcut !verbose pop !macroend /** * Adds a Start Menu Programs shortcut entry to the shortcuts log ini file. * * @param _FILE_NAME * The shortcut file name (e.g. shortcut.lnk) */ !macro LogSMProgramsShortcut !ifndef LogSMProgramsShortcut !insertmacro LogShortcut !verbose push !verbose ${_MOZFUNC_VERBOSE} !define LogSMProgramsShortcut "!insertmacro LogSMProgramsShortcutCall" Function LogSMProgramsShortcut Call LogShortcut FunctionEnd !verbose pop !endif !macroend !macro LogSMProgramsShortcutCall _FILE_NAME !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "SMPROGRAMS" Push "${_FILE_NAME}" Call LogSMProgramsShortcut !verbose pop !macroend /** * Adds the relative path from the Start Menu Programs directory for the * application's Start Menu directory if it is different from the existing value * to the shortcuts log ini file. * * @param _REL_PATH_TO_DIR * The relative path from the Start Menu Programs directory to the * program's directory. * * $R9 = _REL_PATH_TO_DIR */ !macro LogSMProgramsDirRelPath _REL_PATH_TO_DIR Push $R9 !insertmacro initShortcutsLog ReadINIStr $R9 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" "RelativePathToDir" StrCmp "$R9" "${_REL_PATH_TO_DIR}" +2 +1 WriteINIStr "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" "RelativePathToDir" "${_REL_PATH_TO_DIR}" Pop $R9 !macroend !define LogSMProgramsDirRelPath "!insertmacro LogSMProgramsDirRelPath" /** * Copies the value for the relative path from the Start Menu programs directory * (e.g. $SMPROGRAMS) to the Start Menu directory as it is stored in the * shortcuts log ini file to the variable specified in the first parameter. */ !macro GetSMProgramsDirRelPath _VAR ReadINIStr ${_VAR} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" \ "RelativePathToDir" !macroend !define GetSMProgramsDirRelPath "!insertmacro GetSMProgramsDirRelPath" /** * Copies the shortcuts log ini file path to the variable specified in the * first parameter. */ !macro GetShortcutsLogPath _VAR StrCpy ${_VAR} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" !macroend !define GetShortcutsLogPath "!insertmacro GetShortcutsLogPath" ################################################################################ # Macros for managing specific Windows version features /** * Sets the permitted layered service provider (LSP) categories * for the application. Consumers should call this after an * installation log section has completed since this macro will log the results * to the installation log along with a header. * * !IMPORTANT - When calling this macro from an uninstaller do not specify a * parameter. The paramter is hardcoded with 0x00000000 to remove * the LSP category for the application when performing an * uninstall. * * @param _LSP_CATEGORIES * The permitted LSP categories for the application. When called by an * uninstaller this will always be 0x00000000. * * $R5 = error code popped from the stack for the WSCSetApplicationCategory call * $R6 = return value from the WSCSetApplicationCategory call * $R7 = string length for the long path to the main application executable * $R8 = long path to the main application executable * $R9 = _LSP_CATEGORIES */ !macro SetAppLSPCategories !ifndef ${_MOZFUNC_UN}SetAppLSPCategories !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}SetAppLSPCategories "!insertmacro ${_MOZFUNC_UN}SetAppLSPCategoriesCall" Function ${_MOZFUNC_UN}SetAppLSPCategories Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR\${FileMainEXE}" $R8 StrLen $R7 "$R8" ; Remove existing categories by setting the permitted categories to ; 0x00000000 since new categories are ANDed with existing categories. If ; the param value stored in $R9 is 0x00000000 then skip the removal since ; the categories will be removed by the second call to ; WSCSetApplicationCategory. StrCmp "$R9" "0x00000000" +2 +1 System::Call "Ws2_32::WSCSetApplicationCategory(w R8, i R7, w n, i 0,\ i 0x00000000, i n, *i) i" ; Set the permitted LSP categories System::Call "Ws2_32::WSCSetApplicationCategory(w R8, i R7, w n, i 0,\ i R9, i n, *i .s) i.R6" Pop $R5 !ifndef NO_LOG ${LogHeader} "Setting Permitted LSP Categories" StrCmp "$R6" 0 +3 +1 ${LogMsg} "** ERROR Setting LSP Categories: $R5 **" GoTo +2 ${LogMsg} "Permitted LSP Categories: $R9" !endif ClearErrors Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro SetAppLSPCategoriesCall _LSP_CATEGORIES !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_LSP_CATEGORIES}" Call SetAppLSPCategories !verbose pop !macroend !macro un.SetAppLSPCategoriesCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "0x00000000" Call un.SetAppLSPCategories !verbose pop !macroend !macro un.SetAppLSPCategories !ifndef un.SetAppLSPCategories !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro SetAppLSPCategories !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Checks if any pinned TaskBar lnk files point to the executable's path passed * to the macro. * * @param _EXE_PATH * The executable path * @return _RESULT * false if no pinned shotcuts were found for this install location. * true if pinned shotcuts were found for this install location. * * $R5 = stores whether a TaskBar lnk file has been found for the executable * $R6 = long path returned from GetShortCutTarget and GetLongPath * $R7 = file name returned from FindFirst and FindNext * $R8 = find handle for FindFirst and FindNext * $R9 = _EXE_PATH and _RESULT */ !macro IsPinnedToTaskBar !ifndef IsPinnedToTaskBar !insertmacro GetLongPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !define IsPinnedToTaskBar "!insertmacro IsPinnedToTaskBarCall" Function IsPinnedToTaskBar Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 StrCpy $R5 "false" ${If} ${AtLeastWin7} ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar" FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\TaskBar\*.lnk" ${Do} ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar\$R7" ShellLink::GetShortCutTarget "$QUICKLAUNCH\User Pinned\TaskBar\$R7" Pop $R6 ${GetLongPath} "$R6" $R6 ${If} "$R6" == "$R9" StrCpy $R5 "true" ${ExitDo} ${EndIf} ${EndIf} ClearErrors FindNext $R8 $R7 ${If} ${Errors} ${ExitDo} ${EndIf} ${Loop} FindClose $R8 ${EndIf} ClearErrors StrCpy $R9 $R5 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro IsPinnedToTaskBarCall _EXE_PATH _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_EXE_PATH}" Call IsPinnedToTaskBar Pop ${_RESULT} !verbose pop !macroend /** * Checks if any pinned Start Menu lnk files point to the executable's path * passed to the macro. * * @param _EXE_PATH * The executable path * @return _RESULT * false if no pinned shotcuts were found for this install location. * true if pinned shotcuts were found for this install location. * * $R5 = stores whether a Start Menu lnk file has been found for the executable * $R6 = long path returned from GetShortCutTarget and GetLongPath * $R7 = file name returned from FindFirst and FindNext * $R8 = find handle for FindFirst and FindNext * $R9 = _EXE_PATH and _RESULT */ !macro IsPinnedToStartMenu !ifndef IsPinnedToStartMenu !insertmacro GetLongPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !define IsPinnedToStartMenu "!insertmacro IsPinnedToStartMenuCall" Function IsPinnedToStartMenu Exch $R9 Push $R8 Push $R7 Push $R6 Push $R5 StrCpy $R5 "false" ${If} ${AtLeastWin7} ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu" FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\StartMenu\*.lnk" ${Do} ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu\$R7" ShellLink::GetShortCutTarget "$QUICKLAUNCH\User Pinned\StartMenu\$R7" Pop $R6 ${GetLongPath} "$R6" $R6 ${If} "$R6" == "$R9" StrCpy $R5 "true" ${ExitDo} ${EndIf} ${EndIf} ClearErrors FindNext $R8 $R7 ${If} ${Errors} ${ExitDo} ${EndIf} ${Loop} FindClose $R8 ${EndIf} ClearErrors StrCpy $R9 $R5 Pop $R5 Pop $R6 Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro IsPinnedToStartMenuCall _EXE_PATH _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_EXE_PATH}" Call IsPinnedToStartMenu Pop ${_RESULT} !verbose pop !macroend /** * Gets the number of pinned shortcut lnk files pinned to the Task Bar. * * @return _RESULT * number of pinned shortcut lnk files. * * $R7 = file name returned from FindFirst and FindNext * $R8 = find handle for FindFirst and FindNext * $R9 = _RESULT */ !macro PinnedToTaskBarLnkCount !ifndef PinnedToTaskBarLnkCount !insertmacro GetLongPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !define PinnedToTaskBarLnkCount "!insertmacro PinnedToTaskBarLnkCountCall" Function PinnedToTaskBarLnkCount Push $R9 Push $R8 Push $R7 StrCpy $R9 0 ${If} ${AtLeastWin7} ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar" FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\TaskBar\*.lnk" ${Do} ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar\$R7" IntOp $R9 $R9 + 1 ${EndIf} ClearErrors FindNext $R8 $R7 ${If} ${Errors} ${ExitDo} ${EndIf} ${Loop} FindClose $R8 ${EndIf} ClearErrors Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro PinnedToTaskBarLnkCountCall _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Call PinnedToTaskBarLnkCount Pop ${_RESULT} !verbose pop !macroend /** * Gets the number of pinned shortcut lnk files pinned to the Start Menu. * * @return _RESULT * number of pinned shortcut lnk files. * * $R7 = file name returned from FindFirst and FindNext * $R8 = find handle for FindFirst and FindNext * $R9 = _RESULT */ !macro PinnedToStartMenuLnkCount !ifndef PinnedToStartMenuLnkCount !insertmacro GetLongPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !define PinnedToStartMenuLnkCount "!insertmacro PinnedToStartMenuLnkCountCall" Function PinnedToStartMenuLnkCount Push $R9 Push $R8 Push $R7 StrCpy $R9 0 ${If} ${AtLeastWin7} ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu" FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\StartMenu\*.lnk" ${Do} ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\StartMenu\$R7" IntOp $R9 $R9 + 1 ${EndIf} ClearErrors FindNext $R8 $R7 ${If} ${Errors} ${ExitDo} ${EndIf} ${Loop} FindClose $R8 ${EndIf} ClearErrors Pop $R7 Pop $R8 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro PinnedToStartMenuLnkCountCall _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Call PinnedToStartMenuLnkCount Pop ${_RESULT} !verbose pop !macroend /** * Update Start Menu / TaskBar lnk files that point to the executable's path * passed to the macro and all other shortcuts installed by the application with * the current application user model ID. Requires ApplicationID. * * NOTE: this does not update Desktop shortcut application user model ID due to * bug 633728. * * @param _EXE_PATH * The main application executable path * @param _APP_ID * The application user model ID for the current install * @return _RESULT * false if no pinned shotcuts were found for this install location. * true if pinned shotcuts were found for this install location. */ !macro UpdateShortcutAppModelIDs !ifndef UpdateShortcutAppModelIDs !insertmacro GetLongPath !verbose push !verbose ${_MOZFUNC_VERBOSE} !define UpdateShortcutAppModelIDs "!insertmacro UpdateShortcutAppModelIDsCall" Function UpdateShortcutAppModelIDs ; stack: path, appid Exch $R9 ; stack: $R9, appid | $R9 = path Exch 1 ; stack: appid, $R9 Exch $R8 ; stack: $R8, $R9 | $R8 = appid Push $R7 ; stack: $R7, $R8, $R9 Push $R6 Push $R5 Push $R4 Push $R3 ; stack: $R3, $R5, $R6, $R7, $R8, $R9 Push $R2 ; $R9 = main application executable path ; $R8 = appid ; $R7 = path to the application's start menu programs directory ; $R6 = path to the shortcut log ini file ; $R5 = shortcut filename ; $R4 = GetShortCutTarget result StrCpy $R3 "false" ${If} ${AtLeastWin7} ; installed shortcuts ${${_MOZFUNC_UN}GetLongPath} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" $R6 ${If} ${FileExists} "$R6" ; Update the Start Menu shortcuts' App ID for this application StrCpy $R2 -1 ${Do} IntOp $R2 $R2 + 1 ; Increment the counter ClearErrors ReadINIStr $R5 "$R6" "STARTMENU" "Shortcut$R2" ${If} ${Errors} ${ExitDo} ${EndIf} ${If} ${FileExists} "$SMPROGRAMS\$R5" ShellLink::GetShortCutTarget "$SMPROGRAMS\$$R5" Pop $R4 ${GetLongPath} "$R4" $R4 ${If} "$R4" == "$R9" ; link path == install path ApplicationID::Set "$SMPROGRAMS\$R5" "$R8" "true" Pop $R4 ${EndIf} ${EndIf} ${Loop} ; Update the Quick Launch shortcuts' App ID for this application StrCpy $R2 -1 ${Do} IntOp $R2 $R2 + 1 ; Increment the counter ClearErrors ReadINIStr $R5 "$R6" "QUICKLAUNCH" "Shortcut$R2" ${If} ${Errors} ${ExitDo} ${EndIf} ${If} ${FileExists} "$QUICKLAUNCH\$R5" ShellLink::GetShortCutTarget "$QUICKLAUNCH\$R5" Pop $R4 ${GetLongPath} "$R4" $R4 ${If} "$R4" == "$R9" ; link path == install path ApplicationID::Set "$QUICKLAUNCH\$R5" "$R8" "true" Pop $R4 ${EndIf} ${EndIf} ${Loop} ; Update the Start Menu Programs shortcuts' App ID for this application ClearErrors ReadINIStr $R7 "$R6" "SMPROGRAMS" "RelativePathToDir" ${Unless} ${Errors} ${${_MOZFUNC_UN}GetLongPath} "$SMPROGRAMS\$R7" $R7 ${Unless} "$R7" == "" StrCpy $R2 -1 ${Do} IntOp $R2 $R2 + 1 ; Increment the counter ClearErrors ReadINIStr $R5 "$R6" "SMPROGRAMS" "Shortcut$R2" ${If} ${Errors} ${ExitDo} ${EndIf} ${If} ${FileExists} "$R7\$R5" ShellLink::GetShortCutTarget "$R7\$R5" Pop $R4 ${GetLongPath} "$R4" $R4 ${If} "$R4" == "$R9" ; link path == install path ApplicationID::Set "$R7\$R5" "$R8" "true" Pop $R4 ${EndIf} ${EndIf} ${Loop} ${EndUnless} ${EndUnless} ${EndIf} StrCpy $R7 "$QUICKLAUNCH\User Pinned" StrCpy $R3 "false" ; $R9 = main application executable path ; $R8 = appid ; $R7 = user pinned path ; $R6 = find handle ; $R5 = found filename ; $R4 = GetShortCutTarget result ; TaskBar links FindFirst $R6 $R5 "$R7\TaskBar\*.lnk" ${Do} ${If} ${FileExists} "$R7\TaskBar\$R5" ShellLink::GetShortCutTarget "$R7\TaskBar\$R5" Pop $R4 ${If} "$R4" == "$R9" ; link path == install path ApplicationID::Set "$R7\TaskBar\$R5" "$R8" "true" Pop $R4 ; pop Set result off the stack StrCpy $R3 "true" ${EndIf} ${EndIf} ClearErrors FindNext $R6 $R5 ${If} ${Errors} ${ExitDo} ${EndIf} ${Loop} FindClose $R6 ; Start menu links FindFirst $R6 $R5 "$R7\StartMenu\*.lnk" ${Do} ${If} ${FileExists} "$R7\StartMenu\$R5" ShellLink::GetShortCutTarget "$R7\StartMenu\$R5" Pop $R4 ${If} "$R4" == "$R9" ; link path == install path ApplicationID::Set "$R7\StartMenu\$R5" "$R8" "true" Pop $R4 ; pop Set result off the stack StrCpy $R3 "true" ${EndIf} ${EndIf} ClearErrors FindNext $R6 $R5 ${If} ${Errors} ${ExitDo} ${EndIf} ${Loop} FindClose $R6 ${EndIf} ClearErrors StrCpy $R9 $R3 Pop $R2 Pop $R3 ; stack: $R4, $R5, $R6, $R7, $R8, $R9 Pop $R4 ; stack: $R5, $R6, $R7, $R8, $R9 Pop $R5 ; stack: $R6, $R7, $R8, $R9 Pop $R6 ; stack: $R7, $R8, $R9 Pop $R7 ; stack: $R8, $R9 Exch $R8 ; stack: appid, $R9 | $R8 = old $R8 Exch 1 ; stack: $R9, appid Exch $R9 ; stack: path, appid | $R9 = old $R9 FunctionEnd !verbose pop !endif !macroend !macro UpdateShortcutAppModelIDsCall _EXE_PATH _APP_ID _RESULT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_APP_ID}" Push "${_EXE_PATH}" Call UpdateShortcutAppModelIDs Pop ${_RESULT} !verbose pop !macroend !macro IsUserAdmin ; Copied from: http://nsis.sourceforge.net/IsUserAdmin Function IsUserAdmin Push $R0 Push $R1 Push $R2 ClearErrors UserInfo::GetName IfErrors Win9x Pop $R1 UserInfo::GetAccountType Pop $R2 StrCmp $R2 "Admin" 0 Continue StrCpy $R0 "true" Goto Done Continue: StrCmp $R2 "" Win9x StrCpy $R0 "false" Goto Done Win9x: StrCpy $R0 "true" Done: Pop $R2 Pop $R1 Exch $R0 FunctionEnd !macroend /** * Retrieve if present or generate and store a 64 bit hash of an install path * using the City Hash algorithm. On return the resulting id is saved in the * $AppUserModelID variable declared by inserting this macro. InitHashAppModelId * will attempt to load from HKLM/_REG_PATH first, then HKCU/_REG_PATH. If found * in either it will return the hash it finds. If not found it will generate a * new hash and attempt to store the hash in HKLM/_REG_PATH, then HKCU/_REG_PATH. * Subsequent calls will then retreive the stored hash value. On any failure, * $AppUserModelID will be set to an empty string. * * A second string that will be used for Private Browsing mode is also generated by * taking the regular $AppUserModelID and appending ";PrivateBrowsingAUMID" to it. * This is stored in $AppUserModelIDPrivate upon successful completion of this * function. * * Registry format: root/_REG_PATH/"_EXE_PATH" = "hash" * * @param _EXE_PATH * The main application executable path * @param _REG_PATH * The HKLM/HKCU agnostic registry path where the key hash should * be stored. ex: "Software\Mozilla\Firefox\TaskBarIDs" * @result (Var) $AppUserModelID and $AppUserModelIDPrivate contain the * app model id and the private app model id, respectively. */ !macro InitHashAppModelId !ifndef ${_MOZFUNC_UN}InitHashAppModelId !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}GetLongPath !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !ifndef InitHashAppModelId Var AppUserModelID Var AppUserModelIDPrivate !endif !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}InitHashAppModelId "!insertmacro ${_MOZFUNC_UN}InitHashAppModelIdCall" Function ${_MOZFUNC_UN}InitHashAppModelId ; stack: apppath, regpath Exch $R9 ; stack: $R9, regpath | $R9 = apppath Exch 1 ; stack: regpath, $R9 Exch $R8 ; stack: $R8, $R9 | $R8 = regpath Push $R7 ${If} ${AtLeastWin7} ${${_MOZFUNC_UN}GetLongPath} "$R9" $R9 ; Always create a new AppUserModelID and overwrite the existing one ; for the current installation path. CityHash::GetCityHash64 "$R9" Pop $AppUserModelID ${If} $AppUserModelID == "error" GoTo end ${EndIf} ClearErrors WriteRegStr HKLM "$R8" "$R9" "$AppUserModelID" ${If} ${Errors} ClearErrors WriteRegStr HKCU "$R8" "$R9" "$AppUserModelID" ${If} ${Errors} StrCpy $AppUserModelID "error" ${EndIf} ${EndIf} ${EndIf} end: ${If} "$AppUserModelID" == "error" StrCpy $AppUserModelID "" StrCpy $AppUserModelIDPrivate "" ${Else} StrCpy $AppUserModelIDPrivate "$AppUserModelID;PrivateBrowsingAUMID" ${EndIf} ClearErrors Pop $R7 Exch $R8 Exch 1 Exch $R9 FunctionEnd !verbose pop !endif !macroend !macro InitHashAppModelIdCall _EXE_PATH _REG_PATH !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_REG_PATH}" Push "${_EXE_PATH}" Call InitHashAppModelId !verbose pop !macroend !macro un.InitHashAppModelIdCall _EXE_PATH _REG_PATH !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_REG_PATH}" Push "${_EXE_PATH}" Call un.InitHashAppModelId !verbose pop !macroend !macro un.InitHashAppModelId !ifndef un.InitHashAppModelId !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro InitHashAppModelId !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Try to locate the default profile of this install from AppUserModelID * using installs.ini. * FIXME This could instead use the Install entries in profiles.ini? * * - `SetShellVarContext current` must be called before this macro so * $APPDATA gets the current user's data. * - InitHashAppModelId must have been called before this macro to set * $AppUserModelID * * @result: Path of the profile directory (not checked for existence), * or "" if not found, left on top of the stack. */ !macro FindInstallSpecificProfileMaybeUn _MOZFUNC_UN Push $R0 Push $0 Push $1 Push $2 StrCpy $R0 "" ; Look for an install-specific profile, which might be listed as ; either a relative or an absolute path (installs.ini doesn't say which). ${If} ${FileExists} "$APPDATA\Mozilla\Firefox\installs.ini" ClearErrors ReadINIStr $1 "$APPDATA\Mozilla\Firefox\installs.ini" "$AppUserModelID" "Default" ${IfNot} ${Errors} ${${_MOZFUNC_UN}GetLongPath} "$APPDATA\Mozilla\Firefox\$1" $2 ${If} ${FileExists} $2 StrCpy $R0 $2 ${Else} ${${_MOZFUNC_UN}GetLongPath} "$1" $2 ${If} ${FileExists} $2 StrCpy $R0 $2 ${EndIf} ${EndIf} ${EndIf} ${EndIf} Pop $2 Pop $1 Pop $0 Exch $R0 !macroend !define FindInstallSpecificProfile "!insertmacro FindInstallSpecificProfileMaybeUn ''" !define un.FindInstallSpecificProfile "!insertmacro FindInstallSpecificProfileMaybeUn un." /** * Copy the post-signing data, which was left alongside the installer * by the self-extractor stub, into the installation directory. * * If the post-signing data file doesn't exist, or is empty, "0" is * pushed on the stack, and nothing is copied. * Otherwise the first line of the post-signing data (including newline, * if any) is pushed on the stack. */ !macro CopyPostSigningData !ifndef CopyPostSigningData !verbose push !verbose ${_MOZFUNC_VERBOSE} !define CopyPostSigningData "Call CopyPostSigningData" Function CopyPostSigningData Push $0 ; Stack: old $0 Push $1 ; Stack: $1, old $0 ${LineRead} "$EXEDIR\postSigningData" "1" $0 ${If} ${Errors} ClearErrors StrCpy $0 "0" ${Else} CopyFiles /SILENT "$EXEDIR\postSigningData" "$INSTDIR" ${Endif} Pop $1 ; Stack: old $0 Exch $0 ; Stack: postSigningData FunctionEnd !verbose pop !endif !macroend /** * Copy the zone id provenance data, which was left alongside the installer by * the self-extractor stub, into the installation directory. */ !macro CopyProvenanceData !ifndef CopyProvenanceData !verbose push !verbose ${_MOZFUNC_VERBOSE} !define CopyProvenanceData "Call CopyProvenanceData" Function CopyProvenanceData CopyFiles /SILENT "$EXEDIR\zoneIdProvenanceData" "$INSTDIR" FunctionEnd !verbose pop !endif !macroend ################################################################################ # Helpers for taskbar progress !ifndef CLSCTX_INPROC_SERVER !define CLSCTX_INPROC_SERVER 1 !endif !define CLSID_ITaskbarList {56fdf344-fd6d-11d0-958a-006097c9a090} !define IID_ITaskbarList3 {ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf} !define ITaskbarList3->SetProgressValue $ITaskbarList3->9 !define ITaskbarList3->SetProgressState $ITaskbarList3->10 /** * Creates a single uninitialized object of the ITaskbarList class with a * reference to the ITaskbarList3 interface. This object can be used to set * progress and state on the installer's taskbar icon using the helper macros * in this section. */ !macro ITBL3Create !ifndef ${_MOZFUNC_UN}ITBL3Create Var ITaskbarList3 !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}ITBL3Create "!insertmacro ${_MOZFUNC_UN}ITBL3CreateCall" Function ${_MOZFUNC_UN}ITBL3Create ; Setting to 0 allows the helper macros to detect when the object was not ; created. StrCpy $ITaskbarList3 0 ; Don't create when running silently. ${Unless} ${Silent} ; This is only supported on Win 7 and above. ${If} ${AtLeastWin7} System::Call "ole32::CoCreateInstance(g '${CLSID_ITaskbarList}', \ i 0, \ i ${CLSCTX_INPROC_SERVER}, \ g '${IID_ITaskbarList3}', \ *i .s)" Pop $ITaskbarList3 ${EndIf} ${EndUnless} FunctionEnd !verbose pop !endif !macroend !macro ITBL3CreateCall !verbose push !verbose ${_MOZFUNC_VERBOSE} Call ITBL3Create !verbose pop !macroend !macro un.ITBL3CreateCall _PATH_TO_IMAGE !verbose push !verbose ${_MOZFUNC_VERBOSE} Call un.ITBL3Create !verbose pop !macroend !macro un.ITBL3Create !ifndef un.ITBL3Create !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro ITBL3Create !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Sets the percentage completed on the taskbar process icon progress indicator. * * @param _COMPLETED * The proportion of the operation that has been completed in relation * to _TOTAL. * @param _TOTAL * The value _COMPLETED will have when the operation has completed. * * $R8 = _COMPLETED * $R9 = _TOTAL */ !macro ITBL3SetProgressValueCall _COMPLETED _TOTAL Push ${_COMPLETED} Push ${_TOTAL} ${CallArtificialFunction} ITBL3SetProgressValue_ !macroend !define ITBL3SetProgressValue "!insertmacro ITBL3SetProgressValueCall" !define un.ITBL3SetProgressValue "!insertmacro ITBL3SetProgressValueCall" !macro ITBL3SetProgressValue_ Exch $R9 Exch 1 Exch $R8 ${If} $ITaskbarList3 <> 0 System::Call "${ITaskbarList3->SetProgressValue}(i$HWNDPARENT, l$R8, l$R9)" ${EndIf} Exch $R8 Exch 1 Exch $R9 !macroend ; Normal state / no progress bar !define TBPF_NOPROGRESS 0x00000000 ; Marquee style progress bar !define TBPF_INDETERMINATE 0x00000001 ; Standard progress bar !define TBPF_NORMAL 0x00000002 ; Red taskbar button to indicate an error occurred !define TBPF_ERROR 0x00000004 ; Yellow taskbar button to indicate user attention (input) is required to ; resume progress !define TBPF_PAUSED 0x00000008 /** * Sets the state on the taskbar process icon progress indicator. * * @param _STATE * The state to set on the taskbar icon progress indicator. Only one of * the states defined above should be specified. * * $R9 = _STATE */ !macro ITBL3SetProgressStateCall _STATE Push ${_STATE} ${CallArtificialFunction} ITBL3SetProgressState_ !macroend !define ITBL3SetProgressState "!insertmacro ITBL3SetProgressStateCall" !define un.ITBL3SetProgressState "!insertmacro ITBL3SetProgressStateCall" !macro ITBL3SetProgressState_ Exch $R9 ${If} $ITaskbarList3 <> 0 System::Call "${ITaskbarList3->SetProgressState}(i$HWNDPARENT, i$R9)" ${EndIf} Exch $R9 !macroend ################################################################################ # Helpers for the new user interface !ifndef MAXDWORD !define MAXDWORD 0xffffffff !endif !ifndef DT_WORDBREAK !define DT_WORDBREAK 0x0010 !endif !ifndef DT_SINGLELINE !define DT_SINGLELINE 0x0020 !endif !ifndef DT_NOCLIP !define DT_NOCLIP 0x0100 !endif !ifndef DT_CALCRECT !define DT_CALCRECT 0x0400 !endif !ifndef DT_EDITCONTROL !define DT_EDITCONTROL 0x2000 !endif !ifndef DT_RTLREADING !define DT_RTLREADING 0x00020000 !endif !ifndef DT_NOFULLWIDTHCHARBREAK !define DT_NOFULLWIDTHCHARBREAK 0x00080000 !endif !define /ifndef GWL_STYLE -16 !define /ifndef GWL_EXSTYLE -20 !ifndef WS_EX_NOINHERITLAYOUT !define WS_EX_NOINHERITLAYOUT 0x00100000 !endif !ifndef PBS_MARQUEE !define PBS_MARQUEE 0x08 !endif !ifndef PBM_SETRANGE32 !define PBM_SETRANGE32 0x406 !endif !ifndef PBM_GETRANGE !define PBM_GETRANGE 0x407 !endif !ifndef SHACF_FILESYSTEM !define SHACF_FILESYSTEM 1 !endif !define MOZ_LOADTRANSPARENT ${LR_LOADFROMFILE}|${LR_LOADTRANSPARENT}|${LR_LOADMAP3DCOLORS} ; Extend nsDialogs.nsh to support creating centered labels if it is already ; included !ifmacrodef __NSD_DefineControl !insertmacro __NSD_DefineControl LabelCenter !define __NSD_LabelCenter_CLASS STATIC !define __NSD_LabelCenter_STYLE ${DEFAULT_STYLES}|${SS_NOTIFY}|${SS_CENTER} !define __NSD_LabelCenter_EXSTYLE ${WS_EX_TRANSPARENT} !endif /** * Draws an image file (BMP, GIF, or JPG) onto a bitmap control, with scaling. * Adapted from https://stackoverflow.com/a/13405711/1508094 * * @param CONTROL bitmap control created by NSD_CreateBitmap * @param IMAGE path to image file to draw to the bitmap * @param HANDLE output bitmap handle which must be freed via NSD_FreeImage * after nsDialogs::Show has been called */ !macro __SetStretchedImageOLE CONTROL IMAGE HANDLE !ifndef IID_IPicture !define IID_IPicture {7BF80980-BF32-101A-8BBB-00AA00300CAB} !endif !ifndef SRCCOPY !define SRCCOPY 0xCC0020 !endif !ifndef HALFTONE !define HALFTONE 4 !endif !ifndef IMAGE_BITMAP !define IMAGE_BITMAP 0 !endif Push $0 ; HANDLE Push $1 ; memory DC Push $2 ; IPicture created from IMAGE Push $3 ; HBITMAP obtained from $2 Push $4 ; BITMAPINFO obtained from $3 Push $5 ; width of IMAGE Push $6 ; height of IMAGE Push $7 ; width of CONTROL Push $8 ; height of CONTROL Push $R0 ; CONTROL StrCpy $R0 ${CONTROL} ; in case ${CONTROL} is $0 StrCpy $7 "" StrCpy $8 "" System::Call '*(i, i, i, i) i.s' Pop $0 ${If} $0 <> 0 System::Call 'user32::GetClientRect(i R0, i r0)' System::Call '*$0(i, i, i .s, i .s)' System::Free $0 Pop $7 Pop $8 ${EndIf} ${If} $7 > 0 ${AndIf} $8 > 0 System::Call 'oleaut32::OleLoadPicturePath(w"${IMAGE}",i0,i0,i0,g"${IID_IPicture}",*i.r2)i.r1' ${If} $1 = 0 System::Call 'user32::GetDC(i0)i.s' System::Call 'gdi32::CreateCompatibleDC(iss)i.r1' System::Call 'gdi32::CreateCompatibleBitmap(iss,ir7,ir8)i.r0' System::Call 'user32::ReleaseDC(i0,is)' System::Call '$2->3(*i.r3)i.r4' ; IPicture->get_Handle ${If} $4 = 0 System::Call 'gdi32::SetStretchBltMode(ir1,i${HALFTONE})' System::Call '*(&i40,&i1024)i.r4' ; BITMAP / BITMAPINFO System::Call 'gdi32::GetObject(ir3,i24,ir4)' System::Call 'gdi32::SelectObject(ir1,ir0)i.s' System::Call '*$4(i40,i.r5,i.r6,i0,i,i.s)' ; Grab size and bits-ptr AND init as BITMAPINFOHEADER System::Call 'gdi32::GetDIBits(ir1,ir3,i0,i0,i0,ir4,i0)' ; init BITMAPINFOHEADER System::Call 'gdi32::GetDIBits(ir1,ir3,i0,i0,i0,ir4,i0)' ; init BITMAPINFO System::Call 'gdi32::StretchDIBits(ir1,i0,i0,ir7,ir8,i0,i0,ir5,ir6,is,ir4,i0,i${SRCCOPY})' System::Call 'gdi32::SelectObject(ir1,is)' System::Free $4 SendMessage $R0 ${STM_SETIMAGE} ${IMAGE_BITMAP} $0 ${EndIf} System::Call 'gdi32::DeleteDC(ir1)' System::Call '$2->2()' ; IPicture->release() ${EndIf} ${EndIf} Pop $R0 Pop $8 Pop $7 Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Exch $0 Pop ${HANDLE} !macroend !define SetStretchedImageOLE "!insertmacro __SetStretchedImageOLE" /** * Display a task dialog box with custom strings and button labels. * * The task dialog is highly customizable. The specific style being used here * is similar to a MessageBox except that the button text is customizable. * MessageBox-style buttons are used instead of command link buttons; this can * be made configurable if command buttons are needed. * * See https://msdn.microsoft.com/en-us/library/windows/desktop/bb760544.aspx * for the TaskDialogIndirect function's documentation, and links to definitions * of the TASKDIALOGCONFIG and TASKDIALOG_BUTTON structures it uses. * * @param INSTRUCTION Dialog header string; use empty string if unneeded * @param CONTENT Secondary message string; use empty string if unneeded * @param BUTTON1 Text for the first button, the one selected by default * @param BUTTON2 Text for the second button * * @return One of the following values will be left on the stack: * 1001 if the first button was clicked * 1002 if the second button was clicked * 2 (IDCANCEL) if the dialog was closed * 0 on error */ !macro _ShowTaskDialog INSTRUCTION CONTENT BUTTON1 BUTTON2 !ifndef SIZEOF_TASKDIALOGCONFIG_32BIT !define SIZEOF_TASKDIALOGCONFIG_32BIT 96 !endif !ifndef TDF_ALLOW_DIALOG_CANCELLATION !define TDF_ALLOW_DIALOG_CANCELLATION 0x0008 !endif !ifndef TDF_RTL_LAYOUT !define TDF_RTL_LAYOUT 0x02000 !endif !ifndef TD_WARNING_ICON !define TD_WARNING_ICON 0x0FFFF !endif Push $0 ; return value Push $1 ; TASKDIALOGCONFIG struct Push $2 ; TASKDIALOG_BUTTON array Push $3 ; dwFlags member of the TASKDIALOGCONFIG StrCpy $3 ${TDF_ALLOW_DIALOG_CANCELLATION} !ifdef ${AB_CD}_rtl IntOp $3 $3 | ${TDF_RTL_LAYOUT} !endif ; Build an array of two TASKDIALOG_BUTTON structs System::Call "*(i 1001, \ w '${BUTTON1}', \ i 1002, \ w '${BUTTON2}' \ ) p.r2" ; Build a TASKDIALOGCONFIG struct System::Call "*(i ${SIZEOF_TASKDIALOGCONFIG_32BIT}, \ p $HWNDPARENT, \ p 0, \ i $3, \ i 0, \ w '$(INSTALLER_WIN_CAPTION)', \ p ${TD_WARNING_ICON}, \ w '${INSTRUCTION}', \ w '${CONTENT}', \ i 2, \ p r2, \ i 1001, \ i 0, \ p 0, \ i 0, \ p 0, \ p 0, \ p 0, \ p 0, \ p 0, \ p 0, \ p 0, \ p 0, \ i 0 \ ) p.r1" System::Call "comctl32::TaskDialogIndirect(p r1, *i 0 r0, p 0, p 0)" System::Free $1 System::Free $2 Pop $3 Pop $2 Pop $1 Exch $0 !macroend !define ShowTaskDialog "!insertmacro _ShowTaskDialog" /** * Removes a single style from a control. * * _HANDLE the handle of the control * _STYLE the style to remove */ !macro _RemoveStyle _HANDLE _STYLE Push $0 System::Call 'user32::GetWindowLongW(i ${_HANDLE}, i ${GWL_STYLE}) i .r0' IntOp $0 $0 | ${_STYLE} IntOp $0 $0 - ${_STYLE} System::Call 'user32::SetWindowLongW(i ${_HANDLE}, i ${GWL_STYLE}, i r0)' Pop $0 !macroend !define RemoveStyle "!insertmacro _RemoveStyle" /** * Adds a single extended style to a control. * * _HANDLE the handle of the control * _EXSTYLE the extended style to add */ !macro _AddExStyle _HANDLE _EXSTYLE Push $0 System::Call 'user32::GetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}) i .r0' IntOp $0 $0 | ${_EXSTYLE} System::Call 'user32::SetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}, i r0)' Pop $0 !macroend !define AddExStyle "!insertmacro _AddExStyle" /** * Removes a single extended style from a control. * * _HANDLE the handle of the control * _EXSTYLE the extended style to remove */ !macro _RemoveExStyle _HANDLE _EXSTYLE Push $0 System::Call 'user32::GetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}) i .r0' IntOp $0 $0 | ${_EXSTYLE} IntOp $0 $0 - ${_EXSTYLE} System::Call 'user32::SetWindowLongW(i ${_HANDLE}, i ${GWL_EXSTYLE}, i r0)' Pop $0 !macroend !define RemoveExStyle "!insertmacro _RemoveExStyle" /** * Set the necessary styles to configure the given window as right-to-left * * _HANDLE the handle of the control to configure */ !macro _MakeWindowRTL _HANDLE !define /ifndef WS_EX_RIGHT 0x00001000 !define /ifndef WS_EX_LEFT 0x00000000 !define /ifndef WS_EX_RTLREADING 0x00002000 !define /ifndef WS_EX_LTRREADING 0x00000000 !define /ifndef WS_EX_LAYOUTRTL 0x00400000 ${AddExStyle} ${_HANDLE} ${WS_EX_LAYOUTRTL} ${RemoveExStyle} ${_HANDLE} ${WS_EX_RTLREADING} ${RemoveExStyle} ${_HANDLE} ${WS_EX_RIGHT} ${AddExStyle} ${_HANDLE} ${WS_EX_LEFT}|${WS_EX_LTRREADING} !macroend !define MakeWindowRTL "!insertmacro _MakeWindowRTL" /** * Gets the extent of the specified text in pixels for sizing a control. * * _TEXT the text to get the text extent for * _FONT the font to use when getting the text extent * _RES_WIDTH return value - control width for the text * _RES_HEIGHT return value - control height for the text */ !macro GetTextExtentCall _TEXT _FONT _RES_WIDTH _RES_HEIGHT Push "${_TEXT}" Push "${_FONT}" ${CallArtificialFunction} GetTextExtent_ Pop ${_RES_WIDTH} Pop ${_RES_HEIGHT} !macroend !define GetTextExtent "!insertmacro GetTextExtentCall" !define un.GetTextExtent "!insertmacro GetTextExtentCall" !macro GetTextExtent_ Exch $0 ; font Exch 1 Exch $1 ; text Push $2 Push $3 Push $4 Push $5 Push $6 Push $7 ; Reuse the existing NSIS control which is used for BrandingText instead of ; creating a new control. GetDlgItem $2 $HWNDPARENT 1028 System::Call 'user32::GetDC(i r2) i .r3' System::Call 'gdi32::SelectObject(i r3, i r0)' StrLen $4 "$1" System::Call '*(i, i) i .r5' System::Call 'gdi32::GetTextExtentPoint32W(i r3, t$\"$1$\", i r4, i r5)' System::Call '*$5(i .r6, i .r7)' System::Free $5 System::Call 'user32::ReleaseDC(i r2, i r3)' StrCpy $1 $7 StrCpy $0 $6 Pop $7 Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Exch $1 ; return height Exch 1 Exch $0 ; return width !macroend /** * Gets the width and the height of a control in pixels. * * _HANDLE the handle of the control * _RES_WIDTH return value - control width for the text * _RES_HEIGHT return value - control height for the text */ !macro GetDlgItemWidthHeightCall _HANDLE _RES_WIDTH _RES_HEIGHT Push "${_HANDLE}" ${CallArtificialFunction} GetDlgItemWidthHeight_ Pop ${_RES_WIDTH} Pop ${_RES_HEIGHT} !macroend !define GetDlgItemWidthHeight "!insertmacro GetDlgItemWidthHeightCall" !define un.GetDlgItemWidthHeight "!insertmacro GetDlgItemWidthHeightCall" !macro GetDlgItemWidthHeight_ Exch $0 ; handle for the control Push $1 Push $2 System::Call '*(i, i, i, i) i .r2' ; The left and top values will always be 0 so the right and bottom values ; will be the width and height. System::Call 'user32::GetClientRect(i r0, i r2)' System::Call '*$2(i, i, i .r0, i .r1)' System::Free $2 Pop $2 Exch $1 ; return height Exch 1 Exch $0 ; return width !macroend /** * Gets the number of pixels from the beginning of the dialog to the end of a * control in a RTL friendly manner. * * _HANDLE the handle of the control * _RES_PX return value - pixels from the beginning of the dialog to the end of * the control */ !macro GetDlgItemEndPXCall _HANDLE _RES_PX Push "${_HANDLE}" ${CallArtificialFunction} GetDlgItemEndPX_ Pop ${_RES_PX} !macroend !define GetDlgItemEndPX "!insertmacro GetDlgItemEndPXCall" !define un.GetDlgItemEndPX "!insertmacro GetDlgItemEndPXCall" !macro GetDlgItemEndPX_ Exch $0 ; handle of the control Push $1 Push $2 ; #32770 is the dialog class FindWindow $1 "#32770" "" $HWNDPARENT System::Call '*(i, i, i, i) i .r2' System::Call 'user32::GetWindowRect(i r0, i r2)' System::Call 'user32::MapWindowPoints(i 0, i r1,i r2, i 2)' System::Call '*$2(i, i, i .r0, i)' System::Free $2 Pop $2 Pop $1 Exch $0 ; pixels from the beginning of the dialog to the end of the control !macroend /** * Gets the number of pixels from the top of a dialog to the bottom of a control * * _CONTROL the handle of the control * _RES_PX return value - pixels from the top of the dialog to the bottom * of the control */ !macro GetDlgItemBottomPXCall _CONTROL _RES_PX Push "${_CONTROL}" ${CallArtificialFunction} GetDlgItemBottomPX_ Pop ${_RES_PX} !macroend !define GetDlgItemBottomPX "!insertmacro GetDlgItemBottomPXCall" !define un.GetDlgItemBottomPX "!insertmacro GetDlgItemBottomPXCall" !macro GetDlgItemBottomPX_ Exch $0 ; handle of the control Push $1 Push $2 ; #32770 is the dialog class FindWindow $1 "#32770" "" $HWNDPARENT System::Call '*(i, i, i, i) i .r2' System::Call 'user32::GetWindowRect(i r0, i r2)' System::Call 'user32::MapWindowPoints(i 0, i r1, i r2, i 2)' System::Call '*$2(i, i, i, i .r0)' System::Free $2 Pop $2 Pop $1 Exch $0 ; pixels from the top of the dialog to the bottom of the control !macroend /** * Gets the width and height for sizing a control that has the specified text. * The control's height and width will be dynamically determined for the maximum * width specified. * * _TEXT the text * _FONT the font to use when getting the width and height * _MAX_WIDTH the maximum width for the control in pixels * _RES_WIDTH return value - control width for the text in pixels. * This might be larger than _MAX_WIDTH if that constraint couldn't * be satisfied, e.g. a single word that couldn't be broken up is * longer than _MAX_WIDTH by itself. * _RES_HEIGHT return value - control height for the text in pixels */ !macro GetTextWidthHeight !ifndef ${_MOZFUNC_UN}GetTextWidthHeight !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} !insertmacro ${_MOZFUNC_UN_TMP}WordFind !undef _MOZFUNC_UN !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} !undef _MOZFUNC_UN_TMP !verbose push !verbose ${_MOZFUNC_VERBOSE} !define ${_MOZFUNC_UN}GetTextWidthHeight "!insertmacro ${_MOZFUNC_UN}GetTextWidthHeightCall" Function ${_MOZFUNC_UN}GetTextWidthHeight ; Stack contents after each instruction (top of the stack on the left): ; _MAX_WIDTH _FONT _TEXT Exch $0 ; $0 _FONT _TEXT Exch 1 ; _FONT $0 _TEXT Exch $1 ; $1 $0 _TEXT Exch 2 ; _TEXT $0 $1 Exch $2 ; $2 $0 $1 ; That's all the parameters, now save our scratch registers. Push $3 ; handle to a temporary control for drawing the text into Push $4 ; DC handle Push $5 ; string length of the text argument Push $6 ; RECT struct to call DrawText with Push $7 ; width returned from DrawText Push $8 ; height returned from DrawText Push $9 ; flags to pass to DrawText StrCpy $9 "${DT_NOCLIP}|${DT_CALCRECT}|${DT_WORDBREAK}" !ifdef ${AB_CD}_rtl StrCpy $9 "$9|${DT_RTLREADING}" !endif ; Reuse the existing NSIS control which is used for BrandingText instead ; of creating a new control. GetDlgItem $3 $HWNDPARENT 1028 System::Call 'user32::GetDC(i r3) i .r4' System::Call 'gdi32::SelectObject(i r4, i r1)' StrLen $5 "$2" ; text length System::Call '*(i, i, i r0, i) i .r6' System::Call 'user32::DrawTextW(i r4, t $\"$2$\", i r5, i r6, i r9)' System::Call '*$6(i, i, i .r7, i .r8)' System::Free $6 System::Call 'user32::ReleaseDC(i r3, i r4)' StrCpy $1 $8 StrCpy $0 $7 ; Restore the values that were in our scratch registers. Pop $9 Pop $8 Pop $7 Pop $6 Pop $5 Pop $4 Pop $3 ; Restore our parameter registers and return our results. ; Stack contents after each instruction (top of the stack on the left): ; $2 $0 $1 Pop $2 ; $0 $1 Exch 1 ; $1 $0 Exch $1 ; _RES_HEIGHT $0 Exch 1 ; $0 _RES_HEIGHT Exch $0 ; _RES_WIDTH _RES_HEIGHT FunctionEnd !verbose pop !endif !macroend !macro GetTextWidthHeightCall _TEXT _FONT _MAX_WIDTH _RES_WIDTH _RES_HEIGHT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_TEXT}" Push "${_FONT}" Push "${_MAX_WIDTH}" Call GetTextWidthHeight Pop ${_RES_WIDTH} Pop ${_RES_HEIGHT} !verbose pop !macroend !macro un.GetTextWidthHeightCall _TEXT _FONT _MAX_WIDTH _RES_WIDTH _RES_HEIGHT !verbose push !verbose ${_MOZFUNC_VERBOSE} Push "${_TEXT}" Push "${_FONT}" Push "${_MAX_WIDTH}" Call un.GetTextWidthHeight Pop ${_RES_WIDTH} Pop ${_RES_HEIGHT} !verbose pop !macroend !macro un.GetTextWidthHeight !ifndef un.GetTextWidthHeight !verbose push !verbose ${_MOZFUNC_VERBOSE} !undef _MOZFUNC_UN !define _MOZFUNC_UN "un." !insertmacro GetTextWidthHeight !undef _MOZFUNC_UN !define _MOZFUNC_UN !verbose pop !endif !macroend /** * Convert a number of dialog units to a number of pixels. * * _DU Number of dialog units to convert * _AXIS Which axis you want to convert a value along, X or Y * _RV Register or variable to return the number of pixels in */ !macro _DialogUnitsToPixels _DU _AXIS _RV Push $0 Push $1 ; The dialog units value might be a string ending with a 'u', ; so convert it to a number. IntOp $0 "${_DU}" + 0 !if ${_AXIS} == 'Y' System::Call '*(i 0, i 0, i 0, i r0) i .r1' System::Call 'user32::MapDialogRect(p $HWNDPARENT, p r1)' System::Call '*$1(i, i, i, i . r0)' !else if ${_AXIS} == 'X' System::Call '*(i 0, i 0, i r0, i 0) i .r1' System::Call 'user32::MapDialogRect(p $HWNDPARENT, p r1)' System::Call '*$1(i, i, i . r0, i)' !else !error "Invalid axis ${_AXIS} passed to DialogUnitsToPixels; please use X or Y" !endif System::Free $1 Pop $1 Exch $0 Pop ${_RV} !macroend !define DialogUnitsToPixels "!insertmacro _DialogUnitsToPixels" /** * Convert a given left coordinate for a dialog control to flip the control to * the other side of the dialog if we're using an RTL locale. * * _LEFT_DU Number of dialog units to convert * _WIDTH Width of the control in either pixels or DU's * If the string has a 'u' on the end, it will be interpreted as * dialog units, otherwise it will be interpreted as pixels. * _RV Register or variable to return converted coordinate, in pixels */ !macro _ConvertLeftCoordForRTLCall _LEFT_DU _WIDTH _RV Push "${_LEFT_DU}" Push "${_WIDTH}" ${CallArtificialFunction} _ConvertLeftCoordForRTL Pop ${_RV} !macroend !define ConvertLeftCoordForRTL "!insertmacro _ConvertLeftCoordForRTLCall" !define un.ConvertLeftCoordForRTL "!insertmacro _ConvertLeftCoordForRTLCall" !macro _ConvertLeftCoordForRTL ; Stack contents after each instruction (top of the stack on the left): ; _WIDTH _LEFT_DU Exch $0 ; $0 _LEFT_DU Exch 1 ; _LEFT_DU $0 Exch $1 ; $1 $0 ; That's all the parameters, now save our scratch registers. Push $2 ; width of the entire dialog, in pixels Push $3 ; _LEFT_DU converted to pixels Push $4 ; temp string search result !ifndef ${AB_CD}_rtl StrCpy $0 "$1" !else ${GetDlgItemWidthHeight} $HWNDPARENT $2 $3 ${DialogUnitsToPixels} $1 X $3 ClearErrors ${${_MOZFUNC_UN}WordFind} "$0" "u" "E+1{" $4 ${IfNot} ${Errors} ${DialogUnitsToPixels} $4 X $0 ${EndIf} IntOp $1 $2 - $3 IntOp $1 $1 - $0 StrCpy $0 $1 !endif ; Restore the values that were in our scratch registers. Pop $4 Pop $3 Pop $2 ; Restore our parameter registers and return our result. ; Stack contents after each instruction (top of the stack on the left): ; $1 $0 Pop $1 ; $0 Exch $0 ; _RV !macroend /** * Gets the elapsed time in seconds between two values in milliseconds stored as * an int64. The caller will typically get the millisecond values using * GetTickCount with a long return value as follows. * System::Call "kernel32::GetTickCount()l .s" * Pop $varname * * _START_TICK_COUNT * _FINISH_TICK_COUNT * _RES_ELAPSED_SECONDS return value - elapsed time between _START_TICK_COUNT * and _FINISH_TICK_COUNT in seconds. */ !macro GetSecondsElapsedCall _START_TICK_COUNT _FINISH_TICK_COUNT _RES_ELAPSED_SECONDS Push "${_START_TICK_COUNT}" Push "${_FINISH_TICK_COUNT}" ${CallArtificialFunction} GetSecondsElapsed_ Pop ${_RES_ELAPSED_SECONDS} !macroend !define GetSecondsElapsed "!insertmacro GetSecondsElapsedCall" !define un.GetSecondsElapsed "!insertmacro GetSecondsElapsedCall" !macro GetSecondsElapsed_ Exch $0 ; finish tick count Exch 1 Exch $1 ; start tick count System::Int64Op $0 - $1 Pop $0 ; Discard the top bits of the int64 by bitmasking with MAXDWORD System::Int64Op $0 & ${MAXDWORD} Pop $0 ; Convert from milliseconds to seconds System::Int64Op $0 / 1000 Pop $0 Pop $1 Exch $0 ; return elapsed seconds !macroend /** * Create a process to execute a command line. If it is successfully created, * wait on it with WaitForInputIdle, to avoid exiting the current process too * early (exiting early can cause the created process's windows to be opened in * the background). * * CMDLINE Is the command line to execute, like the argument to Exec */ !define ExecAndWaitForInputIdle "!insertmacro ExecAndWaitForInputIdle_" !define CREATE_DEFAULT_ERROR_MODE 0x04000000 !macro ExecAndWaitForInputIdle_ CMDLINE ; derived from https://stackoverflow.com/a/13960786/3444805 by Anders Kjersem Push $0 Push $1 Push $2 ; Command line StrCpy $0 "${CMDLINE}" ; STARTUPINFO System::Alloc 68 Pop $1 ; fill in STARTUPINFO.cb (first field) with sizeof(STARTUPINFO) System::Call "*$1(i 68)" ; PROCESS_INFORMATION System::Call "*(i, i, i, i) i . r2" ; CREATE_DEFAULT_ERROR_MODE follows NSIS myCreateProcess used in Exec System::Call "kernel32::CreateProcessW(i 0, t r0, i 0, i 0, i 0, i ${CREATE_DEFAULT_ERROR_MODE}, i 0, i 0, i r1, i r2) i . r0" System::Free $1 ${If} $0 <> 0 System::Call "*$2(i . r0, i . r1)" ; $0: hProcess, $1: hThread System::Call "user32::WaitForInputIdle(i $0, i 10000)" System::Call "kernel32::CloseHandle(i $0)" System::Call "kernel32::CloseHandle(i $1)" ${EndIf} System::Free $2 Pop $2 Pop $1 Pop $0 !macroend Function WriteRegQWORD ; Stack contents: ; VALUE, VALUE_NAME, SUBKEY, ROOTKEY Exch $3 ; $3, VALUE_NAME, SUBKEY, ROOTKEY Exch 1 ; VALUE_NAME, $3, SUBKEY, ROOTKEY Exch $2 ; $2, $3, SUBKEY, ROOTKEY Exch 2 ; SUBKEY, $3, $2, ROOTKEY Exch $1 ; $1, $3, $2, ROOTKEY Exch 3 ; ROOTKEY, $3, $2, $1 Exch $0 ; $0, $3, $2, $1 System::Call "advapi32::RegSetKeyValueW(p r0, w r1, w r2, i 11, *l r3, i 8) i.r0" ${IfNot} $0 = 0 SetErrors ${EndIf} Pop $0 Pop $3 Pop $2 Pop $1 FunctionEnd !macro WriteRegQWORD ROOTKEY SUBKEY VALUE_NAME VALUE ${If} "${ROOTKEY}" == "HKCR" Push 0x80000000 ${ElseIf} "${ROOTKEY}" == "HKCU" Push 0x80000001 ${ElseIf} "${ROOTKEY}" == "HKLM" Push 0x80000002 ${Endif} Push "${SUBKEY}" Push "${VALUE_NAME}" System::Int64Op ${VALUE} + 0 ; The result is pushed on the stack Call WriteRegQWORD !macroend !define WriteRegQWORD "!insertmacro WriteRegQWORD" Function ReadRegQWORD ; Stack contents: ; VALUE_NAME, SUBKEY, ROOTKEY Exch $2 ; $2, SUBKEY, ROOTKEY Exch 1 ; SUBKEY, $2, ROOTKEY Exch $1 ; $1, $2, ROOTKEY Exch 2 ; ROOTKEY, $2, $1 Exch $0 ; $0, $2, $1 System::Call "advapi32::RegGetValueW(p r0, w r1, w r2, i 0x48, p 0, *l s, *i 8) i.r0" ${IfNot} $0 = 0 SetErrors ${EndIf} ; VALUE, $0, $2, $1 Exch 3 ; $1, $0, $2, VALUE Pop $1 ; $0, $2, VALUE Pop $0 ; $2, VALUE Pop $2 ; VALUE FunctionEnd !macro ReadRegQWORD DEST ROOTKEY SUBKEY VALUE_NAME ${If} "${ROOTKEY}" == "HKCR" Push 0x80000000 ${ElseIf} "${ROOTKEY}" == "HKCU" Push 0x80000001 ${ElseIf} "${ROOTKEY}" == "HKLM" Push 0x80000002 ${Endif} Push "${SUBKEY}" Push "${VALUE_NAME}" Call ReadRegQWORD Pop ${DEST} !macroend !define ReadRegQWORD "!insertmacro ReadRegQWORD"