Source code
Revision control
Copy as Markdown
Other Tools
# 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↩
↩
!ifndef UNINSTALLER_HELPERS_NSH↩
!define UNINSTALLER_HELPERS_NSH↩
↩
!include get_installation_type.nsh↩
↩
/**↩
* 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}↩
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 hideshortcuts↩
↩
; 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 PostUpdate↩
${CreateShortcutsLog}↩
↩
; Remove registry entries for non-existent apps and for apps that point to our↩
; install location in the Software\Mozilla key and uninstall registry entries↩
; that point to our install location for both HKCU and HKLM.↩
SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU)↩
${RegCleanMain} "Software\Mozilla"↩
${RegCleanUninstall}↩
${UpdateProtocolHandlers}↩
↩
; setup the application model id registration value↩
${InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs"↩
↩
ClearErrors↩
WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" "Write Test"↩
${If} ${Errors}↩
StrCpy $RegHive "HKCU"↩
${Else}↩
SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM)↩
DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"↩
StrCpy $RegHive "HKLM"↩
${RegCleanMain} "Software\Mozilla"↩
${RegCleanUninstall}↩
${UpdateProtocolHandlers}↩
${FixShellIconHandler} "HKLM"↩
${SetAppLSPCategories} ${LSP_CATEGORIES}↩
↩
; Add the Firewall entries after an update↩
Call AddFirewallEntries↩
↩
ReadRegStr $0 HKLM "Software\mozilla.org\Mozilla" "CurrentVersion"↩
${If} "$0" != "${GREVersion}"↩
WriteRegStr HKLM "Software\mozilla.org\Mozilla" "CurrentVersion" "${GREVersion}"↩
${EndIf}↩
${EndIf}↩
↩
!ifdef DESKTOP_LAUNCHER_ENABLED↩
Call OnUpdateDesktopLauncherHandler↩
!endif↩
↩
; Update the name/icon/AppModelID of our shortcuts as needed, then update the↩
; lastwritetime of the Start Menu shortcut to clear the tile icon cache.↩
; Do this for both shell contexts in case the user has shortcuts in multiple↩
; locations, then restore the previous context at the end.↩
SetShellVarContext all↩
${UpdateShortcutsBranding}↩
${TouchStartMenuShortcut}↩
Call FixShortcutAppModelIDs↩
SetShellVarContext current↩
${UpdateShortcutsBranding}↩
${TouchStartMenuShortcut}↩
Call FixShortcutAppModelIDs↩
${If} $RegHive == "HKLM"↩
SetShellVarContext all↩
${ElseIf} $RegHive == "HKCU"↩
SetShellVarContext current↩
${EndIf}↩
↩
${RemoveDeprecatedKeys}↩
${Set32to64DidMigrateReg}↩
↩
${SetAppKeys}↩
${FixClassKeys}↩
${SetUninstallKeys}↩
${If} $RegHive == "HKLM"↩
${SetStartMenuInternet} HKLM↩
${ElseIf} $RegHive == "HKCU"↩
${SetStartMenuInternet} HKCU↩
${EndIf}↩
↩
; Remove files that may be left behind by the application in the↩
; VirtualStore directory.↩
${CleanVirtualStore}↩
↩
${RemoveDeprecatedFiles}↩
↩
; Fix the distribution.ini file if applicable↩
${FixDistributionsINI}↩
↩
; Migrate postSigningData file if present, and if it doesn't already exist.↩
${GetLocalAppDataFolder} $0↩
${If} ${FileExists} "$INSTDIR\postSigningData"↩
; If it already exists, just delete the appdata one.↩
; It's possible this was for a different install, but it's impossible to↩
; know for sure, so we may as well just get rid of it.↩
Delete /REBOOTOK "$0\Mozilla\Firefox\postSigningData"↩
${Else}↩
${If} ${FileExists} "$0\Mozilla\Firefox\postSigningData"↩
Rename "$0\Mozilla\Firefox\postSigningData" "$INSTDIR\postSigningData"↩
${EndIf}↩
${EndIf}↩
↩
RmDir /r /REBOOTOK "$INSTDIR\${TO_BE_DELETED}"↩
↩
; Register AccessibleMarshal.dll with COM (this requires write access to HKLM)↩
${RegisterAccessibleMarshal}↩
↩
; Record the Windows Error Reporting module↩
WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\Windows Error Reporting\RuntimeExceptionHelperModules" "$INSTDIR\mozwer.dll" 0↩
↩
; Apply LPAC permissions to install directory.↩
Push "Marker"↩
AccessControl::GrantOnFile \↩
"$INSTDIR" "(${LpacFirefoxInstallFilesSid})" "GenericRead + GenericExecute"↩
Pop $TmpVal ; get "Marker" or error msg↩
${If} $TmpVal != "Marker"↩
Pop $TmpVal ; get "Marker"↩
${EndIf}↩
↩
!ifdef MOZ_MAINTENANCE_SERVICE↩
Call IsUserAdmin↩
Pop $R0↩
${If} $R0 == "true"↩
; Only proceed if we have HKLM write access↩
${AndIf} $RegHive == "HKLM"↩
; We check to see if the maintenance service install was already attempted.↩
; Since the Maintenance service can be installed either x86 or x64,↩
; always use the 64-bit registry for checking if an attempt was made.↩
${If} ${RunningX64}↩
${OrIf} ${IsNativeARM64}↩
SetRegView 64↩
${EndIf}↩
ReadRegDWORD $5 HKLM "Software\Mozilla\MaintenanceService" "Attempted"↩
ClearErrors↩
${If} ${RunningX64}↩
${OrIf} ${IsNativeARM64}↩
SetRegView lastused↩
${EndIf}↩
↩
; Add the registry keys for allowed certificates.↩
${AddMaintCertKeys}↩
↩
; If the maintenance service is already installed, do nothing.↩
; The maintenance service will launch:↩
; maintenanceservice_installer.exe /Upgrade to upgrade the maintenance↩
; service if necessary. If the update was done from updater.exe without↩
; the service (i.e. service is failing), updater.exe will do the update of↩
; the service. The reasons we do not do it here is because we don't want↩
; to have to prompt for limited user accounts when the service isn't used↩
; and we currently call the PostUpdate twice, once for the user and once↩
; for the SYSTEM account. Also, this would stop the maintenance service↩
; and we need a return result back to the service when run that way.↩
${If} $5 == ""↩
; An install of maintenance service was never attempted.↩
; We know we are an Admin and that we have write access into HKLM↩
; based on the above checks, so attempt to just run the EXE.↩
; In the worst case, in case there is some edge case with the↩
; IsAdmin check and the permissions check, the maintenance service↩
; will just fail to be attempted to be installed.↩
nsExec::Exec "$\"$INSTDIR\maintenanceservice_installer.exe$\""↩
${EndIf}↩
${EndIf}↩
!endif↩
↩
!ifdef MOZ_LAUNCHER_PROCESS↩
${ResetLauncherProcessDefaults}↩
!endif↩
↩
${WriteToastNotificationRegistration} $RegHive↩
↩
; Make sure the scheduled task registration for the default browser agent gets↩
; updated, but only if we're not the instance of PostUpdate that was started↩
; by the service, because this needs to run as the actual user. Also, don't do↩
; that if the installer was told not to register the agent task at all.↩
; XXXbytesized - This also needs to un-register any scheduled tasks for the WDBA↩
; that were registered using elevation, but currently it does↩
; not. See Bugs 1638509 and 1902719.↩
!ifdef MOZ_DEFAULT_BROWSER_AGENT↩
${If} $RegHive == "HKCU"↩
ClearErrors↩
ReadRegDWORD $0 HKCU "Software\Mozilla\${AppName}\Installer\$AppUserModelID" \↩
"DidRegisterDefaultBrowserAgent"↩
${If} $0 != 0↩
${OrIf} ${Errors}↩
ExecWait '"$INSTDIR\default-browser-agent.exe" register-task $AppUserModelID'↩
${EndIf}↩
${EndIf}↩
!endif↩
↩
${RemoveDefaultBrowserAgentShortcut}↩
!macroend↩
!define PostUpdate "!insertmacro PostUpdate"↩
↩
Function OnUpdateDesktopLauncherHandler↩
Push $0↩
Push "$INSTDIR\installation_telemetry.json"↩
Call GetInstallationType↩
; Pop the result from the stack into $0↩
Pop $0↩
${If} $0 == "stub"↩
${If} $RegHive == "HKLM"↩
SetShellVarContext all↩
Call OnUpdateDesktopLauncher_HKLM↩
${Else}↩
SetShellVarContext current↩
Call OnUpdateDesktopLauncher_HKCU↩
${EndIf}↩
${EndIf}↩
; Restore $0 to its original value↩
Pop $0↩
FunctionEnd↩
↩
Function OnUpdateDesktopLauncher_HKLM↩
; This is elevated. In this instance, we won't be installing the desktop launcher, but we may be deleting the shared shortcut↩
Push $0↩
Push $1↩
; Have we deleted the shared shortcut before?↩
StrCpy $0 "0"↩
ReadRegDWORD $0 HKLM "Software\Mozilla\${BrandFullNameInternal}" "UpdaterDeletedShortcut"↩
Call IsDesktopShortcutPresent↩
Pop $1↩
${If} $0 != "1"↩
${AndIf} $1 != "0"↩
; shared shortcut exists, and we haven't deleted it before. So let's delete it now.↩
Delete "$DESKTOP\${BrandShortName}.lnk"↩
WriteRegDWORD HKLM "Software\Mozilla\${BrandFullNameInternal}" "UpdaterDeletedShortcut" "1"↩
${EndIf}↩
Pop $1↩
Pop $0↩
FunctionEnd↩
↩
Function OnUpdateDesktopLauncher_HKCU↩
; If there is a desktop launcher installed, call InstallDesktopLauncher (this is how the launcher gets updated)↩
${If} ${FileExists} "$DESKTOP\${BrandShortName}.exe"↩
Call InstallDesktopLauncher↩
; Early return↩
Return↩
${EndIf}↩
↩
Push $0↩
Push $1↩
Push $2↩
Push $3↩
↩
; $0 is 1 if a shortcut is found in user's desktop or 0 otherwise↩
StrCpy $0 "0"↩
; $1 is 1 if there was a "recently deleted" shortcut or 0 otherwise↩
StrCpy $1 "0"↩
; $2 is 1 if the desktop launcher was ever installed or 0 otherwise↩
StrCpy $2 "0"↩
; $3 is 1 if a shortcut is found in shared desktop or 0 otherwise↩
StrCpy $3 "0"↩
↩
; see if there is a shortcut on the user's own desktop↩
Call IsDesktopShortcutPresent↩
Pop $0↩
↩
; see if there is a shortcut in the shared desktop folder↩
SetShellVarContext all↩
Call IsDesktopShortcutPresent↩
Pop $3↩
SetShellVarContext current↩
↩
ReadRegDWORD $1 HKLM "Software\Mozilla\${BrandFullNameInternal}" "UpdaterDeletedShortcut"↩
ReadRegDWORD $2 HKCU "Software\Mozilla\${BrandFullNameInternal}" "DesktopLauncherAppInstalled"↩
↩
${If} $2 == "1"↩
; We previously installed desktop launcher. Don't reinstall↩
${ElseIf} $0 == "1"↩
; There was a shortcut on the user's desktop. Delete it and install launcher↩
Delete "$DESKTOP\${BrandShortName}.lnk"↩
Call InstallDesktopLauncher↩
${ElseIf} $1 == "1"↩
${OrIf} $3 == "1"↩
; This block covers these two cases:↩
; - If the elevated post-update script runs before the unelevated one, then it will have deleted the shortcut and set the UpdaterDeletedShortcut regkey.↩
; - Or, if the unelevated script is running now befor the elevated one, then there will still be a shortcut in the shared location.↩
; In either case, we need to install the desktop launcher now. It's the responsibility of the elevated post-update script to delete↩
; the shared shortcut, and that is implemented in OnUpdateDesktopLauncher_HKLM↩
Call InstallDesktopLauncher↩
${EndIf}↩
Pop $3↩
Pop $2↩
Pop $1↩
Pop $0↩
FunctionEnd↩
↩
; Looks for the desktop shortcut (.lnk) in the $DESKTOP directory↩
; relative to the shell var context. Caller is expected to call↩
; SetShellVarContext to set the shell var context.↩
; Args: none↩
; Return value is pushed onto the stack: "1" if the shortcut↩
; is found, "0" otherwise↩
Function IsDesktopShortcutPresent↩
Push $0 ; will be used to store the result↩
Push $1 ; will be used as a temp variable↩
StrCpy $0 "0"↩
↩
${If} ${FileExists} "$DESKTOP\${BrandShortName}.lnk"↩
ShellLink::GetShortCutArgs "$DESKTOP\${BrandShortName}.lnk"↩
Pop $1↩
${If} "$1" == ""↩
; Let's see if we can find out anything about the shortcut↩
ShellLink::GetShortCutTarget "$DESKTOP\${BrandShortName}.lnk"↩
Pop $1↩
${GetLongPath} "$1" $1↩
${If} "$1" == "$INSTDIR\${FileMainEXE}"↩
; We had permission to look at the shortcut properties and its target was the Firefox executable↩
StrCpy $0 "1" ; set the result to 1↩
${ElseIf} "$1" == ""↩
; Most likely case is that we don't have permission to read the shortcut properties, so just report that it exists↩
StrCpy $0 "1" ; set the result to 1↩
${EndIf}↩
${EndIf}↩
${EndIf}↩
Pop $1 ; restore the register↩
Exch $0 ; restore the register and place result on the stack↩
FunctionEnd↩
↩
!endif↩