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. C# 将datatable 转换json

    public static string DataTableToJson(DataTable dt) { StringBuilder jsonBuilder = new StringBuilder() ...

  2. 深层解析:构建facebook应用商店推荐引擎

    Under the Hood: Building the App Center recommendation engine   As more apps on Facebook Platform ha ...

  3. C# DataTable

    http://www.cnblogs.com/xun126/archive/2010/12/30/1921557.html http://msdn.microsoft.com/zh-cn/librar ...

  4. 【leetcode】Palindrome Number (easy)

    Determine whether an integer is a palindrome. Do this without extra space. Some hints: Could negativ ...

  5. POJ1002487-3279(map)

    http://poj.org/problem?id=1002 题意:是说很多公司用了容易记住的电话号码,例如有英文字母的或者是用了很多连字符或没有连字符的.每个电话号码都有标准模式,而为了统计有没有重 ...

  6. CodeForces 299A Ksusha and Array

    http://codeforces.com/problemset/problem/299/A 题意 :输入n个数,要求找出一个数能让其他所有的数整除,如果没有的话输出-1.有多个的话输出其中一个. 思 ...

  7. Android EditText边框颜色的selector 使用focus标记当前填写的框

    案例:当选中一个EditText时,将其边框变为蓝色,其他未被选中的EditText则为灰色. 主界面: <?xml version="1.0" encoding=" ...

  8. 选择排序的openMP实现

    // test.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <stdio.h> #include < ...

  9. Netcat for Windows

    April 10, 2009 Netcat is a simple networking utility which reads and writes data across network conn ...

  10. bugumongo--ConnectToMongoDB

    连接MongoDB 在能够对MongDB进行操作之前,需要使用BuguConnection连接到MongoDB数据库.代码如下: BuguConnection conn = BuguConnectio ...