2007-01-01 Miguel de Icaza <miguel@novell.com>
[mono-project.git] / web / embedded-api
blob3b405c98ddd191575e917267cc3f469c39528146
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
5         invoke C code from CIL
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: 
20         <ul>
21                 * Compiling and linking the Mono runtime
23                 * Initializing the Mono runtime
25                 * Optionally expose C code to the C#/CIL universe.
27         </ul>
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:
37         <pre>
38                 pkg-config --cflags --libs mono
39         </pre>
41         Like this:
43         <pre>
44                 gcc sample.c `pkg-config --cflags --libs mono`
45         </pre>
47         You can separate the compilation flags from the linking flags, for 
48         instance, you can use the following macros in your makefile:
50         <pre>
51                 CFLAGS=`pkg-config --cflags mono`
52                 LDFLAGS=`pkg-config --libs mono`
53         </pre>
55 ** Initializing the Mono runtime
57         To initialize the runtime, call mono_jit_init, like this:
59         <pre>
60                 MonoDomain *domain;
62                 domain = mono_jit_init ("domain-name");
63         </pre>
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:
74         <pre>
75                 void *user_data = NULL;
77                 mono_runtime_exec_managed_code (domain, main_thread_handler, user_data);
78         </pre>
80         Where your main_thread_handler can load your assembly and execute it:
82         <pre>
83         static void main_thread_handler (gpointer user_data)
84         {       
85                 MonoAssembly *assembly;
87                 assembly = mono_domain_assembly_open (domain, "file.dll");
88                 if (!assembly)
89                         error ();
90         </pre>
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:
101         <pre>
102                 retval = mono_jit_exec (domain, assembly, argc - 1, argv + 1);
103         </pre>
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:
113         <pre>
114                 mono_jit_cleanup (domain);
115         </pre>
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 &lt;gc/gc.h&gt; 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
133         runtime uses.
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
137         mechanisms.
139         To register an internal call, use this call in the C code:
141         <pre>
142         mono_add_internal_call ("Hello::Sample", sample);
143         </pre>
145         Now, you need to declare this on the C# side:
147         <pre>
148                 using System;
149                 using System.Runtime.CompilerServices;
150         </pre>
153         <pre>
154         class Hello {
155                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
156                 extern static string Sample ();
157         }
158         </pre>
160         Since this routine returns a string, here is the C definition:
162         <pre>
163                 static MonoString*
164                 Sample () 
165                 {
166                         return mono_string_new (mono_domain_get (), "Hello!");
167                 }
168         </pre>
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:
177         <ul>
178                 * Obtaining the MonoMethod handle to the method.
180                 * The method invocation.
181         </ul>
183 ** Obtaining a MonoMethod
185         To get a MonoMethod there are several ways.
187         You can get a MonoClass (the structure representing a type)
188         using:
190         <pre>
191         MonoClass *
192         mono_class_from_name (MonoImage *image, const char* name_space, const char *name);
193         </pre>
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
199         the duplicates.
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:
205         
206         <pre>
207                 "System.Object:GetHashCode()"
208         </pre>
209         
210         and create a MonoMethodDesc out of it with:
211         
212         <pre>
213         MonoMethodDesc* mono_method_desc_new (const char *name, gboolean include_namespace);
214         </pre>
215         
216         You can then use:
217         
218         <pre>
219         MonoMethod*     mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass);
220         MonoMethod*     mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image);
221         </pre>
222         
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.
226                         
227 ** Invoking a Method
229         There are two functions to call a managed method:
230         
231         <pre>
232         MonoObject*
233         mono_runtime_invoke         (MonoMethod *method, void *obj, void **params,
234                                      MonoObject **exc);
235         and
236         MonoObject*
237         mono_runtime_invoke_array   (MonoMethod *method, void *obj, MonoArray *params,
238                                      MonoObject **exc);
239         </pre>
240         
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.
251         
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,
259         though).
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
267         reference.
268         
269         We have plans for providing an additional method that returns
270         an unmanaged->managed thunk like this:
271         
272         <pre>
273         void* mono_method_get_unmanaged_thunk (MonoMethod *method);
274         </pre>
275         
276         You'll be able to store the returned pointer in a function
277         pointer with the proper signature and call that directly from
278         C:
279         
280         <pre>
281         typedef gint32 (*GetHashCode) (MonoObject *obj);
282         
283         GetHashCode func = mono_method_get_unmanaged_thunk (System_Object_GetHashCode_method);
284         
285         gint32 hashvalue = func (myobject);
286         </pre>
287         
288         It may not be possible to manage exceptions in that case,
289         though. I need to think more about it.
291 ** Threading issues
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
300 * Samples
302         See the sample programs in mono/sample/embed for examples of
303         embedding the Mono runtime in your application.