/* * 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 } }