Win32 only - Bug 369221: Fails to install with xpicleanup error message. r=sspitzer, sr=mscott for Thunderbird
authorrob_strong@exchangecode.com
Thu, 03 May 2007 16:40:54 -0700
changeset 1069 34dcf8e94bdbe8a1162f376fd0bdc32773651b6b
parent 1068 d300d6434463bc88dcda787de75e4a22eb125f2a
child 1070 e50c429c224caae705742cfcf1d38c572c554fd0
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssspitzer, mscott
bugs369221
milestone1.9a5pre
Win32 only - Bug 369221: Fails to install with xpicleanup error message. r=sspitzer, sr=mscott for Thunderbird
browser/installer/windows/nsis/installer.nsi
toolkit/mozapps/installer/windows/nsis/common.nsh
--- a/browser/installer/windows/nsis/installer.nsi
+++ b/browser/installer/windows/nsis/installer.nsi
@@ -102,17 +102,16 @@ VIAddVersionKey "FileDescription" "${Bra
 !insertmacro RegCleanUninstall
 !insertmacro CloseApp
 !insertmacro WriteRegStr2
 !insertmacro WriteRegDWORD2
 !insertmacro CreateRegKey
 !insertmacro CanWriteToInstallDir
 !insertmacro CheckDiskSpace
 !insertmacro AddHandlerValues
-!insertmacro DisplayCopyErrMsg
 
 !include shared.nsh
 
 Name "${BrandFullName}"
 OutFile "setup.exe"
 InstallDirRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} (${AppVersion})" "InstallLocation"
 InstallDir "$PROGRAMFILES\${BrandFullName}\"
 ShowInstDetails nevershow
@@ -188,47 +187,67 @@ Page custom preShortcuts leaveShortcuts
 ################################################################################
 # Install Sections
 
 Section "-Application" Section1
   SectionIn 1 RO
   SetDetailsPrint textonly
   DetailPrint $(STATUS_CLEANUP)
   SetDetailsPrint none
-  SetOutPath $INSTDIR
 
   ; Try to delete the app's main executable and if we can't delete it try to
   ; close the app. This allows running an instance that is located in another
   ; directory and prevents the launching of the app during the installation.
-  ClearErrors
+  ; A copy of the executable is placed in a temporary directory so it can be
+  ; copied back in the case where a specific file is checked / found to be in
+  ; use that would prevent a successful install.
+
+  ; Create a temporary backup directory.
+  GetTempFileName $TmpVal "$TEMP"
+  ${DeleteFile} $TmpVal
+  SetOutPath $TmpVal
+
   ${If} ${FileExists} "$INSTDIR\${FileMainEXE}"
-    ${DeleteFile} "$INSTDIR\${FileMainEXE}"
-  ${EndIf}
-  ${If} ${Errors}
     ClearErrors
-    ${CloseApp} "true" $(WARN_APP_RUNNING_INSTALL)
-    ; Try to delete it again to prevent launching the app while we are
-    ; installing.
-    ClearErrors
-    ${DeleteFile} "$INSTDIR\${FileMainEXE}"
+    CopyFiles /SILENT "$INSTDIR\${FileMainEXE}" "$TmpVal\${FileMainEXE}"
+    Delete "$INSTDIR\${FileMainEXE}"
     ${If} ${Errors}
       ClearErrors
-      ; Try closing the app a second time
       ${CloseApp} "true" $(WARN_APP_RUNNING_INSTALL)
-      retry:
+      ; Try to delete it again to prevent launching the app while we are
+      ; installing.
       ClearErrors
-      ${DeleteFile} "$INSTDIR\${FileMainEXE}"
+      CopyFiles /SILENT "$INSTDIR\${FileMainEXE}" "$TmpVal\${FileMainEXE}"
+      Delete "$INSTDIR\${FileMainEXE}"
       ${If} ${Errors}
-        ; Fallback to the FileError_NoIgnore error with retry/cancel options
-        ${DisplayCopyErrMsg} "${FileMainEXE}"
-        GoTo retry
+        ClearErrors
+        ; Try closing the app a second time
+        ${CloseApp} "true" $(WARN_APP_RUNNING_INSTALL)
+        StrCpy $R1 "${FileMainEXE}"
+        Call CheckInUse
       ${EndIf}
     ${EndIf}
   ${EndIf}
 
+  StrCpy $R1 "freebl3.dll"
+  Call CheckInUse
+
+  StrCpy $R1 "nssckbi.dll"
+  Call CheckInUse
+
+  StrCpy $R1 "nspr4.dll"
+  Call CheckInUse
+
+  StrCpy $R1 "xpicleanup.exe"
+  Call CheckInUse
+
+  SetOutPath $INSTDIR
+  RmDir /r "$TmpVal"
+  ClearErrors
+
   ; During an install Vista checks if a new entry is added under the uninstall
   ; registry key (e.g. ARP). When the same version of the app is installed on
   ; top of an existing install the key is deleted / added and the Program
   ; Compatibility Assistant doesn't see this as a new entry and displays an
   ; error to the user. See Bug 354000.
   StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} (${AppVersion})"
   DeleteRegKey HKLM "$0"
 
@@ -539,17 +558,17 @@ Function installTalkback
     DetailPrint $(STATUS_INSTALL_OPTIONAL)
     SetDetailsPrint none
     StrCpy $R1 "$INSTDIR\extensions\talkback@mozilla.org"
     ${If} ${FileExists} "$R1"
       ; If there is an existing InstallDisabled file copy it to the source dir.
       ; This will add it during install to the uninstall.log and retains the
       ; original disabled state from the installation.
       ${If} ${FileExists} "$R1\InstallDisabled"
-        CopyFiles "$R1\InstallDisabled" "$R0"
+        CopyFiles /SILENT "$R1\InstallDisabled" "$R0"
       ${EndIf}
       ; Remove the existing install of talkback
       RmDir /r "$R1"
     ${ElseIf} $InstallType == 1
       ; For standard installations only enable talkback for the x percent as
       ; defined by the application. We use QueryPerformanceCounter for the seed
       ; since it returns a 64bit integer which should improve the accuracy.
       System::Call "kernel32::QueryPerformanceCounter(*l.r1)"
@@ -564,16 +583,41 @@ Function installTalkback
       ${EndIf}
     ${EndIf}
     ClearErrors
     ${LogHeader} "Installing Quality Feedback Agent"
     Call DoCopyFiles
   ${EndIf}
 FunctionEnd
 
+; Copies a file to a temporary backup directory and then checks if it is in use
+; by attempting to delete the file. If the file is in use an error is displayed
+; and the user is given the options to either retry or cancel. If cancel is
+; selected then the files are restored.
+Function CheckInUse
+  ${If} ${FileExists} "$INSTDIR\$R1"
+    retry:
+    ClearErrors
+    CopyFiles /SILENT "$INSTDIR\$R1" "$TmpVal\$R1"
+    ${Unless} ${Errors}
+      Delete "$INSTDIR\$R1"
+    ${EndUnless}
+    ${If} ${Errors}
+      StrCpy $0 "$INSTDIR\$R1"
+      ${WordReplace} "$(^FileError_NoIgnore)" "\r\n" "$\r$\n" "+*" $0
+      MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$0" IDRETRY retry
+      Delete "$TmpVal\$R1"
+      CopyFiles /SILENT "$TmpVal\*" "$INSTDIR\"
+      SetOutPath $INSTDIR
+      RmDir /r "$TmpVal"
+      Quit
+    ${EndIf}
+  ${EndIf}
+FunctionEnd
+
 ; Adds a section divider to the human readable log.
 Function WriteLogSeparator
   FileWrite $fhInstallLog "$\r$\n-------------------------------------------------------------------------------$\r$\n"
 FunctionEnd
 
 ; Check whether to display the current page (e.g. if we aren't performing a
 ; custom install don't display the custom pages).
 Function CheckCustom
@@ -645,47 +689,57 @@ Function CopyFile
   retry:
   ClearErrors
   ${If} $R6 ==  ""
     ${Unless} ${FileExists} "$R1$R3\$R7"
       ClearErrors
       CreateDirectory "$R1$R3\$R7"
       ${If} ${Errors}
         ${LogMsg}  "** ERROR Creating Directory: $R1$R3\$R7 **"
-        ${DisplayCopyErrMsg} "$R7"
-        GoTo retry
+        StrCpy $0 "$R1$R3\$R7"
+        ${WordReplace} "$(^FileError_NoIgnore)" "\r\n" "$\r$\n" "+*" $0
+        MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$0" IDRETRY retry
+        Quit
       ${Else}
         ${LogMsg}  "Created Directory: $R1$R3\$R7"
       ${EndIf}
     ${EndUnless}
   ${Else}
     ${Unless} ${FileExists} "$R1$R3"
       ClearErrors
       CreateDirectory "$R1$R3"
       ${If} ${Errors}
         ${LogMsg}  "** ERROR Creating Directory: $R1$R3 **"
-        ${DisplayCopyErrMsg} "$R3"
-        GoTo retry
+        StrCpy $0 "$R1$R3"
+        ${WordReplace} "$(^FileError_NoIgnore)" "\r\n" "$\r$\n" "+*" $0
+        MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$0" IDRETRY retry
+        Quit
       ${Else}
         ${LogMsg}  "Created Directory: $R1$R3"
       ${EndIf}
     ${EndUnless}
     ${If} ${FileExists} "$R1$R3\$R7"
+      ClearErrors
       Delete "$R1$R3\$R7"
       ${If} ${Errors}
-        ${DisplayCopyErrMsg} "$R7"
-        GoTo retry
+        ${LogMsg} "** ERROR Deleting File: $R1$R3\$R7 **"
+        StrCpy $0 "$R1$R3\$R7"
+        ${WordReplace} "$(^FileError_NoIgnore)" "\r\n" "$\r$\n" "+*" $0
+        MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$0" IDRETRY retry
+        Quit
       ${EndIf}
     ${EndIf}
     ClearErrors
     CopyFiles /SILENT $R9 "$R1$R3"
     ${If} ${Errors}
       ${LogMsg} "** ERROR Installing File: $R1$R3\$R7 **"
-      ${DisplayCopyErrMsg} "$R7"
-      GoTo retry
+      StrCpy $0 "$R1$R3\$R7"
+      ${WordReplace} "$(^FileError_NoIgnore)" "\r\n" "$\r$\n" "+*" $0
+      MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$0" IDRETRY retry
+      Quit
     ${Else}
       ${LogMsg} "Installed File: $R1$R3\$R7"
     ${EndIf}
     ; 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
--- a/toolkit/mozapps/installer/windows/nsis/common.nsh
+++ b/toolkit/mozapps/installer/windows/nsis/common.nsh
@@ -1874,63 +1874,8 @@ Exch $R9 ; exchange the new $R9 value wi
    !insertmacro GetPathFromString
 
    !undef _MOZFUNC_UN
    !define _MOZFUNC_UN
    !verbose pop
  !endif
 !macroend
 
-/**
- * Displays a error message when a file can't be copied.
- *
- * $0 = file name inserted into the error message
- */
-!macro DisplayCopyErrMsg
-
-  !ifndef ${_MOZFUNC_UN}DisplayCopyErrMsg
-    !verbose push
-    !verbose ${_MOZFUNC_VERBOSE}
-    !define ${_MOZFUNC_UN}DisplayCopyErrMsg "!insertmacro ${_MOZFUNC_UN}DisplayCopyErrMsgCall"
-
-    Function ${_MOZFUNC_UN}DisplayCopyErrMsg
-      Exch $0
-
-      MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$(^FileError_NoIgnore)" IDRETRY +2
-      Quit
-
-      Exch $0
-    FunctionEnd
-
-    !verbose pop
-  !endif
-!macroend
-
-!macro DisplayCopyErrMsgCall _FILE
-  !verbose push
-  !verbose ${_MOZFUNC_VERBOSE}
-  Push "${_FILE}"
-  Call DisplayCopyErrMsg
-  !verbose pop
-!macroend
-
-!macro un.DisplayCopyErrMsgCall _FILE
-  !verbose push
-  !verbose ${_MOZFUNC_VERBOSE}
-  Push "${_FILE}"
-  Call un.DisplayCopyErrMsg
-  !verbose pop
-!macroend
-
-!macro un.DisplayCopyErrMsg
-  !ifndef un.DisplayCopyErrMsg
-    !verbose push
-    !verbose ${_MOZFUNC_VERBOSE}
-    !undef _MOZFUNC_UN
-    !define _MOZFUNC_UN "un."
-
-    !insertmacro DisplayCopyErrMsg
-
-    !undef _MOZFUNC_UN
-    !define _MOZFUNC_UN
-    !verbose pop
-  !endif
-!macroend