Host the CLR and Generate IL to call a MessageBox


Here’s some C++ code to host the CLR. It’s an alternative to using COM Interop (see A Visual Basic COM object is simple to create, call and debug from Excel), or using a User Control (see Create a .Net UserControl that calls a web service that acts as an ActiveX control to use in Excel, VB6, Foxpro)


 


I created a C++ native project in a Visual Studio Solution and added a method called “foobar” which  uses COM to start the CLR using CorBindToRuntimeEx. It then loads an assembly and calls the “EntryPoint” method, with a single string parameter.


 


I added a VB.Net Class Library project into the VS Solution which created an assembly (d:\dev\vb\CLRHostTest\bin\debug\CLRHostTest.dll) that has a static method called “EntryPoint”  that takes a single string parameter. The method dynamically generates (using System.Reflection.Emit) an assembly called “testasm” with a module called “MyModule”, which has a public class called “FoobarType” and a static method called “Main”. The code in “Main” shows a messagebox of the parameter passed to “EntryPoint”


 


Quite a bit of work just to show a MessageBox!


 


#include “assert.h”


#include <mscoree.h>


 


#import <mscorlib.tlb> raw_interfaces_only rename(“ReportEvent”,“ReportEventManaged”) //high_property_prefixes(“_get”,”_put”,”_putref”)


using namespace mscorlib;


 


 


void foobar() {


      HRESULT hr;


      CComPtr<ICLRRuntimeHost> pHost = NULL;


 


      hr = CorBindToRuntimeEx(L“v2.0.50727”,L“wks”,0 //STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN | STARTUP_CONCURRENT_GC


            ,CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (void **)&pHost);


      _ASSERT(hr == S_OK);


      hr = pHost->Start();


      _ASSERT(hr == S_OK);


      DWORD retVal;


      hr = pHost->ExecuteInDefaultAppDomain(L“d:\\dev\\vb\\CLRHostTest\\bin\\debug\\CLRHostTest.dll”,


            L“CLRHostTest.CLRHostTestClass”,L“EntryPoint”,L“System.Windows.Forms.MessageBox.Show(\”test\”)”,&retVal);


      _ASSERT(hr == S_OK);


      pHost->Stop();


      exit(0);


}


 


 


 


Here’s the VB code that gets called:


 


Imports System.Reflection


Imports System.Reflection.Emit


 


Public Class CLRHostTestClass


        Shared Function EntryPoint(ByVal cArg As String) As Integer


                MsgBox(“here in CLRHostTest ” & cArg)


        Dim asmName As AssemblyName = New AssemblyName(“testasm”)


 


        Dim appDomain As AppDomain = System.Threading.Thread.GetDomain


        Dim asmBldr As AssemblyBuilder = appDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run)


        Dim moduleBldr As ModuleBuilder = asmBldr.DefineDynamicModule(“MyModule”)


        Dim typeBldr As TypeBuilder = moduleBldr.DefineType(“FoobarType”, TypeAttributes.Class + TypeAttributes.Public)


        Dim methodBldr As MethodBuilder = typeBldr.DefineMethod(Main, MethodAttributes.Public + MethodAttributes.Static, _


            GetType(Integer), New System.Type() {GetType(String)})


        Dim ilg As ILGenerator = methodBldr.GetILGenerator()


        Dim msgboxMethodInfo As Reflection.MethodInfo = GetType(System.Windows.Forms.MessageBox).GetMethod( _


            “Show”, BindingFlags.Public + BindingFlags.Static, Nothing, _


            CallingConventions.Standard, New System.Type() {GetType(String)}, Nothing)


 


        ilg.Emit(OpCodes.Ldstr, cArg)


        ilg.EmitCall(OpCodes.Call, msgboxMethodInfo, Nothing)


        ilg.Emit(OpCodes.Ret)


        Dim mytype As Type = typeBldr.CreateType()


        mytype.InvokeMember(Main, BindingFlags.Public + BindingFlags.InvokeMethod + BindingFlags.Static _


            , Nothing, Nothing, New String() {“aa”})


 


        Return 10


    End Function


 


End Class


 


 


Another way to call the method using mixed mode managed C++ (compiling with /clr)


 


 


#using “d:\dev\vb\CLRHostTest\bin\debug\CLRHostTest.dll”


 


void foobar()


{


   System::String^ s = “Some text”;


   CLRHostTestClass::EntryPoint(s);


}


 


 


BTW, it was very hard to find documentation on the “^” (circumflex or caret) character. Try typing it into a search engine!  Here’s a link: Handle to Object on Managed Heap


 

Comments (6)

  1. Hi Calvin,

    nice shot. I experimented some stuff writing a host for CLR inside of Visual FoxPro. I created an FLL to ease usage in VFP. On of my next steps is to create an object reference (added to _VFP or _Screen) in order to execute .NET assemblies in VFP. Second, I’m stuck with configuring my own ApplicationDomain for VFP to separate memory stuff from the default app domain.

    Maybe this could be an idea to extend Sedna… 😉

    Anyway, here’s the C++ code I use inside my FLL to create the CLR host:

    HRESULT hr = CorBindToRuntimeEx(

    NULL,

    NULL,

    0,

    CLSID_CLRRuntimeHost,

    IID_ICLRRuntimeHost,

    (PVOID*)&pRuntimeHost);

    This way, always the latest, installed version of .NET Framework is returned. Would be nice to share some thoughts about writing an CLR Host for VFP.

    Kind regards, Jochen "JoKi" Kirstätter

  2. rstrahl says:

    So how would this be more benficial than say doing COM interop into the CLR which automatically creates a default AppDomain?

    I can see this being useful for pure C++ code, but I’m not sure I see the immediate benefit for doing this higher up the stack for say FoxPro or VB 6 since you still need to pass data across somehow. I don’t think that there’s a big performance gain either when you compare COM interop vs. directly calling into the CLR.

    Can you give a use case when this would be useful?

    I’m just thinking out loud here. A while back I built an Add-in interface into Help Builder for example, that allows Add-in creation in .NET even though the application is a FoxPro application. It uses COM interop and that works just fine. i just don’t see the benefit of a ‘pure’ .NET hosting situation unless you need to have a primary gateway (ie. IIS, IE etc.).

  3. rsl says:

    Hi Calvin,

      Thanks for the information. I’ve tried doing the same way to use my managed c++ code in unmanaged c++ . But the API ExecuteInDefaultAppDomain(..) fails. May I know why is it so?

    Regards,

    RSL

  4. Olgunka-ev says:

    <a href= http://index1.ystins.com >laguardia rising stars 2006</a> <a href= http://index2.ystins.com >northumberland county va</a> <a href= http://index3.ystins.com >holy ghost prep bensalem craft</a> <a href= http://index4.ystins.com >miles away from the ordinary</a> <a href= http://index5.ystins.com >star trader software</a>