1 * Embedding the Mono runtime, preliminary version
3 This document describes how to embed the Mono runtime in your
4 application, and how to invoke CIL methods from C, and how to
7 Slides for Paolo's presentation at .NET ONE on the embedding
8 API are available here: <a
9 href="http://primates.ximian.com/~lupus/slides/embed">Hosting the Mono
10 Runtime</a>. You can also get his <a
11 href="http://primates.ximian.com/~lupus/slides/embed/Mono-0.01.tar.gz">sample
12 Mono module for Perl</a>
14 Authors: Paolo Molaro, Miguel de Icaza.
16 * Embedding the runtime.
18 Embedding the runtime consists of various steps:
21 * Compiling and linking the Mono runtime
23 * Initializing the Mono runtime
25 * Optionally expose C code to the C#/CIL universe.
29 These are discussed in detail next.
31 ** Compiling and Linking
33 To embed the runtime, you have to link your code against the
34 Mono runtime libraries. To do this, you want to pass the
35 flags returned by pkg-config to your compiler:
38 pkg-config --cflags --libs mono
44 gcc sample.c `pkg-config --cflags --libs mono`
47 You can separate the compilation flags from the linking flags, for
48 instance, you can use the following macros in your makefile:
51 CFLAGS=`pkg-config --cflags mono`
52 LDFLAGS=`pkg-config --libs mono`
55 ** Initializing the Mono runtime
57 To initialize the runtime, call mono_jit_init, like this:
62 domain = mono_jit_init ("domain-name");
65 That will return a MonoDomain where your code will be
66 executed. You can create multiple domains. Each domain is
67 isolated from the other domains and code in one domain will
68 not interfere with code in other domains. This is useful if
69 you want to host different applications in your program.
71 Now, it is necessary to transfer control to Mono, and setup
72 the threading infrastructure, you do this like this:
75 void *user_data = NULL;
77 mono_runtime_exec_managed_code (domain, main_thread_handler, user_data);
80 Where your main_thread_handler can load your assembly and execute it:
83 static void main_thread_handler (gpointer user_data)
85 MonoAssembly *assembly;
87 assembly = mono_domain_assembly_open (domain, "file.dll");
92 In the above example, the contents of `file.dll' will be
93 loaded into the domain. This only loads the code, but it will
94 not execute anything yet. You can replace `file.dll' with
95 another transport file, like `file.exe'
97 To start executing code, you must invoke a method in the
98 assembly, or if you have provided a static Main method (an
99 entry point), you can use the convenience function:
102 retval = mono_jit_exec (domain, assembly, argc - 1, argv + 1);
105 If you want to invoke a different method, look at the
106 `Invoking Methods in the CIL universe' section later on.
108 ** Shutting down the runtime
110 To shutdown the Mono runtime, you have to clean up all the
111 domains that were created, use this function:
114 mono_jit_cleanup (domain);
117 ** Applications that use threads.
119 The Boehm GC system needs to catch your calls to the pthreads
120 layer, so in each file where you use pthread.h you should
121 include the <gc/gc.h> file.
123 If you can not do this for any reasons, just remember that you
124 can not store pointers to Mono Objects on the stack, you can
125 store them safely in the heap, or in global variables though
127 * Exposing C code to the CIL universe
129 The Mono runtime provides two mechanisms to expose C code to
130 the CIL universe: internal calls and native C code. Internal
131 calls are tightly integrated with the runtime, and have the
132 least overhead, as they use the same data types that the
135 The other option is to use the Platform Invoke (P/Invoke) to
136 call C code from the CIL universe, using the standard P/Invoke
139 To register an internal call, use this call in the C code:
142 mono_add_internal_call ("Hello::Sample", sample);
145 Now, you need to declare this on the C# side:
149 using System.Runtime.CompilerServices;
155 [MethodImplAttribute(MethodImplOptions.InternalCall)]
156 extern static string Sample ();
160 Since this routine returns a string, here is the C definition:
166 return mono_string_new (mono_domain_get (), "Hello!");
170 Notice that we have to return a `MonoString', and we use the
171 `mono_string_new' API call to obtain this from a string.
173 * Invoking Methods in the CIL universe
175 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.
183 ** Obtaining a MonoMethod
185 To get a MonoMethod there are several ways.
187 You can get a MonoClass (the structure representing a type)
192 mono_class_from_name (MonoImage *image, const char* name_space, const char *name);
195 and then loop in the returned class method array until you get
196 the one you're looking for. There are examples of such
197 searches as static functions in several C files in
198 metadata/*.c: we need to expose one through the API and remove
201 The other, simpler, way is to use the functions in
202 debug-helpers.h: there are examples of their use in monograph,
203 mint and the jit as well. You basically use a string
204 description of the method, like:
207 "System.Object:GetHashCode()"
210 and create a MonoMethodDesc out of it with:
213 MonoMethodDesc* mono_method_desc_new (const char *name, gboolean include_namespace);
219 MonoMethod* mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass);
220 MonoMethod* mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image);
223 to search for the method in a class or in an image. You would
224 tipically do this just once at the start of the program and
225 store the result for reuse somewhere.
229 There are two functions to call a managed method:
233 mono_runtime_invoke (MonoMethod *method, void *obj, void **params,
237 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
241 obj is the 'this' pointer, it should be NULL for static
242 methods, a MonoObject* for object instances and a pointer to
243 the value type for value types.
245 The params array contains the arguments to the method with the
246 same convention: MonoObject* pointers for object instances and
247 pointers to the value type otherwise. The _invoke_array
248 variant takes a C# object[] as the params argument (MonoArray
249 *params): in this case the value types are boxed inside the
250 respective reference representation.
252 From unmanaged code you'll usually use the
253 mono_runtime_invoke() variant.
255 Note that this function doesn't handle virtual methods for
256 you, it will exec the exact method you pass: we still need to
257 expose a function to lookup the derived class implementation
258 of a virtual method (there are examples of this in the code,
261 You can pass NULL as the exc argument if you don't want to
262 catch exceptions, otherwise, *exc will be set to the exception
263 thrown, if any. if an exception is thrown, you can't use the
264 MonoObject* result from the function.
266 If the method returns a value type, it is boxed in an object
269 We have plans for providing an additional method that returns
270 an unmanaged->managed thunk like this:
273 void* mono_method_get_unmanaged_thunk (MonoMethod *method);
276 You'll be able to store the returned pointer in a function
277 pointer with the proper signature and call that directly from
281 typedef gint32 (*GetHashCode) (MonoObject *obj);
283 GetHashCode func = mono_method_get_unmanaged_thunk (System_Object_GetHashCode_method);
285 gint32 hashvalue = func (myobject);
288 It may not be possible to manage exceptions in that case,
289 though. I need to think more about it.
293 If your application creates threads on its own, and you want them to
294 be able to call code into the CIL universe with Mono, you have to
295 register the thread with Mono before issuing the call.
297 To do so, call the mono_thread_attach() function before you execute
298 any managed code from the thread
302 See the sample programs in mono/sample/embed for examples of
303 embedding the Mono runtime in your application.