41

I have a question similar to Inno Setup: Verify that .NET 4.0 is installed, but it seems to be slightly different.

[Files]
Source: "dependencies\dotNetFx40_Full_x86_x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall; Check: FrameworkIsNotInstalled
Source: "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\MySql.Data\v4.0_6.5.4.0__c5687fc88969c44d\MySql.Data.dll"; DestDir: "{app}\lib"; StrongAssemblyName: "MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, ProcessorArchitecture=MSIL"; Flags: "gacinstall sharedfile uninsnosharedfileprompt"

[Run]
Filename: {tmp}\dotNetFx40_Full_x86_x64.exe; Description: Install Microsoft .NET Framework 4.0; Parameters: /q /norestart; Check: FrameworkIsNotInstalled

[code]
function FrameworkIsNotInstalled: Boolean;
begin
  Result := not RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\Microsoft\.NETFramework\policy\v4.0');
end;

As you can see, I'm trying to register a file with the GAC. Unfortunately on some machines it's possible that the .NET framework is not installed. So I need to install it first. Is there anyway that I can force an installation of the .NET runtime before I try to register my files?

Martin Prikryl
  • 167,268
  • 50
  • 405
  • 846
Wayne Werner
  • 45,646
  • 26
  • 189
  • 275
  • possible duplicate of [InnoSetup: Verify that .NET 4.0 is installed](http://stackoverflow.com/questions/4104011/innosetup-verify-that-net-4-0-is-installed) – stuartd Dec 23 '13 at 23:51
  • 1
    @stuartd, it is not a duplicate... – TLama Dec 23 '13 at 23:52
  • 5
    Definitely *not* a duplicate - that simply checks, which I'm already doing. I'm distributing the executable and want it to be installed before I try to install the next file to the GAC. (Also that question is the one I linked to ;) – Wayne Werner Dec 23 '13 at 23:54
  • 2
    Notice that the correct parameter is `/norestart` instead of `/noreboot`. – Marc.2377 Apr 14 '15 at 15:28
  • @Marc.2377 updated to the correct parameter for those who don't read the comments ;) – Wayne Werner Apr 14 '15 at 16:47

4 Answers4

68

Since the [Run] section is processed after the [Files] section, it is naturally impossible to do it with the script you've shown (hence your question). There are few ways where the one I would recommend is to execute the .NET setup from the AfterInstall parameter function of the setup entry itself. So you would remove your current [Run] section and write a script like this:

[Files]
Source: "dependencies\dotNetFx40_Full_x86_x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall; AfterInstall: InstallFramework; Check: FrameworkIsNotInstalled
Source: "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\MySql.Data\v4.0_6.5.4.0__c5687fc88969c44d\MySql.Data.dll"; DestDir: "{app}\lib"; StrongAssemblyName: "MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, ProcessorArchitecture=MSIL"; Flags: gacinstall sharedfile uninsnosharedfileprompt

[Code]
procedure InstallFramework;
var
  ResultCode: Integer;
begin
  if not Exec(ExpandConstant('{tmp}\dotNetFx40_Full_x86_x64.exe'), '/q /norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
  begin
    { you can interact with the user that the installation failed }
    MsgBox('.NET installation failed with code: ' + IntToStr(ResultCode) + '.',
      mbError, MB_OK);
  end;
end;

The process is easy, if the Check function of the .NET setup entry of the [Files] section evaluates to True (FrameworkIsNotInstalled), the entry is processed, which copies the setup binary into the Inno Setup's temporary folder and if that succeeds, the AfterInstall function InstallFramework is called immediately after. Inside of this function, the .NET setup is manually executed by calling Exec function.

And finally, if all of that succeeds, the installation continues to process the next [Files] section entry, which is your assembly that is going to be registered. Now, with the installed .NET framework. So as you can see, the order of the [Files] section entries is crucial here.


You've additionally asked in your comment, how to show to the user some progress, since executing the .NET setup in the way I've posted here blocks the [Files] entry, which leads to showing the stopped progress bar and text about extracting files. Since it wouldn't be easy to get the .NET setup's installation progress, I would simply show to the user endless marquee progress bar during that setup execution.

To do this wrap that setup execution into a code like this:

procedure InstallFramework;
var
  StatusText: string;
begin
  StatusText := WizardForm.StatusLabel.Caption;
  WizardForm.StatusLabel.Caption := 'Installing .NET framework...';
  WizardForm.ProgressGauge.Style := npbstMarquee;
  try
    { here put the .NET setup execution code }
  finally
    WizardForm.StatusLabel.Caption := StatusText;
    WizardForm.ProgressGauge.Style := npbstNormal;
  end;
end;

This is how the wizard form looks like during that .NET setup execution (the progress bar is animated):

enter image description here

Community
  • 1
  • 1
TLama
  • 73,451
  • 17
  • 201
  • 368
  • Epic. This totally works - however there is one oddness - it appears to hang on "extracting files" while it performs the install. Is there any way I can show the user that something is, in fact, happening here? – Wayne Werner Dec 24 '13 at 00:44
  • 2
    I've added a code skeleton for how to turn the installation progress bar into a marquee style and a text about installing .NET framework during that .NET setup execution. When that setup finishes, the progress bar changes back to the normal style and the text is restored to "Extracting files...". – TLama Dec 24 '13 at 01:52
  • 3
    I wish I could +2 this. It's a fantastic solution! – Wayne Werner Dec 24 '13 at 02:05
  • Rather than doing the Marque myself, I've just used the /passive option for the .NET installer (also the VC++ runtime). This does have the downside of popping up extra message boxes, but it's a slightly simpler solution. – CJBrew Mar 07 '14 at 17:35
  • 1
    adding the /q will fail the installation again, sadly, however thanks a lot and I will delete em – CularBytes Dec 23 '14 at 23:28
  • yup, doesnt report any error, it is probably because on install you have to accept license agreement, inno can't handle that.. You could start a chat if you like.. – CularBytes Dec 23 '14 at 23:32
  • Hi @Tlama .I use your answer to install SQL-server . Help me How can change marquee to progress-bar f? – sina Aug 10 '20 at 18:28
11

I just want to add something to @TLama: The close when the setup fails. It's not so easy because WizardForm.Close; just invokes the cancel-button which can be aborted by the user. Finally, the code can look like that:

[Code]
var CancelWithoutPrompt: boolean;

function InitializeSetup(): Boolean;
begin
  CancelWithoutPrompt := false;
  result := true;
end;

procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
  if CurPageID=wpInstalling then
    Confirm := not CancelWithoutPrompt;
end;

function FrameworkIsNotInstalled: Boolean;
begin
  Result := not RegKeyExists(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full');
end;

procedure InstallFramework;
var
  StatusText: string;
  ResultCode: Integer;
begin
  StatusText := WizardForm.StatusLabel.Caption;
  WizardForm.StatusLabel.Caption := 'Installing .NET framework...';
  WizardForm.ProgressGauge.Style := npbstMarquee;
  try
      if not Exec(ExpandConstant('{tmp}\dotNetFx45_Full_asetup.exe'), '/q /norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
  begin
    // you can interact with the user that the installation failed
    MsgBox('.NET installation failed with code: ' + IntToStr(ResultCode) + '.',
      mbError, MB_OK);
    CancelWithoutPrompt := true;
    WizardForm.Close;       
  end;
  finally
    WizardForm.StatusLabel.Caption := StatusText;
    WizardForm.ProgressGauge.Style := npbstNormal;
  end;
end;
Martin Prikryl
  • 167,268
  • 50
  • 405
  • 846
Snicker
  • 867
  • 10
  • 16
  • Err, *close when the setup fails*, in what ? Where ? And mainly why ? The question did not ask for how to close the wizard form when the installation fails. Anyway, forcefully closing the wizard form smells like a bad UX idea. Or did I miss something ? – TLama Jan 10 '15 at 23:27
  • 2
    Why? In your code, the setup would continue even if the installation of the Framework fails. No, he did not ask for that, but it's an advantage if it doesn't finish with "successful installed" and the user can't execute the program. And no, it doesn't kill the installer. It just skips the question to the user "do you really want to cancel". – Snicker Jan 11 '15 at 00:03
  • Ah, I see the problem now. Well, I should have probably suggest installing from the `PrepareToInstall` event rather than using `AfterInstall` feature. That allows you to *more gracefully* exit the setup. – TLama Jan 11 '15 at 01:46
7

just my 2 cents on checking for .NET Framework 4.7, fits right in with @Snicker's answer:

function FrameworkIsNotInstalled: Boolean;
var
  ver: Cardinal;
begin
  Result :=
    not
    (
    (RegKeyExists(
      HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client')
    and
        RegQueryDWordValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client', 'Release', ver)
    )
    or
    (RegKeyExists(
      HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full')
    and
        RegQueryDWordValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', ver)
    )
    )
    and (ver < 460798)
end;
BananaAcid
  • 2,890
  • 33
  • 34
  • 1
    Your function is awesome. If some looking for other version of .net look at this page https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed – Amir Jul 02 '17 at 19:05
  • EXACTLY what I was looking for, during HOURS ! Thanks a lot mate ! Note, for 4.7.1, last line should be and (ver < 461308) – cdie Oct 18 '17 at 15:12
0

You can also set it up to download the web bootstrapper and run it if you don't want to package in the very heavy full .NET installer. I have written a blog post on how to do that with Inno Download Plugin.

RandomEngy
  • 14,459
  • 5
  • 69
  • 108