Loader for loading embedded assemblies z

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
 
namespace Utility
{
public class Loader
{
const string LibsFolder = "Libs";
 
static readonly Dictionary<string, Assembly> Libraries = new Dictionary<string, Assembly>();
static readonly Dictionary<string, Assembly> ReflectionOnlyLibraries = new Dictionary<string, Assembly>();
 
public static void Start()
{
AppDomain.CurrentDomain.AssemblyResolve += FindAssembly;
 
PreloadUnmanagedLibraries();
 
var app = new App();
app.Run();
}
 
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string dllToLoad);
 
private static void PreloadUnmanagedLibraries()
{
// Preload correct library
var bittyness = "x86";
if (IntPtr.Size == 8)
bittyness = "x64";
 
var assemblyName = Assembly.GetExecutingAssembly().GetName();
 
var libraries = Assembly.GetExecutingAssembly().GetManifestResourceNames()
.Where(s => s.StartsWith(String.Format("{1}.{2}.{0}.", bittyness, assemblyName.Name, LibsFolder)))
.ToArray();
 
var dirName = Path.Combine(Path.GetTempPath(), String.Format("{2}.{1}.{0}", assemblyName.Version, bittyness, assemblyName.Name));
if (!Directory.Exists(dirName))
Directory.CreateDirectory(dirName);
 
foreach (var lib in libraries)
{
string dllPath = Path.Combine(dirName, String.Join(".", lib.Split('.').Skip(3)));
 
if (!File.Exists(dllPath))
{
using (Stream stm = Assembly.GetExecutingAssembly().GetManifestResourceStream(lib))
{
// Copy the assembly to the temporary file
try
{
using (Stream outFile = File.Create(dllPath))
{
stm.CopyTo(outFile);
}
}
catch
{
// This may happen if another process has already created and loaded the file.
// Since the directory includes the version number of this assembly we can
// assume that it's the same bits, so we just ignore the excecption here and
// load the DLL.
}
}
}
 
// We must explicitly load the DLL here because the temporary directory
// is not in the PATH.
// Once it is loaded, the DllImport directives that use the DLL will use
// the one that is already loaded into the process.
LoadLibrary(dllPath);
}
}
 
internal static Assembly LoadAssembly(string fullName)
{
Assembly a;
 
var executingAssembly = Assembly.GetExecutingAssembly();
 
var assemblyName = executingAssembly.GetName();
 
var shortName = new AssemblyName(fullName).Name;
if (Libraries.ContainsKey(shortName))
return Libraries[shortName];
 
var resourceName = String.Format("{0}.{2}.{1}.dll", assemblyName.Name, shortName, LibsFolder);
var actualName = executingAssembly.GetManifestResourceNames().FirstOrDefault(n => string.Equals(n, resourceName, StringComparison.OrdinalIgnoreCase));
 
if (string.IsNullOrEmpty(actualName))
{
// The library might be a mixed mode assembly. Try loading from the bitty folders.
var bittyness = "x86";
if (IntPtr.Size == 8)
bittyness = "x64";
 
resourceName = String.Format("{0}.{3}.{1}.{2}.dll", assemblyName.Name, bittyness, shortName, LibsFolder);
actualName = executingAssembly.GetManifestResourceNames().FirstOrDefault(n => string.Equals(n, resourceName, StringComparison.OrdinalIgnoreCase));
 
if (string.IsNullOrEmpty(actualName))
{
Libraries[shortName] = null;
return null;
}
 
// Ok, mixed mode assemblies cannot be loaded through Assembly.Load.
// See http://stackoverflow.com/questions/2945080/ and http://connect.microsoft.com/VisualStudio/feedback/details/97801/
// But, since it's an unmanaged library we've already dumped it to disk to preload it into the process.
// So, we'll just load it from there.
var dirName = Path.Combine(Path.GetTempPath(), String.Format("{2}.{1}.{0}", assemblyName.Version, bittyness, assemblyName.Name));
var dllPath = Path.Combine(dirName, String.Join(".", actualName.Split('.').Skip(3)));
 
if (!File.Exists(dllPath))
{
Libraries[shortName] = null;
return null;
}
 
a = Assembly.LoadFile(dllPath);
Libraries[shortName] = a;
return a;
}
 
using (var s = executingAssembly.GetManifestResourceStream(actualName))
{
var data = new BinaryReader(s).ReadBytes((int)s.Length);
 
byte[] debugData = null;
if (executingAssembly.GetManifestResourceNames().Contains(String.Format("{0}.{2}.{1}.pdb", assemblyName.Name, shortName, LibsFolder)))
{
using (var ds = executingAssembly.GetManifestResourceStream(String.Format("{0}.{2}.{1}.pdb", assemblyName.Name, shortName, LibsFolder)))
{
debugData = new BinaryReader(ds).ReadBytes((int)ds.Length);
}
}
 
if (debugData != null)
{
a = Assembly.Load(data, debugData);
Libraries[shortName] = a;
return a;
}
a = Assembly.Load(data);
Libraries[shortName] = a;
return a;
}
}
 
internal static Assembly ReflectionOnlyLoadAssembly(string fullName)
{
var executingAssembly = Assembly.GetExecutingAssembly();
 
var assemblyName = Assembly.GetExecutingAssembly().GetName();
 
string shortName = new AssemblyName(fullName).Name;
if (ReflectionOnlyLibraries.ContainsKey(shortName))
return ReflectionOnlyLibraries[shortName];
 
var resourceName = String.Format("{0}.{2}.{1}.dll", assemblyName.Name, shortName, LibsFolder);
 
if (!executingAssembly.GetManifestResourceNames().Contains(resourceName))
{
ReflectionOnlyLibraries[shortName] = null;
return null;
}
 
using (var s = executingAssembly.GetManifestResourceStream(resourceName))
{
var data = new BinaryReader(s).ReadBytes((int)s.Length);
 
var a = Assembly.ReflectionOnlyLoad(data);
ReflectionOnlyLibraries[shortName] = a;
 
return a;
}
}
 
internal static Assembly FindAssembly(object sender, ResolveEventArgs args)
{
return LoadAssembly(args.Name);
}
 
internal static Assembly FindReflectionOnlyAssembly(object sender, ResolveEventArgs args)
{
return ReflectionOnlyLoadAssembly(args.Name);
}
}
}
原文地址:https://www.cnblogs.com/zeroone/p/3737380.html