Hi guys,
is there some easy way to detect which version
of M$ Windows Installer is present on user's system?
What I want to achieve is this:
I have created my NSIS installer which detects the version
of .NET Framework (via DotNET.nsh) and runs dotnetfx.exe externally if needed.
The problem is, however, that this package requires another M$ prerequisite to be there => WindowsInstaller-KB893803-v2-x86.exe
How can one find out whether this MSI 3.1 is already installed on user's system?
How to detect Windows Installer version?
19 posts
Do a GetDLLVersion (as described in the manual or here: http://nsis.sourceforge.net/GetDllVe...mand_Explained) on "$SYSDIR\msi.dll"
You probably don't need to check release & build parts though.
You probably don't need to check release & build parts though.
You can check the version of $SYSDIR\msi.dll using GetDLLVersion. It's hardly the official method, but I couldn't find anything about it in MSDN.
Originally posted by kichikIt's probably the closest thing to an official method that you are going to get. It's what the Windows Installer team says you should do.
You can check the version of $SYSDIR\msi.dll using GetDLLVersion. It's hardly the official method, but I couldn't find anything about it in MSDN.
http://blogs.msdn.com/windows_instal...09/458528.aspx
Many thanks to all of you for quick replies.
I'll try what you are suggesting.🙂
I'll try what you are suggesting.🙂
i thank to all too.. 😁
What happens if there is no Windows Installer installed at all? Will the script crash?
No, you'll just get no version from GetDLLVersion.
go to start=>run and type msiexec
I know this thread is old but here's a working example:
!macro CHECK_MSI_VERSION
GetDllVersion "$SYSDIR\msi.dll" $R0 $R1
IntOp $R2 $R0 >> 16
IntOp $R2 $R2 & 0x0000FFFF ; $R2 now contains major version
IntOp $R3 $R0 & 0x0000FFFF ; $R3 now contains minor version
IntOp $R4 $R1 >> 16
IntOp $R4 $R4 & 0x0000FFFF ; $R4 now contains release
IntOp $R5 $R1 & 0x0000FFFF ; $R5 now contains build
StrCpy $0 "$R2.$R3.$R4.$R5" ; $0 now contains string like "1.2.0.192"
MessageBox MB_ICONINFORMATION|MB_OK "The version is: $R2.$R3.$R4.$R5"
!macroend
!macro CHECK_MSI_VERSION
GetDllVersion "$SYSDIR\msi.dll" $R0 $R1
IntOp $R2 $R0 >> 16
IntOp $R2 $R2 & 0x0000FFFF ; $R2 now contains major version
IntOp $R3 $R0 & 0x0000FFFF ; $R3 now contains minor version
IntOp $R4 $R1 >> 16
IntOp $R4 $R4 & 0x0000FFFF ; $R4 now contains release
IntOp $R5 $R1 & 0x0000FFFF ; $R5 now contains build
StrCpy $0 "$R2.$R3.$R4.$R5" ; $0 now contains string like "1.2.0.192"
MessageBox MB_ICONINFORMATION|MB_OK "The version is: $R2.$R3.$R4.$R5"
!macroend
How do you detect if you have an older version installed?
For example, .net framework 2.0 requires at least version 3.1 (the above installed is 3.1.4000.2435).
However I have 4.5.6001.22299 installed.
Doesn't seem to work.
For example, .net framework 2.0 requires at least version 3.1 (the above installed is 3.1.4000.2435).
However I have 4.5.6001.22299 installed.
Doesn't seem to work.
How can I use the individual numbers since I need it to have at least 3.1 to go on, so anything less has to have it install.
GetDllVersion "$SYSDIR\msi.dll" $R0 $R1
IntOp $R2 $R0 >> 16
IntOp $R2 $R2 & 0x0000FFFF ; $R2 now contains major version
IntOp $R3 $R0 & 0x0000FFFF ; $R3 now contains minor version
IntOp $R4 $R1 >> 16
IntOp $R4 $R4 & 0x0000FFFF ; $R4 now contains release
IntOp $R5 $R1 & 0x0000FFFF ; $R5 now contains build
StrCpy $0 "$R2.$R3.$R4.$R5" ; $0 now contains string like "1.2.0.192"
MessageBox MB_ICONINFORMATION|MB_OK "The version is: $R2.$R3.$R4.$R5"
${If} $0 < "3.1.4000.2435"
MessageBox MB_ICONINFORMATION|MB_OK "Install 3.1"
${Else}
MessageBox MB_ICONINFORMATION|MB_OK "Go away!"
${EndIf}
Use ${VersionCompare} out of WordFunc.nsh (ships with NSIS) for comparing version numbers. Right now you're using a string comparison which can fail on version numbers.Originally Posted by jweinraub View PostFor example, .net framework 2.0 requires at least version 3.1 (the above installed is 3.1.4000.2435).
However I have 4.5.6001.22299 installed.
Doesn't seem to work.
${If} $0 < "3.1.4000.2435"
( You can also replace the first part of your code with ${GetFileVersion} out of FileFunc.nsh (ships with NSIS) )
That said... even with the above deficiency, this particular case should work just fine and pop up the "Go away!" messagebox. try sticking a 'MessageBox MB_OK "[$0]"' just in front of the ${If} so you can double-check that the value of $0 is what you're expecting it to be.
( since you're reading from $SYSDIR, also keep in mind any filesystem redirection magic on 64bit platforms )
Is there a different installer needed if there is a 64-bit system in place?
Because I have both .net installers for 32-bit and 64-bit versions of Windows.
My software is installed on laptops that will not have internet access therefore it is critical all prerequisites are met from the installation media itself.
What should I be aware of for 64-bit versions for the checker?
Because I have both .net installers for 32-bit and 64-bit versions of Windows.
My software is installed on laptops that will not have internet access therefore it is critical all prerequisites are met from the installation media itself.
What should I be aware of for 64-bit versions for the checker?
${VersionCompare} $0 "3.1.4000.2435" $R0
MessageBox MB_ICONINFORMATION|MB_OK $R0 ; if R0 is 2 then install msi 3.1 installer, else go on?
No, you can have both 32bit and 64bit installers in the same package.Originally Posted by jweinraub View PostIs there a different installer needed if there is a 64-bit system in place?
Specifically, the Sytem32 folder.Originally Posted by jweinraub View PostWhat should I be aware of for 64-bit versions for the checker?
On x64 platforms, if a 32bit application reads from the system folder (i.e. $SYSDIR), it gets redirected to a different folder named SysWOW64 (Windows(32) On Windows64). So if you need to target the 64bit version of the windows installer for that part, then you will have to disable filesystem redirection (Windows XP) or read from the SysNative folder (Vista, 7) instead.
Have a search through the forums - this pops up a few times 🙂
correct - but, again, check whether the value of $0 is what you're expecting it to be with a little messagebox first.. if you have further scripts inbetween $0 might be overwritten, or perhaps the file doesn't exist and the version returned would be 0.0.0.0, etc.Originally Posted by jweinraub View Post
${VersionCompare} $0 "3.1.4000.2435" $R0
MessageBox MB_ICONINFORMATION|MB_OK $R0 ; if R0 is 2 then install msi 3.1 installer, else go on?
No I meant the WindowsInstaller-KB893803-v2-x86.exe installer. Is ther an x64 version as well.Originally Posted by Animaether View PostNo, you can have both 32bit and 64bit installers in the same package.
Because I do this for x64 when it comes to .net.
; Detect .net 2.0 here ;
System::Call `mscoree::GetCORVersion(w .R0, i ${NSIS_MAX_STRLEN}, *i) ?u`
StrCpy $R0 $R0 1 1
; Compare if $R0 < 2 using ${If}
${If} $R0 < 2
; First detect if this is a 64 bit OS because you will want to install that instead ...
GetVersion::WindowsPlatformArchitecture
Pop $R1
${AndIf} $R1 == 64
SetDetailsPrint textonly
DetailPrint "Installing Microsoft .NET 2.0 x64. This may take up to ten minutes, please be patient."
SetDetailsPrint none
ExecWait `"$INSTDIR\Misc\NetFx64.exe" /q:a /c:"install.exe /noaspupgrade /qb"` $R0
;SetRebootFlag true
${OrIf} $R1 == 32
SetDetailsPrint textonly
DetailPrint "Installing Microsoft .NET 2.0..."
SetDetailsPrint none
ExecWait `"$INSTDIR\Misc\dotnetfx.exe" /q:a /c:"install.exe /noaspupgrade /qb"` $R0
;SetRebootFlag true
${Else}
Goto go_on
${EndIf}
I apologise but this part I am still unclear with. I understand the different sys dirs (like program dirs), but isnt the global variable determine the correct path at runtime?Originally Posted by AnimaetherSpecifically, the Sytem32 folder.
On x64 platforms, if a 32bit application reads from the system folder (i.e. $SYSDIR), it gets redirected to a different folder named SysWOW64 (Windows(32) On Windows64). So if you need to target the 64bit version of the windows installer for that part, then you will have to disable filesystem redirection (Windows XP) or read from the SysNative folder (Vista, 7) instead.
Essentially if the user doesnt have msi installer, or an older version than 3.1 I like for it to be installed. Other wise if the version is equal to or newer than the minimum it should do nothing and go on.
why do i get all that whitespace at line breaks?!
There doesn't appear to be a 64-bit version of Windows Installer 3.1 - I assume 4.5 is for those platforms. The forum puts in those new lines. I did ask one of the administrators but they haven't done anything. Instead of using the GetVersion plug-in you can just !include x64.nsh and use ${If} ${RunningX64}.
Edit: If you're thinking of SetShellVarContext then that is something else. File system redirection is part of the OS and as already mentioned specifying for example C:\Windows\System32 when querying the file system from a 32-bit application, it will be redirected to C:\Windows\SysWOW64.
Edit #2: In other words MessageBox MB_OK $SYSDIR will print the expected value (System32) but if you write to it your file will be in SysWOW64 instead unless you do ${DisableX64FSRedirection} first.
Stu
Edit: If you're thinking of SetShellVarContext then that is something else. File system redirection is part of the OS and as already mentioned specifying for example C:\Windows\System32 when querying the file system from a 32-bit application, it will be redirected to C:\Windows\SysWOW64.
Edit #2: In other words MessageBox MB_OK $SYSDIR will print the expected value (System32) but if you write to it your file will be in SysWOW64 instead unless you do ${DisableX64FSRedirection} first.
Stu
What does SetShellVarContext have to do with this? I actually make use of it only so that it installs on desktop shortcuts for All Users rather than local user (i already assume its being installed by admin).
So for intents and purposes, I can use the VersionCompare the way I am so I can just call the installer if necessary?
I assume even if it 0.0.0.0, the 3.x.x.x is still greater so it'll still install if needed, correct?
So what am I missing here by just doing it the way above?
Can I just do this?
; ... snip
${VersionCompare} $0 "3.1.4000.2435" $R0
${If} $R0 == 2
SetDetailsPrint textonly
DetailPrint "Installing Microsoft Windows Installer 3.1..."
SetDetailsPrint none
ExecWait `"$INSTDIR\Misc\WindowsInstaller-KB893803-v2-x86.exe" /quiet"` $R0
${EndIf}
; ... snip
So for intents and purposes, I can use the VersionCompare the way I am so I can just call the installer if necessary?
I assume even if it 0.0.0.0, the 3.x.x.x is still greater so it'll still install if needed, correct?
So what am I missing here by just doing it the way above?
Can I just do this?
; ... snip
${VersionCompare} $0 "3.1.4000.2435" $R0
${If} $R0 == 2
SetDetailsPrint textonly
DetailPrint "Installing Microsoft Windows Installer 3.1..."
SetDetailsPrint none
ExecWait `"$INSTDIR\Misc\WindowsInstaller-KB893803-v2-x86.exe" /quiet"` $R0
${EndIf}
; ... snip
SetShellVarContext has nothing to do with it, hence why I said that. VersionCompare will read an empty string as 0 (so an empty $0 will not break the code).
Stu
Stu