How to ensure a required version of .NET Framework is installed
Author: John J. Pike (talk, contrib) |
Description
This function allows you to select a minimum version of the .NET Framework be installed. If it or a higher version is not present the function will abort the installation.
The Function
; Usage ; Define in your script two constants: ; DOT_MAJOR "(Major framework version)" ; DOT_MINOR "{Minor framework version)" ; ; Call IsDotNetInstalled ; This function will abort the installation if the required version ; or higher version of the .NET Framework is not installed. Place it in ; either your .onInit function or your first install section before ; other code. Function IsDotNetInstalled StrCpy $0 "0" StrCpy $1 "SOFTWARE\Microsoft\.NETFramework" ;registry entry to look in. StrCpy $2 0 StartEnum: ;Enumerate the versions installed. EnumRegKey $3 HKLM "$1\policy" $2 ;If we don't find any versions installed, it's not here. StrCmp $3 "" noDotNet notEmpty ;We found something. notEmpty: ;Find out if the RegKey starts with 'v'. ;If it doesn't, goto the next key. StrCpy $4 $3 1 0 StrCmp $4 "v" +1 goNext StrCpy $4 $3 1 1 ;It starts with 'v'. Now check to see how the installed major version ;relates to our required major version. ;If it's equal check the minor version, if it's greater, ;we found a good RegKey. IntCmp $4 ${DOT_MAJOR} +1 goNext yesDotNetReg ;Check the minor version. If it's equal or greater to our requested ;version then we're good. StrCpy $4 $3 1 3 IntCmp $4 ${DOT_MINOR} yesDotNetReg goNext yesDotNetReg goNext: ;Go to the next RegKey. IntOp $2 $2 + 1 goto StartEnum yesDotNetReg: ;Now that we've found a good RegKey, let's make sure it's actually ;installed by getting the install path and checking to see if the ;mscorlib.dll exists. EnumRegValue $2 HKLM "$1\policy\$3" 0 ;$2 should equal whatever comes after the major and minor versions ;(ie, v1.1.4322) StrCmp $2 "" noDotNet ReadRegStr $4 HKLM $1 "InstallRoot" ;Hopefully the install root isn't empty. StrCmp $4 "" noDotNet ;build the actuall directory path to mscorlib.dll. StrCpy $4 "$4$3.$2\mscorlib.dll" IfFileExists $4 yesDotNet noDotNet noDotNet: ;Nope, something went wrong along the way. Looks like the ;proper .NET Framework isn't installed. MessageBox MB_OK "You must have v${DOT_MAJOR}.${DOT_MINOR} or greater of the .NET Framework installed. Aborting!" Abort yesDotNet: ;Everything checks out. Go on with the rest of the installation. FunctionEnd
I hope this is helpful.
Description
Hi John,
thanks for writing this function, I've used it in my installer. However I did a slight modification to it, because I needed to recognize minor version as well (e.g. 2.0.50727), because our project does not work with .NET 2.0 beta which differs only in the last number. Here is the code:
The Function
; Usage ; Define in your script two constants: ; DOT_MAJOR "(Major framework version)" ; DOT_MINOR "{Minor framework version)" ; DOT_MINOR_MINOR "{Minor framework version - last number after the second dot)" ; ; Call IsDotNetInstalledAdv ; This function will abort the installation if the required version ; or higher version of the .NET Framework is not installed. Place it in ; either your .onInit function or your first install section before ; other code. Function IsDotNetInstalledAdv Push $0 Push $1 Push $2 Push $3 Push $4 Push $5 StrCpy $0 "0" StrCpy $1 "SOFTWARE\Microsoft\.NETFramework" ;registry entry to look in. StrCpy $2 0 StartEnum: ;Enumerate the versions installed. EnumRegKey $3 HKLM "$1\policy" $2 ;If we don't find any versions installed, it's not here. StrCmp $3 "" noDotNet notEmpty ;We found something. notEmpty: ;Find out if the RegKey starts with 'v'. ;If it doesn't, goto the next key. StrCpy $4 $3 1 0 StrCmp $4 "v" +1 goNext StrCpy $4 $3 1 1 ;It starts with 'v'. Now check to see how the installed major version ;relates to our required major version. ;If it's equal check the minor version, if it's greater, ;we found a good RegKey. IntCmp $4 ${DOT_MAJOR} +1 goNext yesDotNetReg ;Check the minor version. If it's equal or greater to our requested ;version then we're good. StrCpy $4 $3 1 3 IntCmp $4 ${DOT_MINOR} +1 goNext yesDotNetReg ;detect sub-version - e.g. 2.0.50727 ;takes a value of the registry subkey - it contains the small version number EnumRegValue $5 HKLM "$1\policy\$3" 0 IntCmpU $5 ${DOT_MINOR_MINOR} yesDotNetReg goNext yesDotNetReg goNext: ;Go to the next RegKey. IntOp $2 $2 + 1 goto StartEnum yesDotNetReg: ;Now that we've found a good RegKey, let's make sure it's actually ;installed by getting the install path and checking to see if the ;mscorlib.dll exists. EnumRegValue $2 HKLM "$1\policy\$3" 0 ;$2 should equal whatever comes after the major and minor versions ;(ie, v1.1.4322) StrCmp $2 "" noDotNet ReadRegStr $4 HKLM $1 "InstallRoot" ;Hopefully the install root isn't empty. StrCmp $4 "" noDotNet ;build the actuall directory path to mscorlib.dll. StrCpy $4 "$4$3.$2\mscorlib.dll" IfFileExists $4 yesDotNet noDotNet noDotNet: ;Nope, something went wrong along the way. Looks like the ;proper .NET Framework isn't installed. ;Uncomment the following line to make this function throw a message box right away ; MessageBox MB_OK "You must have v${DOT_MAJOR}.${DOT_MINOR}.${DOT_MINOR_MINOR} or greater of the .NET Framework installed. Aborting!" ; Abort StrCpy $0 0 Goto done yesDotNet: ;Everything checks out. Go on with the rest of the installation. StrCpy $0 1 done: Pop $4 Pop $3 Pop $2 Pop $1 Exch $0 FunctionEnd
Macro Conversion
Hello lads, I was very pleased with this function. However, copying constantly "IsDotNetInstalled" or "IsDotNetInstalledAdv" (or even saving them to a .nsh file) may be a bother to some people. As well, I did this just to make your script more organized, sense-full, and well, I was bored.
Instead, create a new file into your "${NSISDIR}\Includes" folder, and name it "DotNetSearch.nsh"
Open it for editing, and copy all the code below then save it. (simple ZIP download may be available soon, however I do not often do this as I like users to see the code they are copying)
!macro DotNetSearch DOTNETVMAJOR DOTNETVMINOR DOTNETVMINORMINOR DOTNETLASTFUNCTION DOTNETPATH Var /GLOBAL DOTNET1 Var /GLOBAL DOTNET2 Var /GLOBAL DOTNET3 Var /GLOBAL DOTNET4 Var /GLOBAL DOTNET5 Var /GLOBAL DOTNET6 Push $DOTNET1 Push $DOTNET2 Push $DOTNET3 Push $DOTNET4 Push $DOTNET5 Push $DOTNET6 StrCpy $DOTNET1 "0" StrCpy $DOTNET2 "SOFTWARE\Microsoft\.NETFramework" StrCpy $DOTNET3 0 DotNetStartEnum: EnumRegKey $DOTNET4 HKLM "$DOTNET2\policy" $DOTNET3 StrCmp $DOTNET4 "" noDotNet dotNetFound dotNetFound: StrCpy $DOTNET5 $DOTNET4 1 0 StrCmp $DOTNET5 "v" +1 goNextDotNet StrCpy $DOTNET5 $DOTNET4 1 1 IntCmp $DOTNET5 ${DOTNETVMAJOR} +1 goNextDotNet yesDotNetReg StrCpy $DOTNET5 $DOTNET4 1 3 IntCmp $DOTNET5 ${DOTNETVMINOR} +1 goNextDotNet yesDotNetReg StrCmp ${DOTNETVMINORMINOR} "" yesDotNetReg +1 yesDotNetReg ;StrCmp ${DOTNETVMINORMINOR} "" yesDotNetReg +1 ;Changed this line (otherwise it would not work with my setup!) - Vinz0r IntCmpU $DOTNET5 ${DOTNETVMINORMINOR} yesDotNetReg goNextDotNet yesDotNetReg goNextDotNet: IntOp $DOTNET3 $DOTNET3 + 1 Goto DotNetStartEnum yesDotNetReg: EnumRegValue $DOTNET3 HKLM "$DOTNET2\policy\$DOTNET4" 0 StrCmp $DOTNET3 "" noDotNet ReadRegStr $DOTNET5 HKLM $DOTNET2 "InstallRoot" StrCmp $DOTNET5 "" noDotNet StrCpy $DOTNET5 "$DOTNET5$DOTNET4.$DOTNET3\mscorlib.dll" IfFileExists $DOTNET5 yesDotNet noDotNet noDotNet: StrCmp ${DOTNETLASTFUNCTION} "INSTALL_ABORT" +1 nDN2 MessageBox MB_YESNO|MB_ICONQUESTION \ "You must have Microsoft .NET Framework version ${DOTNETVMAJOR}.${DOTNETVMINOR}.${DOTNETVMINORMINOR}$\nor higher installed. Install now?" \ IDYES +2 IDNO +1 Abort ExecWait '${DOTNETPATH}' Goto DotNetStartEnum nDN2: StrCmp ${DOTNETLASTFUNCTION} "INSTALL_NOABORT" +1 nDN3 MessageBox MB_YESNO|MB_ICONQUESTION \ "Microsoft .NET Framework version ${DOTNETVMAJOR}.${DOTNETVMINOR}.${DOTNETVMINORMINOR} is not installed.$\nDo so now?" \ IDYES +1 IDNO +3 ExecWait '${DOTNETPATH}' Goto DotNetStartEnum StrCpy $DOTNET1 0 Goto DotNetFinish nDN3: StrCmp ${DOTNETLASTFUNCTION} "WARNING" +1 nDN4 MessageBox MB_OK|MB_ICONEXCLAMATION \ "Warning:$\n$\n$\t$\tMicrosoft .NET Framework version$\n$\t$\t${DOTNETVMAJOR}.${DOTNETVMINOR}.${DOTNETVMINORMINOR} is not installed!" \ IDOK 0 StrCpy $DOTNET1 0 Goto DotNetFinish nDN4: StrCmp ${DOTNETLASTFUNCTION} "ABORT" +1 nDN5 MessageBox MB_OK|MB_ICONEXCLAMATION \ "Error:$\n$\n$\t$\tMicrosoft .NET Framework version$\n$\t$\t${DOTNETVMAJOR}.${DOTNETVMINOR}.${DOTNETVMINORMINOR} is not installed, aborting!" \ IDOK 0 Abort nDN5: StrCmp ${DOTNETLASTFUNCTION} "IGNORE" +1 nDN6 StrCpy $DOTNET1 0 Goto DotNetFinish nDN6: MessageBox MB_OK \ "$(^Name) Setup internal error.$\nMacro 'DotNetSearch', parameter '4'(${DOTNETLASTFUNCTION})invalid.$\nValue must be INSTALL_ABORT|INSTALL_NOABORT|WARNING|ABORT|IGNORE$\nSorry for the inconvenience.$\n$\tAborting..." \ IDOK 0 Abort yesDotNet: StrCpy $DOTNET1 1 DotNetFinish: Pop $DOTNET6 Pop $DOTNET5 Pop $DOTNET4 Pop $DOTNET3 Pop $DOTNET2 !define ${DOTNETOUTCOME} $DOTNET1 Exch $DOTNET1 !macroend
This macro is just a slightly edited (for easier use as a macro, user choices, and avoiding possible conflicts). It was actually edited off of "DotNetSearchAdv" and was made able to have the following capabilities pointed out below.
Using the Macro
When using the DotNetSearch macro, there are 5 simple parameters that will be explained. Parameter 1 is the Major version of the required .NET Framework. Parameter 2 is the Minor version of the required .NET Framework. Parameter 3 is the Secondary Minor version of the required .NET Framework. Keep in mind, the DotNetSearch macro must be used within a function/section. (In Example:)
Function .onInit !insertmacro DotNetSearch 2 0 50727 "" "" FunctionEnd ;or Function .onInit !insertmacro DotNetSearch 2 0 "" "" "" FunctionEnd
Parameter 4 defines what happens if the required version of .NET Framework is not found. There are 5 different options:
- INSTALL_ABORT
- Shows a message box asking whether or not to install .NET Framework (pressing no aborts setup)
- INSTALL_NOABORT
- Shows a message box asking whether or not to install .NET Framework (pressing no continues setup without installing .NET Framework)
- WARNING
- Shows a message box warning the user that they do not have the required .NET Framework version, then after clicking OK, simply continues the setup.
- ABORT
- Shows a message box informing the user that they do not have the required .NET Framework version, then after clicking OK, aborts the setup.
- IGNORE
- Ignore continues the setup even if the required version of .NET Framework version is not installed, without warning, aborting, or installing.
Parameter 5 defines the location that the executable file to install .NET Framework is. This is so that if the file is external, it can be called upon. If it's not, then you can try other tricks to install it. Perhaps defining parameter 4 as IGNORE, then telling your setup to extract the setup file from your setup file to a temporary folder (IE: $TEMP) then installing, or finding a way to install from online. However, this macro does not support online installing, and I do not plan on modifying it too. But, I am very open to anyone modifying the code, in-fact, the result of whether or not .NET Framework is installed is saved to ;;${DOTNETOUTCOME}, so if you wish to include code after the macro depending on whether it is installed (${DOTNETOUTCOME} will equal 0) or whether it is (${DOTNETOUTCOME} will equal 1), you can. Using this you could probably easily insert your own message box or download .NET Framework online.
Yet again, that is you burden.
Description
There are some problems in the detecting .NET version in a such way. First of all, not all the frameworks write their versions under the "Policy" branch. For example, I have Framework 3.5 on my Windows XP, but in "Policy" branch there are only v1.1 and v2.0. Maybe, the better approach is to cycle through "Software\Microsoft\NET Framework Setup\NDP" branch? Also, the way to ensure that's FW is installed by checking the existing of the mscorlib.dll in the directory with FW version in its path is rather tricky and risky. Again in my case with Framework 3.5, I have no mscorlib.dll in C:\Windows\Microsoft.NET\Framework\v3.5, nor in C:\Windows\Microsoft.NET\Framework\v3.0, only in C:\Windows\Microsoft.NET\Framework\v1.1 and C:\Windows\Microsoft.NET\Framework\v2.0. So this check I'm failing too. Maybe my issues will be helpful to someone...
See also How to Detect any .NET Framework, which appears to use the method suggested here.