'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Decal Installer Library <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Option Explicit


'FSO Constants
Private Const WindowsFolder   = 0
Private Const SystemFolder    = 1
Private Const TemporaryFolder = 2

'WindowsInstaller Constants
Private Const msiInstallStateUnknown = -1
Private Const msiInstallStateAbsent  =  2
Private Const msiUILevelFull         =  5

'Minimum versions
Private Const MIN_WSH_VERSION = "5.1"
Private Const MIN_WI_VERSION  = "1.11.2405.0"

'Global Objects
Private WshShell, WI, FSO, AllProducts
'prevent premature errors if objects don't exist
On Error Resume Next
Set WshShell 	= WScript.CreateObject("WScript.Shell")      	'needed for reg access and file execution
Set WI       	= CreateObject("WindowsInstaller.Installer") 	'the MSI related functions need this object
Set FSO     	= CreateObject("Scripting.FileSystemObject") 	'can never have too many of these around
Set AllProducts = CreateObject("Scripting.Dictionary")			'All of the product IDs that this should remove before installing
On Error GoTo 0
'Now make sure we got them all
'There is some error checking deeper in, but I've seen a lot of errors so I'm not removing any of it :)
If Not IsObject(WshShell) Then
	MsgBox 	"Internal error creating Windows Scripting Host object (WshShell). Please make sure you have IE6+ installed", _
			vbOKOnly, _
			"Decal Installer Library"
	WScript.Quit
End If
If Not IsObject(FSO) Then
	MsgBox 	"Internal error creating Windows Scripting Host object (FSO). Please make sure you have IE6+ installed", _
			vbOKOnly, _
			"Decal Installer Library"
	WScript.Quit
End If
If Not IsObject(AllProducts) Then
	MsgBox 	"Internal error creating Windows Scripting Host object (Dictionary). Please make sure you have IE6+ installed", _
			vbOKOnly, _
			"Decal Installer Library"
	WScript.Quit
End If
If Not IsObject(WI) Then
	MsgBox 	"Internal error creating Windows Installer object. Please make sure you have Windows Installer installed", _
			vbOKOnly, _
			"Decal Installer Library"
	WScript.Quit
End If

'YOU MUST EDIT THESE FOR YOUR PARTICULAR INSTALLER!!!!!!

'All of these -must- be specified
Private Const ThisProduct 		= "Decal"									' The name of your product, used it dialogs and such
Private Const ThisVersion 		= "2.6.0.1"	' The version of your product, used in dialogs and such
Private Const MSIFileName		= "Decal.msi"	' The name of the MSI file that will be excuted
'Add all of your previous product IDs to the dictionary for removal by the installer
AllProducts.Add	"1.0.1.0",  "{4AFA7857-D10F-4A74-A504-9C10320A6DB9}"
AllProducts.Add	"1.0.2.0", "{840FA8EC-CA4D-46BE-94E6-2C85F4E29EDD}" 
AllProducts.Add	"1.0.2.2", "{DBBE8C7F-F27D-48D7-BBC1-5BFA30485980}"
AllProducts.Add	"1.1.0.0", "{DFB254B2-F9B4-42F1-8B16-C045B18C8DBE}"
AllProducts.Add	"2.0.0.0 RC1", "{3CFF0D79-376D-4557-8376-A9B48E50F775}"
AllProducts.Add	"2.0.0.0 RC2", "{701F72C7-421E-4DBE-B8C7-0A8B5258D539}"
AllProducts.Add	"2.0.0.0 RC3 ", "{D6E309A7-290D-48E0-9992-0DAB18EA4CE4}"
AllProducts.Add	"2.0.0.0 RC4", "{3C2F8BE2-2B35-402F-9BAE-F9FDCA9C22A9}"
AllProducts.Add	"2.0.0.0", "{F7DC5688-E3A0-432B-A5DF-F7CB4B02DE03}"
AllProducts.Add	"2.1.0.2", "{6C6B886C-66E0-41C9-AF1A-1B02372D5E77}"
AllProducts.Add	"2.1.0.4", "{83CE1E0E-E441-4764-A3CC-DBF1A53C40F0}"
AllProducts.Add "2.1.0.5", "{B388C87C-F59D-457F-A839-B6F3A2642CE7}"
AllProducts.Add "2.2.0.0", "{9FB34BE5-A2A3-4509-8A21-133FC27387F7}"
AllProducts.Add "2.2.0.1", "{BE7BB776-FE47-41B7-AACE-1F958A7CE214}"
AllProducts.Add "2.2.2.0", "{92A0F954-9A9D-4FCC-B874-F0A8DBD8BF1B}"
AllProducts.Add "2.2.3.0", "{775AB855-075F-462B-A482-D555569E2C03}"
AllProducts.Add "2.2.4.0", "{0C844C18-2021-4660-AD25-7922653E1A16}"
AllProducts.Add "2.3.0.0", "{DE512CE7-2417-41E5-9C7F-5C091F171785}"
AllProducts.Add "2.3.1.0", "{660E1D69-140D-437E-9D23-9137DA6F0162}"
AllProducts.Add "2.3.1.1", "{A0ACDD8E-3730-4007-926A-55D7B1A5A7B7}"
AllProducts.Add "2.3.1.2", "{E6E77F45-0B35-4F92-9CD3-4B70A821158D}"
AllProducts.Add "2.3.1.3", "{92872CC7-2722-4534-81BE-E99B4D472A95}"
AllProducts.Add "2.3.1.4", "{8186889F-BF27-4F79-9D94-4DD7CB9956F2}"
AllProducts.Add "2.3.1.5", "{09A9F4AE-C043-43CF-85D1-6F14BCAAEB11}"
AllProducts.Add "2.3.1.6", "{A6749A61-B1E5-4FFB-BA4D-AE93E5443EC8}"
AllProducts.Add "2.3.1.7", "{C667B179-E270-4BE5-9C73-0533C1D2B758}"
AllProducts.Add "2.3.1.8", "{88947320-85FC-4327-908D-7801365AD4D9}"
AllProducts.Add "2.3.1.9", "{1CF52690-D209-47C7-97EF-F38D64463AD5}"
AllProducts.Add "2.4.0.0", "{4D7BE8B5-6B0A-4135-8C75-BE8E4BB2E351}"
AllProducts.Add "2.4.1.0", "{E6E9AB9D-812C-40D7-A57C-ED298B48557F}"
AllProducts.Add "2.4.1.2", "{09C6E670-D686-11D6-BFDA-009027B6A4F1}"
AllProducts.Add "2.4.1.3", "{E62F700A-E214-11D6-B2DA-009027B6A4F1}"
AllProducts.Add "2.5.0.0 RC1", "{940240A5-39C7-496A-B2FB-21D87220FCFE}"
AllProducts.Add "2.5.0.0 RC2", "{F685D7CA-12EB-11D7-B2DA-009027B6A4F1}"
AllProducts.Add "2.5.0.0 RC3", "{F15D5960-13C9-11D7-B2DA-009027B6A4F1}"
AllProducts.Add "2.5.0.1 RC1", "{B5B0E8D6-FE22-467C-B09E-1AB5CC837942}"
AllProducts.Add "2.5.0.1", "{CE4276BF-04AE-41C9-B7C2-3DD65B4DAEDD}"
AllProducts.Add "2.5.0.2", "{F794642A-63D5-11D7-B2DA-009027B6A4F1}"
AllProducts.Add "2.5.0.4", "{29E8FB17-4C4E-4F5D-8C5D-F3826ECE2CF6}"
AllProducts.Add "2.5.0.5", "{35012CC1-DC9F-49C3-9593-2B246AE68D3A}"
AllProducts.Add "2.5.2.0 RC1", "{ED4744B7-3F12-453B-9908-D192E0F5477A}"
AllProducts.Add "2.5.2.0 RC2", "{3EA7A26F-9112-45D4-BDE0-9BE451D42A9F}"
AllProducts.Add "2.5.2.0 RC3", "{B04617E3-2AFF-4650-84AF-10BE73B22A15}"
AllProducts.Add "2.6.0.0 RC1", "{6E766A51-09A9-4571-B55A-EE2E4E74B8BC}"
AllProducts.Add "2.6.0.0 RC2", "{4C22590F-22B8-4413-B91D-0403B2F84979}"
AllProducts.Add "2.6.0.0 RC3", "{E86FBB39-9061-475A-B575-F8F9AC12DB74}"
AllProducts.Add "2.6.0.0 RC4", "{16673809-CA94-4E31-9E0B-B2FCA0CBDFAB}"
AllProducts.Add "2.6.0.0 RC5", "{67E0D07C-8A6A-4357-B44F-CCA1A513DFE7}"
AllProducts.Add "2.6.0.0", "{B0DC3DCD-44BD-47C7-AB9D-CC68FB63F4C3}"
AllProducts.Add "2.6.0.1", "{32767F66-7F62-4C0B-81F7-C42B4C7C0148}"


' These are optional 
' The features they provide will be ignored if they are left as empty strings
Private Const PathRegValue 		= "HKLM\SOFTWARE\Decal\Agent\AgentPath"		' Path to a registry key containing the install location of your product
Private Const FavoriteName 		= "Decal Homepage"				' Name of the Favorite to add at the end of the install
Private Const FavoriteURL 		= "http://decaldev.sourceforge.net/"		' URL for the Favorite to point to
Private Const FavoriteIconFile 	= "Denagent.exe"					' File to get the icon for the favorite from (default IE icon if blank)
Private Const FavoriteIconID 	= "0"							' Icon ID to use from the above file (default IE icon if blank)

' END OF EDITABLE OPTIONS

Private Function IsVersionAgreeable(pActualVersion, pMinumumVersion)
	Dim actual, expected, i
	IsVersionAgreeable = True
	'msgbox "pActualVersion: " & pActualVersion & vbCRLF & "pMinumumVersion: " & pMinumumVersion
	actual = split (pActualVersion, ".")
	expected = split (pMinumumVersion, ".")
	
	For i = 0 To UBound(expected)
		'msgbox cstr(i & " : " & actual(i) & " : " & expected(i))
		If CInt(actual(i)) > CInt(expected(i)) Then 
			'msgbox("greater")
			Exit For
		ElseIf CInt(actual(i)) < CInt(expected(i)) Then 
			'msgbox("less")
			IsVersionAgreeable = False
			Exit For
		End If
	Next
End Function

Private Sub WSHVersionCheck()
  'Function:       Check the Windows Scripting Host version, give URL for updating if not good enough, 
  '                then kill the script.
  'Args:           N/A
  'Returns:        N/A
  '
  'Requirements:   WshShell = WScript.Shell 
  '
	Dim actualVersion, rc
	
	On Error Resume Next
	actualVersion = WScript.Version
	On Error GoTo 0
		
	'Bail here if things are ok
	If IsVersionAgreeable(actualVersion, MIN_WSH_VERSION) Then Exit Sub
	
	'Didn't bail, so need to prompt for an upgrade
	rc = MsgBox ("The " & ThisProduct & " Installer has determined that you do not have a new enough version of Windows Scripting Host to use this installer." & _
				String(2, vbCRLF) & _
				"The newest version is available with Windows Scripting Host 5.6 which you can download at: " & _
				String(2, vbCRLF) & _
				"http://download.microsoft.com/download/winscript56/Install/5.6/W9XNT4Me/EN-US/scr56en.exe" & _
				String(2, vbCRLF) & _
				"Would you like to go there now?", _
				vbYesNo + vbQuestion, _
				ThisProduct & " Installer")
	If rc = vbYes Then WshShell.Run "http://download.microsoft.com/download/winscript56/Install/5.6/W9XNT4Me/EN-US/scr56en.exe"
	WScript.Quit
End Sub

Private Sub WIVersionCheck()
  'Function:       Check the windows installer version, give URL for updating if not good enough, 
  '                then kill the script.
  'Args:           N/A
  'Returns:        N/A
  '
  'Requirements:   WI = WindowsInstaller.Installer
  '                WshShell = WScript.Shell 
	
	Dim actualVersion, rc, fileInSysFolder, fileInWinFolder, windowsVersion, strURL, strFailMsg
	
	On Error Resume Next
	actualVersion = WI.Version
	On Error GoTo 0
	
	'Bail here if things are ok
	If IsVersionAgreeable(actualVersion, MIN_WI_VERSION) Then Exit Sub
		
	'Didn't bail, so need to prompt for an upgrade
	With FSO
		fileInSysFolder = .BuildPath(.GetSpecialFolder(SystemFolder), "winver.exe")
		fileInWinFolder = .BuildPath(.GetSpecialFolder(WindowsFolder), "winver.exe")
		If .FileExists(fileInSysFolder) Then
			windowsVersion = split(.GetFileVersion(fileInSysFolder),".")
		ElseIf .FileExists(fileInWinFolder) Then
			windowsVersion = split(.GetFileVersion(fileInWinFolder),".")
		Else
			rc = MsgBox("The Decal Installer was unable to determine your Windows version. Are you using Windows 2000 or Windows XP?", _
						vbYesNo + vbQuestion, _
						ThisProduct & " Installer")
			If rc = vbYes Then
				windowsVersion = split("5.0.0.0", ".")
			ElseIf rc = vbNo Then
				windowsVersion = split("4.0.0.0", ".")
			Else
				MsgBox "An unknown error occured in Windows Version detection. Please make sure you have Windows Installer properly installed and try again.", _
						vbOKOnly, _
						ThisProduct & " Installer"
				WScript.Quit
			End If
		End If
	End With 'With FSO
		
	If CInt(windowsVersion(1)) < 5 Then
		strURL = "http://www.microsoft.com/downloads/release.asp?releaseid=32831"
		strFailMsg = "Windows 98/ME users can upgrade at: " & strURL
	Else 'If work(0) < 5 Then
		strURL = "http://www.microsoft.com/downloads/release.asp?releaseid=32832"
		strFailMsg = "Windows 2000 users can upgrade at: " & strURL
	End If 'If work(0) < 5 Then
	
	rc = MsgBox ("The " & ThisProduct & " Installer has determined that you do not have a new enough version of Windows Installer to use this installer. " & _
					String(2,vbCRLF) & _
					strFailMsg & _
					String(2,vbCRLF) & _
					"Would you like to go there now?", _
					vbYesNo + vbQuestion, _
					ThisProduct & " Installer")
	If rc = vbYes Then 
		'open the browser and exit
		WshShell.Run strURL
	End If
	WScript.Quit
End Sub

Private Sub WipeProduct(pProdID)
	'Function:       Check for the product ID. If it exists, silently and forcefully uninstall.
	'
	'Args:           pProdID = a string of the MSI Product ID to be wiped
	'Returns:        N/A
	'
	'Requirements:   WI = WindowsInstaller.Installer
	
	Dim rc 
	
	rc = WI.ProductState(pProdID)
	'FIXME
	'something about this check is not as precise as it should be. Need to find info
	'about different install states and find ways to handle them all
	'TEMP FIX ONLY
	On Error Resume Next
	'END OF TEMP FIX
	If rc <> msiInstallStateUnknown Then
		'remove it
		WI.ConfigureProduct pProdID, 0, msiInstallStateAbsent 'second param is ignored
	End If
End Sub

' VERSION CHECKING
WSHVersionCheck
WIVersionCheck

'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> End of Decal Installer Library <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

'>>>>>>>>>>>>>>>>>>>>>>>>>>>START SCRIPT<<<<<<<<<<<<<<<<<<<<<<<<




'variables
Dim retval, strProductFolder, strProp, strUninstaller, strPathToFavIcon, TXT, i, ProductsToRemove

'make sure they really want to do this
retval = MsgBox("You are about to remove all old " & ThisProduct & " versions and install " & ThisProduct & " v" & ThisVersion & "        ", _
				vbOkCancel + vbQuestion, _
				ThisProduct &" Installer")
	  
If retval = vbCancel Then WScript.Quit

'Before starting, lookup and store the Decal path if it exists
On Error Resume Next 'will fail if not found, leaving an empty string
strDecalFolder = WshShell.RegRead(PathRegValue)
On Error GoTo 0
 
'>>>>>>>>>>>>>>>UNINSTALLING OLD VERSIONS<<<<<<<<<<<<<<<<<

'Remove MSIs by product code
ProductsToRemove = AllProducts.Items
For i = 0 To UBound(ProductsToRemove)
	WipeProduct ProductsToRemove(i)
Next


'>>>>>>>>>>>>>>>>>>>>INSTALLING PDODUCT<<<<<<<<<<<<<<<<<<<<<<<<<<
'install .msi with remembered install path if it exists

strProp = "DISABLEADVTSHORTCUTS=True"
If Len(strProductFolder) > 0 Then strProp = strProp & " TARGETDIR=""" & strProductFolder & """"
WI.UILevel = msiUILevelFull
On Error Resume Next
WI.InstallProduct MSIFileName, strProp
On Error GoTo 0
If Err.Number <> 0 Then WScript.Quit
'The old command line:
'WshShell.Run "msiexec /i Decal.msi  " & strProp

'Favorites icon?
If Len(FavoriteName) > 0 And Len(FavoriteURL) > 0 Then
	strPathToFavIcon = FSO.BuildPath(WshShell.SpecialFolders("Favorites"), FavoriteName & ".url")
	'is is there already?
	If Not FSO.FileExists(strPathToFavIcon) Then
		retval = MsgBox("Would you like a shortcut to the " & ThisProduct & " Homepage placed in your Favorites menu?", _
						vbYesNo + vbQuestion, _
						ThisProduct & " Installer")                  
		If retval = vbYes Then
		
			Set TXT = FSO.CreateTextFile(strPathToFavIcon)
			TXT.WriteLine "[InternetShortcut]"
			TXT.WriteLine "URL=" & FavoriteURL
			On Error Resume Next
			strProductFolder = WshShell.RegRead(PathRegValue)
			On Error GoTo 0
			If Len(FavoriteIconFile) > 0 And Len(FavoriteIconID) > 0 And Len(strProductFolder) > 0 Then
				TXT.WriteLine "IconFile=" & FSO.BuildPath(strProductFolder, FavoriteIconFile)
				TXT.WriteLine "IconIndex=" & FavoriteIconID
			End If
			TXT.Close
		End If
	End If
End If

MsgBox 	ThisProduct & " Installation Completed", _
		vbOkOnly + vbInformation, _
		ThisProduct & " Installer"
