/*
* Util.AssemblyLocator.cs
* Authors: Adam Nabinger
* Copyright (c) 2007-2008 Cornell University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Util
{
///
/// Collects and stores a list of referenced assemblies, for retrieving minigames dynamically.
///
public static class AssemblyLocator
{
#region Fields
// Should be Sets?
// List of assemblies
private static readonly ICollection assemblies = new List();
// List of minigame infos
private static readonly List minigameinfos = new List();
// List of locations to search through
private static readonly Queue searchLocations = new Queue();
// Whether or not the list of assemblies has been resolved.
private static bool resolved;
#endregion
#region Properties
///
/// A collection of strings, each item of which is the name of a known assembly.
///
public static ICollection AllKnownAssemblies
{
get
{
if (!resolved)
{
Resolve();
}
ICollection temp = new List();
foreach (AssemblyInfo info in assemblies)
{
temp.Add(info.path);
}
return temp;
}
}
///
/// A collection of MiniGameInfos, each item of which representing a found minigame.
///
public static List AllKnownMiniGames
{
get
{
if (!resolved)
{
Resolve();
}
return minigameinfos;
}
}
#endregion
#region Creation
///
/// Constructor
///
static AssemblyLocator()
{
searchLocations.Enqueue(ProjectInfo.HomeDirectory);
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
#endregion
#region Location
///
/// Add a directory path to search for minigames in.
/// Subdirectories under the main executable are searched by default.
///
/// The current root directory
public static void AddSearchLocation(string rootDirectory)
{
searchLocations.Enqueue(rootDirectory);
resolved = false;
}
///
/// Get the location of an assembly by it's name.
///
/// The name of the desired assembly.
/// The fully qualified path to the directory containing the assembly, or null if it is not known.
public static string GetLocation(string assemblyName)
{
foreach (AssemblyInfo a in assemblies)
{
if (a.fullname == assemblyName)
{
return a.path.Substring(0, a.path.LastIndexOf('\\'));
}
}
return null;
}
#endregion
#region Resolve
///
/// An Event triggered when a dependant assembly cannot be found by the C# libraries.
///
/// Sender of the event
/// All arguments associtated with the resolved event
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
#if DEBUG
Console.WriteLine("Debug: Trying to resolve " + args.Name);
#endif
if (!resolved)
{
Resolve();
}
foreach (AssemblyInfo info in assemblies)
{
if (args.Name != info.fullname)
{
continue;
}
if (info.assembly == null)
{
info.assembly = Assembly.LoadFrom(info.path);
}
return info.assembly;
}
throw new InvalidOperationException("Error trying to load " + args.Name + ". Could not find assembly.");
}
///
/// Search through the given locations for any assemblies.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
private static void Resolve()
{
AppDomain privateAppDomain = AppDomain.CreateDomain("Private Minigame Search AppDomain");
string fullname = Assembly.GetExecutingAssembly().FullName;
if (string.IsNullOrEmpty(fullname))
{
return;
}
AssemblySearchWorker worker = (AssemblySearchWorker)privateAppDomain.CreateInstanceAndUnwrap(fullname, typeof(AssemblySearchWorker).FullName);
worker.Resolve(searchLocations);
foreach (AssemblyType pair in worker.Types)
{
if (!string.IsNullOrEmpty(pair.TypeName))
{
Assembly asm = Assembly.LoadFrom(pair.Assembly);
Type t = asm.GetType(pair.TypeName);
assemblies.Add(new AssemblyInfo(asm, pair.Assembly, pair.FullName));
MiniGameInfo info = (MiniGameInfo)t.GetConstructor(Type.EmptyTypes).Invoke(null);
info.RootDirectory = pair.Assembly.Substring(0, pair.Assembly.LastIndexOf('\\'));
minigameinfos.Add(info);
}
else
{
assemblies.Add(new AssemblyInfo(null, pair.Assembly, pair.FullName));
}
minigameinfos.Sort();
}
AppDomain.Unload(privateAppDomain);
}
#endregion
}
///
/// Defines the info associated with any assembly
///
internal sealed class AssemblyInfo
{
#region Fields
///
/// The assembly
///
internal Assembly assembly;
///
/// The path name
///
internal readonly string path;
///
/// The full name
///
internal readonly string fullname;
#endregion
#region Creation
///
/// Constructor
///
/// The assembly
/// The path name
/// The full name
public AssemblyInfo(Assembly asm, string p, string name)
{
assembly = asm;
path = p;
fullname = name;
}
#endregion
}
}