My simple timesheet software, Timesheets Lite is a a C# program based on Winforms and the DXperience library for WinForms. It is installed with an innosetup script. Up until yesterday the software required the .NET 2.0 library and the installer could detect if .NET 2.0 was installed and download and install it if it wasn’t. Windows 8 was an exception to this rule as .NET 2.0 (actually .NET 3.5) is a Windows feature that needs to be enabled rather than something that needed to be installed. This wasn’t too difficult to get around because you (used) to be able to use DISM to enable Windows features.
Previously my innosetup script detected if Windows 8 was the target OS and then could simply enable the .NET 3.5 feature using this:
Exec('Dism', ' /online /enable-feature /featurename:NetFx3 /All /NoRestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
This had worked fine previously because Windows went away (presumably to the Windows Update site) and downloaded what it needed from there. But it doesn’t work any longer and to get DISM to enable .NET 3.5 the /source parameter must be specified pointing to a local copy of the Windows 8 installation media or an ISO. Clearly this isn’t acceptable for my purposes. Hence I decided to update Timesheets Lite to require the .NET 4.0 library (which is installed on W8 by default). This threw up some other problems though because now I needed to detect .NET 4.0 on earlier versions of Windows, and download and install it during the Timesheets Lite installation process.
This was (surprisingly) easy. I made use of the innosetup .NET detection function from this page and modified the inno script I’d written years ago to download and install .NET 2.0. Here’s some code from my innosetup script for giggles. Firstly, the InitializeSetup function which determines what version of Windows is the target and uses the IsDotNetDetected function to check for the .NET 4.0 client or full installation.
function InitializeSetup(): Boolean; begin dotNetNeeded := false; Windows8 := false; Result := true; if (Version.Major=6) and (Version.Minor=2) then begin Windows8:=true; end; if (not IsDotNetDetected('v4\Client', 0)) and (not Windows8) then begin if not IsDotNetDetected('v4\Full', 0) then begin dotNetNeeded := true; end end if dotNetNeeded then begin if (not IsAdminLoggedOn()) then begin MsgBox('This program needs the Microsoft .NET 4.0 Framework to be installed by an Administrator', mbInformation, MB_OK); Result := false; end else begin dotnetRedistPath := ExpandConstant('{src}\dotnetfx.exe'); if not FileExists(dotnetRedistPath) then begin dotnetRedistPath := ExpandConstant('{tmp}\dotnetfx.exe'); if not FileExists(dotnetRedistPath) then begin isxdl_AddFile(dotnetRedistURL, dotnetRedistPath); downloadNeeded := true; end end SetIniString('install', 'dotnetRedist', dotnetRedistPath, ExpandConstant('{tmp}\dep.ini')); end end end;
Next up I’ve added some code to the NextButtonClick function that runs when the current page is wpReady (read to install).
dotnetRedistURL = 'http://download.microsoft.com/download/9/5/A/95A9616B-7A37-4AF6-BC36-D6EA96C8DAAE/dotNetFx40_Full_x86_x64.exe'; function NextButtonClick(CurPage: Integer): Boolean; var hWnd: Integer; begin Result := true; //********************************************************************************* // Only run this at the "Ready To Install" wizard page. //********************************************************************************* if CurPage = wpReady then begin hWnd := StrToInt(ExpandConstant('{wizardhwnd}')); // don't try to init isxdl if it's not needed because it will error on < ie 3 //********************************************************************************* // Download the .NET 4.0 redistribution file. //********************************************************************************* if downloadNeeded and (dotNetNeeded = true) and Windows8 = false then begin isxdl_SetOption('label', 'Downloading Microsoft .NET Framework 4.0'); isxdl_SetOption('description', 'This program needs to install the Microsoft .NET Framework 4.0. Please wait while Setup is downloading extra files to your computer.'); if isxdl_DownloadFiles(hWnd) = 0 then Result := false; end; //********************************************************************************* // Run the install file for .NET Framework 4.0. This is usually dotnetfx.exe //********************************************************************************* if ((dotNetNeeded = true)) then begin if Exec(ExpandConstant(dotnetRedistPath), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin // handle success if necessary; ResultCode contains the exit code if not (ResultCode = 0) then begin Result := false; end end else begin // handle failure if necessary; ResultCode contains the error code Result := false; end; end; end; end;
I tested this script on XP, Vista, Windows 7 and Windows 8 and it works very well. The .NET 4.0 download is about 50MB so it’s not too big an impost for users. And I suspect most people will have .NET 4.0 installed anyway. Note that you’ll have to to be using the isxdl innosetup plugin for this installation procedure to work.