Fix CounterGroup to use built-in types
[mono-project.git] / samples / embed / test-invoke.c
blob9d53716957513a48a04ade4b7fee8df99e8db224
1 #include <mono/jit/jit.h>
2 #include <mono/metadata/object.h>
3 #include <mono/metadata/environment.h>
4 #include <mono/metadata/assembly.h>
5 #include <mono/metadata/debug-helpers.h>
6 #include <string.h>
7 #include <stdlib.h>
9 #ifndef FALSE
10 #define FALSE 0
11 #endif
14 * Simple mono embedding example.
15 * We show how to create objects and invoke methods and set fields in them.
16 * Compile with:
17 * gcc -Wall -o test-invoke test-invoke.c `pkg-config --cflags --libs mono-2` -lm
18 * mcs invoke.cs
19 * Run with:
20 * ./test-invoke invoke.exe
23 static void
24 access_valuetype_field (MonoObject *obj)
26 MonoClass *klass;
27 MonoClassField *field;
28 int val;
30 klass = mono_object_get_class (obj);
32 /* Now we'll change the value of the 'val' field (see invoke.cs) */
33 field = mono_class_get_field_from_name (klass, "val");
35 /* This time we also add a bit of error checking... */
36 if (!field) {
37 fprintf (stderr, "Can't find field val in MyType\n");
38 exit (1);
40 /* Check that val is an int (if you're paranoid or if you need to
41 * show how this API is used)
43 if (mono_type_get_type (mono_field_get_type (field)) != MONO_TYPE_I4) {
44 fprintf (stderr, "Field val is not a 32 bit integer\n");
45 exit (1);
48 /* Note we pass a pointer to the value */
49 mono_field_get_value (obj, field, &val);
50 printf ("Value of field is: %d\n", val);
51 val = 10;
53 /* Note we pass a pointer to the value here as well */
54 mono_field_set_value (obj, field, &val);
58 static void
59 access_reference_field (MonoObject *obj)
61 MonoClass *klass;
62 MonoDomain *domain;
63 MonoClassField *str;
64 MonoString *strval;
65 char *p;
67 klass = mono_object_get_class (obj);
68 domain = mono_object_get_domain (obj);
70 /* Now we'll see that a reference type is handled slightly differently.
71 * First, get the MonoClassField representing it.
73 str = mono_class_get_field_from_name (klass, "str");
75 /* No change here, we always pass a pointer */
76 mono_field_get_value (obj, str, &strval);
78 /* get the string in UTF-8 encoding to print it */
79 p = mono_string_to_utf8 (strval);
80 printf ("Value of str is: %s\n", p);
81 /* we need to free the result from mono_string_to_utf8 () */
82 mono_free (p);
84 /* string are immutable, so we need to create a different string */
85 strval = mono_string_new (domain, "hello from the embedding API");
87 /* Here is the slight difference: for reference types we pass
88 * the pointer directly, instead of a pointer to the value.
90 mono_field_set_value (obj, str, strval);
94 /* Demostrate how to call methods */
95 static void
96 call_methods (MonoObject *obj)
98 MonoClass *klass;
99 MonoDomain *domain;
100 MonoMethod *method = NULL, *m = NULL, *ctor = NULL, *fail = NULL, *mvalues;
101 MonoProperty *prop;
102 MonoObject *result, *exception;
103 MonoString *str;
104 char *p;
105 void* iter;
106 void* args [2];
107 int val;
109 klass = mono_object_get_class (obj);
110 domain = mono_object_get_domain (obj);
112 /* retrieve all the methods we need */
113 iter = NULL;
114 while ((m = mono_class_get_methods (klass, &iter))) {
115 if (strcmp (mono_method_get_name (m), "method") == 0) {
116 method = m;
117 } else if (strcmp (mono_method_get_name (m), "Fail") == 0) {
118 fail = m;
119 } else if (strcmp (mono_method_get_name (m), "Values") == 0) {
120 mvalues = m;
121 } else if (strcmp (mono_method_get_name (m), ".ctor") == 0) {
122 /* Check it's the ctor that takes two args:
123 * as you see a contrsuctor is a method like any other.
125 MonoMethodSignature * sig = mono_method_signature (m);
126 if (mono_signature_get_param_count (sig) == 2) {
127 ctor = m;
131 /* Now we'll call method () on obj: since it takes no arguments
132 * we can pass NULL as the third argument to mono_runtime_invoke ().
133 * The method will print the updated value.
135 mono_runtime_invoke (method, obj, NULL, NULL);
137 /* mono_object_new () doesn't call any constructor: this means that
138 * we'll have to invoke the constructor if needed ourselves. Note:
139 * invoking a constructor is no different than calling any other method,
140 * so we'll still call mono_runtime_invoke (). This also means that we
141 * can invoke a constructor at any time, like now.
142 * First, setup the array of arguments and their values.
145 /* As usual, we use the address of the data for valuetype arguments */
146 val = 7;
147 args [0] = &val;
148 /* and the pointer for reference types: mono_array_new () returns a MonoArray* */
149 args [1] = mono_array_new (domain, mono_get_byte_class (), 256);
150 mono_runtime_invoke (ctor, obj, args, NULL);
152 /* A property exists only as a metadata entity, so getting or setting the value
153 * is nothing more than calling mono_runtime_invoke () on the getter or setter method.
155 prop = mono_class_get_property_from_name (klass, "Value");
156 method = mono_property_get_get_method (prop);
157 result = mono_runtime_invoke (method, obj, NULL, NULL);
158 /* mono_runtime_invoke () always boxes the return value if it's a valuetype */
159 val = *(int*)mono_object_unbox (result);
161 printf ("Value of val from property is: %d\n", val);
163 /* we also have an helper method: note that reference types are returned as is */
164 prop = mono_class_get_property_from_name (klass, "Message");
165 str = (MonoString*)mono_property_get_value (prop, obj, NULL, NULL);
166 /* get the string in UTF-8 encoding to print it */
167 p = mono_string_to_utf8 (str);
168 printf ("Value of str from property is: %s\n", p);
169 /* we need to free the result from mono_string_to_utf8 () */
170 mono_free (p);
172 /* Now we'll show two things:
173 * 1) static methods are invoked with mono_runtime_invoke () as well,
174 * we just pass NULL as the second argument.
175 * 2) we can catch exceptions thrown by the called method.
176 * Note: fail is declared as static void Fail () in invoke.cs.
177 * We first set result to NULL: if after the invocation it will have
178 * a different value, it will be the exception that was thrown from
179 * the Fail () method. Note that if an exception was thrown, the return
180 * value (if any) is undefined and can't be used in any way (yes, the above
181 * invocations don't have this type of error checking to make things simpler).
183 exception = NULL;
184 mono_runtime_invoke (fail, NULL, NULL, &exception);
185 if (exception) {
186 printf ("An exception was thrown in Fail ()\n");
189 /* Now let's see how to handle methods that take by ref arguments:
190 * Valuetypes continue to be passed as pointers to the data.
191 * Reference arguments passed by ref (ref or out is the same)
192 * are handled the same way: a pointer to the pointer is used
193 * (so that the result can be read back).
194 * Small note: in this case (a System.Int32 valuetype) we can just
195 * use &val where val is a C 32 bit integer. In the general case
196 * unmanaged code doesn't know the size of a valuetype, since the
197 * runtime may decide to lay it out in what it thinks is a better way
198 * (unless ExplicitLayout is set). To avoid issues, the best thing is to
199 * create an object of the valuetype's class and retrieve the pointer
200 * to the data with the mono_object_unbox () function.
202 val = 100;
203 str = mono_string_new (domain, "another string");
204 args [0] = &val;
205 args [1] = &str;
206 mono_runtime_invoke (mvalues, obj, args, NULL);
207 /* get the string in UTF-8 encoding to print it */
208 p = mono_string_to_utf8 (str);
209 printf ("Values of str/val from Values () are: %s/%d\n", p, val);
210 /* we need to free the result from mono_string_to_utf8 () */
211 mono_free (p);
214 static void
215 more_methods (MonoDomain *domain)
217 MonoClass *klass;
218 MonoMethodDesc* mdesc;
219 MonoMethod *method, *vtmethod;
220 MonoString *str;
221 MonoObject *obj;
222 char *p;
223 int val;
225 /* Now let's call an instance method on a valuetype. There are two
226 * different case:
227 * 1) calling a virtual method defined in a base class, like ToString ():
228 * we need to pass the value boxed in an object
229 * 2) calling a normal instance method: in this case
230 * we pass the address to the valuetype as the second argument
231 * instead of an object.
232 * First some initialization.
234 val = 25;
235 klass = mono_get_int32_class ();
236 obj = mono_value_box (domain, klass, &val);
238 /* A different way to search for a method */
239 mdesc = mono_method_desc_new (":ToString()", FALSE);
240 vtmethod = mono_method_desc_search_in_class (mdesc, klass);
242 str = (MonoString*)mono_runtime_invoke (vtmethod, &val, NULL, NULL);
243 /* get the string in UTF-8 encoding to print it */
244 p = mono_string_to_utf8 (str);
245 printf ("25.ToString (): %s\n", p);
246 /* we need to free the result from mono_string_to_utf8 () */
247 mono_free (p);
249 /* Now: see how the result is different if we search for the ToString ()
250 * method in System.Object: mono_runtime_invoke () doesn't do any sort of
251 * virtual method invocation: it calls the exact method that it was given
252 * to execute. If a virtual call is needed, mono_object_get_virtual_method ()
253 * can be called.
255 method = mono_method_desc_search_in_class (mdesc, mono_get_object_class ());
256 str = (MonoString*)mono_runtime_invoke (method, obj, NULL, NULL);
257 /* get the string in UTF-8 encoding to print it */
258 p = mono_string_to_utf8 (str);
259 printf ("25.ToString (), from System.Object: %s\n", p);
260 /* we need to free the result from mono_string_to_utf8 () */
261 mono_free (p);
263 /* Now get the method that overrides ToString () in obj */
264 vtmethod = mono_object_get_virtual_method (obj, method);
265 if (mono_class_is_valuetype (mono_method_get_class (vtmethod))) {
266 printf ("Need to unbox this for call to virtual ToString () for %s\n", mono_class_get_name (klass));
269 mono_method_desc_free (mdesc);
272 static void
273 create_object (MonoDomain *domain, MonoImage *image)
275 MonoClass *klass;
276 MonoObject *obj;
278 klass = mono_class_from_name (image, "Embed", "MyType");
279 if (!klass) {
280 fprintf (stderr, "Can't find MyType in assembly %s\n", mono_image_get_filename (image));
281 exit (1);
284 obj = mono_object_new (domain, klass);
285 /* mono_object_new () only allocates the storage:
286 * it doesn't run any constructor. Tell the runtime to run
287 * the default argumentless constructor.
289 mono_runtime_object_init (obj);
291 access_valuetype_field (obj);
292 access_reference_field (obj);
294 call_methods (obj);
295 more_methods (domain);
298 static void main_function (MonoDomain *domain, const char *file, int argc, char **argv)
300 MonoAssembly *assembly;
302 /* Loading an assembly makes the runtime setup everything
303 * needed to execute it. If we're just interested in the metadata
304 * we'd use mono_image_load (), instead and we'd get a MonoImage*.
306 assembly = mono_domain_assembly_open (domain, file);
307 if (!assembly)
308 exit (2);
310 * mono_jit_exec() will run the Main() method in the assembly.
311 * The return value needs to be looked up from
312 * System.Environment.ExitCode.
314 mono_jit_exec (domain, assembly, argc, argv);
316 create_object (domain, mono_assembly_get_image (assembly));
319 int
320 main (int argc, char* argv[]) {
321 MonoDomain *domain;
322 const char *file;
323 int retval;
325 if (argc < 2){
326 fprintf (stderr, "Please provide an assembly to load\n");
327 return 1;
329 file = argv [1];
331 * mono_jit_init() creates a domain: each assembly is
332 * loaded and run in a MonoDomain.
334 domain = mono_jit_init (file);
336 main_function (domain, file, argc - 1, argv + 1);
338 retval = mono_environment_exitcode_get ();
340 mono_jit_cleanup (domain);
341 return retval;