2008-01-02 21:49:43 +00:00
|
|
|
|
|
|
|
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
|
|
|
* This program is released under GNU General Public License
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Namespaces
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Globalization;
|
|
|
|
using System.Text;
|
|
|
|
using System.IO;
|
|
|
|
using System.Reflection;
|
2008-05-29 11:34:01 +00:00
|
|
|
using CodeImp.DoomBuilder.Actions;
|
2008-11-27 10:33:09 +00:00
|
|
|
using CodeImp.DoomBuilder.Editing;
|
2008-01-02 21:49:43 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
namespace CodeImp.DoomBuilder.Plugins
|
|
|
|
{
|
2008-05-13 22:28:30 +00:00
|
|
|
internal class Plugin : IDisposable
|
2008-01-02 21:49:43 +00:00
|
|
|
{
|
|
|
|
#region ================== Constants
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Variables
|
|
|
|
|
|
|
|
// The plugin assembly
|
|
|
|
private Assembly asm;
|
|
|
|
|
2008-05-13 22:28:30 +00:00
|
|
|
// The plug
|
|
|
|
private Plug plug;
|
|
|
|
|
2008-01-02 21:49:43 +00:00
|
|
|
// Unique name used to refer to this assembly
|
|
|
|
private string name;
|
|
|
|
|
|
|
|
// Disposing
|
|
|
|
private bool isdisposed = false;
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Properties
|
|
|
|
|
|
|
|
public Assembly Assembly { get { return asm; } }
|
2008-05-13 22:28:30 +00:00
|
|
|
public Plug Plug { get { return plug; } }
|
2008-01-02 21:49:43 +00:00
|
|
|
public string Name { get { return name; } }
|
|
|
|
public bool IsDisposed { get { return isdisposed; } }
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
public Plugin(string filename)
|
|
|
|
{
|
|
|
|
// Initialize
|
|
|
|
name = Path.GetFileNameWithoutExtension(filename);
|
|
|
|
General.WriteLogLine("Loading plugin '" + name + "' from '" + Path.GetFileName(filename) + "'...");
|
2008-05-13 22:28:30 +00:00
|
|
|
|
2009-01-10 22:34:36 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
// Load assembly
|
|
|
|
asm = Assembly.LoadFile(filename);
|
|
|
|
}
|
|
|
|
catch(Exception)
|
|
|
|
{
|
2009-03-01 09:15:58 +00:00
|
|
|
General.ErrorLogger.Add(ErrorType.Error, "Could not load plugin '" + name + "', the DLL file could not be read.");
|
2009-01-10 22:34:36 +00:00
|
|
|
throw new InvalidProgramException();
|
|
|
|
}
|
|
|
|
|
2008-05-13 22:28:30 +00:00
|
|
|
// Find the class that inherits from Plugin
|
|
|
|
Type t = FindSingleClass(typeof(Plug));
|
|
|
|
if(t != null)
|
|
|
|
{
|
|
|
|
// Are the multiple plug classes?
|
|
|
|
if(FindClasses(typeof(Plug)).Length > 1)
|
|
|
|
{
|
|
|
|
// Show a warning
|
2009-03-01 09:15:58 +00:00
|
|
|
General.ErrorLogger.Add(ErrorType.Warning, "Plugin '" + name + "' has more than one plug.");
|
2008-05-13 22:28:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make plug instance
|
|
|
|
plug = CreateObject<Plug>(t);
|
|
|
|
plug.Plugin = this;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// How can we plug something in without a plug?
|
2009-03-01 09:15:58 +00:00
|
|
|
General.ErrorLogger.Add(ErrorType.Error, "Could not load plugin '" + name + "', plugin is missing the plug.");
|
2008-05-14 21:48:36 +00:00
|
|
|
throw new InvalidProgramException();
|
2008-05-13 22:28:30 +00:00
|
|
|
}
|
2008-01-02 21:49:43 +00:00
|
|
|
|
|
|
|
// We have no destructor
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disposer
|
|
|
|
public void Dispose()
|
|
|
|
{
|
|
|
|
// Not already disposed?
|
|
|
|
if(!isdisposed)
|
|
|
|
{
|
|
|
|
// Clean up
|
|
|
|
asm = null;
|
|
|
|
|
|
|
|
// Done
|
|
|
|
isdisposed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Methods
|
2008-11-27 10:33:09 +00:00
|
|
|
|
2008-01-02 21:49:43 +00:00
|
|
|
// This creates a stream to read a resource or returns null when not found
|
2008-05-13 22:28:30 +00:00
|
|
|
public Stream GetResourceStream(string resourcename)
|
2008-01-02 21:49:43 +00:00
|
|
|
{
|
|
|
|
string[] resnames;
|
|
|
|
|
|
|
|
// Find a resource
|
|
|
|
resnames = asm.GetManifestResourceNames();
|
|
|
|
foreach(string rn in resnames)
|
|
|
|
{
|
|
|
|
// Found it?
|
|
|
|
if(rn.EndsWith(resourcename, StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
{
|
|
|
|
// Get a stream from the resource
|
|
|
|
return asm.GetManifestResourceStream(rn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nothing found
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This finds all class types that inherits from the given type
|
|
|
|
public Type[] FindClasses(Type t)
|
|
|
|
{
|
|
|
|
List<Type> found = new List<Type>();
|
|
|
|
Type[] types;
|
|
|
|
|
|
|
|
// Get all exported types
|
|
|
|
types = asm.GetExportedTypes();
|
|
|
|
foreach(Type it in types)
|
|
|
|
{
|
|
|
|
// Compare types
|
|
|
|
if(t.IsAssignableFrom(it)) found.Add(it);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return list
|
|
|
|
return found.ToArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
// This finds a single class type that inherits from the given type
|
|
|
|
// Returns null when no valid type was found
|
|
|
|
public Type FindSingleClass(Type t)
|
|
|
|
{
|
|
|
|
Type[] types = FindClasses(t);
|
|
|
|
if(types.Length > 0) return types[0]; else return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This creates an instance of a class
|
|
|
|
public T CreateObject<T>(Type t, params object[] args)
|
|
|
|
{
|
|
|
|
return CreateObjectA<T>(t, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This creates an instance of a class
|
|
|
|
public T CreateObjectA<T>(Type t, object[] args)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Create instance
|
|
|
|
return (T)asm.CreateInstance(t.FullName, false, BindingFlags.Default, null, args, CultureInfo.CurrentCulture, new object[0]);
|
|
|
|
}
|
|
|
|
catch(TargetInvocationException e)
|
|
|
|
{
|
|
|
|
// Error!
|
2009-03-01 09:15:58 +00:00
|
|
|
General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance '" + t.Name + "' from plugin '" + name + "'");
|
2008-01-02 21:49:43 +00:00
|
|
|
General.WriteLogLine(e.InnerException.GetType().Name + ": " + e.InnerException.Message);
|
|
|
|
return default(T);
|
|
|
|
}
|
|
|
|
catch(Exception e)
|
|
|
|
{
|
|
|
|
// Error!
|
2009-03-01 09:15:58 +00:00
|
|
|
General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance '" + t.Name + "' from plugin '" + name + "'");
|
2008-01-02 21:49:43 +00:00
|
|
|
General.WriteLogLine(e.GetType().Name + ": " + e.Message);
|
|
|
|
return default(T);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|