Creating a Host to the .NET Common Language Runtime

We have all seen the different type of applications the .NET Common Language Runtime (CLR) caters for,
Web applications (ASP.NET), GUI-based ones (WinForms), simple console-based ones and managed ActiveX controls
hosted by Internet Explorer

When we write code targeted for the 'managed world' in the languages that .NET currently supports, .NET
aware language compilers emit assemblies that contain the CPU agnostic IL in them. These assemblies are
executed by the CLR

One could guess that in Windows' unmanaged world, when one invokes an executable from the Windows shell,
it would have to be a WIN32 process with its own 4GB address spaces. Hence one could also guess that when
one invokes a .NET application, before the managed code starts to execute on the CLR, a small amount of
unmanaged code must run to creates the environment necessary for the CLR. This piece of code is known as the
'host' for the CLR

It is this host that initializes entities called AppDomains within the managed world of the .NET CLR.
AppDomains are CLR's way of representing isolated application services (much like operating system tasks).
One or more AppDomains can coexist within the CLR without interfering with each other, just as WIN32
processes share computing resources without interference

Some standard CLR hosts that are shipped as a part of the .NET runtime are

ASP.NET

Loads the runtime into the process that handles Web requests. ASP.NET creates an AppDomain for each Web
application that will run on a Web server. ASP.NET applications are actually loaded and executed by an
ISAPI filter DLL extension to the IIS web server, that accepts HTTP requests for the .aspx files associated
with the application.

Internet Explorer

Creates AppDomains to run managed controls. The .NET framework supports the downloading and execution of
browser-based controls. It uses the extensibility mechanism of Internet Explorer through a MIME filter to
create AppDomains for any managed controls hosted on a web-site. By default, one AppDomain is created for
each web-site visited.

Shell Executables

Invokes runtime hosting code to transfer control to the runtime each time an executable is launched from
the shell. (Note: A .NET Portable Executable (PE) file contains unmanaged code at the entrypoint to set up
the runtime and transfer control to it and thereby the rest of the managed code. Naturally, this runs first
when the executable is launched from the Windows shell.)

The .NET framework allows easy usage of managed components running under the CLR in the unmanaged world:
it creates COM Callable Wrappers (CCW) silently. Consider the following example for a component written in
C#.

To use this (not very useful) C# component in an unmanaged application as a COM component, one
would:

compile the component as a .NET assembly (a DLL)

use the command-line tool regasm.exe to register the DLL. This generates an equivalent type library for
use in COM environments, and creates the traditional COM registry entries (HKCR/CLSID) for
CoCreateInstance/CreateObject to locate these types.

But, have you ever wondered what exactly happens when this tool is run? Well, it generates an equivalent
type-library for use in the COM environment and creates the traditional COM registry entries under
"HKCR\CLSID" for CoCreateInstance or CreateObject to locate the types in it. Here's what the registry
entries look like:

Notice that the InprocServer32 section's default key points to mscoree.dll? Aha!! The other
keys show that there is information available to the CLR that indicate the assembly name and the type name,
among other attributes of the managed component.

This begs the question: 'What is mscoree.dll doing under that InprocServer32 section?'
Mscoree.dll is the Microsoft .NET Runtime Execution Engine, which hosts the .NET CLR in an unmanaged
environment, and exposes a generic-hosting API for the same.

Here is the TypeLibrary generated by RegAsm.

When one wants to use the type-library generated through the RegAsm or TlbExp tools:

A call is made to CoCreateInstance with the GUID of the CoClass within the generated type-library
that loads mscoree.dll.

The method DllGetClassObject (internally called by CoCreateInstance, traditional COM) is
exported by the mscoree.dll. The COM Interoperability portion of .NET provides a standard
class-factory implementation to create an instance of any .NET framework class. This class-factory is
returned to the caller, who makes a call to the CreateInstance method, passing in the type requested.
In our sample above, HelloHostDemo is a class with a single method Hi in it. Since no explicit
interfaces is declared nor any advanced type-library overriding attributes are used, the type-library
generates types for the ClassInterface, after exposing NO dispids(by default). Hence IDispatch is the
default interface.

This interface pointer is what is returned back by the call to CreateInstance from the
class factory, which is the COM Callable Wrapper (known as CCW for short) that's fabricated by the CLR at
runtime.

This is how .NET uses mscoree.dll to add a layer above a managed component, so that COM is totally
unaware of any such thing as a managed environment.

Now that we've finished explaining (whew!) how a CCW is used to make calls in to any .NET component within
an unmanaged environment, let's talk about what this article is all about, how mscoree.dll actually
loads the CLR within the process address-space of the callee and how we can write a very simple host for the
CLR.

Here is what our simple CLR host would do:

host the Common Language Runtime using CLR's Hosting API's.

load a type from a .NET assembly - HelloHostDemo, in our example, from the HelloMsgBox.dll
assembly. (See instructions on how to build the sample for the .NET Framework SDK, Beta2.)

retrieve this type as a IDispatch pointer and use that to locate the dispid of the method
(Hi, in our example) through a call to GetIDsOfNames.

Use Invoke on the IDispatch pointer with the dispid retrieved, and that's all!

The most important hosting API is CorBindToRuntimeEx as described by Steven Pratschner from Microsoft,
is more like a 'shim' code that exports the above mentioned API.

CorBindToRuntimeEx accepts version numbers of CLR's and other configurable parameters based on
which it returns an instance of the ICorRuntimeHost interface pointer.

The Hosting API lets a custom host fine tune some of the CLR settings like:

Version of the CLR to be loaded

Build of the CLR to be loaded, Workstation or Server for client applications and multiprocessor
server scenarios respectively. In case of multi-processor machines the server build allows garbage collection
to be done on each processor in parallel.

Domain Neutrality settings, that specify the way in which copies of frequently used Assemblies in
multiple AppDomains are loaded, either different copies for all AppDomains or Shared copy across all
AppDomains, the latter being AppDomain neutral.

retrieve a pointer to the default AppDomain of the managed code, e.g.:

spRuntimeHost->GetDefaultDomain(&pUnk);

retrieve a pointer to the ICorConfiguration through which additional fine tuning can be achieved
(see the documentation
for CLR issues involved.)

There! Notice that in the SimpleCLRHost example, we find that no call is made to to the traditional
CoInitialize function before retrieving the COM interface, so no apartment is specified explicitly.
I have a clue to this, but need more ideas to confirm/clarify my suspicions.

To run the sample, first run buildmanaged.bat before building and executing the
SimpleCLRHost.

There are a couple of things to note before running the sample:

The sample uses the header file mscoree.h which is located typically in the
C:\PROGRAM FILES\ MICROSOFT.NET\FRAMEWORKSDK\INCLUDE directory, and so I chose to add that in my list
of include paths through Tools -> Options in Visual Studio.

It uses the MsCorLib.Tlb which provides interface definitions used within the program, which is
located typically in the path C:\WINNT\Microsoft.NET\Framework\v1.0.2914 for beta2 versions of the
CLR, so I just hardcoded the path.

References:

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

I am originally from Mumbai, India, Currently living in Los Angeles doing Software Development. If there is something I miss here in LA, its the crazy Mumbai monsoon and delicious "wadapavs".Apart from spending time writing software, I spend most of my time with XBox riding the Warthog and killing covenants in Halo.

Hi,nice article! I'm here to ask you a simple question:how can I run a UserControl or EXE windows application that I developed using .NET from within IE so that it can be easily deployed on the net and downloaded on demand?How do I launch it using and HTML page or ASP page?

I am trying to do similar things with GCC (and a C program, not C++, maybe that's why?...)(I am using SDK.NET2.0 beta2)

But my program just don't compile as, when I include <mscoree.h> it produces plenty of error, kind of:../mscoree.h:487: error: syntax error before numeric constant../mscoree.h:487: warning: data definition has no type or storage class

At line 487 (in mscoree.h) there is something like that:EXTERN_GUID(LIBID_mscoree, 0x5477469e,0x83b1,0x11d2,0x8b,0x49,0x00,0xa0,0xc9,0xb7,0xc9,0xc4);

any idea what could that be?(this gibberish means nothing to me!)

Note: Using gcc is preferable for me as I try to mix an ObjectiveC code with a .NET application.But if I have to use a VS.NET C++ I guess I could do something about it...

what difference does it make? You'll still need the runtime installed on the target machine (just like IE) so might as well just develop it all in .NET. I don't think there is any way to escape .net framework installation yest use .net