2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * (c) 2001-2003 Ximian, Inc. (http://www.ximian.com)
16 #include <mono/os/gc_wrapper.h>
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/assembly.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/socket-io.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/gc-internal.h>
27 HANDLE mono_delegate_semaphore = NULL;
28 CRITICAL_SECTION mono_delegate_section;
30 static gunichar2 process_guid [36];
31 static gboolean process_guid_set = FALSE;
34 mono_domain_assembly_preload (MonoAssemblyName *aname,
35 gchar **assemblies_path,
39 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
42 look_for_method_by_name (MonoClass *klass, const gchar *name);
46 * @domain: domain returned by mono_init ()
48 * Initialize the core AppDomain: this function will run also some
49 * IL initialization code, so it needs the execution engine to be fully
52 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
53 * we know the entry_assembly.
57 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
58 MonoThreadAttachCB attach_cb)
60 MonoAppDomainSetup *setup;
64 mono_install_assembly_preload_hook (mono_domain_assembly_preload, NULL);
65 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
66 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
68 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
69 setup = (MonoAppDomainSetup *) mono_object_new (domain, class);
71 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
72 ad = (MonoAppDomain *) mono_object_new (domain, class);
75 domain->setup = setup;
77 mono_delegate_semaphore = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
78 g_assert (mono_delegate_semaphore != INVALID_HANDLE_VALUE);
79 InitializeCriticalSection (&mono_delegate_section);
81 mono_context_init (domain);
82 mono_context_set (domain->default_context);
84 mono_thread_init (start_cb, attach_cb);
86 /* GC init has to happen after thread init */
95 mono_context_init (MonoDomain *domain)
98 MonoAppContext *context;
100 class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
101 context = (MonoAppContext *) mono_object_new (domain, class);
102 context->domain_id = domain->domain_id;
103 context->context_id = 0;
104 domain->default_context = context;
107 /* This must not be called while there are still running threads executing
111 mono_runtime_cleanup (MonoDomain *domain)
113 /* Not really needed, but do it anyway */
116 mono_network_cleanup ();
120 mono_domain_has_type_resolve (MonoDomain *domain)
122 static MonoClassField *field = NULL;
126 MonoClass *klass = mono_defaults.appdomain_class;
129 for (i = 0; i < klass->field.count; ++i)
130 if (strcmp (klass->fields [i].name, "TypeResolve") == 0)
131 field = &klass->fields [i];
135 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
139 MonoReflectionAssembly *
140 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
144 static MonoMethod *method = NULL;
146 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
148 if (method == NULL) {
149 klass = domain->domain->mbr.obj.vtable->klass;
152 method = look_for_method_by_name (klass, "DoTypeResolve");
153 if (method == NULL) {
154 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
160 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
163 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
167 ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup)
169 MonoDomain* domain = mono_domain_get ();
170 MonoAssembly *assembly;
172 gchar *config_suffix;
176 if (!domain->entry_assembly)
177 assembly = mono_root_domain->entry_assembly;
179 assembly = domain->entry_assembly;
183 setup->application_base = mono_string_new (domain, assembly->basedir);
185 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
186 str = g_build_filename (assembly->basedir, config_suffix, NULL);
187 g_free (config_suffix);
188 setup->configuration_file = mono_string_new (domain, str);
193 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
195 MonoDomain *add = ad->data;
201 g_assert (ad != NULL);
202 g_assert (name != NULL);
204 str = mono_string_to_utf8 (name);
206 mono_domain_lock (add);
208 if (!strcmp (str, "APPBASE"))
209 o = (MonoObject *)add->setup->application_base;
210 else if (!strcmp (str, "APP_CONFIG_FILE"))
211 o = (MonoObject *)add->setup->configuration_file;
212 else if (!strcmp (str, "DYNAMIC_BASE"))
213 o = (MonoObject *)add->setup->dynamic_base;
214 else if (!strcmp (str, "APP_NAME"))
215 o = (MonoObject *)add->setup->application_name;
216 else if (!strcmp (str, "CACHE_BASE"))
217 o = (MonoObject *)add->setup->cache_path;
218 else if (!strcmp (str, "PRIVATE_BINPATH"))
219 o = (MonoObject *)add->setup->private_bin_path;
220 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
221 o = (MonoObject *)add->setup->private_bin_path_probe;
222 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
223 o = (MonoObject *)add->setup->shadow_copy_directories;
224 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
225 o = (MonoObject *)add->setup->shadow_copy_files;
227 o = mono_g_hash_table_lookup (add->env, name);
229 mono_domain_unlock (add);
239 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
241 MonoDomain *add = ad->data;
245 g_assert (ad != NULL);
246 g_assert (name != NULL);
248 mono_domain_lock (add);
250 mono_g_hash_table_insert (add->env, name, data);
252 mono_domain_unlock (add);
256 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
260 g_assert (ad != NULL);
261 g_assert (ad->data != NULL);
263 return ad->data->setup;
267 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
271 g_assert (ad != NULL);
272 g_assert (ad->data != NULL);
274 return mono_string_new (ad->data, ad->data->friendly_name);
278 ves_icall_System_AppDomain_getCurDomain ()
280 MonoDomain *add = mono_domain_get ();
288 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
290 /*MonoDomain *domain = mono_domain_get (); */
297 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
299 /* FIXME: pin all those objects */
300 data = mono_domain_create();
302 ad = (MonoAppDomain *) mono_object_new (data, adclass);
306 data->friendly_name = mono_string_to_utf8 (friendly_name);
308 mono_context_init (data);
310 /* FIXME: what to do next ? */
319 } add_assembly_helper_t;
322 add_assembly (gpointer key, gpointer value, gpointer user_data)
324 add_assembly_helper_t *ah = (add_assembly_helper_t *) user_data;
326 mono_array_set (ah->res, gpointer, ah->idx++, mono_assembly_get_object (ah->domain, value));
330 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad)
332 MonoDomain *domain = ad->data;
333 static MonoClass *System_Reflection_Assembly;
335 add_assembly_helper_t ah;
339 if (!System_Reflection_Assembly)
340 System_Reflection_Assembly = mono_class_from_name (
341 mono_defaults.corlib, "System.Reflection", "Assembly");
343 res = mono_array_new (domain, System_Reflection_Assembly, g_hash_table_size (domain->assemblies));
348 mono_domain_lock (domain);
349 g_hash_table_foreach (domain->assemblies, add_assembly, &ah);
350 mono_domain_unlock (domain);
356 * Used to find methods in AppDomain class.
357 * It only works if there are no multiple signatures for any given method name
360 look_for_method_by_name (MonoClass *klass, const gchar *name)
365 for (i = 0; i < klass->method.count; i++) {
366 method = klass->methods [i];
367 if (!strcmp (method->name, name))
374 static MonoReflectionAssembly *
375 try_assembly_resolve (MonoDomain *domain, MonoString *fname)
381 g_assert (domain != NULL && fname != NULL);
383 klass = domain->domain->mbr.obj.vtable->klass;
386 method = look_for_method_by_name (klass, "DoAssemblyResolve");
387 if (method == NULL) {
388 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
393 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
397 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass)
401 if (g_hash_table_lookup (domain->assemblies, ass->aname.name))
402 return; /* This is ok while no lazy loading of assemblies */
404 mono_domain_lock (domain);
405 g_hash_table_insert (domain->assemblies, (gpointer) ass->aname.name, ass);
406 mono_domain_unlock (domain);
408 for (i = 0; ass->image->references [i] != NULL; i++)
409 add_assemblies_to_domain (domain, ass->image->references [i]);
413 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
415 MonoDomain *domain = mono_domain_get ();
416 MonoReflectionAssembly *ref_assembly;
421 klass = domain->domain->mbr.obj.vtable->klass;
424 method = look_for_method_by_name (klass, "DoAssemblyLoad");
425 if (method == NULL) {
426 g_warning ("Method AppDomain.DoAssemblyLoad not found.\n");
430 add_assemblies_to_domain (domain, assembly);
432 ref_assembly = mono_assembly_get_object (domain, assembly);
433 g_assert (ref_assembly);
435 *params = ref_assembly;
436 mono_runtime_invoke (method, domain->domain, params, NULL);
440 set_domain_search_path (MonoDomain *domain)
442 MonoAppDomainSetup *setup;
447 gchar **pvt_split = NULL;
448 GError *error = NULL;
450 if ((domain->search_path != NULL) && !domain->setup->path_changed)
453 setup = domain->setup;
454 if (setup->application_base)
457 if (setup->private_bin_path) {
458 utf8 = mono_string_to_utf8 (setup->private_bin_path);
459 pvt_split = g_strsplit (utf8, G_SEARCHPATH_SEPARATOR_S, 1000);
461 for (tmp = pvt_split; *tmp; tmp++, npaths++);
466 g_strfreev (pvt_split);
468 * Don't do this because the first time is called, the domain
469 * setup is not finished.
471 * domain->search_path = g_malloc (sizeof (char *));
472 * domain->search_path [0] = NULL;
477 if (domain->search_path)
478 g_strfreev (domain->search_path);
480 domain->search_path = tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
482 if (setup->application_base) {
483 *tmp = mono_string_to_utf8 (setup->application_base);
485 /* FIXME: is this needed? */
486 if (strncmp (*tmp, "file://", 7) == 0) {
491 uri = g_strdup_printf ("file:///%s", uri + 7);
493 *tmp = g_filename_from_uri (uri, NULL, &error);
498 g_warning ("%s\n", error->message);
499 g_error_free (error);
507 *tmp = g_strdup ("");
510 for (i = 1; pvt_split && i < npaths; i++) {
511 if (*tmp [0] == '\0' || g_path_is_absolute (pvt_split [i - 1])) {
512 tmp [i] = g_strdup (pvt_split [i - 1]);
516 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
519 if (setup->private_bin_path_probe != NULL && setup->application_base) {
521 tmp [0] = g_strdup ("");
524 domain->setup->path_changed = FALSE;
526 g_strfreev (pvt_split);
529 static MonoAssembly *
530 real_load (gchar **search_path, gchar *filename)
532 MonoAssembly *result;
536 for (path = search_path; *path; path++) {
538 continue; /* Ignore empty ApplicationBase */
539 fullpath = g_build_filename (*path, filename, NULL);
540 result = mono_assembly_open (fullpath, NULL);
550 * Try loading the assembly from ApplicationBase and PrivateBinPath
551 * and then from assemblies_path if any.
553 static MonoAssembly *
554 mono_domain_assembly_preload (MonoAssemblyName *aname,
555 gchar **assemblies_path,
558 MonoDomain *domain = mono_domain_get ();
559 MonoAssembly *result;
562 set_domain_search_path (domain);
564 dll = g_strconcat (aname->name, ".dll", NULL);
565 exe = g_strdup (dll);
566 strcpy (exe + strlen (exe) - 4, ".exe");
568 if (domain->search_path && domain->search_path [0] != NULL) {
569 /* TODO: should also search in name/name.dll and name/name.exe from appbase */
570 result = real_load (domain->search_path, dll);
577 result = real_load (domain->search_path, exe);
585 if (assemblies_path && assemblies_path [0] != NULL) {
586 result = real_load (assemblies_path, dll);
593 result = real_load (assemblies_path, exe);
606 MonoReflectionAssembly *
607 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname)
609 MonoDomain *domain = mono_domain_get ();
610 char *name, *filename;
611 MonoImageOpenStatus status = MONO_IMAGE_OK;
617 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
618 mono_raise_exception (exc);
621 name = filename = mono_string_to_utf8 (fname);
623 ass = mono_assembly_open (filename, &status);
628 MonoException *exc = mono_get_exception_file_not_found (fname);
629 mono_raise_exception (exc);
632 return mono_assembly_get_object (domain, ass);
636 free_assembly_name (MonoAssemblyName *aname)
641 g_free ((void *) aname->name);
642 g_free ((void *) aname->culture);
643 g_free ((void *) aname->hash_value);
647 get_info_from_assembly_name (MonoReflectionAssemblyName *assRef, MonoAssemblyName *aname)
653 gint major, minor, build, revision;
655 memset (aname, 0, sizeof (MonoAssemblyName));
657 name = mono_string_to_utf8 (assRef->name);
658 parts = tmp = g_strsplit (name, ",", 4);
665 value = g_strstrip (*tmp);
666 /* g_print ("Assembly name: %s\n", value); */
667 aname->name = g_strdup (value);
674 value = g_strstrip (*tmp);
675 if (strncmp (value, "Version=", 8)) {
680 if (sscanf (value + 8, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4) {
685 /* g_print ("Version: %u.%u.%u.%u\n", major, minor, build, revision); */
686 aname->major = major;
687 aname->minor = minor;
688 aname->build = build;
689 aname->revision = revision;
697 value = g_strstrip (*tmp);
698 if (strncmp (value, "Culture=", 8)) {
703 /* g_print ("Culture: %s\n", aname->culture); */
704 aname->culture = g_strstrip (g_strdup (value + 8));
712 value = g_strstrip (*tmp);
713 if (strncmp (value, "PublicKeyToken=", 15)) {
719 if (*value && strcmp (value, "null")) {
724 value = g_strstrip (g_strdup (value));
725 len = strlen (value);
732 aname->hash_len = len / 2;
733 aname->hash_value = g_malloc0 (aname->hash_len);
734 result = (gchar *) aname->hash_value;
736 for (i = 0; i < len; i++) {
738 l = g_ascii_xdigit_value (value [i]);
744 result [i / 2] = (h * 16) + l;
746 h = g_ascii_xdigit_value (value [i]);
757 g_print ("PublicKeyToken: ");
758 for (i = 0; i < aname->hash_len; i++) {
759 g_print ("%x", 0x00FF & aname->hash_value [i]);
769 MonoReflectionAssembly *
770 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoReflectionAssemblyName *assRef, MonoObject *evidence)
772 MonoDomain *domain = ad->data;
773 MonoImageOpenStatus status = MONO_IMAGE_OK;
775 MonoAssemblyName aname;
776 MonoReflectionAssembly *refass = NULL;
780 memset (&aname, 0, sizeof (aname));
782 /* FIXME : examine evidence? */
784 g_assert (assRef != NULL);
785 g_assert (assRef->name != NULL);
787 if (!get_info_from_assembly_name (assRef, &aname)) {
790 free_assembly_name (&aname);
791 /* This is a parse error... */
792 exc = mono_get_exception_file_not_found (assRef->name);
793 mono_raise_exception (exc);
796 ass = mono_assembly_load (&aname, NULL, &status);
797 free_assembly_name (&aname);
799 if (!ass && (refass = try_assembly_resolve (domain, assRef->name)) == NULL){
800 /* FIXME: it doesn't make much sense since we really don't have a filename ... */
801 MonoException *exc = mono_get_exception_file_not_found (assRef->name);
802 mono_raise_exception (exc);
808 return mono_assembly_get_object (domain, ass);
812 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
814 MonoDomain * domain = mono_domain_get_by_id (domain_id);
818 if (NULL == domain) {
819 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
820 mono_raise_exception (exc);
824 mono_domain_unload (domain, FALSE);
828 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file,
829 MonoObject *evidence, MonoArray *args)
831 MonoAssembly *assembly;
839 filename = mono_string_to_utf8 (file);
840 assembly = mono_assembly_open (filename, NULL);
844 mono_raise_exception ((MonoException *)mono_exception_from_name (
845 mono_defaults.corlib, "System.IO", "FileNotFoundException"));
848 image = assembly->image;
850 method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
853 g_error ("No entry point method found in %s", image->name);
856 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
858 res = mono_runtime_exec_main (method, (MonoArray *)args, NULL);
864 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
868 return ad->data->domain_id;
872 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
874 MonoDomain *old_domain = mono_domain_get();
878 mono_domain_set(ad->data);
880 return old_domain->domain;
884 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
886 MonoDomain *current_domain = mono_domain_get ();
887 MonoDomain *domain = mono_domain_get_by_id (domainid);
891 mono_domain_set (domain);
893 return current_domain->domain;
897 ves_icall_System_AppDomain_InternalGetContext ()
901 return mono_context_get ();
905 ves_icall_System_AppDomain_InternalGetDefaultContext ()
909 return mono_domain_get ()->default_context;
913 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
915 MonoAppContext *old_context = mono_context_get ();
919 mono_context_set (mc);
925 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
927 mono_domain_lock (mono_root_domain);
928 if (process_guid_set) {
929 mono_domain_unlock (mono_root_domain);
930 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
932 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
933 process_guid_set = TRUE;
934 mono_domain_unlock (mono_root_domain);