There are several excellent posts about loading the .NET CLR from a C/C++ application or dll. However, Microsoft changed the methods and procedure slightly for .NET 4.0, so I'm writing this to bridge the gap.
First you will need to start the CLR for the version of .NET you wish to run. In order to call this correctly you will need to find the exact version number of .NET on your machine. The easy way is to simply look in the C:\Windows\Microsoft.NET\Framework directory and copy the full text of the directory with the highest number. On my machine this results in "v4.0.30319". There are more robust ways of obtaining this string of course.
Pass that string into this function to start the CLR:
Code:
/// <summary>
/// Returns a pointer to a running CLR host of the specified version
/// </summary>
/// <param name="dotNetVersion">The exact version number of the CLR you want to
/// run. This can be obtained by looking in the C:\Windows\Microsoft.NET\Framework
/// directory and copy the name of the last directory.</param>
/// <returns>A running CLR host or NULL. You are responsible for calling Release() on it.</returns>
ICLRRuntimeHost* GetRuntimeHost(LPCWSTR dotNetVersion)
{
ICLRMetaHost* metaHost = NULL;
ICLRRuntimeInfo* info = NULL;
ICLRRuntimeHost* runtimeHost = NULL;
// Get the CLRMetaHost that tells us about .NET on this machine
if (S_OK == CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&metaHost))
{
// Get the runtime information for the particular version of .NET
if (S_OK == metaHost->GetRuntime(dotNetVersion, IID_ICLRRuntimeInfo, (LPVOID*)&info))
{
// Get the actual host
if (S_OK == info->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost))
{
// Start it. This is okay to call even if the CLR is already running
runtimeHost->Start();
}
}
}
if (NULL != info)
info->Release();
if (NULL != metaHost)
metaHost->Release();
return runtimeHost;
}
Great! Now you've got a running CLR. Its time to run a function. The function must have a particular signature: public static int Function(string param). Here's the code to call that function:
Code:
/// <summary>
/// Executes some code in the CLR. The function must have the signature: public static int Function(string param)
/// </summary>
/// <param name="host">A started instance of the CLR</param>
/// <param name="assemblyPath">The full path to your compiled code file.
/// i.e. "C:\MyProject\MyCode.dll"</param>
/// <param name="typeName">The full type name of the class to be called, including the
/// namespace. i.e. "MyCode.MyClass"</param>
/// <param name="function">The name of the function to be called. i.e. "MyFunction"</param>
/// <param name="param">A string parameter to pass to the function.</param>
/// <returns>The integer return code from the function or -1 if the function did not run</returns>
int ExecuteClrCode(ICLRRuntimeHost* host, LPCWSTR assemblyPath, LPCWSTR typeName,
LPCWSTR function, LPCWSTR param)
{
if (NULL == host)
return -1;
DWORD result = -1;
if (S_OK != host->ExecuteInDefaultAppDomain(assemblyPath, typeName, function, param, &result))
return -1;
return result;
}
Let's put it all together and run something. Let's suppose you create a new C# dll with the code below and install it as C:\MyLibrary.dll
Code:
using System;
using System.Windows;
namespace MyLibrary
{
class MyClass
{
public static int ShowMessage(string message)
{
MessageBox.Show(message);
return 1;
}
}
}
From you C/C++ code you can now show the message box like so (assuming your version of .NET 4.0 is the same as mine):
Code:
ICLRRuntimeHost* host = GetRuntimeHost(L"v4.0.30319");
ExecuteClrCode(host , L"C:\\MyLibrary.dll", L"MyLibrary.MyClass", L"ShowMessage", L"Hello World");
// At some point you will need to call Release(). You can do it now or during cleanup code
host->Release();
Of course the ShowMessage function is rather trivial and non-helpful as there are easier ways to do that in C/C++, but you can do anything C# you need to from that function, including starting new threads, opening windows, launching processes, hooking other functions, etc. Its simply your doorway into .NET 4.0.
Edit: I forgot the includes you'll need for the C/C++ code:
Code:
#include <metahost.h>
#include <mscoree.h>
Edit: Fixed resource leak