/*
* Util.AssemblySearchWorker.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.IO;
using System.Reflection;
namespace Util
{
///
/// A storage class for assembly information
///
[Serializable]
public sealed class AssemblyType
{
#region Fields
// The file holding this assembly
private readonly string assembly;
// The full name of the Minigameinfo type
private readonly string typeName;
// The full name of the assembly
private readonly string fullName;
#endregion
#region Properties
///
/// The file holding this assembly.
///
public string Assembly { get { return assembly; } }
///
/// The full name of the Minigameinfo Type.
///
public string TypeName { get { return typeName; } }
///
/// The full name of the assembly.
///
public string FullName { get { return fullName; } }
#endregion
#region Creation
///
/// Construct an Assembly type for holding the information for a minigame.
///
/// The file holding this assembly
/// The full name of the Minigameinfo type
/// The full name of the assembly
public AssemblyType(string asm, string type, string name)
{
assembly = asm;
typeName = type;
fullName = name;
}
#endregion
}
///
/// Worker class to loading assemblies for reflection in a separate appdomain.
///
[Serializable]
public sealed class AssemblySearchWorker
{
#region Fields
// The collection of found assemblies.
private readonly ICollection types = new List();
#endregion
#region Properties
///
/// The collection of found assemblies.
///
public ICollection Types { get { return types; } }
#endregion
#region Getters
///
/// Find all assemblys in a directory, and all within every nested directory.
///
/// The starting directory you want to use.
/// A string array containing all the file names.
private static ICollection GetAllAssemblyNames(string baseDir)
{
// Store results in the file results list.
ICollection fileResults = new List();
// Store a stack of our directories.
Stack directoryStack = new Stack();
directoryStack.Push(Path.GetFullPath(baseDir));
// While there are directories to process
while (directoryStack.Count > 0)
{
string currentDir = directoryStack.Pop();
if (!Directory.Exists(currentDir))
{
continue;
}
// Add all files at this directory.
foreach (string fileName in Directory.GetFiles(currentDir, "*.dll"))
{
fileResults.Add(fileName);
}
foreach (string fileName in Directory.GetFiles(currentDir, "*.exe"))
{
fileResults.Add(fileName);
}
// Add all directories at this directory.
foreach (string directoryName in Directory.GetDirectories(currentDir))
{
directoryStack.Push(directoryName);
}
}
return fileResults;
}
#endregion
#region Resolve
///
/// Search for minigames in the assemblies in searchlocations.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
public void Resolve(Queue searchLocations)
{
// Should be Sets?
ICollection assemblys = new List();
while (searchLocations.Count > 0)
{
foreach (string fileName in GetAllAssemblyNames(searchLocations.Dequeue()))
{
bool add = true;
foreach (string file in assemblys)
{
int val = file.LastIndexOf('\\');
if (val != -1)
{
if (fileName.EndsWith(file.Substring(val), StringComparison.OrdinalIgnoreCase))
{
add = false;
break;
}
}
else
{
if (fileName.EndsWith(file, StringComparison.OrdinalIgnoreCase))
{
add = false;
break;
}
}
}
if (add)
{
assemblys.Add(fileName);
}
}
}
//AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomain_ReflectionOnlyAssemblyResolve);
Type MiniGameInfoType = typeof(MiniGameInfo);
foreach (string file in assemblys)
{
try
{
bool foundone = false;
Assembly asm = Assembly.LoadFrom(file);
foreach (Type t in asm.GetTypes())
{
if (!t.IsSubclassOf(MiniGameInfoType))
{
continue;
}
types.Add(new AssemblyType(file, t.FullName, asm.FullName));
foundone = true;
}
if (!foundone)
{
types.Add(new AssemblyType(file, null, asm.FullName));
}
}
// Some exceptions are to be expected.
catch (BadImageFormatException)
{
#if DEBUG
Console.Write(file);
Console.WriteLine(" could not be loaded as a C# assembly.");
#endif
}
catch (ReflectionTypeLoadException e)
{
Console.WriteLine(e);
#if DEBUG
foreach (Exception x in e.LoaderExceptions)
{
Console.WriteLine(x);
}
#endif
}
}
}
#endregion
}
}