2 Embedding the Mono runtime, preliminary version
4 Miguel de Icaza, Paolo Molaro.
6 This document describes how to embed the Mono runtime in your
7 application, and how to invoke CIL methods from C, and how to
8 invoke C code from CIL.
10 * Embedding the runtime.
12 Embedding the runtime consists of various steps:
14 * Compiling and linking the Mono runtime
16 * Initializing the Mono runtime
18 * Optionally expose C code to the C#/CIL universe.
20 These are discussed in detail next.
22 ** Compiling and Linking
24 To embed the runtime, you have to link your code against the
25 Mono runtime libraries. To do this, you want to pass the
26 flags returned by pkg-config to your compiler:
28 pkg-config --cflags --libs mono
32 gcc sample.c `pkg-config --cflags --libs mono`
34 You can separate the compilation flags from the linking flags, for
35 instance, you can use the following macros in your makefile:
37 CFLAGS=`pkg-config --cflags mono`
38 LDFLAGS=`pkg-config --libs mono`
40 ** Initializing the Mono runtime
42 To initialize the runtime, call mono_jit_init, like this:
46 domain = mono_jit_init ("domain-name");
48 That will return a MonoDomain where your code will be
49 executed. You can create multiple domains. Each domain is
50 isolated from the other domains and code in one domain will
51 not interfere with code in other domains. This is useful if
52 you want to host different applications in your program.
54 Then you can load an assembly containing code into the domain:
56 MonoAssembly *assembly;
58 assembly = mono_domain_assembly_open ("file.dll");
62 In the above example, the contents of `file.dll' will be
63 loaded into the domain. This only loads the code, but it will
64 not execute anything yet. You can replace `file.dll' with
65 another transport file, like `file.exe'
67 To start executing code, you must invoke a method in the
68 assembly, or if you have provided a static Main method (an
69 entry point), you can use the convenience function:
71 retval = mono_jit_exec (domain, assembly, argc - 1, argv + 1);
73 If you want to invoke a different method, look at the
74 `Invoking Methods in the CIL universe' section later on.
76 ** Shutting down the runtime
78 To shutdown the Mono runtime, you have to clean up all the
79 domains that were created, use this function:
81 mono_jit_cleanup (domain);
83 * Exposing C code to the CIL universe
85 The Mono runtime provides two mechanisms to expose C code to
86 the CIL universe: internal calls and native C code. Internal
87 calls are tightly integrated with the runtime, and have the
88 least overhead, as they use the same data types that the
91 The other option is to use the Platform Invoke (P/Invoke) to
92 call C code from the CIL universe, using the standard P/Invoke
95 To register an internal call, use this call in the C code:
97 mono_add_internal_call ("Hello::Sample", sample);
99 Now, you need to declare this on the C# side:
102 using System.Runtime.CompilerServices;
105 [MethodImplAttribute(MethodImplOptions.InternalCall)]
106 extern static string Sample ();
109 Since this routine returns a string, here is the C definition:
114 return mono_string_new (mono_domain_get (), "Hello!");
117 Notice that we have to return a `MonoString', and we use the
118 `mono_string_new' API call to obtain this from a string.
120 * Invoking Methods in the CIL universe
122 Calling a method in the CIL universe from C requires a number of steps:
124 * Obtaining the MonoMethod handle to the method.
126 * The method invocation.
128 ** Obtaining a MonoMethod
130 To get a MonoMethod there are several ways.
132 You can get a MonoClass (the structure representing a type)
136 mono_class_from_name (MonoImage *image, const char* name_space, const char *name);
138 and then loop in the returned class method array until you get
139 the one you're looking for. There are examples of such
140 searches as static functions in several C files in
141 metadata/*.c: we need to expose one through the API and remove
144 The other, simpler, way is to use the functions in
145 debug-helpers.h: there are examples of their use in monograph,
146 mint and the jit as well. You basically use a string
147 description of the method, like:
149 "System.Object:GetHashCode()"
151 and create a MonoMethodDesc out of it with:
153 MonoMethodDesc* mono_method_desc_new (const char *name, gboolean include_namespace);
157 MonoMethod* mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass);
158 MonoMethod* mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image);
160 to search for the method in a class or in an image. You would
161 tipically do this just once at the start of the program and
162 store the result for reuse somewhere.
166 There are two functions to call a managed method:
169 mono_runtime_invoke (MonoMethod *method, void *obj, void **params,
173 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
176 obj is the 'this' pointer, it should be NULL for static
177 methods, a MonoObject* for object instances and a pointer to
178 the value type for value types.
180 The params array contains the arguments to the method with the
181 same convention: MonoObject* pointers for object instances and
182 pointers to the value type otherwise. The _invoke_array
183 variant takes a C# object[] as the params argument (MonoArray
184 *params): in this case the value types are boxed inside the
185 respective reference representation.
187 From unmanaged code you'll usually use the
188 mono_runtime_invoke() variant.
190 Note that this function doesn't handle virtual methods for
191 you, it will exec the exact method you pass: we still need to
192 expose a function to lookup the derived class implementation
193 of a virtual method (there are examples of this in the code,
196 You can pass NULL as the exc argument if you don't want to
197 catch exceptions, otherwise, *exc will be set to the exception
198 thrown, if any. if an exception is thrown, you can't use the
199 MonoObject* result from the function.
201 If the method returns a value type, it is boxed in an object
204 We have plans for providing an additional method that returns
205 an unmanaged->managed thunk like this:
207 void* mono_method_get_unmanaged_thunk (MonoMethod *method);
209 You'll be able to store the returned pointer in a function
210 pointer with the proper signature and call that directly from
213 typedef gint32 (*GetHashCode) (MonoObject *obj);
215 GetHashCode func = mono_method_get_unmanaged_thunk (System_Object_GetHashCode_method);
217 gint32 hashvalue = func (myobject);
219 It may not be possible to manage exceptions in that case,
220 though. I need to think more about it.
224 See the sample programs inmono/sample/embed for examples of
225 embedding the Mono runtime in your application.