>From 504d6731cfad1464e6f8305788e2d505b1fb41dc Mon Sep 17 00:00:00 2001
From: unknown <Administrator@.testdomain.com>
Date: Fri, 30 Oct 2009 17:27:34 -0600
Subject: [PATCH] Add VC runtime merge module - Add migration
 The passsync msi now includes the correct VC runtime library, included into
 and installed as a merge module.  The build scripts have code to detect
 and find the correct merge module for the platform.
 Added some simple migration - if the install directory for the upgrade
 is different than what is currently on the system, the upgrade will copy
 the security database files from the old directory to the new directory -
 without this step, a renamed upgrade will fail because the service cannot
 be restarted.

---
 passwordsync/build.bat        |   56 ++++++++++------------
 passwordsync/package.mak      |    3 +-
 passwordsync/wix/PassSync.wxs |  103 +++++++++++++++++++++++++++++++++++++---
 3 files changed, 121 insertions(+), 41 deletions(-)

diff --git a/passwordsync/build.bat b/passwordsync/build.bat
index 416af12..aad1ace 100644
--- a/passwordsync/build.bat
+++ b/passwordsync/build.bat
@@ -77,6 +77,7 @@ if [%CPU%] == [AMD64] (
   set USE64=1
   set PLATFORM=x86_64
   set LDAPDATE=20091019.1
+  set MSMPLAT=x64
 if [%BUILD_DEBUG%] == [optimize] (
     set OPTDBG=_OPT
     set CFG1="passsync - Win64 Release"
@@ -96,6 +97,7 @@ if [%BUILD_DEBUG%] == [optimize] (
 ) else (
   set PLATFORM=i386
   set LDAPDATE=20091017.1
+  set MSMPLAT=x86
 if [%BUILD_DEBUG%] == [optimize] (
     set OPTDBG=_OPT
     set CFG1="passsync - Win32 Release"
@@ -118,38 +120,30 @@ set FLAVOR=WINNT%WINVER%%FLAG64%%OPTDBG%.OBJ
 
 echo Build flavor is %FLAVOR%
 
-REM this next part assumes you have set up the environment by running
-REM one of the start-msvcxx.bat or SetEnv.cmd batch files/scripts
-REM provided with MS Visual C++, Visual Studio, or SDK - those batch
-REM files set certain environment variables we use to figure out
-REM where the redistributable files are that we need to package
-REM we will pass this information down into package.mak and the .wxs
-if ["%VCRoot%"] == [] (
-    if ["%VCINSTALLDIR%"] == [] (
-        echo Error: could not find the location of the MSVC redistributable package
-        echo please make sure either VCRoot or VCINSTALLDIR is set to the
-        echo base VC location e.g.
-        echo "set VCRoot=C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\"
-        exit 1
-    ) else (
-        set vcredistroot="%VCINSTALLDIR%redist\%platdir%"
-    )
-) else (
-    set vcredistroot="%VCRoot%redist\%platdir%"
-)
+REM Look for the merge module containing the redistributable
+REM runtime for our platform
 
-REM figure out which version we're using
-if exist "%vcredistroot%\Microsoft.VC71.%subdir%\msvcr71%suf%.dll" (
-   set vcredistdllname=msvcr71%suf%.dll
-   set vcredistdll=%vcredistroot%\Microsoft.VC71.%subdir%\msvcr71%suf%.dll
-)
-if exist "%vcredistroot%\Microsoft.VC80.%subdir%\msvcr80%suf%.dll" (
-   set vcredistdllname=msvcr80%suf%.dll
-   set vcredistdll=%vcredistroot%\Microsoft.VC80.%subdir%\msvcr80%suf%.dll
+REM on 64-bit platforms
+for %%i in ("%COMMONPROGRAMFILES(X86)%\Merge Modules\"Microsoft_*_CRT_*%MSMPLAT%.msm) do set CRTMSM="%%i"
+for %%i in ("%COMMONPROGRAMFILES(X86)%\Merge Modules\"policy_*Microsoft_*_CRT_*%MSMPLAT%.msm) do set POLICYCRTMSM="%%i"
+
+REM on 32-bit platforms
+for %%i in ("%COMMONPROGRAMFILES%\Merge Modules\"Microsoft_*_CRT_*%MSMPLAT%.msm) do set CRTMSM="%%i"
+for %%i in ("%COMMONPROGRAMFILES%\Merge Modules\"policy_*Microsoft_*_CRT_*%MSMPLAT%.msm) do set POLICYCRTMSM="%%i"
+
+if not defined CRTMSM (
+   if not ["%MSSDK%"] == [] (
+      set CRTMSM="%MSSDK%"\Redist\VC\microsoft.vcxx.crt.%MSMPLAT%_msm.msm
+      set POLICYCRTMSM="%MSSDK%"\Redist\VC\policy.x.xx.microsoft.vcxx.crt.%MSMPLAT%_msm.msm
+   )
 )
-if exist "%vcredistroot%\Microsoft.VC90.%subdir%\msvcr90%suf%.dll" (
-   set vcredistdllname=msvcr90%suf%.dll
-   set vcredistdll=%vcredistroot%\Microsoft.VC90.%subdir%\msvcr90%suf%.dll
+
+if not defined CRTMSM (
+   echo ERROR: could not find the merge modules for the Visual C++
+   echo runtime side by side assemblies - they should be provided
+   echo with the Visual Studio C++ and/or the Windows SDK
+   echo cannot continue
+   exit 1
 )
 
 if [%BRAND%] == [] (
@@ -305,7 +299,7 @@ rem ======== Package ========
 cd ..
 echo -------- Beginning Packaging --------
 
-nmake /nologo CFG=%CFG1% USE64=%USE64% PLATFORM=%PLATFORM% "BRAND=%BRAND%" BRANDNOSPACE=%BRANDNOSPACE%  "VENDOR=%VENDOR%" VCREDISTDLL=%vcredistdll% VCREDISTDLLNAME=%vcredistdllname% VERSION=%VERSION% /f package.mak
+nmake /nologo CFG=%CFG1% USE64=%USE64% PLATFORM=%PLATFORM% "BRAND=%BRAND%" BRANDNOSPACE=%BRANDNOSPACE%  "VENDOR=%VENDOR%" CRTMSM=%CRTMSM% POLICYCRTMSM=%POLICYCRTMSM% VERSION=%VERSION% /f package.mak
 set /a OK=%OK% + %ERRORLEVEL%
 
 set PKGNAME=%BRANDNOSPACE%-PassSync-%VERSION%-%PLATFORM%.msi
diff --git a/passwordsync/package.mak b/passwordsync/package.mak
index dd4456b..1ec7c0d 100644
--- a/passwordsync/package.mak
+++ b/passwordsync/package.mak
@@ -51,11 +51,10 @@ LAYOUT :
 	copy /Y "$(LIBROOT)\nss\lib\*.dll" "$(PKGDIR)"
 	copy /Y "$(LIBROOT)\nss\bin\certutil.exe" "$(PKGDIR)"
 	copy /Y "$(LIBROOT)\nss\bin\pk12util.exe" "$(PKGDIR)"
-	copy /Y "$(VCREDISTDLL)" "$(PKGDIR)"
 
 PassSync.msi : LAYOUT
 	if not exist "$(PKGDIR)\Binary" mkdir "$(PKGDIR)\Binary"
 	copy /Y wix\Binary "$(PKGDIR)\Binary"
 	cd "$(PKGDIR)"
-	"$(CANDLE)" -dVERSION=$(VERSION) -dUSE64=$(USE64) "-dBRAND=$(BRAND)" "-dVENDOR=$(VENDOR)" "-dVCREDISTDLLNAME=$(VCREDISTDLLNAME)" "$(WXSDIR)\PassSync.wxs"
+	"$(CANDLE)" -trace -v0 "-dCRTMSM=$(CRTMSM)" "-dPOLICYCRTMSM=$(POLICYCRTMSM)" -dVERSION=$(VERSION) -dUSE64=$(USE64) "-dBRAND=$(BRAND)" "-dVENDOR=$(VENDOR)" "$(WXSDIR)\PassSync.wxs"
 	"$(LIGHT)" PassSync.wixobj -out $(BRANDNOSPACE)-PassSync-$(VERSION)-$(PLATFORM).msi
diff --git a/passwordsync/wix/PassSync.wxs b/passwordsync/wix/PassSync.wxs
index 0209123..e4c53ab 100644
--- a/passwordsync/wix/PassSync.wxs
+++ b/passwordsync/wix/PassSync.wxs
@@ -36,7 +36,7 @@
  All rights reserved.
  END COPYRIGHT BLOCK -->
 
-<?define Property_ProductCode = "D9C09AE2-F504-4875-8C7E-70BF2D791CEB" ?>
+<?define Property_ProductCode = "53b6d41b-c9a3-4b87-8b5e-06ec25bb9526" ?>
 <?if $(var.USE64)=1 ?>
     <?define Property_SysFolder = "System64Folder" ?>
     <?define Property_PFilesFolder = "ProgramFiles64Folder" ?>
@@ -100,10 +100,97 @@
                       Name="Search Base" Type="raw" />
     </Property>
 
+    <Property Id="OLDINSTALLDIR">
+      <RegistrySearch Id="OldInstPath" Root="HKLM" Key="Software\PasswordSync"
+                      Name="Install Path" Type="raw" />
+    </Property>
+
     <CustomAction Id='AlreadyUpdated' Error='[ProductName] [ProductVersion] is already installed.' />
     <CustomAction Id='NoDowngrade' Error='A later version of [ProductName] is already installed.' />
+    <CustomAction Id='Migrate.SetProperty' Property="Migrate" Value="[INSTALLDIR];[OLDINSTALLDIR]" />
+    <CustomAction Id='Migrate' Script='vbscript' Execute='deferred'>
+      <![CDATA[
+      On error resume next
+      set rec = Session.installer.CreateRecord(1)
+      msgtype = &H04000000
+      rec.StringData(1) = "Migrate: Begin"
+      Session.Message msgtype, rec
+      cad = Session.Property("CustomActionData")
+      rec.StringData(1) = "Migrate: CustomActionData=" & cad
+      Session.Message msgtype, rec
+      ary = Split(cad, ";")
+      newdir = ary(0)
+      olddir = ary(1)
+      rec.StringData(1) = "Migrate: migrating security and log files from [" & olddir & "] to [" & newdir & "]"
+      Session.Message msgtype, rec
+      testdir = "C:\Program Files"
+      Dim fso
+      Set fso = CreateObject("Scripting.FileSystemObject")
+      ' for debugging
+      If testdir <> Null And Not IsEmpty(testdir) Then
+        Set parfolder = fso.GetFolder(testdir)
+        rec.StringData(1) = "Migrate: listing contents of " & testdir & " parent folder " & parfolder.name
+        Session.Message msgtype, rec
+        For Each ff in parfolder.Files
+          rec.StringData(1) = "Migrate: file=" & ff.name
+          Session.Message msgtype, rec
+        Next
+        For Each fl in parfolder.SubFolder
+          rec.StringData(1) = "Migrate: folder=" & fl.name
+          Session.Message msgtype, rec
+        Next
+      End If
+      ' for debugging
+
+      If olddir = Null Or IsEmpty(olddir) Then
+        rec.StringData(1) = "Migrate: There is no old installation - nothing to migrate " & olddir
+        Session.Message &H04000000, rec
+        ' nothing to do
+        WScript.Quit 0 ' quit seems not to be working
+      ElseIf olddir = newdir Then
+        rec.StringData(1) = "Migrate: The old and new installation directories are the same: " & olddir & ": nothing to migrate"
+        Session.Message msgtype, rec
+        ' nothing to do
+        WScript.Quit 0
+      ElseIf not fso.FolderExists(olddir) Then
+        rec.StringData(1) = "Migrate: Cannot migrate because source folder " & olddir & " does not exist"
+        Session.Message msgtype, rec
+        WScript.Quit 0
+      ElseIf not fso.FolderExists(newdir) Then
+        rec.StringData(1) = "Migrate: Error: Cannot migrate because destination folder " & newdir & " does not exist"
+        Session.Message msgtype, rec
+        WScript.Quit 1
+      Else
+        rec.StringData(1) = "Migrate: Copying files from " & olddir & " to " & newdir
+        Session.Message msgtype, rec
+        set srcfl = fso.GetFolder(olddir)
+        For Each fi In srcfl.Files
+          newfi = newdir & fi.name
+          If fso.FileExists(newfi) Then
+            rec.StringData(1) = "Migrate: skipping file " & newfi & " because it already exists"
+            Session.Message msgtype, rec
+          Else
+            rec.StringData(1) = "Migrate: copying file " & fi.name & " to " & newdir
+            Session.Message msgtype, rec
+            Err.Clear
+            fi.Copy(newdir & fi.name)
+            If Err <> 0 Then
+              rec.StringData(1) = "Migrate: error copying file " & Err.Number & " " & Err.Description
+              Session.Message msgtype, rec
+            End If
+          End If
+        Next
+      End If
+      Set fso = Nothing
+      rec.StringData(1) = "Migrate: End"
+      Session.Message msgtype, rec
+      ]]>
+    </CustomAction>
 
     <Directory Id='TARGETDIR' Name='SourceDir'>
+      <!-- the VC runtime redist package -->
+      <Merge Id='CRT' Language='0' src='$(var.CRTMSM)' DiskId='1'/>
+      <Merge Id='PolicyCRT' Language='0' src='$(var.POLICYCRTMSM)' DiskId='1'/>
 
       <Directory Id='$(var.Property_SysFolder)' Name='SysDir'>
         <Component Id='HookLibrary' Guid='93790ACE-F522-413C-AEE3-DF05D99BAA6D' Win64='$(var.Property_Win64)'>
@@ -173,7 +260,7 @@
 
 		  <ServiceInstall Id='PassSyncEXE' Name='PassSync' DisplayName='Password Synchronization' Type='ownProcess' 
 		   Interactive='yes' Start='auto' Vital='yes' ErrorControl='normal'/>
-		  <ServiceControl Id='PassSyncEXE' Name='PassSync' Start='install' Stop='both' Remove='uninstall' Wait='no'/>
+		  <ServiceControl Id='PassSyncEXE' Name='PassSync' Start='install' Stop='both' Remove='uninstall' Wait='yes'/>
 
 		  <Registry Id='InstPath' Root='HKLM' Key='Software\PasswordSync' Name='Install Path' Action='write' Type='string' Value='[INSTALLDIR]' />
 		  <Registry Id='HostName' Root='HKLM' Key='Software\PasswordSync' Name='Host Name' Action='write' Type='string' Value='[HOSTNAME]' />
@@ -217,11 +304,6 @@
               <File Id='NSLDIF' LongName='nsldif32v60.dll' Name='nsldif.dll' DiskId='1' src='nsldif32v60.dll' Vital='yes' />
             </Component>
 
-            <!-- mozldap requires msvc redist runtime dll -->
-            <Component Id='NSLDAPmsvcrLibrary' Guid='C0E8DA53-B61A-4b60-8886-8549C29CACE7' Win64='$(var.Property_Win64)'>
-              <File Id='NSLDAPmsvcr' LongName='$(var.VCREDISTDLLNAME)' Name='$(var.VCREDISTDLLNAME)' DiskId='1' src='$(var.VCREDISTDLLNAME)' Vital='yes' />
-            </Component>
-
           </Directory>
       </Directory>
       <Directory Id="DesktopFolder" Name="Desktop" />
@@ -238,7 +320,6 @@
 	  <ComponentRef Id='NSLDAPSSLLibrary' />
 	  <ComponentRef Id='NSLDAPPRLibrary' />
 	  <ComponentRef Id='NSLDIFLibrary' />
-          <ComponentRef Id='NSLDAPmsvcrLibrary' />
 	  <ComponentRef Id='NSPRLibrary' />
 	  <ComponentRef Id='NSPRpldsLibrary' />
 	  <ComponentRef Id='NSPRplcLibrary' />
@@ -254,6 +335,10 @@
 	  <ComponentRef Id='NSScertutil' />
 	  <ComponentRef Id='NSSpk12util' />
       </Feature>
+      <Feature Id='CRT_WinSXS' Title='CRT WinSXS' AllowAdvertise="no" Display="hidden" Level='1'>
+          <MergeRef Id='CRT' />
+          <MergeRef Id='PolicyCRT' />
+      </Feature>
     </Feature>
 
     <UI>
@@ -1379,6 +1464,8 @@
 
     <InstallExecuteSequence>
       <Custom Action='NoDowngrade' After='FindRelatedProducts'>NEWERFOUND</Custom>
+      <Custom Action='Migrate.SetProperty' Before='Migrate' />
+      <Custom Action='Migrate' Before='StartServices' ><![CDATA[OLDINSTALLDIR AND (OLDINSTALLDIR <> INSTALLDIR)]]></Custom>
       <RemoveExistingProducts After='InstallFinalize' />
     </InstallExecuteSequence>
 
-- 
1.5.6.1.1071.g76fb

