3

How do I detect in the Windows Registry if a user has .Net Framework installed? I am not looking for a .Net based solution, as the query is from InnoSetup.

I know from reading another post here on Stack Overflow that .Net Framework is an inplace upgrade to 4.0.

I already know how to check if a user has version 4.0 installed on the system, namely by checking the following:

function FindFramework(): Boolean; 
var
 bVer4x0: Boolean;
 bVer4x0Client: Boolean;
 bVer4x0Full: Boolean;
 bSuccess: Boolean;
 iInstalled: Cardinal;
begin
 Result := False;
 bVer4x0Client := False;
 bVer4x0Full := False;


 bVer4x0 := RegKeyExists(HKLM, 'SOFTWARE\Microsoft\.NETFramework\policy\v4.0'); 
 bSuccess := RegQueryDWordValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4    \Client', 'Install', iInstalled);
 if (1 = iInstalled) AND (True = bSuccess) then bVer4x0Client := True;
 bSuccess := RegQueryDWordValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4        \Full', 'Install', iInstalled);
 if (1 = iInstalled) AND (True = bSuccess) then bVer4x0Full := True;

 if (True = bVer4x0Full) then begin
    Result := True;
 end;
end;

I checked the registry and there is no v4.5 folder, which makes sense if .Net Framework 4.5 is an inplace upgrade. Still, the Control Panel Programs and Features includes the listing.

I know that probably "issuing dotNetFx45_Full_setup.exe /q" will have no bad effect if installing on a system that already has version 4.5, but I still would like to not install the upgrade if the upgrade already exists, faster and less problems.

TLama
  • 75,147
  • 17
  • 214
  • 392
Sarah Weinberger
  • 15,041
  • 25
  • 83
  • 130
  • It is highly likely that `dotNetFx45_Full_setup.exe` performs its own auto-detection, and will simply exit if it is already installed – Robert Harvey Oct 10 '12 at 21:16
  • That thought also crossed my mind, but I cannot proceed on a "probably". As Microsoft does not state obviously on the download page, or anywhere, where I personally can easily answer that question conclusively, I need to proceed under the assumption that they do not. Besides, it does not hurt for me to learn a bit more about how to use InnoSetup. – Sarah Weinberger Oct 10 '12 at 21:32

2 Answers2

5

I wanted to share the actual Inno Setup code that I wrote, which specifically answers my question. Thanks to the previous answer for pushing me in the right direction.

function FindFramework45(): Boolean; 
var
 bVer4x5: Boolean;
 bSuccess: Boolean;
 iInstalled: Cardinal;
 strVersion: String;
 iPos: Cardinal;
begin
 Result := False;

 bSuccess := RegQueryDWordValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Install', iInstalled);
 if (1 = iInstalled) AND (True = bSuccess) then
  begin
    bSuccess := RegQueryStringValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Version', strVersion);
    if (True = bSuccess) then
     Begin
        iPos := Pos('4.5.', strVersion);
        if (0 < iPos) then bVer4x5 := True;
     End
  end;

 if (True = bVer4x5) then begin
    Result := True;
 end;
end;

The NextButtonClick() event would call this function right after the welcome.

The File and Run sections merely contain a function which uses the Check and checks that variable.

[Run]
Filename: "{app}\dotNetFx45_Full_setup.exe"; Parameters: "/q"; StatusMsg: "Installing Microsoft .Net 4.5 Framework..."; Check: InstallFramework45();

[Files]
Source: "{#MySourceBaseDir}\{#MyAppVersion}\{#MyDirBinaries}\dotNetFx45_Full_setup.exe"; Flags: deleteafterinstall; DestDir: "{app}"; Check: InstallFramework45();

I will state the obvious that one has to make sure that .Net Framework 4.0 is installed first and then check / install .Net Framework 4.5.

Now, if System.Data.SQLite.org would come out with a Visual Studio 2012 compliant version, I can check off my other big upgrade task.

Update: 2010.10.11 (Per TLana's comment) Note: I decided to leave the original code, because I figure that others would like to see where I started. The code below is where I am at now. The code below also uses the proper registry location and checks for both .Net 4.0 and the new .Net 4.5. What about the future? When .Net 6.0 and 6.5 comes out, all that is needed is change the 4 to a 6, unless Microsoft changes the formula. it seems that the .5 upgrade is not a new framework but an upgrade to the existing one.

[Files]
Source: "{#MySourceBaseDir}\{#MyDirBinaries}\dotNetFx40_Full_x86_x64.exe"; Flags: deleteafterinstall; DestDir: "{app}"; Check: Framework40IsNotInstalled();
Source: "{#MySourceBaseDir}\{#MyDirBinaries}\dotNetFx45_Full_setup.exe"; Flags: deleteafterinstall; DestDir: "{app}"; Check: Framework45IsNotInstalled();
Source: "{#MySourceBaseDir}\{#MyDirBinaries}\mysql-connector-net-6.5.4.msi"; Flags: deleteafterinstall; DestDir: "{tmp}";

[Run]
Filename: "{app}\vcredist_x86.exe"; Parameters: "/q"; StatusMsg: "Installing Microsoft Visual C++ 2010 Redistributable Package...";
Filename: "{app}\dotNetFx40_Full_x86_x64.exe"; Parameters: "/q"; StatusMsg: "Installing Microsoft .Net 4.0 Full Framework..."; Check: Framework40IsNotInstalled();
Filename: "{app}\dotNetFx45_Full_setup.exe"; Parameters: "/q"; StatusMsg: "Installing Microsoft .Net 4.5 Framework..."; Check: Framework45IsNotInstalled();
Filename: "msiexec"; Parameters: "/package ""{tmp}\mysql-connector-net-6.5.4.msi"" /quiet"; StatusMsg: "Installing MySQL Connector...";

[Code]

function Framework40IsNotInstalled: Boolean;
var
 bVer4x0Client: Boolean;
 bVer4x0Full: Boolean;
 bSuccess: Boolean;
 iInstalled: Cardinal;
begin
 Result := True;
 bVer4x0Client := False;
 bVer4x0Full := False;


 bSuccess := RegQueryDWordValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4\Client', 'Install', iInstalled);
 if (1 = iInstalled) AND (True = bSuccess) then bVer4x0Client := True;
 bSuccess := RegQueryDWordValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Install', iInstalled);
 if (1 = iInstalled) AND (True = bSuccess) then bVer4x0Full := True;

 if (True = bVer4x0Full) then begin
    Result := False;
 end;
end;

function Framework45IsNotInstalled: Boolean;
var
 bVer4x5: Boolean;
 bSuccess: Boolean;
 iInstalled: Cardinal;
 strVersion: String;
 iPos: Cardinal;
begin
 Result := True;
 bVer4x5 := False;

 bSuccess := RegQueryDWordValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Install', iInstalled);
 if (1 = iInstalled) AND (True = bSuccess) then
  begin
    bSuccess := RegQueryStringValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Version', strVersion);
    if (True = bSuccess) then
     Begin
        iPos := Pos('4.5.', strVersion);
        if (0 < iPos) then bVer4x5 := True;
     End
  end;

 if (True = bVer4x5) then begin
    Result := False;
 end;
end;
Sarah Weinberger
  • 15,041
  • 25
  • 83
  • 130
  • Some responded to my post on Inno Setup's newsgroup and stated that using the "policy" key is wrong and that the accepted way of checking for installations is to use the NDP key. Even after implementing the answer to this post, I did not make the leap that the policy method is wrong and that I need to change that. I got the code originally from the community on Inno Setup's forum. As I recall, more than one person gave the code. Sadly, it seems that others are unclear about the correct method. It took another person just now for clearing things up. I hope that it helps someone. – Sarah Weinberger Oct 10 '12 at 22:41
  • 1
    Why the `NextButtonClick` event will call that check function and return the value that you store. Use simply the `Check` without any event. When you return true to the function assigned to the `Check`, the file from the `[Run]` section will be executed, False otherwise. You don't need to bother with the check so early, consider also that I can cancel the setup after the first next button click. In that case your function execution would be useless. Why don't you stick to [`the similar`](http://stackoverflow.com/a/10111173/960757) changing only way of registry verification ? – TLama Oct 11 '12 at 09:09
  • You are right TLama. It appears the only problem in the other posting is the author's use of the policy key rather than the NDP key. I posted the updated streamlined code above. The code installs .Net Framework 4.0 if it is not there and then the update .Net Framework 4.5. I also included the install of MySQL too, as a bonus. Sadly, System.Data.SQLite is a manual thing with no nice auto install. – Sarah Weinberger Oct 11 '12 at 14:49
  • The author was me and I've used that key hence I've found it (I can't remember where) most probably on some MS site. Anyway, your update wouldn't even compile at this time. And please use `Variable = Value` statements, not `Value = Variable`. Next thing is that your `Framework40IsNotInstalled` function takes into account only `bVer4x0Full` on it's output and in `Framework45IsNotInstalled` the `bVer4x5` may be undefined ;-) – TLama Oct 11 '12 at 15:11
  • I added the initialization of bVer4x5 to my update. The code compiles and executes perfectly. I just checked. My only complaint is that I do not have a check for the MySQL connector and the VC++ redistribution items. Also, the System.Data.SQLite stuff is still missing, although I am using the static binaries, so not a big deal there. The if-statement comparison construct "if (1 == iValue) then" is purposeful. I know that most people do the other way, but that is dangerous. Let the compiler catch potential gotchas for you. That is especially true in C/C++/C#/VB and in Pascal too. – Sarah Weinberger Oct 11 '12 at 16:19
  • There is nothing dangerous on use condition like `1 = Value` or `Value = 1` in PascalScript, Pascal or Delphi (I'm using Delphi about 11 years so I'd probably meet that). `1 = Value` is just worse readable and almost nobody uses it. – TLama Oct 11 '12 at 23:10
1

How to: Determine Which .NET Framework Versions Are Installed
http://msdn.microsoft.com/en-us/library/hh925568.aspx

How to: Determine Which .NET Framework Updates Are Installed
http://msdn.microsoft.com/en-us/library/hh925567.aspx

The code provided in these two articles works through Version 4.5 of the Framework. The update detection code identifies all routine updates, security updates and hotfixes.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • Well, and how does this answer how to do it in InnoSetup ? Ok, taking back, wrong asked question... There's no need for InnoSetup tag then. – TLama Oct 10 '12 at 21:11
  • @TLama: The code in the articles can be translated fairly easily to InnoWhatever. – Robert Harvey Oct 10 '12 at 21:14
  • Could be, but it's more about registry entries than InnoSetup solution (thus I've removed InnoSetup tag). Anyway, I've seen here a [`very bad way`](http://stackoverflow.com/a/4104226/960757) to do so in InnoSetup. – TLama Oct 10 '12 at 21:19
  • The purpose of the InnoSetup tag is because the solution needs to be InnoSetup friendly and that I am implementing in InnoSetup. The tag is definitely needed. Yes, it has to do with the registry, but not exclusively. – Sarah Weinberger Oct 10 '12 at 21:30
  • Well, then combine registry entries from links from this post with [`something like this`](http://stackoverflow.com/a/10111173/960757). – TLama Oct 10 '12 at 21:36
  • I have something very similar. The examples above and the MSDN sample solved the problem. Okay, the Inno Setup code compiles, but I have yet to test the code. I tested the .Net code under VS2012 and it works great! The solution in Inno Setup is a mere one line. Add a new line using RegQueryStringValue instead of the RegQueryDWordValue and instead of Install use Version. After that use the Pos() function to query for the string '4.5.0'. Inno does not like double quotes for stringes. – Sarah Weinberger Oct 10 '12 at 22:17