/// <summary> /// Loads all the available plugins from the Dll files located in the specified directory /// </summary> /// <param name="pluginDirectoryPath">The path to the directory where the files which contains plugins are</param> /// <param name="pluginExtension">The extension of the plugin files</param> public void LoadPlugins(string pluginDirectoryPath, string pluginExtension) { string[] files; DllInfo dllInfo; lock (lockObject) { if (!pluginExtension.StartsWith("*.")) { pluginExtension = "*." + pluginExtension; } files = Directory.GetFiles(pluginDirectoryPath, pluginExtension); for (int i = 0; i < files.Length; ++i) { try { Assembly assembly = Assembly.LoadFrom(files[i]); dllInfo = DllInfo.GetDllInfo(files[i]); //if (IntPtr.Size != dllInfo.PointerSize) //{ // message += "File: " + files[i] + ", Ptr: " + dllInfo.PointerSize + "\r\n"; // continue; //} this.rwPluginsLock.AcquireWriterLock(-1); if (dllInfo.IsManagedAssembly) { LoadPluginsFromManagedDll(dllInfo); } else { LoadPluginsFromUnmanagedDll(dllInfo); } this.rwPluginsLock.ReleaseWriterLock(); } //catch (BadImageFormatException) //{ // plugin = LoadUnmanagedPlugin(files[i]); // if(plugin != null) // plugins.Add(plugin); //} catch { } } } }
/// <summary> /// Loads plugins from a managed Dll file /// </summary> /// <param name="dll">A DllInfo object which contains information about the file which contains the plugins to load</param> protected virtual void LoadPluginsFromManagedDll(DllInfo dll) { Assembly assembly; Type[] types; Plugin instance; assembly = Assembly.LoadFile(dll.FilePath); if (assembly.ManifestModule.Name == "Robotics.dll") { return; } types = assembly.GetTypes(); foreach (Type type in types) { if ((type.GetInterface(pluginTypeName) == null) || type.IsAbstract) { continue; } try { instance = (Plugin)assembly.CreateInstance(type.FullName); if (String.IsNullOrEmpty(instance.Name) || plugins.ContainsKey(instance.Name)) { continue; } this.plugins.Add(instance.Name, instance); this.pluginsInitialized = false; } catch { continue; } } }
/// <summary> /// GEts information about a Dll /// </summary> /// <param name="fileName">Path of the dll file</param> /// <returns>A DllInfo object which contains information about the Dll</returns> public static DllInfo GetDllInfo(string fileName) { // Code from // http://stackoverflow.com/questions/367761/how-to-determine-whether-a-dll-is-a-managed-assembly-or-native-prevent-loading // Enhanced with code from // http://stackoverflow.com/questions/8593264/determining-if-a-dll-is-a-valid-clr-dll-by-reading-the-pe-directly-64bit-issue uint peHeader; uint peHeaderSignature; ushort dataDictionaryStart; int dataDirectoriesOffset; Stream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); BinaryReader reader = new BinaryReader(fs); DllInfo dllInfo = new DllInfo(); dllInfo.filePath = (new FileInfo(fileName)).FullName; //PE Header starts at 0x3C (60). Its a 4 byte header. fs.Position = 0x3C; peHeader = reader.ReadUInt32(); //Moving to PE Header start location... fs.Position = peHeader; peHeaderSignature = reader.ReadUInt32(); // Number identifying type of target machine. // Section 3.3.1 of the PE format specification. dllInfo.machine = reader.ReadUInt16(); // Number of sections; indicates size of the Section Table, // which immediately follows the headers. dllInfo.sections = reader.ReadUInt16(); // Time and date the file was created. dllInfo.timestamp = reader.ReadUInt32(); // File offset of the COFF symbol table or 0 if none is present. dllInfo.pSymbolTable = reader.ReadUInt32(); // Number of entries in the symbol table. // This data can be used in locating the string table, which immediately follows the symbol table dllInfo.noOfSymbol = reader.ReadUInt32(); // Size of the optional header, which is required for executable files but not for object files dllInfo.optionalHeaderSize = reader.ReadUInt16(); // dllInfo.characteristics = reader.ReadUInt16(); dataDirectoriesOffset = GetDataDirectoriesOffset(fs, reader); // Now we are at the end of the PE Header and from here, // the PE Optional Headers starts... // To go directly to the datadictionary, we'll increase the stream’s // current position to with 96 (0x60). // 96 because, 28 for Standard fields 68 for NT-specific fields // From here DataDictionary starts...and its of total 128 bytes. // // DataDictionay has 16 directories in total, doing simple maths 128/16 = 8. // So each directory is of 8 bytes. In this 8 bytes, 4 bytes is of RVA and 4 bytes of Size. // By the way, the 15th directory consist of CLR header! if its 0, its not a CLR file :) dataDictionaryStart = Convert.ToUInt16(Convert.ToUInt16(fs.Position) + dataDirectoriesOffset); fs.Position = dataDictionaryStart; for (int i = 0; i < 15; i++) { dllInfo.directories[i] = new DataDictionay(reader.ReadUInt32(), reader.ReadUInt32()); } fs.Close(); return(dllInfo); }
/// <summary> /// When overriden in a derived class, it allows the PLuginManager to load plugins from an unmanaged Dll file. /// By default no unmanaged plugins are loaded. /// </summary> /// <param name="dll">A DllInfo object which contains information about the file which contains the plugins to load</param> protected virtual void LoadPluginsFromUnmanagedDll(DllInfo dll) { }