3

As the title says: Is there a common way in C# and especially unmanaged native C++ to determine installed CLR versions? This means not just checking whether the Framework is installed according this KB article. I want to do it by using the CLR interface, as done here for CLR1, CLR1.1 and CLR2. In this way I can make sure that they are really installed. But this doesn't apply to CLR4. Any Ideas?

My goal is to create an enumeration of available CLR versions like Clrver (regardless the process list functionallity) does.

Abel
  • 56,041
  • 24
  • 146
  • 247
Christoph Meißner
  • 1,511
  • 2
  • 21
  • 40
  • where I've had to do it I've always used the registry method and any library you pull in will probably be doing the same thing. It would be really nice if there was a better way to do this but I don't think there is. – Yaur Mar 18 '12 at 18:19
  • I think regarding to a common way you are right. The problem is, that in this case all versions have to be well known, what also accounts to beta versions. But as in the Code example I've posted sometimes maybe also betaversions need to be considered. And I think that there must be a way because CLRVER of VS2008 also works when installing .NET4 but not VS2010 (and a new version of CLRVER). So there must be a way to detect all installed CLR versions without exactly knowing them. – Christoph Meißner Mar 19 '12 at 16:22

2 Answers2

5

"Common way" or not, but dotNetInstaller at Codeplex does this in native, unmanaged C++ code.
SInce it's open source, take a look how they do it.

Further, you can use the ICLRMetaHost::EnumerateInstalledRuntimes Method to detect .NET v4+ and GetRequestedRuntimeInfoInfo (much the same way as clrver.cpp does it) to detect .NET v1 - v2. So you have to make two calls, but that should cover it.

Magnus Johansson
  • 28,010
  • 19
  • 106
  • 164
  • I had a look at the sourcecode. But if I'm right, it seems to use the wellknown approach as mentioned above. It looks for installed .NET-Frameworks but not explicitly for installed CLR-Versions. – Christoph Meißner Mar 19 '12 at 16:23
  • OK, added EnumerateInstalledRuntimes – Magnus Johansson Mar 19 '12 at 16:53
  • The method `EnumerateInstalledRuntimes` is only available since .NET Framework 4.0. – Abel Mar 19 '12 at 17:05
  • 1
    _"So you have to make two calls, but that should cover it."_ >> actually, clrver.cpp makes many more calls and checks, because of differences between 1.0, 1.1 and 2.0. I'm not certain whether this also finds all beta-versions (not sure OP wants that yet). I'd suggest to update clrver.cpp and make your own "one call function", not ideal, but it'd work (unfortunately, the latest, more functional version of clrver is only available as binary...). – Abel Mar 20 '12 at 08:00
  • More: clrver detects 1.0, 1.1 and the latest of any 2.x-3.5 version (knowing that 3.5 is actually reported as a later 2.x version). It does not find the version numbers of [List Of Version Numbers](http://en.wikipedia.org/wiki/List_of_.NET_Framework_versions). Strangely, [`GetRequestedRuntimeInfo`](http://msdn.microsoft.com/en-us/library/ms230176.aspx) doesn't find "latest version" as it says, it finds latest 2.x. The docs are vague on what it should return. – Abel Mar 20 '12 at 08:27
-1

While reading Jeffrey Richters book Applied Microsoft® .NET Framework Programming I've found some interesting hints towards that topic. Towards the topic Loading the Common Language Runtime (p. 41) he mentioned to examine the registry path (and subkeys) HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\policy to check for installed runtimes. Therefore I've found an interesting KB article towards that topic. Furthermore in the section How the Runtime Resolves Type References (p. 132) he mentioned that mscorlib.dll is tied to the CLR version. So i think it should be possible to check the found registry keys against this file and its version to ensure that the found key is installed CLR version.

In the following you will find my conclusion about that in code. :) I think Clrver does something similar. And I think this solution should be also applicable for a native C++ application since my following code is C# and is just using very basic framework functions.

List<string> installedRuntimes = new List<string>();

Regex rxVersion = new Regex(@"^[v](\d{1,5})([\.](\d{1,5})){0,3}$");
Regex rxVersionPart = new Regex(@"^\d{1,5}$");            

try
{
    string installPath = Convert.ToString(Registry.GetKey("HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework").GetValue("InstallRoot"));
    string[] shortVersions = Registry.GetKey("HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework/Policy", false).GetSubKeyNames();
    foreach (string shortVersion in shortVersions)
        if (rxVersion.IsMatch(shortVersion))
        {
            string[] versionExtensions = Registry.GetKey("HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework/Policy/" + shortVersion, false).GetValueNames();
            foreach (string versionExtension in versionExtensions)
                if (rxVersionPart.IsMatch(versionExtension))
                {
                    string fullVersion = shortVersion + "." + versionExtension;
                    if (rxVersion.IsMatch(fullVersion))
                    {
                        string clrPath = installPath + fullVersion + "\\mscorlib.dll";
                        if (File.Exists(clrPath) && FileVersionInfo.GetVersionInfo(clrPath).FileVersion.StartsWith(fullVersion.Substring(1))) installedRuntimes.Add(fullVersion);
                    }
                }
        }
}
catch { } // May fails while getting a specific registry key, if Microsoft changes the naming rules.

(Don't mess up with Registry.GetKey(...) - its just a wrapper for the .NET Registry functionality, to easify it towards the way I am used to use the registry.) In the end you should have the CLR version strings inside the list installedRuntimes as Clrver lists it.

Christoph Meißner
  • 1,511
  • 2
  • 21
  • 40
  • Good question! As you may see, this code relies on naming rules, which may change in future versions of CLR/.NET. So the code still runs but the naming and position of the CLR in registry has changed. In this case method calls like `GetKey` (and submethods) will fail. The result will be an empty list of versions. But for the moment this code should work without the try catch block. – Christoph Meißner Nov 03 '12 at 11:03
  • When a target machine does not have any CLR version installed How Your managed code application can detect the installed CLR's before the application code even gets a chance to run. I think you need to rewrite the code in an unmanaged platform like C++ – NET3 Nov 09 '12 at 19:13
  • 1
    Regarding the usage of exactly this code, you are correct, that there is no possibility to run it without any CLR installed. The code above is used to show the rules, how Clrver works maybe, and could be adopted to any other language and/or runtime environment easily. – Christoph Meißner Nov 10 '12 at 15:59