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);
}
}
}

Loader for loading embedded assemblies z的更多相关文章

  1. sencha警告:[WARN][Anonymous] [Ext.Loader] Synchronously loading 'Ext.field.Text'

    chrome开发者工具下提示: [WARN][Anonymous] [Ext.Loader] Synchronously loading 'Ext.field.Text'; consider addi ...

  2. Best Practices for Assembly Loading

    原文链接 This article discusses ways to avoid problems of type identity that can lead to InvalidCastExce ...

  3. ExtJS笔记 Ext.Loader

    Ext.Loader is the heart of the new dynamic dependency loading capability in Ext JS 4+. It is most co ...

  4. 63.1拓展之纯 CSS 创作一个摇摇晃晃的 loader

    效果地址:https://scrimba.com/c/cqKv4VCR HTML code: <div class="loader"> <span>Load ...

  5. 63.(原65)纯 CSS 创作一个摇摇晃晃的 loader

    原文地址:https://segmentfault.com/a/1190000015424389 修改后地址:https://scrimba.com/c/cqKv4VCR HTML code: < ...

  6. [Angular] Show a Loading Indicator for Lazy Routes in Angular

    We can easily code split and lazy load a route in Angular. However when the user then clicks that la ...

  7. 前端每日实战:65# 视频演示如何用纯 CSS 创作一个摇摇晃晃的 loader

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览.https://codepen.io/comehope/pen/oyJvpe 可交互视频 此视频是可以 ...

  8. mono环境变量

    mono环境变量 2013-05-11 01:14:33|  分类: mono|举报|字号 订阅     下载LOFTER我的照片书  |     Name mono - Mono's ECMA-CL ...

  9. 转载:.NET Memory Leak: XmlSerializing your way to a Memory Leak

    原文地址:http://blogs.msdn.com/b/tess/archive/2006/02/15/532804.aspx I hate to give away the resolution ...

随机推荐

  1. 监控SQL Server的job执行情况

    在服务器没有设置发邮件并且不允许发邮件的情况下, 可以通过下列语句来检查SQL Server 的job的执行情况 select top 150 a.run_date,a.run_time, b.nam ...

  2. js验证码倒计时

    var wait=59; function time(){ if(wait >= 0){ $("#buttons").val("" + wait + &q ...

  3. JAVA CAS单点登录(SSO) 教程

    一.教程前言 教程目的:从头到尾细细道来单点登录服务器及客户端应用的每个步骤 单点登录(SSO):请看百科解释猛击这里打开 本教程使用的SSO服务器是Yelu大学研发的CAS(Central Auth ...

  4. spoj 416

    又臭又长的烂代码 ...... #include <iostream> #include <cstdio> #include <cstring> #include ...

  5. 进阶:使用 EntityManager

    JPA中要对数据库进行操作前,必须先取得EntityManager实例,这有点类似JDBC在对数据库操作之前,必须先取得Connection实例,EntityManager是JPA操作的基础,它不是设 ...

  6. 批量扫描互联网无线路由设备telnet,并获取WIFI密码

    批量扫描互联网无线路由设备telnet,并获取WIFI密码 http://lcx.cc/?i=4513

  7. Maven for Myeclipse的一个常见错误 Project configuration is not up-to-date with pom.xml

    使用Myeclipse开发Maven项目时,经常会发现一个错误提示: Description Resource Path Location Type Project configuration is ...

  8. MySQL在windows和linux下的表名大小写问题

    MySQL在windows下是不区分大小写的,将script文件导入MySQL后表名也会自动转化为小写,结果再想要将数据库导出放到linux服务 器中使用时就出错了.因为在linux下表名区分大小写而 ...

  9. [itint5]区间相交

    http://www.itint5.com/oj/#14 要记录原来的索引,所以用了额外的空间,新生成一个结构.如果要省空间,可以用指针来排序,最后拿指针减去索引0的位置就是index,见:http: ...

  10. Android:调试之LogCat

    通过 Logcat 查看: 常用的Log有5个:Log.v().Log.d().Log.i() .Log.w(). Log.e(). Log.i( "类":"函数名&qu ...