2006-09-01 Sebastien Pouliot <sebastien@ximian.com>
[mono-project.git] / docs / embedded-api
blobf44f4ed15cad9abbf2274dc5d336b5e1e7f51e5d
1         
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.
13 * IMPORTANT
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.
47         Like this:
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>
63                 MonoDomain *domain;
65                 domain = mono_jit_init ("domain-name");
67         For the interpreted runtime use mono_interp_init instead:
69                 #include <mono/interpreter/embed.h>
71                 MonoDomain *domain;
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");
95                 if (!assembly)
96                         error ();
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
143         runtime uses.
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
147         mechanisms.
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:
155                 using System;
156                 using System.Runtime.CompilerServices;
158         class Hello {
159                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
160                 extern static string Sample ();
161         }
163         Since this routine returns a string, here is the C definition:
165                 static MonoString*
166                 Sample () 
167                 {
168                         return mono_string_new (mono_domain_get (), "Hello!");
169                 }
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)
187         using:
189         MonoClass *
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
196         the duplicates.
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:
202         
203                 "System.Object:GetHashCode()"
204         
205         and create a MonoMethodDesc out of it with:
206         
207         MonoMethodDesc* mono_method_desc_new (const char *name, gboolean include_namespace);
208         
209         You can then use:
210         
211         MonoMethod*     mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass);
212         MonoMethod*     mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image);
213         
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.
217                         
218 ** Invoking a Method
220         There are two functions to call a managed method:
221         
222         MonoObject*
223         mono_runtime_invoke         (MonoMethod *method, void *obj, void **params,
224                                      MonoObject **exc);
225         and
226         MonoObject*
227         mono_runtime_invoke_array   (MonoMethod *method, void *obj, MonoArray *params,
228                                      MonoObject **exc);
229         
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
235         environments.
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.
243         
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,
251         though).
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
259         reference.
260         
261         We have plans for providing an additional method that returns
262         an unmanaged->managed thunk like this:
263         
264         void* mono_method_get_unmanaged_thunk (MonoMethod *method);
265         
266         You'll be able to store the returned pointer in a function
267         pointer with the proper signature and call that directly from
268         C:
269         
270         typedef gint32 (*GetHashCode) (MonoObject *obj);
271         
272         GetHashCode func = mono_method_get_unmanaged_thunk (System_Object_GetHashCode_method);
273         
274         gint32 hashvalue = func (myobject);
275         
276         It may not be possible to manage exceptions in that case,
277         though. I need to think more about it.
279 ** Threading issues
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
288 * Samples
290         See the sample programs in mono/sample/embed for examples of
291         embedding the Mono runtime in your application.