How to determine what CLR versions are installed using C++

You may have multiple versions of the .NET framework installed and used on your machine. The framework has two components: the set of assemblies that provide functionalities for your application, and the common language runtime (CLR) that handles the execution of the application. These two components are versioned separately. If you what to see what versions of the framework are installed, you have to query the Windows Registry. If you want to know what versions of the CLR are installed you could either use clrver.exe or do it programmatically. In this article, we will look at this later option and how to do it in C++.

How to: Determine Which .NET Framework Versions Are Installed

To query the installed CLR versions from C++ we have to:

#include <string>
#include <iostream>

#import <mscorlib.tlb> raw_interfaces_only rename( "value", "value2" ) rename( "ReportEvent", "InteropServices_ReportEvent" )

#include <metahost.h>
#pragma comment( lib, "Mscoree" )

_COM_SMARTPTR_TYPEDEF(ICLRMetaHost, IID_ICLRMetaHost);
_COM_SMARTPTR_TYPEDEF(ICLRRuntimeInfo, IID_ICLRRuntimeInfo);

int main()
{
   ICLRMetaHostPtr pMetaHost{ nullptr };
   HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
   if (FAILED(hr))
      return -1;

   IEnumUnknownPtr enumptr{ nullptr };
   hr = pMetaHost->EnumerateInstalledRuntimes(&enumptr);
   if (FAILED(hr))
      return -1;

   while (true)
   {
      ULONG fetched{ 0 };
      IUnknownPtr uptr{ nullptr };
      hr = enumptr->Next(1, &uptr, &fetched);
      if (hr == S_OK)
      {
         ICLRRuntimeInfoPtr crlri{ uptr };

         DWORD size{ 0 };
         hr = crlri->GetVersionString(nullptr, &size);
         if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) && size > 0)
         {
            std::wstring version(size, 0);
            hr = crlri->GetVersionString(&version.front(), &size);
            if (SUCCEEDED(hr))
               std::wcout << version << std::endl;
         }
      }
      else
         break;
   };

   return 0;
}

In order to call CLRCreateInstance we must include the metahost.h header and link with the Mscoree.lib static library.

To use the ICLRMetaHost and ICLRRuntimeInfo interfaces we must import the mscorlib.tlb type library. The _COM_SMARTPTR_TYPEDEF are used for defining COM smart pointers ICLRMetaHostPtr and ICLRRuntimeInfoPtr that automatically handle the reference counter of the underlying COM object.

The call to the EnumerateInstalledRuntimes method, when successful, returns a pointer to an IEnumUnknown interface. This enables enumerating through a component that contains multiple objects. Its method Next retrieves a specified number of items. In this implementation that number is 1. The return value is a pointer to the IUnknown interface, but what we are enumerating through are actually ICLRRuntimeInfo interfaces.

To retrieve the version info we must use the GetVersionString method of ICLRRuntimeInfo. The arguments are an array of wide characters that will receive the string and the size of the array. In order to retrieve the necessary size of the buffer, we have to first call the method with null for the first argument. In this case the function returns ERROR_INSUFFICIENT_BUFFER as a HRESULT (i.e. HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) and sets the second argument to the necessary size. After allocating the necessary buffer, we call the method again, providing the buffer and its size.

Running this program on my machine prints the following (which is the same as the output from clrver.exe).

v2.0.50727
v4.0.30319

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.