2 Embedding the Mono runtime, preliminary version
3 Miguel de Icaza (miguel@ximian.com),
4 Paolo Molaro (lupus@ximian.com)
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. Both the JIT and interpreter can be
9 embedded in very similar ways so most of what is described
10 here can be used in either case.
12 * Embedding the runtime.
14 Embedding the runtime consists of various steps:
16 * Compiling and linking the Mono runtime
18 * Initializing the Mono runtime
20 * Optionally expose C code to the C#/CIL universe.
22 These are discussed in detail next.
24 ** Compiling and Linking
26 To embed the runtime, you have to link your code against the
27 Mono runtime libraries. To do this, you want to pass the
28 flags returned by pkg-config to your compiler:
30 pkg-config --cflags --libs mono
32 is used to get the flags for the JIT runtime and
34 pkg-config --cflags --libs mint
36 for the interpreted runtime.
40 gcc sample.c `pkg-config --cflags --libs mono`
42 You can separate the compilation flags from the linking flags, for
43 instance, you can use the following macros in your makefile:
45 CFLAGS=`pkg-config --cflags mono`
46 LDFLAGS=`pkg-config --libs mono`
48 ** Initializing the Mono runtime
50 To initialize the JIT runtime, call mono_jit_init, like this:
52 #include <mono/mini/jit.h>
56 domain = mono_jit_init ("domain-name");
58 For the interpreted runtime use mono_interp_init instead:
60 #include <mono/interpreter/embed.h>
64 domain = mono_interp_init ("domain-name");
66 That will return a MonoDomain where your code will be
67 executed. You can create multiple domains. Each domain is
68 isolated from the other domains and code in one domain will
69 not interfere with code in other domains. This is useful if
70 you want to host different applications in your program.
72 Then you can load an assembly containing code into the domain:
74 MonoAssembly *assembly;
76 assembly = mono_domain_assembly_open (domain, "file.dll");
80 In the above example, the contents of `file.dll' will be
81 loaded into the domain. This only loads the code, but it will
82 not execute anything yet. You can replace `file.dll' with
83 another transport file, like `file.exe'
85 To start executing code, you must invoke a method in the
86 assembly, or if you have provided a static Main method (an
87 entry point), you can use the convenience function:
89 retval = mono_jit_exec (domain, assembly, argc - 1, argv + 1);
91 or when using the interpreter use:
93 retval = mono_interp_exec (domain, assembly, argc - 1, argv + 1);
95 If you want to invoke a different method, look at the
96 `Invoking Methods in the CIL universe' section later on.
98 ** Shutting down the runtime
100 To shutdown the Mono runtime, you have to clean up all the
101 domains that were created, use this function:
103 mono_jit_cleanup (domain);
105 Or in the case of the interpreted runtime use:
107 mono_interp_cleanup (domain);
109 ** Applications that use threads.
111 The Boehm GC system needs to catch your calls to the pthreads
112 layer, so in each file where you use pthread.h you should
113 include the <gc/gc.h> file.
115 * Exposing C code to the CIL universe
117 The Mono runtime provides two mechanisms to expose C code to
118 the CIL universe: internal calls and native C code. Internal
119 calls are tightly integrated with the runtime, and have the
120 least overhead, as they use the same data types that the
123 The other option is to use the Platform Invoke (P/Invoke) to
124 call C code from the CIL universe, using the standard P/Invoke
127 To register an internal call, use this call in the C code:
129 mono_add_internal_call ("Hello::Sample", sample);
131 Now, you need to declare this on the C# side:
134 using System.Runtime.CompilerServices;
137 [MethodImplAttribute(MethodImplOptions.InternalCall)]
138 extern static string Sample ();
141 Since this routine returns a string, here is the C definition:
146 return mono_string_new (mono_domain_get (), "Hello!");
149 Notice that we have to return a `MonoString', and we use the
150 `mono_string_new' API call to obtain this from a string.
152 * Invoking Methods in the CIL universe
154 Calling a method in the CIL universe from C requires a number of steps:
156 * Obtaining the MonoMethod handle to the method.
158 * The method invocation.
160 ** Obtaining a MonoMethod
162 To get a MonoMethod there are several ways.
164 You can get a MonoClass (the structure representing a type)
168 mono_class_from_name (MonoImage *image, const char* name_space, const char *name);
170 and then loop in the returned class method array until you get
171 the one you're looking for. There are examples of such
172 searches as static functions in several C files in
173 metadata/*.c: we need to expose one through the API and remove
176 The other, simpler, way is to use the functions in
177 debug-helpers.h: there are examples of their use in monograph,
178 mint and the jit as well. You basically use a string
179 description of the method, like:
181 "System.Object:GetHashCode()"
183 and create a MonoMethodDesc out of it with:
185 MonoMethodDesc* mono_method_desc_new (const char *name, gboolean include_namespace);
189 MonoMethod* mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass);
190 MonoMethod* mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image);
192 to search for the method in a class or in an image. You would
193 tipically do this just once at the start of the program and
194 store the result for reuse somewhere.
198 There are two functions to call a managed method:
201 mono_runtime_invoke (MonoMethod *method, void *obj, void **params,
205 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
208 obj is the 'this' pointer, it should be NULL for static
209 methods, a MonoObject* for object instances and a pointer to
210 the value type for value types.
212 These functions can be used in both the JIT and the interpreted
215 The params array contains the arguments to the method with the
216 same convention: MonoObject* pointers for object instances and
217 pointers to the value type otherwise. The _invoke_array
218 variant takes a C# object[] as the params argument (MonoArray
219 *params): in this case the value types are boxed inside the
220 respective reference representation.
222 From unmanaged code you'll usually use the
223 mono_runtime_invoke() variant.
225 Note that this function doesn't handle virtual methods for
226 you, it will exec the exact method you pass: we still need to
227 expose a function to lookup the derived class implementation
228 of a virtual method (there are examples of this in the code,
231 You can pass NULL as the exc argument if you don't want to
232 catch exceptions, otherwise, *exc will be set to the exception
233 thrown, if any. if an exception is thrown, you can't use the
234 MonoObject* result from the function.
236 If the method returns a value type, it is boxed in an object
239 We have plans for providing an additional method that returns
240 an unmanaged->managed thunk like this:
242 void* mono_method_get_unmanaged_thunk (MonoMethod *method);
244 You'll be able to store the returned pointer in a function
245 pointer with the proper signature and call that directly from
248 typedef gint32 (*GetHashCode) (MonoObject *obj);
250 GetHashCode func = mono_method_get_unmanaged_thunk (System_Object_GetHashCode_method);
252 gint32 hashvalue = func (myobject);
254 It may not be possible to manage exceptions in that case,
255 though. I need to think more about it.
259 If your application creates threads on its own, and you want them to
260 be able to call code into the CIL universe with Mono, you have to
261 register the thread with Mono before issuing the call.
263 To do so, call the mono_thread_attach() function before you execute
264 any managed code from the thread
268 See the sample programs in mono/sample/embed for examples of
269 embedding the Mono runtime in your application.