Click here to Skip to main content
Click here to Skip to main content

Using managed code to detect what .NET Framework versions and service packs are installed

By , 8 Sep 2008
 

Introduction

Developers are increasingly faced with the possibility of multiple .NET Framework versions being installed on the same machine. The .NET architecture was designed to allow multiple versions of a component to be installed and run at the same time on a single system, and this side-by-side deployment extends to the .NET Framework itself. By allowing multiple versions of the .NET Framework to be installed on the same computer, applications built with version 1.0 of the .NET Framework can run using the newer versions, or continue running with the earlier version. By default, client-side applications will use the version of the .NET Framework with which they were built, even when a newer version is available on the client.

There are situations, however, where it becomes important, or at least interesting, to know which versions of the .NET Framework are installed. Typically, this is done during installation, and the best way to do this is using unmanaged C++. Remember, you can only run managed code if a version of the .NET Framework is already installed, so this class is not guaranteed to work as part of an installation process. Aaron Stebner has a great set of blog posts [^] (including sample code) that shows how to do this in C++, and you can also check out this article [^].

While C++ may be the best way to do this, there are still times when this same functionality is needed in managed code. After searching both Google and CodeProject, I was unable to find a satisfactory solution in managed code. As a result, I decided to port Aaron's code to C#. This code uses Generics, so it is only compatible with version 2.0 or later of the .NET Framework.

Background

The correct way to determine if a specific version of the .NET Framework is installed is to look in the Registry. Aaron and a few readers of this article have pointed out that this solution, while the recommended way, is not 100% accurate in all situations. There are occasions when the Registry keys are orphaned, such as OS reinstalls. The solution presented by Aaron uses a technique by Junfeng Zhang [^] which loads mscoree.dll and uses some of its API functions to query for the presence of specific versions of the .NET Framework. The problem with this approach is that it only works from unmanaged code.

I took a slightly different approach, which more closely follows how the .NET Framework 3.5 setup checks for its prerequisites [^]. This approach looks for the presence of mscorwks.dll and, if found, verifies that the version number of the file is greater than or equal to the requested .NET Framework version, in addition to verifying that the Registry value is greater than or equal to the requested .NET Framework version. Consequently, if the file isn't found, I simply test the Registry value.

Using the code

Each major release of the .NET Framework has changed the Registry location and, in some cases, the keys and value names to look for in the Registry. In order to consolidate checking all of the various Registry keys and help isolate changes for future versions of the .NET Framework, the FrameworkVersionDetection class was created. This class exposes the following public methods and properties:

  • public static bool IsInstalled(FrameworkVersion frameworkVersion)
  • public static bool IsInstalled(WindowsFoundationLibrary foundationLibrary)
  • public static int GetServicePackLevel(FrameworkVersion frameworkVersion)
  • public static int GetServicePackLevel(WindowsFoundationLibrary foundationLibrary)
  • public static Version GetExactVersion(FrameworkVersion frameworkVersion)
  • public static Version GetExactVersion(WindowsFoundationLibrary foundationLibrary)
  • public static IEnumerable InstalledFrameworkVersions

As you can see, all of these functions use either the FrameworkVersion or the WindowsFoundationLibrary enumeration. These enumerations have the following definition:

/// <summary>/// Specifies the .NET Framework versions
///// </summary>
public enum FrameworkVersion
{
  /// <summary>
  /// .NET Framework 1.0
  /// </summary>
  Fx10,

  /// <summary>
  /// .NET Framework 1.1
  /// </summary>
  Fx11,

  /// <summary>
  /// .NET Framework 2.0
  /// </summary>
  Fx20,

  /// <summary>
  /// .NET Framework 3.0
  /// </summary>
  Fx30,

  /// <summary>
  /// .NET Framework 3.5
  /// </summary>
  Fx35,
}

/// <summary>
/// Specifies the .NET 3.0 Windows Foundation Library
/// </summary>
public enum WindowsFoundationLibrary
{
  /// <summary>
  /// Windows Communication Foundation
  /// </summary>
  WCF,

  /// <summary>
  /// Windows Presentation Foundation
  /// </summary>
  WPF,

  /// <summary>
  /// Windows Workflow Foundation
  /// </summary>
  WF,

  /// <summary>
  /// Windows CardSpace
  /// </summary>
  CardSpace,
}

A complete example in C# looks like this:

bool fx10Installed = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx10);
bool fx11Installed = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx11);
bool fx20Installed = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx20);
bool fx30Installed = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx30);
bool fx35Installed = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx35);

Console.WriteLine(".NET Framework 1.0 installed? {0}", fx10Installed);
if (fx10Installed)
{
   Console.WriteLine(".NET Framework 1.0 Exact Version: {0}",
      FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx10));
   Console.WriteLine(".NET Framework 1.0 Service Pack: {0}",
      FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx10));
}
Console.WriteLine();

Console.WriteLine(".NET Framework 1.1 installed? {0}", fx11Installed);
if (fx11Installed)
{
   Console.WriteLine(".NET Framework 1.1 Exact Version: {0}",
     FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx11));
   Console.WriteLine(".NET Framework 1.1 Service Pack: {0}",
     FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx11));
}
Console.WriteLine();

Console.WriteLine(".NET Framework 2.0 installed? {0}", fx20Installed);
if (fx20Installed)
{
   Console.WriteLine(".NET Framework 2.0 Exact Version: {0}",
     FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx20));
   Console.WriteLine(".NET Framework 2.0 Service Pack: {0}",
     FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx20));
}
Console.WriteLine();

Console.WriteLine(".NET Framework 3.0 installed? {0}", fx30Installed);
if (fx30Installed)
{
   Console.WriteLine(".NET Framework 3.0 Exact Version: {0}",
     FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx30));
   Console.WriteLine(".NET Framework 3.0 Service Pack: {0}",
     FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx30));

   bool fx30PlusWCFInstalled = 
        FrameworkVersionDetection.IsInstalled(WindowsFoundationLibrary.WCF);
   bool fx30PlusWPFInstalled = 
        FrameworkVersionDetection.IsInstalled(WindowsFoundationLibrary.WPF);
   bool fx30PlusWFInstalled = 
        FrameworkVersionDetection.IsInstalled(WindowsFoundationLibrary.WF);
   bool fx30PlusCardSpacesInstalled =
      FrameworkVersionDetection.IsInstalled(WindowsFoundationLibrary.CardSpace);

   Console.WriteLine();

   Console.WriteLine("Windows Communication Foundation installed? {0}", 
                     fx30PlusWCFInstalled);
   if (fx30PlusWCFInstalled)
   {
     Console.WriteLine("Windows Communication Foundation Exact Version: {0}",
       FrameworkVersionDetection.GetExactVersion(WindowsFoundationLibrary.WCF));
   }
   Console.WriteLine();

   Console.WriteLine("Windows Presentation Foundation installed? {0}", 
                     fx30PlusWPFInstalled);
   if (fx30PlusWPFInstalled)
   {
     Console.WriteLine("Windows Presentation Foundation Exact Version: {0}",
       FrameworkVersionDetection.GetExactVersion(WindowsFoundationLibrary.WPF));
   }
   Console.WriteLine();

   Console.WriteLine("Windows Workflow Foundation installed? {0}", 
                     fx30PlusWFInstalled);
   if (fx30PlusWFInstalled)
   {
     Console.WriteLine("Windows Workflow Foundation Exact Version: {0}",
       FrameworkVersionDetection.GetExactVersion(WindowsFoundationLibrary.WF));
   }
   Console.WriteLine();

   Console.WriteLine("Windows CardSpaces installed? {0}", 
                     fx30PlusCardSpacesInstalled);
   if (fx30PlusCardSpacesInstalled)
   {
     Console.WriteLine("Windows CardSpaces Exact Version: {0}",
       FrameworkVersionDetection.GetExactVersion(WindowsFoundationLibrary.CardSpace));
   }
   Console.WriteLine();
}
Console.WriteLine();

Console.WriteLine(".NET Framework 3.5 installed? {0}", fx35Installed);
if (fx35Installed)
{
   Console.WriteLine(".NET Framework 3.5 Exact Version: {0}",
     FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx35));
   Console.WriteLine(".NET Framework 3.5 Service Pack: {0}",
     FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx35));
}
 
foreach (Version fxVersion in FrameworkVersionDetection.InstalledFrameworkVersions)
{
   Console.WriteLine(fxVersion .ToString());
}

Registry keys

The Registry keys used to determine if a particular version of the .NET Framework is installed are:

Framework Version Registry Key
1.0 HKLM\Software\Microsoft\.NETFramework\Policy\v1.0\3705
1.1 HKLM\Software\Microsoft\NET Framework Setup\NDP\v1.1.4322\Install
2.0 HKLM\Software\Microsoft\NET Framework Setup\NDP\v2.0.50727\Install
3.0 HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.0\Setup\InstallSuccess
3.5 HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.5\Install

For the .NET Framework v1.0, this is a string value; all of the other versions use a DWORD value which, if present and set to 1, indicates that version of the Framework is installed. For .NET 3.0, it is important to also verify that .NET 2.0 is also installed, and for .NET 3.5, you should verify that both .NET 2.0 and 3.0 are also installed. In order to determine the Service Pack level, the following Registry keys are used:

Framework Version Registry Key

1.0

(Windows Media Center

or

Windows XP Tablet Edition)

HKLM\Software\Microsoft\Active Setup\Installed Components\{FDC11A6F-17D1-48f9-9EA3-9051954BAA24}\Version
1.0 HKLM\Software\Microsoft\Active Setup\Installed Components\{78705f0d-e8db-4b2d-8193-982bdda15ecd}\Version
1.1 HKLM\Software\Microsoft\NET Framework Setup\NDP\v1.1.4322\SP
2.0 HKLM\Software\Microsoft\NET Framework Setup\NDP\v2.0.50727\SP
3.0 HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.0\SP
3.5 HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.5\SP

As you can see, in order to determine the Service Pack level for the .NET Framework v1.0, it is necessary to know if the Operating System is Windows Media Center or Windows XP Tablet Edition before looking in the Registry. To complicate things even more, for .NET 1.0, the Registry value at either of these keys is a string value of the format #,#,####,#. The last # is the Service Pack level. For all of the other versions, this is a DWORD value indicating the Service Pack level.

Finally, to determine the exact version number of the Framework, we look at the following Registry keys:

Framework Version Registry Key

1.0

(Windows Media Center

or

Windows XP Tablet Edition)

HKLM\Software\Microsoft\Active Setup\Installed Components\{FDC11A6F-17D1-48f9-9EA3-9051954BAA24}\Version
1.0 HKLM\Software\Microsoft\Active Setup\Installed Components\{78705f0d-e8db-4b2d-8193-982bdda15ecd}\Version
1.1 HKLM\Software\Microsoft\NET Framework Setup\NDP\v1.1.4322
2.0

HKLM\Software\Microsoft\NET Framework Setup\NDP\v2.0.50727\Version

- or -

HKLM\Software\Microsoft\NET Framework Setup\NDP\v2.0.50727\Increment

3.0 HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.0\Version
3.5 HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.5\Version

Again, for .NET 1.0, it is necessary to know if the Operating System is Windows Media Center or Windows XP Tablet Edition before looking in the Registry, and the Registry value at either of these keys is a string value of the format #,#,####,#. The #,#,#### portion of the string is the Framework version.

For .NET 1.1, we use the name of the Registry key itself, which represents the version number, and for .NET 2.0, there are two different methods for determining the exact version number. If .NET 2.0 Original Release (RTM) is installed, then the version number is derived from the key name itself and the Increment Registry value (which is a string value representing the fourth part of the version number). Service Pack 1 for the .NET Framework 2.0 added the Version Registry value.

.NET Framework v3.0 Foundation libraries

In order to detect if any of the Foundation libraries are installed, you need to use the InstallSuccess Registry value from following rRegistry keys:

Foundation Library Registry Key
Windows Communication Foundation HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.0\Setup\Windows Communication Foundation
Windows Presentation Foundation HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.0\Setup\Windows Presentation Foundation
Windows Workflow Foundation HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.0\Setup\Windows Workflow Foundation

As is the case for the .NET Framework 3.0 itself, this is a DWORD value which, if present and set to 1, indicates that the Foundation library is installed. There have not been any service packs released specifically for the Foundation libraries, so at this time, there are no Registry keys to evaluate.

Determining the exact version number for any of the Foundation libraries uses the following Registry keys:

Foundation Library Registry Key
Windows Communication Foundation HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.0\Setup\Windows Communication Foundation\Version
Windows Presentation Foundation HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.0\Setup\Windows Presentation Foundation\Version
Windows Workflow Foundation HKLM\Software\Microsoft\NET Framework Setup\NDP\v3.0\Setup\Windows Workflow Foundation\FileVersion

Determining this information for Windows CardSpace is not as straightforward. The Registry can still be used to determine if Windows CardSpace is installed:

HKLM\System\CurrentControlSet\Services\idsvc\ImagePath

In order to determine the exact version, we must interrogate the file using the FileVersionInfo class and the value returned from the Registry key.

Points of interest

The public methods are simply wrappers that determine which private function should be called. These private functions, in turn, query the appropriate Registry keys and process the result. However, the real work is done in the GetRegistryValue<T> function. This is a generic function that returns a bool value indicating if the requested Registry key was found and an out parameter that contains the value. By making this a generic function, I was able to simply encapsulate all of the Registry access in a single function, and was able to more closely match the original C++ code provided by Aaron. The GetRegistryValue<T> function is defined as:

private static bool GetRegistryValue<T>(RegistryHive hive, string key, string value,
        RegistryValueKind kind, out T data)
{
  bool success = false;
  data = default(T);

  using (RegistryKey baseKey = RegistryKey.OpenRemoteBaseKey(hive, String.Empty))
  {
     if (baseKey != null)
     {
        using (RegistryKey registryKey = baseKey.OpenSubKey(key,
          RegistryKeyPermissionCheck.ReadSubTree))
        {
           if (registryKey != null)
           {
              // If the key was opened, try to retrieve the value.
              RegistryValueKind kindFound = registryKey.GetValueKind(value);
              if (kindFound == kind)
              {
                 object regValue = registryKey.GetValue(value, null);
                 if (regValue != null)
                 {
                    data = (T)Convert.ChangeType(regValue, typeof(T),
                      CultureInfo.InvariantCulture);
                    success = true;
                 }
              }
           }
        }
     }
  }
  return success;
}

It is important to note that if the user does not have the appropriate permissions to access the Registry, this function will throw an exception that will bubble up to the original caller. This was intentionally done to allow the caller the ability to take different actions based on the exception thrown.

Future considerations

I have not tested this code on any of the .NET Compact Framework versions, or determined how to detect the installed Compact Framework versions. If someone wants to do this investigation and let me know their findings, I will update the code accordingly.

If someone wants to test this on Windows XP 64-bit and Windows Vista 64-bit systems, let me know if it runs properly, and if not, what the errors are, and I will correct them.

Revision history

  • 8-September-2008:
    • Revised portions of the article to simplify the way the Registry key information is displayed.
    • Added a new InstalledFrameworkVersions property which returns an IEnumerable of Version objects representing the collection of installed frameworks.
    • Added some additional safety checks to help eliminate false positives from orphaned Registry keys.
    • Changed to using SandCastle for the documentation.
  • 17-August-2007:
    • Updated the Registry key for detecting the exact version of the .NET Framework v3.5 Beta 2.
  • 06-March-2007:
    • Corrected a few typographical errors.
  • 10-February-2007:
    • Corrected the Registry key path for the .NET 3.0 core keys.
    • Added a note asking for people to test this code on 64-bit XP and Vista and let me know what errors occur so I can correct them.
  • 04-February-2007:
    • Added information for the .NET Framework 3.5 (Orcas) January CTP.
    • Added "best guess" support for checking Service Pack level for the .NET Framework v3.0.
    • Added the GetExactVersion function; renamed IsFrameworkInstalled to IsInstalled, and added an overload to handle the Foundation libraries (WPF, WCF, WF, and CardSpace).
    • Added an overload to GetServicePackLevel to handle the Foundation libraries.
    • Added the WindowsFoundationLibrary enum.
    • Added Registry keys to show how to retrieve the version number information for the Framework.
    • Updated the sample code in the article.
    • Updated the formatting of the article.
    • Changed the article title and explanation to help clarify that this isn't intended to be run as part of an installer.
  • 03-February-2007:
    • Original article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Scott Dorman
Software Developer (Senior)
United States United States
Member
Scott is a C# MVP and author who has been involved with computers in one way or another for as long as he can remember, but started professionally in 1993. He has worked at Fortune 500 companies and privately held start-ups focused on IT consulting where he gained experience in embedded systems design and software development to systems administration and database programming, and everything in between.
 
After spending 6 years as a systems administrator, Scott started developing eCommerce store fronts. Since 2001, he has worked on many different projects using .NET and C#. Although his primary focus right now is commercial software applications, he prefers building infrastructure components, reusable shared libraries and helping companies define, develop and automate process standards and guidelines.
 
Scott runs a software architecture-focused user group, speaks extensively, and contributes regularly to online communities such as The Code Project and StackOverflow, and is the Community Manager and Senior Editor for DotNetKicks.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberhazekaizer24 Feb '12 - 21:14 
Vote 5 for you///
QuestionRe: Where is InstalledFrameworkVersionsmemberrobvon20 Jan '12 - 16:08 
Its in the old version of the code.
 
Author maybe forgot to compile his code before he posted the update
 
Needs update for V4.0, 4.5 etc......
GeneralNet Framewrok 4.0 Update Code [modified]memberJavierJJJ27 Apr '11 - 0:26 
I post the update for the code:
 

File FrameworkVersion.cs
using System;
 
namespace Campari.Software
{
	#region enum FrameworkVersion
    
    public enum FrameworkVersion
    {
        /// .NET Framework 1.0
        Fx10,
 
        /// .NET Framework 1.1
        Fx11,
 
        /// .NET Framework 2.0
        Fx20,
 
        /// .NET Framework 3.0
        Fx30,
 
        /// .NET Framework 3.5
        Fx35,
 
        /// .NET Framework 4.0 Client
        Fx40C,
 
        /// .NET Framework 4.0 Full
        Fx40F
    }
    #endregion
}
 

File FrameworkVersionDetection.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
 
using Microsoft.Win32;
 
using Campari.Software.InteropServices;
using System.IO;
using System.Diagnostics;
 
namespace Campari.Software
{
    #region class FrameworkVersionDetection
    /// <summary>
    /// Provides support for determining if a specific version of the .NET
    /// Framework runtime is installed and the service pack level for the
    /// runtime version.
    /// </summary>
    public static class FrameworkVersionDetection
    {
 
        #region class-wide fields
 
        const string Netfx10RegKeyName = "Software\\Microsoft\\.NETFramework\\Policy\\v1.0";
        const string Netfx10RegKeyValue = "3705";
        const string Netfx10SPxMSIRegKeyName = "Software\\Microsoft\\Active Setup\\Installed Components\\{78705f0d-e8db-4b2d-8193-982bdda15ecd}";
        const string Netfx10SPxOCMRegKeyName = "Software\\Microsoft\\Active Setup\\Installed Components\\{FDC11A6F-17D1-48f9-9EA3-9051954BAA24}";
        const string Netfx10SPxRegValueName = "Version";
        const string Netfx11RegKeyName = "Software\\Microsoft\\NET Framework Setup\\NDP\\v1.1.4322";
        const string Netfx20RegKeyName = "Software\\Microsoft\\NET Framework Setup\\NDP\\v2.0.50727";
        const string Netfx30RegKeyName = "Software\\Microsoft\\NET Framework Setup\\NDP\\v3.0";
        const string Netfx35RegKeyName = "Software\\Microsoft\\NET Framework Setup\\NDP\\v3.5";
        /// <summary>
        /// 4.0 Client Profile 
        /// </summary>
        const string Netfx40RegKeyNameClient = "Software\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client";
        /// <summary>
        /// 4.0 Full Profile 
        /// </summary>
        const string Netfx40RegKeyNameFull = "Software\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full";
        
        const string Netfx11PlusRegValueName = "Install";
        const string Netfx30PlusRegValueName = "InstallSuccess";
        const string Netfx11PlusSPxRegValueName = "SP";
        const string Netfx20PlusBuildRegValueName = "Increment";
        const string Netfx30PlusVersionRegValueName = "Version";
        const string Netfx35PlusBuildRegValueName = "Build";
        const string Netfx30PlusWCFRegKeyName = Netfx30RegKeyName + "\\Setup\\Windows Communication Foundation";
        const string Netfx30PlusWPFRegKeyName = Netfx30RegKeyName + "\\Setup\\Windows Presentation Foundation";
        const string Netfx30PlusWFRegKeyName = Netfx30RegKeyName + "\\Setup\\Windows Workflow Foundation";
        const string Netfx30PlusWFPlusVersionRegValueName = "FileVersion";
        const string CardSpaceServicesRegKeyName = "System\\CurrentControlSet\\Services\\idsvc";
        const string CardSpaceServicesPlusImagePathRegName = "ImagePath";
 
        #endregion
 
        #region private and internal properties and methods
 

        #region methods
 
        #region GetRegistryValue
        private static bool GetRegistryValue<T>(RegistryHive hive, string key, string value, RegistryValueKind kind, out T data)
        {
            bool success = false;
            data = default(T);
 
            using (RegistryKey baseKey = RegistryKey.OpenRemoteBaseKey(hive, String.Empty))
            {
                if (baseKey != null)
                {
                    using (RegistryKey registryKey = baseKey.OpenSubKey(key, RegistryKeyPermissionCheck.ReadSubTree))
                    {
                        if (registryKey != null)
                        {
 
                                if (registryKey != null)
                                {
                                    // If the key was opened, try to retrieve the value.
                                    object regValue = registryKey.GetValue(value, null);
                                    if (regValue != null)
                                    {
                                        RegistryValueKind kindFound = registryKey.GetValueKind(value);
                                        if (kindFound == kind)
                                        {
                                            data = (T)Convert.ChangeType(regValue, typeof(T), CultureInfo.InvariantCulture);
                                            success = true;
                                        }
                                    }
                                } 
                        }
                    }
                }
            }
            return success;
        }
        #endregion
 
        #region IsNetfxInstalled functions
 
        #region IsNetfx10Installed
        private static bool IsNetfx10Installed()
        {
            string regValue = string.Empty;
            return (GetRegistryValue(RegistryHive.LocalMachine, Netfx10RegKeyName, Netfx10RegKeyValue, RegistryValueKind.String, out regValue));
        }
        #endregion
 
        #region IsNetfx11Installed
        private static bool IsNetfx11Installed()
        {
            bool found = false;
            int regValue = 0;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx11RegKeyName, Netfx11PlusRegValueName, RegistryValueKind.DWord, out regValue))
            {
                if (regValue == 1)
                {
                    found = true;
                }
            }
 
            return found;
        }
        #endregion
 
        #region IsNetfx20Installed
        private static bool IsNetfx20Installed()
        {
            bool found = false;
            int regValue = 0;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx20RegKeyName, Netfx11PlusRegValueName, RegistryValueKind.DWord, out regValue))
            {
                if (regValue == 1)
                {
                    found = true;
                }
            }
 
            return found;
        }
        #endregion
 
        #region IsNetfx30Installed
        private static bool IsNetfx30Installed()
        {
            bool found = false;
            int regValue = 0;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30RegKeyName, Netfx11PlusRegValueName, RegistryValueKind.DWord, out regValue))
            {
                if (regValue == 1)
                {
                    found = true;
                }
            }
 
            return found;
        }
        #endregion
 
        #region IsNetfx35Installed
        private static bool IsNetfx35Installed()
        {
            bool found = false;
            int regValue = 0;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx35RegKeyName, Netfx11PlusRegValueName, RegistryValueKind.DWord, out regValue))
            {
                if (regValue == 1)
                {
                    found = true;
                }
            }
 
            return found;
        }
        #endregion
 
        #region IsNetfx40ClientInstalled
        private static bool IsNetfx40ClientInstalled()
        {
            bool found = false;
            int regValue = 0;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx40RegKeyNameClient, Netfx11PlusRegValueName, RegistryValueKind.DWord, out regValue))
            {
                if (regValue == 1)
                {
                    found = true;
                }
            }
 
            return found;
        }
        #endregion
 
        #region IsNetfx40FullInstalled
        private static bool IsNetfx40FullInstalled()
        {
            bool found = false;
            int regValue = 0;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx40RegKeyNameFull, Netfx11PlusRegValueName, RegistryValueKind.DWord, out regValue))
            {
                if (regValue == 1)
                {
                    found = true;
                }
            }
 
            return found;
        }
        #endregion
 
        #endregion
 
        #region GetNetfxSPLevel functions
 
        #region GetNetfx10SPLevel
        private static int GetNetfx10SPLevel()
        {
            bool foundKey = false;
            int servicePackLevel = -1;
            string regValue;
 
            if (IsTabletOrMediaCenter())
            {
                foundKey = GetRegistryValue(RegistryHive.LocalMachine, Netfx10SPxOCMRegKeyName, Netfx10SPxRegValueName, RegistryValueKind.String, out regValue);
            }
            else
            {
                foundKey = GetRegistryValue(RegistryHive.LocalMachine, Netfx10SPxMSIRegKeyName, Netfx10SPxRegValueName, RegistryValueKind.String, out regValue);
            }
 
            if (foundKey)
            {
                // This registry value should be of the format
                // #,#,#####,# where the last # is the SP level
                // Try to parse off the last # here
                int index = regValue.LastIndexOf(',');
                if (index > 0)
                {
                    Int32.TryParse(regValue.Substring(index + 1), out servicePackLevel);
                }
            }
 
            return servicePackLevel;
        }
        #endregion
 
        #region GetNetfx11SPLevel
        private static int GetNetfx11SPLevel()
        {
            int regValue = 0;
 
            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            int servicePackLevel = -1;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx11RegKeyName, Netfx11PlusSPxRegValueName, RegistryValueKind.DWord, out regValue))
            {
                servicePackLevel = regValue;
            }
 
            return servicePackLevel;
        }
        #endregion
 
        #region GetNetfx20SPLevel
        private static int GetNetfx20SPLevel()
        {
            int regValue = 0;
 
            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            int servicePackLevel = -1;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx20RegKeyName, Netfx11PlusSPxRegValueName, RegistryValueKind.DWord, out regValue))
            {
                servicePackLevel = regValue;
            }
 
            return servicePackLevel;
        }
        #endregion
 
        #region GetNetfx30SPLevel
        // This code is MOST LIKELY correct but will need to be verified.
        //
        // Currently, there are no service packs available for version 3.0 of 
        // the framework, so we always return -1. When a service pack does
        // become available, this method will need to be revised to correctly
        // determine the service pack level.
        private static int GetNetfx30SPLevel()
        {
            int regValue = 0;
 
            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            int servicePackLevel = -1;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30RegKeyName, Netfx11PlusSPxRegValueName, RegistryValueKind.DWord, out regValue))
            {
                servicePackLevel = regValue;
            }
 
            return servicePackLevel;
        }
        #endregion
 
        #region GetNetfx35SPLevel
        private static int GetNetfx35SPLevel()
        {
            int regValue = 0;
 
            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            int servicePackLevel = -1;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx35RegKeyName, Netfx11PlusSPxRegValueName, RegistryValueKind.DWord, out regValue))
            {
                servicePackLevel = regValue;
            }
 
            return servicePackLevel;
        }
        #endregion
 

        #region GetNetfx40CSPLevel
        private static int GetNetfx40CSPLevel()
        {
            int regValue = 0;
 
            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            int servicePackLevel = -1;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx40RegKeyNameClient, Netfx11PlusSPxRegValueName, RegistryValueKind.DWord, out regValue))
            {
                servicePackLevel = regValue;
            }
 
            return servicePackLevel;
        }
        #endregion
 
        #region GetNetfx40FSPLevel
        private static int GetNetfx40FSPLevel()
        {
            int regValue = 0;
 
            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            int servicePackLevel = -1;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx40RegKeyNameFull, Netfx11PlusSPxRegValueName, RegistryValueKind.DWord, out regValue))
            {
                servicePackLevel = regValue;
            }
 
            return servicePackLevel;
        }
        #endregion
 
        #endregion
 
        #region GetNetfxExactVersion functions
 
        #region GetNetfx10ExactVersion
        private static Version GetNetfx10ExactVersion()
        {
            bool foundKey = false;
            Version fxVersion = new Version();
            string regValue;
 
            if (IsTabletOrMediaCenter())
            {
                foundKey = GetRegistryValue(RegistryHive.LocalMachine, Netfx10SPxOCMRegKeyName, Netfx10SPxRegValueName, RegistryValueKind.String, out regValue);
            }
            else
            {
                foundKey = GetRegistryValue(RegistryHive.LocalMachine, Netfx10SPxMSIRegKeyName, Netfx10SPxRegValueName, RegistryValueKind.String, out regValue);
            }
 
            if (foundKey)
            {
                // This registry value should be of the format
                // #,#,#####,# where the last # is the SP level
                // Try to parse off the last # here
                int index = regValue.LastIndexOf(',');
                if (index > 0)
                {
                    string[] tokens = regValue.Substring(0, index).Split(',');
                    if (tokens.Length == 3)
                    {
                        fxVersion = new Version(Convert.ToInt32(tokens[0], NumberFormatInfo.InvariantInfo), Convert.ToInt32(tokens[1], NumberFormatInfo.InvariantInfo), Convert.ToInt32(tokens[2], NumberFormatInfo.InvariantInfo));
                    }
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #region GetNetfx11ExactVersion
        private static Version GetNetfx11ExactVersion()
        {
            int regValue = 0;
 
            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            Version fxVersion = new Version();
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx11RegKeyName, Netfx11PlusRegValueName, RegistryValueKind.DWord, out regValue))
            {
                if (regValue == 1)
                {
                    // In the strict sense, we are cheating here, but the registry key name itself
                    // contains the version number.
                    string[] tokens = Netfx11RegKeyName.Split(new string[] { "NDP\\v" }, StringSplitOptions.None);
                    if (tokens.Length == 2)
                    {
                        fxVersion = new Version(tokens[1]);
                    }
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #region GetNetfx20ExactVersion
        private static Version GetNetfx20ExactVersion()
        {
            string regValue = String.Empty;
 
            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            Version fxVersion = new Version();
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx20RegKeyName, Netfx20PlusBuildRegValueName, RegistryValueKind.String, out regValue))
            {
                if (!String.IsNullOrEmpty(regValue))
                {
                    // In the strict sense, we are cheating here, but the registry key name itself
                    // contains the version number.
                    string[] versionTokens = Netfx20RegKeyName.Split(new string[] { "NDP\\v" }, StringSplitOptions.None);
                    if (versionTokens.Length == 2)
                    {
                        string[] tokens = versionTokens[1].Split('.');
                        if (tokens.Length == 3)
                        {
                            fxVersion = new Version(Convert.ToInt32(tokens[0], NumberFormatInfo.InvariantInfo), Convert.ToInt32(tokens[1], NumberFormatInfo.InvariantInfo), Convert.ToInt32(tokens[2], NumberFormatInfo.InvariantInfo), Convert.ToInt32(regValue, NumberFormatInfo.InvariantInfo));
                        }
                    }
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #region GetNetfx30ExactVersion
        private static Version GetNetfx30ExactVersion()
        {
            string regValue = String.Empty;
 
            // We can only get the default version if the .NET Framework
            // is not installed or there was some kind of error retrieving
            // the data from the registry
            Version fxVersion = new Version();
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30RegKeyName, Netfx30PlusVersionRegValueName, RegistryValueKind.String, out regValue))
            {
                if (!String.IsNullOrEmpty(regValue))
                {
                    fxVersion = new Version(regValue);
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #region GetNetfx35ExactVersion
        private static Version GetNetfx35ExactVersion()
        {
            string regValue = String.Empty;
 
            // We can only get the default version if the .NET Framework
            // is not installed or there was some kind of error retrieving
            // the data from the registry
            Version fxVersion = new Version();
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx35RegKeyName, Netfx30PlusVersionRegValueName, RegistryValueKind.String, out regValue))
            {
                if (!String.IsNullOrEmpty(regValue))
                {
                    fxVersion = new Version(regValue);
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #region GetNetfx40CExactVersion
        private static Version GetNetfx40CExactVersion()
        {
            string regValue = String.Empty;
 
            // We can only get the default version if the .NET Framework
            // is not installed or there was some kind of error retrieving
            // the data from the registry
            Version fxVersion = new Version();
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx40RegKeyNameClient, Netfx30PlusVersionRegValueName, RegistryValueKind.String, out regValue))
            {
                if (!String.IsNullOrEmpty(regValue))
                {
                    fxVersion = new Version(regValue);
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #region GetNetfx40FExactVersion
        private static Version GetNetfx40FExactVersion()
        {
            string regValue = String.Empty;
 
            // We can only get the default version if the .NET Framework
            // is not installed or there was some kind of error retrieving
            // the data from the registry
            Version fxVersion = new Version();
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx40RegKeyNameFull, Netfx30PlusVersionRegValueName, RegistryValueKind.String, out regValue))
            {
                if (!String.IsNullOrEmpty(regValue))
                {
                    fxVersion = new Version(regValue);
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #endregion
 
        #region WindowsFounationLibrary functions
 
        #region CardSpace
 
        #region IsNetfx30CardSpaceInstalled
        private static bool IsNetfx30CardSpaceInstalled()
        {
            bool found = false;
            string regValue = String.Empty;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, CardSpaceServicesRegKeyName, CardSpaceServicesPlusImagePathRegName, RegistryValueKind.ExpandString, out regValue))
            {
                if (!String.IsNullOrEmpty(regValue))
                {
                    found = true;
                }
            }
 
            return found;
        }
        #endregion
 
        #region GetNetfx30CardSpaceSPLevel
        // Currently, there are no service packs available for version 3.0 of 
        // the framework, so we always return -1. When a service pack does
        // become available, this method will need to be revised to correctly
        // determine the service pack level. Based on the current method for
        // determining if CardSpace is installed, it may not be possible to
        // correctly determine the Service Pack level for CardSpace.
        private static int GetNetfx30CardSpaceSPLevel()
        {
            int servicePackLevel = -1;
            return servicePackLevel;
        }
        #endregion
 
        #region GetNetfx30CardSpaceExactVersion
        private static Version GetNetfx30CardSpaceExactVersion()
        {
            string regValue = String.Empty;
 
            // We can only get the default version if the .NET Framework
            // is not installed or there was some kind of error retrieving
            // the data from the registry
            Version fxVersion = new Version();
 
            if (GetRegistryValue(RegistryHive.LocalMachine, CardSpaceServicesRegKeyName, CardSpaceServicesPlusImagePathRegName, RegistryValueKind.ExpandString, out regValue))
            {
                if (!String.IsNullOrEmpty(regValue))
                {
                    FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(regValue.Trim('"'));
                    int index = fileVersionInfo.FileVersion.IndexOf(' ');
                    fxVersion = new Version(fileVersionInfo.FileVersion.Substring(0, index));
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #endregion
 
        #region Windows Communication Foundation
 
        #region IsNetfx30WCFInstalled
        private static bool IsNetfx30WCFInstalled()
        {
            bool found = false;
            int regValue = 0;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30PlusWCFRegKeyName, Netfx30PlusRegValueName, RegistryValueKind.DWord, out regValue))
            {
                if (regValue == 1)
                {
                    found = true;
                }
            }
 
            return found;
        }
        #endregion
 
        #region GetNetfx30WCFSPLevel
        // This code is MOST LIKELY correct but will need to be verified.
        //
        // Currently, there are no service packs available for version 3.0 of 
        // the framework, so we always return -1. When a service pack does
        // become available, this method will need to be revised to correctly
        // determine the service pack level.
        private static int GetNetfx30WCFSPLevel()
        {
            //int regValue = 0;

            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            int servicePackLevel = -1;
 
            //if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30PlusWCFRegKeyName, Netfx11PlusSPxRegValueName, RegistryValueKind.DWord, out regValue))
            //{
            //    servicePackLevel = regValue;
            //}

            return servicePackLevel;
        }
        #endregion
 
        #region GetNetfx30WCFExactVersion
        private static Version GetNetfx30WCFExactVersion()
        {
            string regValue = String.Empty;
 
            // We can only get the default version if the .NET Framework
            // is not installed or there was some kind of error retrieving
            // the data from the registry
            Version fxVersion = new Version();
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30PlusWCFRegKeyName, Netfx30PlusVersionRegValueName, RegistryValueKind.String, out regValue))
            {
                if (!String.IsNullOrEmpty(regValue))
                {
                    fxVersion = new Version(regValue);
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #endregion
 
        #region Windows Presentation Foundation
 
        #region IsNetfx30WPFInstalled
        private static bool IsNetfx30WPFInstalled()
        {
            bool found = false;
            int regValue = 0;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30PlusWPFRegKeyName, Netfx30PlusRegValueName, RegistryValueKind.DWord, out regValue))
            {
                if (regValue == 1)
                {
                    found = true;
                }
            }
 
            return found;
        }
        #endregion
 
        #region GetNetfx30WPFSPLevel
        // This code is MOST LIKELY correct but will need to be verified.
        //
        // Currently, there are no service packs available for version 3.0 of 
        // the framework, so we always return -1. When a service pack does
        // become available, this method will need to be revised to correctly
        // determine the service pack level.
        private static int GetNetfx30WPFSPLevel()
        {
            //int regValue = 0;

            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            int servicePackLevel = -1;
 
            //if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30PlusWPFRegKeyName, Netfx11PlusSPxRegValueName, RegistryValueKind.DWord, out regValue))
            //{
            //    servicePackLevel = regValue;
            //}

            return servicePackLevel;
        }
        #endregion
 
        #region GetNetfx30WPFExactVersion
        private static Version GetNetfx30WPFExactVersion()
        {
            string regValue = String.Empty;
 
            // We can only get the default version if the .NET Framework
            // is not installed or there was some kind of error retrieving
            // the data from the registry
            Version fxVersion = new Version();
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30PlusWPFRegKeyName, Netfx30PlusVersionRegValueName, RegistryValueKind.String, out regValue))
            {
                if (!String.IsNullOrEmpty(regValue))
                {
                    fxVersion = new Version(regValue);
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #endregion
 
        #region Windows Workflow Foundation
 
        #region IsNetfx30WFInstalled
        private static bool IsNetfx30WFInstalled()
        {
            bool found = false;
            int regValue = 0;
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30PlusWFRegKeyName, Netfx30PlusRegValueName, RegistryValueKind.DWord, out regValue))
            {
                if (regValue == 1)
                {
                    found = true;
                }
            }
 
            return found;
        }
        #endregion
 
        #region GetNetfx30WFSPLevel
        // This code is MOST LIKELY correct but will need to be verified.
        //
        // Currently, there are no service packs available for version 3.0 of 
        // the framework, so we always return -1. When a service pack does
        // become available, this method will need to be revised to correctly
        // determine the service pack level.
        private static int GetNetfx30WFSPLevel()
        {
            //int regValue = 0;

            // We can only get -1 if the .NET Framework is not
            // installed or there was some kind of error retrieving
            // the data from the registry
            int servicePackLevel = -1;
 
            //if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30PlusWFRegKeyName, Netfx11PlusSPxRegValueName, RegistryValueKind.DWord, out regValue))
            //{
            //    servicePackLevel = regValue;
            //}

            return servicePackLevel;
        }
        #endregion
 
        #region GetNetfx30WFExactVersion
        private static Version GetNetfx30WFExactVersion()
        {
            string regValue = String.Empty;
 
            // We can only get the default version if the .NET Framework
            // is not installed or there was some kind of error retrieving
            // the data from the registry
            Version fxVersion = new Version();
 
            if (GetRegistryValue(RegistryHive.LocalMachine, Netfx30PlusWFRegKeyName, Netfx30PlusWFPlusVersionRegValueName, RegistryValueKind.String, out regValue))
            {
                if (!String.IsNullOrEmpty(regValue))
                {
                    fxVersion = new Version(regValue);
                }
            }
 
            return fxVersion;
        }
        #endregion
 
        #endregion
 
        #endregion
 
        #region IsTabletOrMediaCenter
        private static bool IsTabletOrMediaCenter()
        {
            return ((SafeNativeMethods.GetSystemMetrics(SystemMetric.SM_TABLETPC) != 0) || (SafeNativeMethods.GetSystemMetrics(SystemMetric.SM_MEDIACENTER) != 0));
        }
        #endregion
 
        #endregion
 
        #endregion
 
        #region public properties and methods
 
        #region methods
 
        #region IsInstalled
 
        #region IsInstalled(FrameworkVersion frameworkVersion)
        /// <summary>
        /// Determines if the specified .NET Framework version is installed
        /// on the local computer.
        /// </summary>
        /// <param name="frameworkVersion">One of the
        /// <see cref="FrameworkVersion"/> values.</param>
        /// <returns><see langword="true"/> if the specified .NET Framework
        /// version is installed; otherwise <see langword="false"/>.</returns>
        public static bool IsInstalled(FrameworkVersion frameworkVersion)
        {
            bool ret = false;
 
            switch (frameworkVersion)
            {
                case FrameworkVersion.Fx10:
                    ret = IsNetfx10Installed();
                    break;
 
                case FrameworkVersion.Fx11:
                    ret = IsNetfx11Installed();
                    break;
 
                case FrameworkVersion.Fx20:
                    ret = IsNetfx20Installed();
                    break;
 
                case FrameworkVersion.Fx30:
                    ret = IsNetfx30Installed();
                    break;
 
                case FrameworkVersion.Fx35:
                    ret = IsNetfx35Installed();
                    break;
 
                case FrameworkVersion.Fx40C:
                    ret = IsNetfx40ClientInstalled();
                    break;
 
                case FrameworkVersion.Fx40F:
                    ret = IsNetfx40FullInstalled();
                    break;
 
                default:
                    break;
            }
 
            return ret;
        }
        #endregion
 
        #region IsInstalled(WindowsFoundationLibrary foundationLibrary)
        /// <summary>
        /// Determines if the specified .NET Framework Foundation Library is
        /// installed on the local computer.
        /// </summary>
        /// <param name="foundationLibrary">One of the
        /// <see cref="WindowsFoundationLibrary"/> values.</param>
        /// <returns><see langword="true"/> if the specified .NET Framework
        /// Foundation Library is installed; otherwise <see langword="false"/>.</returns>
        public static bool IsInstalled(WindowsFoundationLibrary foundationLibrary)
        {
            bool ret = false;
 
            switch (foundationLibrary)
            {
                case WindowsFoundationLibrary.CardSpace:
                    ret = IsNetfx30CardSpaceInstalled();
                    break;
 
                case WindowsFoundationLibrary.WCF:
                    ret = IsNetfx30WCFInstalled();
                    break;
 
                case WindowsFoundationLibrary.WF:
                    ret = IsNetfx30WFInstalled();
                    break;
 
                case WindowsFoundationLibrary.WPF:
                    ret = IsNetfx30WPFInstalled();
                    break;
 
                default:
                    break;
            }
 
            return ret;
        }
        #endregion
 
        #endregion
 
        #region GetServicePackLevel
 
        #region GetServicePackLevel(FrameworkVersion frameworkVersion)
        /// <summary>
        /// Retrieves the service pack level for the specified .NET Framework
        /// version.
        /// </summary>
        /// <param name="frameworkVersion">One of the
        /// <see cref="FrameworkVersion"/> values.</param>
        /// <returns>An <see cref="Int32">integer</see> value representing
        /// the service pack level for the specified .NET Framework version. If
        /// the specified .NET Frameowrk version is not found, -1 is returned.
        /// </returns>
        public static int GetServicePackLevel(FrameworkVersion frameworkVersion)
        {
            int servicePackLevel = -1;
 
            switch (frameworkVersion)
            {
                case FrameworkVersion.Fx10:
                    servicePackLevel = GetNetfx10SPLevel();
                    break;
 
                case FrameworkVersion.Fx11:
                    servicePackLevel = GetNetfx11SPLevel();
                    break;
 
                case FrameworkVersion.Fx20:
                    servicePackLevel = GetNetfx20SPLevel();
                    break;
 
                case FrameworkVersion.Fx30:
                    servicePackLevel = GetNetfx30SPLevel();
                    break;
 
                case FrameworkVersion.Fx35:
                    servicePackLevel = GetNetfx35SPLevel();
                    break;
 
                case FrameworkVersion.Fx40C:
                    servicePackLevel = GetNetfx40CSPLevel();
                    break;
 
                case FrameworkVersion.Fx40F:
                    servicePackLevel = GetNetfx40FSPLevel();
                    break;
 
                default:
                    break;
            }
 
            return servicePackLevel;
        }
        #endregion
 
        #region GetServicePackLevel(WindowsFoundationLibrary foundationLibrary)
        /// <summary>
        /// Retrieves the service pack level for the specified .NET Framework
        /// Foundation Library.
        /// </summary>
        /// <param name="foundationLibrary">One of the
        /// <see cref="WindowsFoundationLibrary"/> values.</param>
        /// <returns>An <see cref="Int32">integer</see> value representing
        /// the service pack level for the specified .NET Framework Foundation
        /// Library. If the specified .NET Frameowrk Foundation Library is not
        /// found, -1 is returned.
        /// </returns>
        public static int GetServicePackLevel(WindowsFoundationLibrary foundationLibrary)
        {
            int servicePackLevel = -1;
 
            switch (foundationLibrary)
            {
                case WindowsFoundationLibrary.CardSpace:
                    servicePackLevel = GetNetfx30CardSpaceSPLevel();
                    break;
 
                case WindowsFoundationLibrary.WCF:
                    servicePackLevel = GetNetfx30WCFSPLevel();
                    break;
 
                case WindowsFoundationLibrary.WF:
                    servicePackLevel = GetNetfx30WFSPLevel();
                    break;
 
                case WindowsFoundationLibrary.WPF:
                    servicePackLevel = GetNetfx30WPFSPLevel();
                    break;
 
                default:
                    break;
            }
 
            return servicePackLevel;
        }
        #endregion
 
        #endregion
 
        #region GetExactVersion
 
        #region GetExactVersion(FrameworkVersion frameworkVersion)
        /// <summary>
        /// Retrieves the exact version number for the specified .NET Framework
        /// version.
        /// </summary>
        /// <param name="frameworkVersion">One of the
        /// <see cref="FrameworkVersion"/> values.</param>
        /// <returns>A <see cref="Version">version</see> representing
        /// the exact version number for the specified .NET Framework version.
        /// If the specified .NET Frameowrk version is not found, a 
        /// <see cref="Version"/> is returned that represents a 0.0.0.0 version
        /// number.
        /// </returns>
        public static Version GetExactVersion(FrameworkVersion frameworkVersion)
        {
            Version fxVersion = new Version();
 
            switch (frameworkVersion)
            {
                case FrameworkVersion.Fx10:
                    fxVersion = GetNetfx10ExactVersion();
                    break;
 
                case FrameworkVersion.Fx11:
                    fxVersion = GetNetfx11ExactVersion();
                    break;
 
                case FrameworkVersion.Fx20:
                    fxVersion = GetNetfx20ExactVersion();
                    break;
 
                case FrameworkVersion.Fx30:
                    fxVersion = GetNetfx30ExactVersion();
                    break;
 
                case FrameworkVersion.Fx35:
                    fxVersion = GetNetfx35ExactVersion();
                    break;
 
                case FrameworkVersion.Fx40C:
                    fxVersion = GetNetfx40CExactVersion();
                    break;
 
                case FrameworkVersion.Fx40F:
                    fxVersion = GetNetfx40FExactVersion();
                    break;
 
                default:
                    break;
            }
 
            return fxVersion;
        }
        #endregion
 
        #region GetExactVersion(WindowsFoundationLibrary foundationLibrary)
        /// <summary>
        /// Retrieves the exact version number for the specified .NET Framework
        /// Foundation Library.
        /// </summary>
        /// <param name="foundationLibrary">One of the
        /// <see cref="WindowsFoundationLibrary"/> values.</param>
        /// <returns>A <see cref="Version">version</see> representing
        /// the exact version number for the specified .NET Framework Foundation
        /// Library. If the specified .NET Frameowrk Foundation Library is not
        /// found, a <see cref="Version"/> is returned that represents a 
        /// 0.0.0.0 version number.
        /// </returns>
        public static Version GetExactVersion(WindowsFoundationLibrary foundationLibrary)
        {
            Version fxVersion = new Version();
 
            switch (foundationLibrary)
            {
                case WindowsFoundationLibrary.CardSpace:
                    fxVersion = GetNetfx30CardSpaceExactVersion();
                    break;
 
                case WindowsFoundationLibrary.WCF:
                    fxVersion = GetNetfx30WCFExactVersion();
                    break;
 
                case WindowsFoundationLibrary.WF:
                    fxVersion = GetNetfx30WFExactVersion();
                    break;
 
                case WindowsFoundationLibrary.WPF:
                    fxVersion = GetNetfx30WPFExactVersion();
                    break;
 
                default:
                    break;
            }
 
            return fxVersion;
        }
        #endregion
 
        #endregion
 
        #endregion
 
        #endregion
    }
    #endregion
}
 
 
File form Framework. Sory I convert from c# to vb. You can change easy.
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
        Try
            Dim fx10Installed As Boolean = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx10)
            Dim fx11Installed As Boolean = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx11)
            Dim fx20Installed As Boolean = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx20)
            Dim fx30Installed As Boolean = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx30)
            Dim fx35Installed As Boolean = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx35)
            Dim fx40CInstalled As Boolean = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx40C)
            Dim fx40FInstalled As Boolean = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx40F)
 
            treeView1.Nodes.Add(Environment.MachineName)
            Dim tn As TreeNode
            If fx10Installed Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = ".NET Framework 1.0"
                tn.Text = ".NET Framework 1.0"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx10).ToString)
                tn.Nodes.Add("Service Pack: " & FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx10).ToString)
                treeView1.Nodes(0).Nodes.Add(tn)
            Else
                tn = New TreeNode()
                tn.ForeColor = Color.Red
                tn.Name = ".NET Framework 1.0"
                tn.Text = ".NET Framework 1.0"
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
 
            If fx11Installed Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = ".NET Framework 1.1"
                tn.Text = ".NET Framework 1.1"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx11).ToString)
                tn.Nodes.Add("Service Pack: " & FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx11))
                treeView1.Nodes(0).Nodes.Add(tn)
            Else
                tn = New TreeNode()
                tn.ForeColor = Color.Red
                tn.Name = ".NET Framework 1.1"
                tn.Text = ".NET Framework 1.1"
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
 
            If fx20Installed Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = ".NET Framework 2.0"
                tn.Text = ".NET Framework 2.0"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx20).ToString)
                tn.Nodes.Add("Service Pack: " & FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx20))
                treeView1.Nodes(0).Nodes.Add(tn)
            Else
                tn = New TreeNode()
                tn.ForeColor = Color.Red
                tn.Name = ".NET Framework 2.0"
                tn.Text = ".NET Framework 2.0"
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
 
            If fx30Installed Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = ".NET Framework 3.0"
                tn.Text = ".NET Framework 3.0"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx30).ToString)
                tn.Nodes.Add("Service Pack: " & FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx30))
                treeView1.Nodes(0).Nodes.Add(tn)
            Else
                tn = New TreeNode()
                tn.ForeColor = Color.Red
                tn.Name = ".NET Framework 3.0"
                tn.Text = ".NET Framework 3.0"
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
 
            If fx35Installed Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = ".NET Framework 3.5"
                tn.Text = ".NET Framework 3.5"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx35).ToString)
                tn.Nodes.Add("Service Pack: " & FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx35))
                treeView1.Nodes(0).Nodes.Add(tn)
            Else
                tn = New TreeNode()
                tn.ForeColor = Color.Red
                tn.Name = ".NET Framework 3.5"
                tn.Text = ".NET Framework 3.5"
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
 
            If fx40CInstalled Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = ".NET Framework 4.0C"
                tn.Text = ".NET Framework 4.0 Client"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx40C).ToString)
                tn.Nodes.Add("Service Pack: " & FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx40C))
                treeView1.Nodes(0).Nodes.Add(tn)
            Else
                tn = New TreeNode()
                tn.ForeColor = Color.Red
                tn.Name = ".NET Framework 4.0C"
                tn.Text = ".NET Framework 4.0 Client"
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
 
            If fx40FInstalled Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = ".NET Framework 4.0F"
                tn.Text = ".NET Framework 4.0 Full"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(FrameworkVersion.Fx40F).ToString)
                tn.Nodes.Add("Service Pack: " & FrameworkVersionDetection.GetServicePackLevel(FrameworkVersion.Fx40F))
                treeView1.Nodes(0).Nodes.Add(tn)
            Else
                tn = New TreeNode()
                tn.ForeColor = Color.Red
                tn.Name = ".NET Framework 4.0F"
                tn.Text = ".NET Framework 4.0 Full"
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
            Dim fx30PlusWCFInstalled As Boolean = FrameworkVersionDetection.IsInstalled(WindowsFoundationLibrary.WCF)
            Dim fx30PlusWPFInstalled As Boolean = FrameworkVersionDetection.IsInstalled(WindowsFoundationLibrary.WPF)
            Dim fx30PlusWFInstalled As Boolean = FrameworkVersionDetection.IsInstalled(WindowsFoundationLibrary.WF)
            Dim fx30PlusCardSpacesInstalled As Boolean = FrameworkVersionDetection.IsInstalled(WindowsFoundationLibrary.CardSpace)
 

            If fx30PlusWCFInstalled Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = "WCF"
                tn.Text = "WCF"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(WindowsFoundationLibrary.WCF).ToString)
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
 
            If fx30PlusWPFInstalled Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = "WPF"
                tn.Text = "WPF"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(WindowsFoundationLibrary.WPF).ToString)
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
 
            If fx30PlusWFInstalled Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = "WF"
                tn.Text = "WF"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(WindowsFoundationLibrary.WF).ToString)
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
 
            If fx30PlusCardSpacesInstalled Then
                tn = New TreeNode()
                tn.ForeColor = Color.Green
                tn.Name = "Card Space"
                tn.Text = "Card Space"
                tn.Nodes.Add("Exact Version: " & FrameworkVersionDetection.GetExactVersion(WindowsFoundationLibrary.CardSpace).ToString)
                treeView1.Nodes(0).Nodes.Add(tn)
            End If
 
            treeView1.Nodes(0).Expand()
        Catch ex As Exception
            MessageBox.Show("Error: " & ex.Message)
        End Try
    End Sub
 

I hope that is helpfull
modified on Wednesday, April 27, 2011 6:34 AM

GeneralRe: Net Framewrok 4.0 Update Code [modified]memberMarkJoel6018 Feb '12 - 5:06 
Yes, very helpful... you missed some things in your code, however, when you cut and pasted it:
 
First, you also need the using statements:
 
using System.Collections;
using System.Diagnostics.CodeAnalysis;
 
Then, in the FrameworkVersionDetection Class, you need to add a Properties Section to the
       #region public properties and methods
 
That looks like this:
#region properties
 
#region InstalledFrameworkVersions
/// <summary>
/// Gets an <see cref="IEnumerable"/> list of the installed .NET Framework
/// versions.
/// </summary>
public static IEnumerable InstalledFrameworkVersions
{
    get
    {
        if (IsInstalled(FrameworkVersion.Fx10))
        {
            yield return GetExactVersion(FrameworkVersion.Fx10);
        }
        if (IsInstalled(FrameworkVersion.Fx11))
        {
            yield return GetExactVersion(FrameworkVersion.Fx11);
        }
        if (IsInstalled(FrameworkVersion.Fx20))
        {
            yield return GetExactVersion(FrameworkVersion.Fx20);
        }
        if (IsInstalled(FrameworkVersion.Fx30))
        {
            yield return GetExactVersion(FrameworkVersion.Fx30);
        }
        if (IsInstalled(FrameworkVersion.Fx35))
        {
            yield return GetExactVersion(FrameworkVersion.Fx35);
        }
    }
}
#endregion
 
#endregion
 
That compiles and works.
 
Anyone who doesn't like dropping into VB, can also test this new code by going into the PROGRAM.CS file that Scott included, and adding the following lines:
 
bool fx40CInstalled = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx40C);
bool fx40FInstalled = FrameworkVersionDetection.IsInstalled(FrameworkVersion.Fx40F);
 
Console.WriteLine(".NET Framework 4.0 Client installed? {0}", fx40CInstalled);
Console.WriteLine(".NET Framework 4.0 FULL installed? {0}", fx40FInstalled);

GeneralRe: Net Framewrok 4.0 Update Code [modified]memberGeorge Hendrickson1 Feb '13 - 2:59 
I compared the code of your version of FrameworkVersionDetection.cs to the original code and there are a lot of differences. Why the big difference?
GeneralRe: Net Framewrok 4.0 Update Code [modified]memberJavierJJJ11 Feb '13 - 0:30 
not it's too much. Only add new procedures to detect the new framework.
If you detect more changes that you expect, it's posible that the author change after some code.
GeneralInstalledFrameworkVersions in codememberalhambra-eidos8 Mar '11 - 4:02 
where is InstalledFrameworkVersions in sourcecode ??
 
foreach (Version fxVersion in FrameworkVersionDetection.InstalledFrameworkVersions)
{
Console.WriteLine(fxVersion .ToString());
}
AE

GeneralUpdate .net 4.0 - Client Profilememberalhambra-eidos8 Mar '11 - 3:02 
http://stackoverflow.com/questions/199080/how-to-detect-what-net-framework-versions-and-service-packs-are-installed[^]
 

4.0 Client Profile HKLM\Software\Microsoft\NET Framework Setup\NDP\v4\Client\Install
4.0 Full Profile HKLM\Software\Microsoft\NET Framework Setup\NDP\v4\Full\Install
AE

QuestionUpdate for Framework 4.0??memberrctaubert10 Sep '10 - 6:31 
Any chance you will be able to update your code to cover Framework 4.0??
 
Great article and software. Thanks for sharing.
AnswerRe: Update for Framework 4.0??memberScott Dorman10 Sep '10 - 15:14 
Yes, I will be updating this to work with .NET 4.0 soon.
Scott Dorman
Microsoft® MVP - Visual C# | MCPD
President - Tampa Bay IASA
 
[Blog][Articles][Forum Guidelines]
Hey, hey, hey. Don't be mean. We don't have to be mean because, remember, no matter where you go, there you are. - Buckaroo Banzai

GeneralRe: Update for Framework 4.0??memberalhambra-eidos2 Mar '11 - 3:56 
any update ??? for 4.0 ?
AE

GeneralRe: Update for Framework 4.0??memberrctaubert5 Jan '12 - 5:44 
It has been over a year now, have you had time to update your code????
AnswerRe: Update for Framework 4.0??memberMarco Ensing19 Sep '10 - 8:30 
/// <summary>
/// 4.0 Client Profile
/// </summary>
const string Netfx40RegKeyNameClient = "Software\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client";
 
/// <summary>
/// 4.0 Full Profile
/// </summary>
const string Netfx40RegKeyNameFull = "Software\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full";
GeneralRe: Update for Framework 4.0??memberrctaubert23 Sep '10 - 5:23 
Thank you Marco for the reply to my post. Unfortunately, I am not a C# programmer and it would take a lot more than those two constants for me to modify Scott Dorman's code. I will have to wait for him to update his code and post it.
GeneralRe: Update for Framework 4.0??memberScott Dorman23 Sep '10 - 6:35 
I'm hoping to have some time to update this by the end of next week.
Scott Dorman
Microsoft® MVP - Visual C# | MCPD
President - Tampa Bay IASA
 
[Blog][Articles][Forum Guidelines]
Hey, hey, hey. Don't be mean. We don't have to be mean because, remember, no matter where you go, there you are. - Buckaroo Banzai

GeneralRe: Update for Framework 4.0??memberrctaubert23 Sep '10 - 8:44 
Thanks for your reply Scott.
 
I went through the code as much as I could to see if I could use Marco's suggestion and realize that it is quiet involved and will take a little time to complete. I am sure you have important things like job and family that should come first. Take your time.
GeneralRe: Update for Framework 4.0??memberalhambra-eidos8 Mar '11 - 2:53 
Please, update to .net 4.0, client profile and full profile
 
http://stackoverflow.com/questions/199080/how-to-detect-what-net-framework-versions-and-service-packs-are-installed[^]
AE

GeneralRun this against another machinememberDimondWolfe16 Oct '09 - 11:06 
Do you think it's possible to run this against another machine on my network? I've got a couple of hundred machines that I need to check to see if they have 3.5 SP1 installed. Would it be possible to point this app at a remote machine, do you think?
 
You know what ol' Jack Burton says at a time like this...

GeneralRe: Run this against another machinememberscot.belshaw18 Oct '09 - 15:09 
try this one...
XFxDetect - A utility to detect which versions of .Net are installed[^]
it works on remote machines
GeneralVery practical article!memberDrABELL16 Sep '09 - 16:25 
Hello Scott:
 
You are just right!
 
.NET side-by-side execution initially came as a great relief from former "DLL-h..ll", but... well, the rest is well presented in your article Smile | :)
 
Great job! Kudos to the author and 5*.
 
My best,
 
Alex
 
PS. ...that's mostly why I like web apps more than their win counterparts Smile | :)
Question4.0 framework?membernmerali26 Aug '09 - 4:54 
Any update about the 4.0 Framework check?
 
Thanks,
Nadin
GeneralDifferent Info on Vista and XPmembervinodonly10 Jul '09 - 23:08 
Thanks for posting this useful article...
 
I tested your library on Vista and XP with all updates installed till now, but it is returning different version information.
 
If you need more details then kindly send me msg and I will provide the same. ( I have used contact form on your blog also to post this same msg)
 
I wanted to request if there is a possibility of fixing this issue.
 
Thanks in advance..
GeneralRe: Different Info on Vista and XPmemberScott Dorman11 Jul '09 - 3:31 
What issues are you running in to? This was developed on an XP machine that was then upgraded to Vista and I haven't seen any issues. If I can narrow down the problem I'll do my best to fix it in the article and code.
 
Scott Dorman
Microsoft® MVP - Visual C# | MCPD
President - Tampa Bay IASA
 
[Blog][Articles][Forum Guidelines]
Hey, hey, hey. Don't be mean. We don't have to be mean because, remember, no matter where you go, there you are. - Buckaroo Banzai

GeneralRe: Different Info on Vista and XPmembervinodonly11 Jul '09 - 3:43 
Thanks for replying..
 
I'm getting following values on Vista. I have just formatted it for your convenience.
 
Net Framework 2 Ver : 2.0.50727.4016 - Service Pack 2
Net Framework 3 Ver : 3.0.30729.4037 - Service Pack 2
Net Framework 3.5 Ver : 3.5.30729.1 - Service Pack 1
 
and following values on XP.
 
Net Framework 2 Ver : 2.2.30729 - Service Pack 2
Net Framework 3 Ver : 3.2.30729 - Service Pack 2
Net Framework 3.5 Ver : 3.5.30729.1 - Service Pack 1
 
You can see that only for 3.5 framework it is returning identical values. For version 2 and 3 it is returning incorrect version. Service Pack Info is correct for all frameworks.
GeneralRe: Different Info on Vista and XPmembervinodonly14 Jul '09 - 22:52 
Any luck on this ?

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 8 Sep 2008
Article Copyright 2007 by Scott Dorman
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid