2 Embedding the Mono runtime, preliminary version
3 Miguel de Icaza (miguel@ximian.com),
4 Paolo Molaro (lupus@ximian.com)
7 This document describes how to embed the Mono runtime in your
8 application, and how to invoke CIL methods from C, and how to
9 invoke C code from CIL. Both the JIT and interpreter can be
10 embedded in very similar ways so most of what is described
11 here can be used in either case.
15 This document is now outdated, see:
17 http://www.mono-project.com/Embedding_Mono
19 For an up-to-date version of this document
21 * Embedding the runtime.
23 Embedding the runtime consists of various steps:
25 * Compiling and linking the Mono runtime
27 * Initializing the Mono runtime
29 * Optionally expose C code to the C#/CIL universe.
31 These are discussed in detail next.
33 ** Compiling and Linking
35 To embed the runtime, you have to link your code against the
36 Mono runtime libraries. To do this, you want to pass the
37 flags returned by pkg-config to your compiler:
39 pkg-config --cflags --libs mono
41 is used to get the flags for the JIT runtime and
43 pkg-config --cflags --libs mint
45 for the interpreted runtime.
49 gcc sample.c `pkg-config --cflags --libs mono`
51 You can separate the compilation flags from the linking flags, for
52 instance, you can use the following macros in your makefile:
54 CFLAGS=`pkg-config --cflags mono`
55 LDFLAGS=`pkg-config --libs mono`
57 ** Initializing the Mono runtime
59 To initialize the JIT runtime, call mono_jit_init, like this:
61 #include <mono/mini/jit.h>
65 domain = mono_jit_init ("domain-name");
67 For the interpreted runtime use mono_interp_init instead:
69 #include <mono/interpreter/embed.h>
73 domain = mono_interp_init ("domain-name");
75 That will return a MonoDomain where your code will be
76 executed. You can create multiple domains. Each domain is
77 isolated from the other domains and code in one domain will
78 not interfere with code in other domains. This is useful if
79 you want to host different applications in your program.
81 Now, it is necessary to transfer control to Mono, and setup
82 the threading infrastructure, you do this like this:
84 void *user_data = NULL;
86 mono_runtime_exec_managed_code (domain, main_thread_handler, user_data);
88 Where your main_thread_handler can load your assembly and execute it:
90 static void main_thread_handler (gpointer user_data)
92 MonoAssembly *assembly;
94 assembly = mono_domain_assembly_open (domain, "file.dll");
98 In the above example, the contents of `file.dll' will be
99 loaded into the domain. This only loads the code, but it will
100 not execute anything yet. You can replace `file.dll' with
101 another transport file, like `file.exe'
103 To start executing code, you must invoke a method in the
104 assembly, or if you have provided a static Main method (an
105 entry point), you can use the convenience function:
107 retval = mono_jit_exec (domain, assembly, argc - 1, argv + 1);
109 or when using the interpreter use:
111 retval = mono_interp_exec (domain, assembly, argc - 1, argv + 1);
113 If you want to invoke a different method, look at the
114 `Invoking Methods in the CIL universe' section later on.
116 ** Shutting down the runtime
118 To shutdown the Mono runtime, you have to clean up all the
119 domains that were created, use this function:
121 mono_jit_cleanup (domain);
123 Or in the case of the interpreted runtime use:
125 mono_interp_cleanup (domain);
127 ** Applications that use threads.
129 The Boehm GC system needs to catch your calls to the pthreads
130 layer, so in each file where you use pthread.h you should
131 include the <gc/gc.h> file.
133 If you can not do this for any reasons, just remember that you
134 can not store pointers to Mono Objects on the stack, you can
135 store them safely in the heap, or in global variables though
137 * Exposing C code to the CIL universe
139 The Mono runtime provides two mechanisms to expose C code to
140 the CIL universe: internal calls and native C code. Internal
141 calls are tightly integrated with the runtime, and have the
142 least overhead, as they use the same data types that the
145 The other option is to use the Platform Invoke (P/Invoke) to
146 call C code from the CIL universe, using the standard P/Invoke
149 To register an internal call, use this call in the C code:
151 mono_add_internal_call ("Hello::Sample", sample);
153 Now, you need to declare this on the C# side:
156 using System.Runtime.CompilerServices;
159 [MethodImplAttribute(MethodImplOptions.InternalCall)]
160 extern static string Sample ();
163 Since this routine returns a string, here is the C definition:
168 return mono_string_new (mono_domain_get (), "Hello!");
171 Notice that we have to return a `MonoString', and we use the
172 `mono_string_new' API call to obtain this from a string.
174 * Invoking Methods in the CIL universe
176 Calling a method in the CIL universe from C requires a number of steps:
178 * Obtaining the MonoMethod handle to the method.
180 * The method invocation.
182 ** Obtaining a MonoMethod
184 To get a MonoMethod there are several ways.
186 You can get a MonoClass (the structure representing a type)
190 mono_class_from_name (MonoImage *image, const char* name_space, const char *name);
192 and then loop in the returned class method array until you get
193 the one you're looking for. There are examples of such
194 searches as static functions in several C files in
195 metadata/*.c: we need to expose one through the API and remove
198 The other, simpler, way is to use the functions in
199 debug-helpers.h: there are examples of their use in monograph,
200 mint and the jit as well. You basically use a string
201 description of the method, like:
203 "System.Object:GetHashCode()"
205 and create a MonoMethodDesc out of it with:
207 MonoMethodDesc* mono_method_desc_new (const char *name, gboolean include_namespace);
211 MonoMethod* mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass);
212 MonoMethod* mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image);
214 to search for the method in a class or in an image. You would
215 tipically do this just once at the start of the program and
216 store the result for reuse somewhere.
220 There are two functions to call a managed method:
223 mono_runtime_invoke (MonoMethod *method, void *obj, void **params,
227 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
230 obj is the 'this' pointer, it should be NULL for static
231 methods, a MonoObject* for object instances and a pointer to
232 the value type for value types.
234 These functions can be used in both the JIT and the interpreted
237 The params array contains the arguments to the method with the
238 same convention: MonoObject* pointers for object instances and
239 pointers to the value type otherwise. The _invoke_array
240 variant takes a C# object[] as the params argument (MonoArray
241 *params): in this case the value types are boxed inside the
242 respective reference representation.
244 From unmanaged code you'll usually use the
245 mono_runtime_invoke() variant.
247 Note that this function doesn't handle virtual methods for
248 you, it will exec the exact method you pass: we still need to
249 expose a function to lookup the derived class implementation
250 of a virtual method (there are examples of this in the code,
253 You can pass NULL as the exc argument if you don't want to
254 catch exceptions, otherwise, *exc will be set to the exception
255 thrown, if any. if an exception is thrown, you can't use the
256 MonoObject* result from the function.
258 If the method returns a value type, it is boxed in an object
261 We have plans for providing an additional method that returns
262 an unmanaged->managed thunk like this:
264 void* mono_method_get_unmanaged_thunk (MonoMethod *method);
266 You'll be able to store the returned pointer in a function
267 pointer with the proper signature and call that directly from
270 typedef gint32 (*GetHashCode) (MonoObject *obj);
272 GetHashCode func = mono_method_get_unmanaged_thunk (System_Object_GetHashCode_method);
274 gint32 hashvalue = func (myobject);
276 It may not be possible to manage exceptions in that case,
277 though. I need to think more about it.
281 If your application creates threads on its own, and you want them to
282 be able to call code into the CIL universe with Mono, you have to
283 register the thread with Mono before issuing the call.
285 To do so, call the mono_thread_attach() function before you execute
286 any managed code from the thread
290 See the sample programs in mono/sample/embed for examples of
291 embedding the Mono runtime in your application.