Mercurial > pidgin
comparison plugins/mono/loader/mono.c @ 11660:a3302d271199
[gaim-migrate @ 13945]
Thanks to the hard work of Eoin 'ecoffey' Coffey, here is the mono plugin loader.
It needs a lot of api wrapping a bit more autotools loving, but with the basic API that is wrapped, it works quite well.
committer: Tailor Script <tailor@pidgin.im>
author | Gary Kramlich <grim@reaperworld.com> |
---|---|
date | Fri, 14 Oct 2005 05:00:17 +0000 |
parents | |
children | f05542391cd2 |
comparison
equal
deleted
inserted
replaced
11659:d9a7befbc3f1 | 11660:a3302d271199 |
---|---|
1 /* | |
2 * Mono Plugin Loader | |
3 * | |
4 * -- Thanks to the perl plugin loader for all the great tips ;-) | |
5 * | |
6 * Eoin Coffey | |
7 */ | |
8 | |
9 #ifdef HAVE_CONFIG_H | |
10 #include <config.h> | |
11 #endif | |
12 | |
13 #include "internal.h" | |
14 #include "debug.h" | |
15 #include "plugin.h" | |
16 #include "version.h" | |
17 #include "mono-helper.h" | |
18 | |
19 #define MONO_PLUGIN_ID "core-mono" | |
20 | |
21 /* This is where our code executes */ | |
22 static MonoDomain *domain; | |
23 | |
24 /* probes the given plugin to determine if its a plugin */ | |
25 static gboolean probe_mono_plugin(GaimPlugin *plugin) | |
26 { | |
27 MonoAssembly *assm; | |
28 MonoMethod *m = NULL; | |
29 MonoMethod *info_method = NULL; | |
30 MonoObject *plugin_info; | |
31 gboolean found_load = FALSE, found_unload = FALSE, found_destroy = FALSE, found_info = FALSE; | |
32 gpointer iter = NULL; | |
33 | |
34 GaimPluginInfo *info; | |
35 GaimMonoPlugin *mplug; | |
36 | |
37 char *file = plugin->path; | |
38 | |
39 assm = mono_domain_assembly_open(domain, file); | |
40 | |
41 if (!assm) { | |
42 return FALSE; | |
43 } | |
44 | |
45 gaim_debug(GAIM_DEBUG_INFO, "mono", "Probing plugin\n"); | |
46 | |
47 if (mono_loader_is_api_dll(mono_assembly_get_image(assm))) { | |
48 gaim_debug(GAIM_DEBUG_INFO, "mono", "Found our GaimAPI.dll\n"); | |
49 return FALSE; | |
50 } | |
51 | |
52 info = g_new0(GaimPluginInfo, 1); | |
53 mplug = g_new0(GaimMonoPlugin, 1); | |
54 | |
55 mplug->assm = assm; | |
56 | |
57 mplug->klass = mono_loader_find_plugin_class(mono_assembly_get_image(mplug->assm)); | |
58 if (!mplug->klass) { | |
59 gaim_debug(GAIM_DEBUG_ERROR, "mono", "no plugin class in \'%s\'\n", file); | |
60 return FALSE; | |
61 } | |
62 | |
63 mplug->obj = mono_object_new(domain, mplug->klass); | |
64 if (!mplug->obj) { | |
65 gaim_debug(GAIM_DEBUG_ERROR, "mono", "obj not valid\n"); | |
66 return FALSE; | |
67 } | |
68 | |
69 mono_runtime_object_init(mplug->obj); | |
70 | |
71 while ((m = mono_class_get_methods(mplug->klass, &iter))) { | |
72 if (strcmp(mono_method_get_name(m), "Load") == 0) { | |
73 mplug->load = m; | |
74 found_load = TRUE; | |
75 } else if (strcmp(mono_method_get_name(m), "Unload") == 0) { | |
76 mplug->unload = m; | |
77 found_unload = TRUE; | |
78 } else if (strcmp(mono_method_get_name(m), "Destroy") == 0) { | |
79 mplug->destroy = m; | |
80 found_destroy = TRUE; | |
81 } else if (strcmp(mono_method_get_name(m), "Info") == 0) { | |
82 info_method = m; | |
83 found_info = TRUE; | |
84 } | |
85 } | |
86 | |
87 if (!(found_load && found_unload && found_destroy && found_info)) { | |
88 gaim_debug(GAIM_DEBUG_ERROR, "mono", "did not find the required methods\n"); | |
89 return FALSE; | |
90 } | |
91 | |
92 plugin_info = mono_runtime_invoke(info_method, mplug->obj, NULL, NULL); | |
93 | |
94 /* now that the methods are filled out we can populate | |
95 the info struct with all the needed info */ | |
96 | |
97 info->name = mono_loader_get_prop_string(plugin_info, "Name"); | |
98 info->version = mono_loader_get_prop_string(plugin_info, "Version"); | |
99 info->summary = mono_loader_get_prop_string(plugin_info, "Summary"); | |
100 info->description = mono_loader_get_prop_string(plugin_info, "Description"); | |
101 info->author = mono_loader_get_prop_string(plugin_info, "Author"); | |
102 info->homepage = mono_loader_get_prop_string(plugin_info, "Homepage"); | |
103 | |
104 info->magic = GAIM_PLUGIN_MAGIC; | |
105 info->major_version = GAIM_MAJOR_VERSION; | |
106 info->minor_version = GAIM_MINOR_VERSION; | |
107 info->type = GAIM_PLUGIN_STANDARD; | |
108 | |
109 /* this plugin depends on us; duh */ | |
110 info->dependencies = g_list_append(info->dependencies, MONO_PLUGIN_ID); | |
111 mplug->plugin = plugin; | |
112 | |
113 plugin->info = info; | |
114 info->extra_info = mplug; | |
115 | |
116 mono_loader_add_plugin(mplug); | |
117 | |
118 return gaim_plugin_register(plugin); | |
119 } | |
120 | |
121 /* Loads a Mono Plugin by calling 'load' in the class */ | |
122 static gboolean load_mono_plugin(GaimPlugin *plugin) | |
123 { | |
124 GaimMonoPlugin *mplug; | |
125 | |
126 gaim_debug(GAIM_DEBUG_INFO, "mono", "Loading plugin\n"); | |
127 | |
128 mplug = (GaimMonoPlugin*)plugin->info->extra_info; | |
129 | |
130 mono_runtime_invoke(mplug->load, mplug->obj, NULL, NULL); | |
131 | |
132 return TRUE; | |
133 } | |
134 | |
135 /* Unloads a Mono Plugin by calling 'unload' in the class */ | |
136 static gboolean unload_mono_plugin(GaimPlugin *plugin) | |
137 { | |
138 GaimMonoPlugin *mplug; | |
139 | |
140 gaim_debug(GAIM_DEBUG_INFO, "mono", "Unloading plugin\n"); | |
141 | |
142 mplug = (GaimMonoPlugin*)plugin->info->extra_info; | |
143 | |
144 gaim_signals_disconnect_by_handle((gpointer)mplug->klass); | |
145 | |
146 mono_runtime_invoke(mplug->unload, mplug->obj, NULL, NULL); | |
147 | |
148 return TRUE; | |
149 } | |
150 | |
151 /* Destroys a Mono Plugin by calling 'destroy' in the class, | |
152 and cleaning up all the malloced memory */ | |
153 static gboolean destroy_mono_plugin(GaimPlugin *plugin) | |
154 { | |
155 GaimMonoPlugin *mplug; | |
156 | |
157 gaim_debug(GAIM_DEBUG_INFO, "mono", "Destroying plugin\n"); | |
158 | |
159 mplug = (GaimMonoPlugin*)plugin->info->extra_info; | |
160 | |
161 mono_runtime_invoke(mplug->destroy, mplug->obj, NULL, NULL); | |
162 | |
163 if (plugin->info) { | |
164 if (plugin->info->name) g_free(plugin->info->name); | |
165 if (plugin->info->version) g_free(plugin->info->version); | |
166 if (plugin->info->summary) g_free(plugin->info->summary); | |
167 if (plugin->info->description) g_free(plugin->info->description); | |
168 if (plugin->info->author) g_free(plugin->info->author); | |
169 if (plugin->info->homepage) g_free(plugin->info->homepage); | |
170 } | |
171 | |
172 if (mplug) { | |
173 if (mplug->assm) { | |
174 mono_assembly_close(mplug->assm); | |
175 } | |
176 | |
177 g_free(mplug); | |
178 mplug = NULL; | |
179 } | |
180 | |
181 return TRUE; | |
182 } | |
183 | |
184 gboolean plugin_destroy(GaimPlugin *plugin) | |
185 { | |
186 mono_jit_cleanup(domain); | |
187 | |
188 return TRUE; | |
189 } | |
190 | |
191 static GaimPluginLoaderInfo loader_info = | |
192 { | |
193 NULL, | |
194 probe_mono_plugin, | |
195 load_mono_plugin, | |
196 unload_mono_plugin, | |
197 destroy_mono_plugin | |
198 }; | |
199 | |
200 static GaimPluginInfo info = | |
201 { | |
202 GAIM_PLUGIN_MAGIC, | |
203 GAIM_MAJOR_VERSION, | |
204 GAIM_MINOR_VERSION, | |
205 GAIM_PLUGIN_LOADER, | |
206 NULL, | |
207 0, | |
208 NULL, | |
209 GAIM_PRIORITY_DEFAULT, | |
210 MONO_PLUGIN_ID, | |
211 N_("Mono Plugin Loader"), | |
212 VERSION, | |
213 N_("Loads .NET plugins with Mono."), | |
214 N_("Loads .NET plugins with Mono."), | |
215 "Eoin Coffey <ecoffey@simla.colostate.edu>", | |
216 GAIM_WEBSITE, | |
217 NULL, | |
218 NULL, | |
219 plugin_destroy, | |
220 NULL, | |
221 &loader_info, | |
222 NULL, | |
223 NULL | |
224 }; | |
225 | |
226 /* Creates the domain to execute in, and setups our CS Gaim API (note: | |
227 in the future the 'mono_add_internal_call' will be spread through out | |
228 the source to whatever module is exposing the API; this function will | |
229 simply call helper functions to do so) */ | |
230 static void init_plugin(GaimPlugin *plugin) | |
231 { | |
232 domain = mono_jit_init("gaim"); | |
233 | |
234 mono_loader_set_domain(domain); | |
235 | |
236 mono_loader_init_internal_calls(); | |
237 | |
238 loader_info.exts = g_list_append(loader_info.exts, "dll"); | |
239 } | |
240 | |
241 GAIM_INIT_PLUGIN(mono, init_plugin, info) |