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
Anonymous
August 07, 2006
PingBack from http://www.robherbst.com/blog/2006/08/07/host-the-clr-in-c/Anonymous
August 08, 2006
The comment has been removedAnonymous
August 08, 2006
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.).Anonymous
December 18, 2006
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, RSLAnonymous
November 04, 2008
<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>