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 ;
2015-10-02 23:15:29 +00:00
using System.Windows.Forms ;
2009-04-19 18:07:22 +00:00
#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
2015-10-09 21:57:32 +00:00
private readonly string name ;
2009-04-19 18:07:22 +00:00
// 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 ) ;
2016-03-08 20:41:06 +00:00
General . WriteLogLine ( "Loading plugin \"" + name + "\" from \"" + shortfilename + "\"..." ) ;
2009-04-19 18:07:22 +00:00
try
{
// Load assembly
2013-11-20 13:29:41 +00:00
asm = Assembly . LoadFrom ( filename ) ;
2009-04-19 18:07:22 +00:00
}
2018-07-16 14:06:49 +00:00
catch ( Exception e )
2009-04-19 18:07:22 +00:00
{
2018-07-16 14:06:49 +00:00
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." + Environment . NewLine + Environment . NewLine + "Exception details: " + Environment . NewLine + e . ToString ( ) ) ;
2009-04-19 18:07:22 +00:00
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
2016-01-20 17:54:56 +00:00
// Verify revision numbers
2010-08-12 18:42:52 +00:00
int thisrevision = General . ThisAssembly . GetName ( ) . Version . Revision ;
2016-01-20 17:54:56 +00:00
//mxd. Revision numbers should match?
if ( plug . StrictRevisionMatching & & plug . MinimumRevision ! = thisrevision )
{
string message = shortfilename + " plugin's assembly version (" + plug . MinimumRevision + ") doesn't match main module version (" + thisrevision + ")." ;
if ( General . ShowWarningMessage ( message + Environment . NewLine +
2016-05-04 14:02:13 +00:00
"It's strongly recommended to update the editor." + Environment . NewLine +
2016-01-20 17:54:56 +00:00
"Program stability is not guaranteed." + Environment . NewLine + Environment . NewLine +
"Continue anyway?" , MessageBoxButtons . YesNo , MessageBoxDefaultButton . Button2 , false ) = = DialogResult . No )
{
General . WriteLogLine ( "Quiting on " + shortfilename + " module version mismatch" ) ;
General . Exit ( General . Map ! = null ) ;
return ;
}
else
{
General . ErrorLogger . Add ( ErrorType . Warning , message ) ;
throw new InvalidProgramException ( ) ;
}
}
// Verify minimum revision number
2010-08-12 18:42:52 +00:00
if ( ( thisrevision ! = 0 ) & & ( plug . MinimumRevision > thisrevision ) )
{
// Can't load this plugin because it is meant for a newer version
2019-12-24 07:12:45 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Could not load plugin \"" + shortfilename + "\", the Plugin is made for Ultimate Doom 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
2015-10-09 21:57:32 +00:00
plug . Dispose ( ) ; //mxd
plug = null ; //mxd
2009-04-19 18:07:22 +00:00
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?
2016-02-01 22:04:00 +00:00
if ( rn . EndsWith ( resourcename , StringComparison . OrdinalIgnoreCase ) )
2009-04-19 18:07:22 +00:00
{
// 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 ) ;
2015-10-02 23:15:29 +00:00
return ( types . Length > 0 ? types [ 0 ] : null ) ;
2009-04-19 18:07:22 +00:00
}
// 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!
2016-03-08 20:41:06 +00:00
string error = "Failed to create class instance \"" + t . Name + "\" from plugin \"" + name + "\"." ;
2015-10-02 23:15:29 +00:00
General . ShowErrorMessage ( error + Environment . NewLine + Environment . NewLine + "See the error log for more details" , MessageBoxButtons . OK , false ) ;
General . WriteLogLine ( error + " " + e . InnerException . GetType ( ) . Name + " at target: "
+ e . InnerException . Message + Environment . NewLine + "Stacktrace: " + e . InnerException . StackTrace . Trim ( ) ) ;
2009-04-19 18:07:22 +00:00
return default ( T ) ;
}
catch ( Exception e )
{
// Error!
2016-03-08 20:41:06 +00:00
string error = "Failed to create class instance \"" + t . Name + "\" from plugin \"" + name + "\"." ;
2015-10-02 23:15:29 +00:00
General . ShowErrorMessage ( error + Environment . NewLine + Environment . NewLine + "See the error log for more details" , MessageBoxButtons . OK , false ) ;
General . WriteLogLine ( error + " " + e . GetType ( ) . Name + ": " + e . Message + Environment . NewLine
+ "Stacktrace: " + e . StackTrace . Trim ( ) ) ;
2009-04-19 18:07:22 +00:00
return default ( T ) ;
}
}
#endregion
}
}