2 // Radegast Metaverse Client
3 // Copyright (c) 2009, Radegast Development Team
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // * Neither the name of the application "Radegast", nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 using System.Collections.Generic;
36 using System.Threading;
37 using System.Reflection;
38 using System.CodeDom.Compiler;
39 using System.Windows.Forms;
41 using Microsoft.CSharp;
46 /// Handles loading Radegast plugins
48 public class PluginManager : IDisposable
50 List<IRadegastPlugin> PluginsLoaded = new List<IRadegastPlugin>();
51 RadegastInstance instance;
53 public PluginManager(RadegastInstance instance)
55 this.instance = instance;
62 List<IRadegastPlugin> unload = new List<IRadegastPlugin>(PluginsLoaded);
63 unload.ForEach(plug =>
65 PluginsLoaded.Remove(plug);
68 plug.StopPlugin(instance);
72 Logger.Log("ERROR in Shutdown Plugin: " + plug + " because " + ex, Helpers.LogLevel.Debug, ex);
78 public static PluginAttribute GetAttributes(IRadegastPlugin plug)
80 PluginAttribute a = null;
82 foreach(Attribute attr in Attribute.GetCustomAttributes(plug.GetType()))
84 if (attr is PluginAttribute)
85 a = (PluginAttribute)attr;
90 a = new PluginAttribute();
91 a.Name = plug.GetType().FullName;
97 public void StartPlugins()
101 foreach (IRadegastPlugin plug in PluginsLoaded)
105 plug.StartPlugin(instance);
109 Logger.Log("ERROR in Starting Radegast Plugin: " + plug + " because " + ex, Helpers.LogLevel.Debug);
115 public void ScanAndLoadPlugins()
117 string dirName = Application.StartupPath;
119 if (!Directory.Exists(dirName)) return;
121 foreach (string loadfilename in Directory.GetFiles(dirName))
123 if (loadfilename.ToLower().EndsWith(".dll") || loadfilename.ToLower().EndsWith(".exe"))
127 Assembly assembly = Assembly.LoadFile(loadfilename);
128 LoadAssembly(loadfilename, assembly);
130 catch (BadImageFormatException)
134 catch (ReflectionTypeLoadException)
136 // Out of date or dlls missing sub dependencies
138 catch (TypeLoadException)
140 // Another version of: Out of date or dlls missing sub dependencies
144 Logger.Log("ERROR in Radegast Plugin: " + loadfilename + " because " + ex, Helpers.LogLevel.Debug);
150 public void LoadCSharpScriptFile(string filename)
152 try { LoadCSharpScript(File.ReadAllText(filename)); }
155 Logger.Log("Failed loading C# script " + filename + ": ", Helpers.LogLevel.Warning, ex);
159 public void LoadCSharpScript(string code)
161 ThreadPool.QueueUserWorkItem(sender =>
165 // *** Generate dynamic compiler
166 Dictionary<string, string> loCompilerOptions = new Dictionary<string, string>();
167 loCompilerOptions.Add("CompilerVersion", "v3.5");
168 CSharpCodeProvider loCompiler = new CSharpCodeProvider(loCompilerOptions);
169 CompilerParameters loParameters = new CompilerParameters();
171 // *** Start by adding any referenced assemblies
172 loParameters.ReferencedAssemblies.Add("OpenMetaverse.StructuredData.dll");
173 loParameters.ReferencedAssemblies.Add("OpenMetaverseTypes.dll");
174 loParameters.ReferencedAssemblies.Add("OpenMetaverse.dll");
175 loParameters.ReferencedAssemblies.Add("Radegast.exe");
176 loParameters.ReferencedAssemblies.Add("System.dll");
177 loParameters.ReferencedAssemblies.Add("System.Core.dll");
178 loParameters.ReferencedAssemblies.Add("System.Drawing.dll");
179 loParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
181 // *** Load the resulting assembly into memory
182 loParameters.GenerateInMemory = true;
183 loParameters.GenerateExecutable = false;
185 // *** Now compile the whole thing
186 CompilerResults loCompiled =
187 loCompiler.CompileAssemblyFromSource(loParameters, code);
189 // *** Check for compilation erros
190 if (loCompiled.Errors.HasErrors)
192 string lcErrorMsg = "";
193 lcErrorMsg = "Compilation failed: " + loCompiled.Errors.Count.ToString() + " errors:";
195 for (int x = 0; x < loCompiled.Errors.Count; x++)
196 lcErrorMsg += "\r\nLine: " +
197 loCompiled.Errors[x].Line.ToString() + " - " +
198 loCompiled.Errors[x].ErrorText;
200 instance.TabConsole.DisplayNotificationInChat(lcErrorMsg, ChatBufferTextStyle.Alert);
204 instance.TabConsole.DisplayNotificationInChat("Compilation successful.");
205 Assembly loAssembly = loCompiled.CompiledAssembly;
206 instance.MainForm.Invoke(new MethodInvoker(() => LoadAssembly("Dynamically compiled", loAssembly, true)));
210 Logger.Log("Failed loading C# script: ", Helpers.LogLevel.Warning, ex);
215 public void LoadAssembly(string loadfilename, Assembly assembly)
217 LoadAssembly(loadfilename, assembly, false);
220 public void LoadAssembly(string loadfilename, Assembly assembly, bool startPlugins)
222 foreach (Type type in assembly.GetTypes())
224 if (typeof(IRadegastPlugin).IsAssignableFrom(type))
226 if (type.IsInterface) continue;
229 IRadegastPlugin plug = null;
230 ConstructorInfo constructorInfo = type.GetConstructor(new Type[] { typeof(RadegastInstance) });
231 if (constructorInfo != null)
232 plug = (IRadegastPlugin)constructorInfo.Invoke(new[] { instance });
235 constructorInfo = type.GetConstructor(new Type[] { });
236 if (constructorInfo != null)
237 plug = (IRadegastPlugin)constructorInfo.Invoke(new object[0]);
240 Logger.Log("ERROR Constructing Radegast Plugin: " + loadfilename + " because " + type + " has no usable constructor.", Helpers.LogLevel.Debug);
244 lock (PluginsLoaded) PluginsLoaded.Add(plug);
245 if (startPlugins && plug != null)
247 try { plug.StartPlugin(instance); }
248 catch (Exception ex) { Logger.Log(string.Format("Failed starting plugin {0}:", type), Helpers.LogLevel.Error, ex); }
253 Logger.Log("ERROR Constructing Radegast Plugin: " + loadfilename + " because " + ex,
254 Helpers.LogLevel.Debug);
261 instance.CommandsManager.LoadType(type);
265 Logger.Log("ERROR in Radegast Plugin: " + loadfilename + " Command: " + type +
266 " because " + ex.Message + " " + ex.StackTrace, Helpers.LogLevel.Debug);