Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Future-proofing the .NET version detection

Tags:

c#

.net

detection

Not to beat the dead horse, however, I am looking for a way to detect the installed .NET frameworks. It seems like the provided solutions (in the links) are all good up until the point a new version of the framework is released and then all bets are off. The reason for this is that the detection relies on the registry keys and it seems that v4 of the framework has broken the convention and one now has to take extra steps to detect v4.

Is there a way to detect the .NET framework that will also work when .NET v5 appears.

EDIT: Ok, for future generations of frustrated .NET Version seekers, here is the code to make it happen:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;
using Microsoft.Win32;

private List<string> GetInstalledDotNetFrameworks()
{
    string key = string.Empty;
    string version = string.Empty;
    List<string> frameworks = new List<string>();

    var matches = Registry.LocalMachine
                .OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP")
                .GetSubKeyNames().Where(keyname => Regex.IsMatch(keyname, @"^v\d"));


    // special handling for v4.0 (deprecated) and v4 (has subkeys with info)
    foreach (var item in matches)
    {
        switch (item)
        {
            case "v4.0":  // deprecated - ignore
                break;

            case "v4":// get more info from subkeys

                key = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\" + item;
                string[] subkeys = Registry.LocalMachine
                    .OpenSubKey(key)
                    .GetSubKeyNames();


                foreach (var subkey in subkeys)
                {
                    key = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\" + item + @"\" + subkey;
                    version = Registry.LocalMachine
                            .OpenSubKey(key)
                            .GetValue("Version").ToString();

                    version = string.Format("{0} ({1})", version, subkey);
                    frameworks.Add(version);
                }


                break;
            case "v1.1.4322":   // special case, as the framework does not follow convention
                frameworks.Add(item);
                break;
            default:

                try
                {
                    // get the Version value
                    key = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\" + item;
                    version = Registry.LocalMachine
                            .OpenSubKey(key)
                            .GetValue("Version").ToString();

                    frameworks.Add(version);

                }
                catch
                {
                    // most likely new .NET Framework got introduced and broke the convention
                }

                break;

        }

    }

    // sort the list, just in case the registry was not sorted
    frameworks.Sort();

    return frameworks;
}
like image 808
AngryHacker Avatar asked Aug 31 '26 15:08

AngryHacker


2 Answers

In short, you can use this approximately (see below for more complete solution):

Microsoft.Win32.Registry.LocalMachine
    .OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP")
    .GetSubKeyNames().Where(keyname=>Regex.IsMatch(keyname,@"^v\d"))

On my machine, this returns: v2.0.50727, v3.0, v3.5, v4, v4.0. Subkeys could be used to detect service packs (which are probably relevant). Also, using the key SOFTWARE\Microsoft\.NETFramework returns v2.0.50727, v3.0 and v4.0.30319 - ehhh, lovely, slightly different!

There's no guarantee this pattern will hold, but it's a pretty reasonable bet :-). http://support.microsoft.com/kb/318785 has some more info on the details of the registry describing the versioning, and in particular, you may need to check for Install - but that's tricky as v4.0 demonstrates.

Edit: I've extended this to detect arbitrary sub-key's of the registry that include installation info so as to detect v4 Client and Full profiles correctly. Also, the RegistryKey type is IDisposable, and it looks like the Dispose method is indeed doing something (registry key unlocking).

var versionList = new List<string>();
using(var ndpKey=Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP")) {
    Action<RegistryKey, Action<RegistryKey,string>> processKids = (node, action) => {
        foreach(var childname in node.GetSubKeyNames())
            using(var child = node.OpenSubKey(childname))
                action(child,childname);
    };

    Action<RegistryKey, Func<RegistryKey, bool>> visitDescendants = null;
    visitDescendants = (regkey, isDone) => {
        if(!isDone(regkey))
            processKids(regkey, (subkey, subkeyname)=>visitDescendants(subkey,isDone));
    };

    processKids(ndpKey, (versionKey, versionKeyName) => {
        if(Regex.IsMatch(versionKeyName,@"^v\d")) {
            visitDescendants(versionKey, key => {
                bool isInstallationNode = Equals(key.GetValue("Install"), 1) && key.GetValue("Version") != null;
                if(isInstallationNode)
                    versionList.Add(
                        key.Name.Substring(ndpKey.Name.Length+1) 
                        + (key.GetValue("SP")!=null ? ", service pack "+ key.GetValue("SP"):"")
                        + " ("+key.GetValue("Version")  +") "
                    );
                return isInstallationNode;
            });
        }
    });
}

versionList then contains:

v2.0.50727, service pack 2 (2.0.50727.4927)   
v3.0, service pack 2 (3.0.30729.4926)   
v3.5, service pack 1 (3.5.30729.4926)   
v4\Client (4.0.30319)   
v4\Full (4.0.30319)   
like image 126
Eamon Nerbonne Avatar answered Sep 03 '26 04:09

Eamon Nerbonne


Do you expect we can tell you the future? :) Why do you need that in the first place? I mean, if you write an app for v4, what difference does it make if v5 is installed or not? You can specify in the app.config what versions you support, but you can't know in advance what the next version will be, or even if your app will run on that. Whenever a new framework comes out, you'll have to test your app, and decide if you want to migrate or not. If you migrate, then you make changes to the app.config and possibly the code, too, and release a new version. If you don't, then you'll still require that an older framework version be installed. It's not like v5 comes out and people will start uninstalling all the previous frameworks. I still have v1.1 and v2 on my machine and I guess they'll stick around for a while.

like image 21
fejesjoco Avatar answered Sep 03 '26 04:09

fejesjoco