2009-04-19 18:07:22 +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.Generic ;
using System.Globalization ;
using System.IO ;
using System.Reflection ;
#endregion
namespace CodeImp.DoomBuilder.Plugins
{
internal class Plugin : IDisposable
{
#region = = = = = = = = = = = = = = = = = = Constants
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
// The plugin assembly
private Assembly asm ;
// The plug
private Plug plug ;
// Unique name used to refer to this assembly
private string name ;
// Disposing
2014-02-21 14:42:12 +00:00
private bool isdisposed ;
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
public Assembly Assembly { get { return asm ; } }
public Plug Plug { get { return plug ; } }
public string Name { get { return name ; } }
public bool IsDisposed { get { return isdisposed ; } }
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
// Constructor
public Plugin ( string filename )
{
// Initialize
string shortfilename = Path . GetFileName ( filename ) ;
name = Path . GetFileNameWithoutExtension ( filename ) ;
General . WriteLogLine ( "Loading plugin '" + name + "' from '" + shortfilename + "'..." ) ;
try
{
// Load assembly
2013-11-20 13:29:41 +00:00
//asm = Assembly.LoadFile(filename); //mxd
asm = Assembly . LoadFrom ( filename ) ;
2009-04-19 18:07:22 +00:00
}
catch ( Exception )
{
General . ErrorLogger . Add ( ErrorType . Error , "Could not load plugin \"" + shortfilename + "\", the DLL file could not be read. This file is not supposed to be in the Plugins subdirectory." ) ;
throw new InvalidProgramException ( ) ;
}
// 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
2015-05-28 10:04:42 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Plugin \"" + shortfilename + "\" has more than one Plug class. The following class is used to create in instance: " + t . FullName ) ;
2009-04-19 18:07:22 +00:00
}
// Make plug instance
plug = CreateObject < Plug > ( t ) ;
plug . Plugin = this ;
2010-08-12 18:42:52 +00:00
// Verify minimum revision number
int thisrevision = General . ThisAssembly . GetName ( ) . Version . Revision ;
if ( ( thisrevision ! = 0 ) & & ( plug . MinimumRevision > thisrevision ) )
{
// Can't load this plugin because it is meant for a newer version
2015-05-28 10:04:42 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Could not load plugin \"" + shortfilename + "\", the Plugin is made for GZDoom Builder R" + plug . MinimumRevision + " or newer and you are running R" + thisrevision + "." ) ;
2010-08-12 18:42:52 +00:00
throw new InvalidProgramException ( ) ;
}
2009-04-19 18:07:22 +00:00
}
else
{
// How can we plug something in without a plug?
2015-05-28 10:04:42 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Could not load plugin \"" + shortfilename + "\", plugin is missing the Plug class. This file is not supposed to be in the Plugins subdirectory." ) ;
2009-04-19 18:07:22 +00:00
throw new InvalidProgramException ( ) ;
}
// 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
// This creates a stream to read a resource or returns null when not found
public Stream GetResourceStream ( string resourcename )
{
// Find a resource
2015-04-10 21:48:12 +00:00
resourcename = "." + resourcename ; //mxd. Otherwise, we can get Properties.Resources.SuperCoolMode.png while searching for CoolMode.png
2014-11-12 11:22:14 +00:00
string [ ] resnames = asm . GetManifestResourceNames ( ) ;
2009-04-19 18:07:22 +00:00
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 > ( ) ;
2014-11-12 11:22:14 +00:00
2009-04-19 18:07:22 +00:00
// Get all exported types
2014-11-12 11:22:14 +00:00
Type [ ] types = asm . GetExportedTypes ( ) ;
2009-04-19 18:07:22 +00:00
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-05-10 16:02:08 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Failed to create class instance '" + t . Name + "' from plugin '" + name + "' " + e . InnerException . GetType ( ) . Name + " at target: " + e . InnerException . Message ) ;
2009-04-19 18:07:22 +00:00
return default ( T ) ;
}
catch ( Exception e )
{
// Error!
2009-05-10 16:02:08 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Failed to create class instance '" + t . Name + "' from plugin '" + name + "' " + e . GetType ( ) . Name + ": " + e . Message ) ;
2009-04-19 18:07:22 +00:00
return default ( T ) ;
}
}
#endregion
}
}