embedded-api 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. * Embedding the Mono runtime, preliminary version
  2. This document describes how to embed the Mono runtime in your
  3. application, and how to invoke CIL methods from C, and how to
  4. invoke C code from CIL
  5. Slides for Paolo's presentation at .NET ONE on the embedding
  6. API are available here: <a
  7. href="http://primates.ximian.com/~lupus/slides/embed">Hosting the Mono
  8. Runtime</a>. You can also get his <a
  9. href="http://primates.ximian.com/~lupus/slides/embed/Mono-0.01.tar.gz">sample
  10. Mono module for Perl</a>
  11. Authors: Paolo Molaro, Miguel de Icaza.
  12. * Embedding the runtime.
  13. Embedding the runtime consists of various steps:
  14. <ul>
  15. * Compiling and linking the Mono runtime
  16. * Initializing the Mono runtime
  17. * Optionally expose C code to the C#/CIL universe.
  18. </ul>
  19. These are discussed in detail next.
  20. ** Compiling and Linking
  21. To embed the runtime, you have to link your code against the
  22. Mono runtime libraries. To do this, you want to pass the
  23. flags returned by pkg-config to your compiler:
  24. <pre>
  25. pkg-config --cflags --libs mono
  26. </pre>
  27. Like this:
  28. <pre>
  29. gcc sample.c `pkg-config --cflags --libs mono`
  30. </pre>
  31. You can separate the compilation flags from the linking flags, for
  32. instance, you can use the following macros in your makefile:
  33. <pre>
  34. CFLAGS=`pkg-config --cflags mono`
  35. LDFLAGS=`pkg-config --libs mono`
  36. </pre>
  37. ** Initializing the Mono runtime
  38. To initialize the runtime, call mono_jit_init, like this:
  39. <pre>
  40. MonoDomain *domain;
  41. domain = mono_jit_init ("domain-name");
  42. </pre>
  43. That will return a MonoDomain where your code will be
  44. executed. You can create multiple domains. Each domain is
  45. isolated from the other domains and code in one domain will
  46. not interfere with code in other domains. This is useful if
  47. you want to host different applications in your program.
  48. Now, it is necessary to transfer control to Mono, and setup
  49. the threading infrastructure, you do this like this:
  50. <pre>
  51. void *user_data = NULL;
  52. mono_runtime_exec_managed_code (domain, main_thread_handler, user_data);
  53. </pre>
  54. Where your main_thread_handler can load your assembly and execute it:
  55. <pre>
  56. static void main_thread_handler (gpointer user_data)
  57. {
  58. MonoAssembly *assembly;
  59. assembly = mono_domain_assembly_open (domain, "file.dll");
  60. if (!assembly)
  61. error ();
  62. </pre>
  63. In the above example, the contents of `file.dll' will be
  64. loaded into the domain. This only loads the code, but it will
  65. not execute anything yet. You can replace `file.dll' with
  66. another transport file, like `file.exe'
  67. To start executing code, you must invoke a method in the
  68. assembly, or if you have provided a static Main method (an
  69. entry point), you can use the convenience function:
  70. <pre>
  71. retval = mono_jit_exec (domain, assembly, argc - 1, argv + 1);
  72. </pre>
  73. If you want to invoke a different method, look at the
  74. `Invoking Methods in the CIL universe' section later on.
  75. ** Shutting down the runtime
  76. To shutdown the Mono runtime, you have to clean up all the
  77. domains that were created, use this function:
  78. <pre>
  79. mono_jit_cleanup (domain);
  80. </pre>
  81. ** Applications that use threads.
  82. The Boehm GC system needs to catch your calls to the pthreads
  83. layer, so in each file where you use pthread.h you should
  84. include the &lt;gc/gc.h&gt; file.
  85. If you can not do this for any reasons, just remember that you
  86. can not store pointers to Mono Objects on the stack, you can
  87. store them safely in the heap, or in global variables though
  88. * Exposing C code to the CIL universe
  89. The Mono runtime provides two mechanisms to expose C code to
  90. the CIL universe: internal calls and native C code. Internal
  91. calls are tightly integrated with the runtime, and have the
  92. least overhead, as they use the same data types that the
  93. runtime uses.
  94. The other option is to use the Platform Invoke (P/Invoke) to
  95. call C code from the CIL universe, using the standard P/Invoke
  96. mechanisms.
  97. To register an internal call, use this call in the C code:
  98. <pre>
  99. mono_add_internal_call ("Hello::Sample", sample);
  100. </pre>
  101. Now, you need to declare this on the C# side:
  102. <pre>
  103. using System;
  104. using System.Runtime.CompilerServices;
  105. </pre>
  106. <pre>
  107. class Hello {
  108. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  109. extern static string Sample ();
  110. }
  111. </pre>
  112. Since this routine returns a string, here is the C definition:
  113. <pre>
  114. static MonoString*
  115. Sample ()
  116. {
  117. return mono_string_new (mono_domain_get (), "Hello!");
  118. }
  119. </pre>
  120. Notice that we have to return a `MonoString', and we use the
  121. `mono_string_new' API call to obtain this from a string.
  122. * Invoking Methods in the CIL universe
  123. Calling a method in the CIL universe from C requires a number of steps:
  124. <ul>
  125. * Obtaining the MonoMethod handle to the method.
  126. * The method invocation.
  127. </ul>
  128. ** Obtaining a MonoMethod
  129. To get a MonoMethod there are several ways.
  130. You can get a MonoClass (the structure representing a type)
  131. using:
  132. <pre>
  133. MonoClass *
  134. mono_class_from_name (MonoImage *image, const char* name_space, const char *name);
  135. </pre>
  136. and then loop in the returned class method array until you get
  137. the one you're looking for. There are examples of such
  138. searches as static functions in several C files in
  139. metadata/*.c: we need to expose one through the API and remove
  140. the duplicates.
  141. The other, simpler, way is to use the functions in
  142. debug-helpers.h: there are examples of their use in monograph,
  143. mint and the jit as well. You basically use a string
  144. description of the method, like:
  145. <pre>
  146. "System.Object:GetHashCode()"
  147. </pre>
  148. and create a MonoMethodDesc out of it with:
  149. <pre>
  150. MonoMethodDesc* mono_method_desc_new (const char *name, gboolean include_namespace);
  151. </pre>
  152. You can then use:
  153. <pre>
  154. MonoMethod* mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass);
  155. MonoMethod* mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image);
  156. </pre>
  157. to search for the method in a class or in an image. You would
  158. tipically do this just once at the start of the program and
  159. store the result for reuse somewhere.
  160. ** Invoking a Method
  161. There are two functions to call a managed method:
  162. <pre>
  163. MonoObject*
  164. mono_runtime_invoke (MonoMethod *method, void *obj, void **params,
  165. MonoObject **exc);
  166. and
  167. MonoObject*
  168. mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
  169. MonoObject **exc);
  170. </pre>
  171. obj is the 'this' pointer, it should be NULL for static
  172. methods, a MonoObject* for object instances and a pointer to
  173. the value type for value types.
  174. The params array contains the arguments to the method with the
  175. same convention: MonoObject* pointers for object instances and
  176. pointers to the value type otherwise. The _invoke_array
  177. variant takes a C# object[] as the params argument (MonoArray
  178. *params): in this case the value types are boxed inside the
  179. respective reference representation.
  180. From unmanaged code you'll usually use the
  181. mono_runtime_invoke() variant.
  182. Note that this function doesn't handle virtual methods for
  183. you, it will exec the exact method you pass: we still need to
  184. expose a function to lookup the derived class implementation
  185. of a virtual method (there are examples of this in the code,
  186. though).
  187. You can pass NULL as the exc argument if you don't want to
  188. catch exceptions, otherwise, *exc will be set to the exception
  189. thrown, if any. if an exception is thrown, you can't use the
  190. MonoObject* result from the function.
  191. If the method returns a value type, it is boxed in an object
  192. reference.
  193. We have plans for providing an additional method that returns
  194. an unmanaged->managed thunk like this:
  195. <pre>
  196. void* mono_method_get_unmanaged_thunk (MonoMethod *method);
  197. </pre>
  198. You'll be able to store the returned pointer in a function
  199. pointer with the proper signature and call that directly from
  200. C:
  201. <pre>
  202. typedef gint32 (*GetHashCode) (MonoObject *obj);
  203. GetHashCode func = mono_method_get_unmanaged_thunk (System_Object_GetHashCode_method);
  204. gint32 hashvalue = func (myobject);
  205. </pre>
  206. It may not be possible to manage exceptions in that case,
  207. though. I need to think more about it.
  208. ** Threading issues
  209. If your application creates threads on its own, and you want them to
  210. be able to call code into the CIL universe with Mono, you have to
  211. register the thread with Mono before issuing the call.
  212. To do so, call the mono_thread_attach() function before you execute
  213. any managed code from the thread
  214. * Samples
  215. See the sample programs in mono/sample/embed for examples of
  216. embedding the Mono runtime in your application.