2 #include <mono/jit/jit.h>
5 #include <mono/metadata/object.h>
6 #include <mono/metadata/environment.h>
7 #include <mono/metadata/assembly.h>
8 #include <mono/metadata/debug-helpers.h>
9 #include <mono/metadata/mono-config.h>
18 * Simple mono embedding example.
19 * We show how to create objects and invoke methods and set fields in them.
21 * gcc -Wall -o test-invoke test-invoke.c `pkg-config --cflags --libs mono-2` -lm
22 * mcs -out:test-embed-invoke-cs.exe invoke.cs
28 access_valuetype_field (MonoObject
*obj
)
31 MonoClassField
*field
;
34 klass
= mono_object_get_class (obj
);
36 /* Now we'll change the value of the 'val' field (see invoke.cs) */
37 field
= mono_class_get_field_from_name (klass
, "val");
39 /* This time we also add a bit of error checking... */
41 fprintf (stderr
, "Can't find field val in MyType\n");
44 /* Check that val is an int (if you're paranoid or if you need to
45 * show how this API is used)
47 if (mono_type_get_type (mono_field_get_type (field
)) != MONO_TYPE_I4
) {
48 fprintf (stderr
, "Field val is not a 32 bit integer\n");
52 /* Note we pass a pointer to the value */
53 mono_field_get_value (obj
, field
, &val
);
54 printf ("Value of field is: %d\n", val
);
57 /* Note we pass a pointer to the value here as well */
58 mono_field_set_value (obj
, field
, &val
);
63 access_reference_field (MonoObject
*obj
)
71 klass
= mono_object_get_class (obj
);
72 domain
= mono_object_get_domain (obj
);
74 /* Now we'll see that a reference type is handled slightly differently.
75 * First, get the MonoClassField representing it.
77 str
= mono_class_get_field_from_name (klass
, "str");
79 /* No change here, we always pass a pointer */
80 mono_field_get_value (obj
, str
, &strval
);
82 /* get the string in UTF-8 encoding to print it */
83 p
= mono_string_to_utf8 (strval
);
84 printf ("Value of str is: %s\n", p
);
85 /* we need to free the result from mono_string_to_utf8 () */
88 /* string are immutable, so we need to create a different string */
89 strval
= mono_string_new (domain
, "hello from the embedding API");
91 /* Here is the slight difference: for reference types we pass
92 * the pointer directly, instead of a pointer to the value.
94 mono_field_set_value (obj
, str
, strval
);
98 /* Demostrate how to call methods */
100 call_methods (MonoObject
*obj
)
104 MonoMethod
*method
= NULL
, *m
= NULL
, *ctor
= NULL
, *fail
= NULL
, *mvalues
;
106 MonoObject
*result
, *exception
;
113 klass
= mono_object_get_class (obj
);
114 domain
= mono_object_get_domain (obj
);
116 /* retrieve all the methods we need */
118 while ((m
= mono_class_get_methods (klass
, &iter
))) {
119 if (strcmp (mono_method_get_name (m
), "method") == 0) {
121 } else if (strcmp (mono_method_get_name (m
), "Fail") == 0) {
123 } else if (strcmp (mono_method_get_name (m
), "Values") == 0) {
125 } else if (strcmp (mono_method_get_name (m
), ".ctor") == 0) {
126 /* Check it's the ctor that takes two args:
127 * as you see a contrsuctor is a method like any other.
129 MonoMethodSignature
* sig
= mono_method_signature (m
);
130 if (mono_signature_get_param_count (sig
) == 2) {
135 /* Now we'll call method () on obj: since it takes no arguments
136 * we can pass NULL as the third argument to mono_runtime_invoke ().
137 * The method will print the updated value.
139 mono_runtime_invoke (method
, obj
, NULL
, NULL
);
141 /* mono_object_new () doesn't call any constructor: this means that
142 * we'll have to invoke the constructor if needed ourselves. Note:
143 * invoking a constructor is no different than calling any other method,
144 * so we'll still call mono_runtime_invoke (). This also means that we
145 * can invoke a constructor at any time, like now.
146 * First, setup the array of arguments and their values.
149 /* As usual, we use the address of the data for valuetype arguments */
152 /* and the pointer for reference types: mono_array_new () returns a MonoArray* */
153 args
[1] = mono_array_new (domain
, mono_get_byte_class (), 256);
154 mono_runtime_invoke (ctor
, obj
, args
, NULL
);
156 /* A property exists only as a metadata entity, so getting or setting the value
157 * is nothing more than calling mono_runtime_invoke () on the getter or setter method.
159 prop
= mono_class_get_property_from_name (klass
, "Value");
160 method
= mono_property_get_get_method (prop
);
161 result
= mono_runtime_invoke (method
, obj
, NULL
, NULL
);
162 /* mono_runtime_invoke () always boxes the return value if it's a valuetype */
163 val
= *(int*)mono_object_unbox (result
);
165 printf ("Value of val from property is: %d\n", val
);
167 /* we also have an helper method: note that reference types are returned as is */
168 prop
= mono_class_get_property_from_name (klass
, "Message");
169 str
= (MonoString
*)mono_property_get_value (prop
, obj
, NULL
, NULL
);
170 /* get the string in UTF-8 encoding to print it */
171 p
= mono_string_to_utf8 (str
);
172 printf ("Value of str from property is: %s\n", p
);
173 /* we need to free the result from mono_string_to_utf8 () */
176 /* Now we'll show two things:
177 * 1) static methods are invoked with mono_runtime_invoke () as well,
178 * we just pass NULL as the second argument.
179 * 2) we can catch exceptions thrown by the called method.
180 * Note: fail is declared as static void Fail () in invoke.cs.
181 * We first set result to NULL: if after the invocation it will have
182 * a different value, it will be the exception that was thrown from
183 * the Fail () method. Note that if an exception was thrown, the return
184 * value (if any) is undefined and can't be used in any way (yes, the above
185 * invocations don't have this type of error checking to make things simpler).
188 mono_runtime_invoke (fail
, NULL
, NULL
, &exception
);
190 printf ("An exception was thrown in Fail ()\n");
193 /* Now let's see how to handle methods that take by ref arguments:
194 * Valuetypes continue to be passed as pointers to the data.
195 * Reference arguments passed by ref (ref or out is the same)
196 * are handled the same way: a pointer to the pointer is used
197 * (so that the result can be read back).
198 * Small note: in this case (a System.Int32 valuetype) we can just
199 * use &val where val is a C 32 bit integer. In the general case
200 * unmanaged code doesn't know the size of a valuetype, since the
201 * runtime may decide to lay it out in what it thinks is a better way
202 * (unless ExplicitLayout is set). To avoid issues, the best thing is to
203 * create an object of the valuetype's class and retrieve the pointer
204 * to the data with the mono_object_unbox () function.
207 str
= mono_string_new (domain
, "another string");
210 mono_runtime_invoke (mvalues
, obj
, args
, NULL
);
211 /* get the string in UTF-8 encoding to print it */
212 p
= mono_string_to_utf8 (str
);
213 printf ("Values of str/val from Values () are: %s/%d\n", p
, val
);
214 /* we need to free the result from mono_string_to_utf8 () */
219 more_methods (MonoDomain
*domain
)
222 MonoMethodDesc
* mdesc
;
223 MonoMethod
*method
, *vtmethod
;
229 /* Now let's call an instance method on a valuetype. There are two
231 * 1) calling a virtual method defined in a base class, like ToString ():
232 * we need to pass the value boxed in an object
233 * 2) calling a normal instance method: in this case
234 * we pass the address to the valuetype as the second argument
235 * instead of an object.
236 * First some initialization.
239 klass
= mono_get_int32_class ();
240 obj
= mono_value_box (domain
, klass
, &val
);
242 /* A different way to search for a method */
243 mdesc
= mono_method_desc_new (":ToString()", FALSE
);
244 vtmethod
= mono_method_desc_search_in_class (mdesc
, klass
);
246 str
= (MonoString
*)mono_runtime_invoke (vtmethod
, &val
, NULL
, NULL
);
247 /* get the string in UTF-8 encoding to print it */
248 p
= mono_string_to_utf8 (str
);
249 printf ("25.ToString (): %s\n", p
);
250 /* we need to free the result from mono_string_to_utf8 () */
253 /* Now: see how the result is different if we search for the ToString ()
254 * method in System.Object: mono_runtime_invoke () doesn't do any sort of
255 * virtual method invocation: it calls the exact method that it was given
256 * to execute. If a virtual call is needed, mono_object_get_virtual_method ()
259 method
= mono_method_desc_search_in_class (mdesc
, mono_get_object_class ());
260 str
= (MonoString
*)mono_runtime_invoke (method
, obj
, NULL
, NULL
);
261 /* get the string in UTF-8 encoding to print it */
262 p
= mono_string_to_utf8 (str
);
263 printf ("25.ToString (), from System.Object: %s\n", p
);
264 /* we need to free the result from mono_string_to_utf8 () */
267 /* Now get the method that overrides ToString () in obj */
268 vtmethod
= mono_object_get_virtual_method (obj
, method
);
269 if (mono_class_is_valuetype (mono_method_get_class (vtmethod
))) {
270 printf ("Need to unbox this for call to virtual ToString () for %s\n", mono_class_get_name (klass
));
273 mono_method_desc_free (mdesc
);
277 create_object (MonoDomain
*domain
, MonoImage
*image
)
282 klass
= mono_class_from_name (image
, "Embed", "MyType");
284 fprintf (stderr
, "Can't find MyType in assembly %s\n", mono_image_get_filename (image
));
288 obj
= mono_object_new (domain
, klass
);
289 /* mono_object_new () only allocates the storage:
290 * it doesn't run any constructor. Tell the runtime to run
291 * the default argumentless constructor.
293 mono_runtime_object_init (obj
);
295 access_valuetype_field (obj
);
296 access_reference_field (obj
);
299 more_methods (domain
);
302 static void main_function (MonoDomain
*domain
, const char *file
, int argc
, char **argv
)
304 MonoAssembly
*assembly
;
306 /* Loading an assembly makes the runtime setup everything
307 * needed to execute it. If we're just interested in the metadata
308 * we'd use mono_image_load (), instead and we'd get a MonoImage*.
310 assembly
= mono_domain_assembly_open (domain
, file
);
314 * mono_jit_exec() will run the Main() method in the assembly.
315 * The return value needs to be looked up from
316 * System.Environment.ExitCode.
318 mono_jit_exec (domain
, assembly
, argc
, argv
);
320 create_object (domain
, mono_assembly_get_image (assembly
));
328 test_mono_embed_invoke_main (void);
331 test_mono_embed_invoke_main (void)
342 (char*)"test-embed-invoke.exe",
343 (char*)"test-embed-invoke-cs.exe",
351 * Load the default Mono configuration file, this is needed
352 * if you are planning on using the dllmaps defined on the
353 * system configuration
355 mono_config_parse (NULL
);
357 * mono_jit_init() creates a domain: each assembly is
358 * loaded and run in a MonoDomain.
360 domain
= mono_jit_init (file
);
362 main_function (domain
, file
, argc
- 1, argv
+ 1);
364 retval
= mono_environment_exitcode_get ();
366 mono_jit_cleanup (domain
);