Объединение библиотек DLL в одну.exe с wpf

в настоящее время я работаю над проектом, в котором у нас много зависимостей. Я хотел бы скомпилировать все ссылки dll в .exe так же, как вы сделали бы со встроенными ресурсами. Я пробовал ILMerge но он не может справиться .ресурсы xaml.

Итак, мой вопрос: есть ли способ объединить проект WPF с несколькими зависимостями в один .exe?

9 ответов


реактор .NET имеет функцию объединения сборок и его не очень дорого.


http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application

это работает как шарм для меня :) и совершенно бесплатно.

добавление кода в случае, если блог не исчезает.

1) Добавьте это в ваш :

<Target Name="AfterResolveReferences">
  <ItemGroup>
    <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
      <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
    </EmbeddedResource>
  </ItemGroup>
</Target>

2) Сделайте свой основной Program.cs выглядит так:

[STAThreadAttribute]
public static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
    App.Main();
}

3) Добавить OnResolveAssembly способ:

private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    AssemblyName assemblyName = new AssemblyName(args.Name);

    var path = assemblyName.Name + ".dll";
    if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false) path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);

    using (Stream stream = executingAssembly.GetManifestResourceStream(path))
    {
        if (stream == null) return null;

        var assemblyRawBytes = new byte[stream.Length];
        stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
        return Assembly.Load(assemblyRawBytes);
    }
}

Costura Fody-это инструмент с открытым исходным кодом, предназначенный для обработки слияния сборок wpf.

https://github.com/Fody/Costura#how-it-works


{smartassembly} является одним из таких продуктов. Он может obsfucate или встраивать ваши DLL.

попробуйте это: http://www.smartassembly.com/

вы также можете сделать много улучшений в своем приложении, чтобы он работал быстрее.

и да. Вы можете использовать его для WPF.

обновление 8/06/2015: ILRepack 2.0.0 (который является альтернативой ILMerge с открытым исходным кодом) теперь поддерживает большинство случаев слияния WPF: https://twitter.com/Gluckies/status/607680149157462016


на сайт ILMerge, рассматривайте эти библиотеки как ресурсы, от Джеффри Рихтера здесь :

многие приложения состоят из EXE-файла, который зависит от многих DLL файлы. При развертывании этого приложения, все файлы должны быть развертываемый. Однако, существует метод, который можно использовать для развертывания просто один EXE файл. Во-первых, определите все DLL-файлы, которые EXE-файл зависит от того, что не поставляются в составе Microsoft .ЧИСТЫЙ Сама структура. Затем добавьте эти библиотеки DLL в проект Visual Studio. Для каждого добавляемого DLL-файла отобразите его свойства и измените его "Build Action" to " встроенный ресурс."Это заставляет компилятор C# вставьте DLL-файл (ы) в EXE-файл, и вы можете развернуть его файл EXE. Во время выполнения среда CLR не сможет найти зависимой Сборки DLL, что является проблемой. Чтобы исправить это, когда ваше приложение инициализирует, регистрирует метод обратного вызова с помощью AppDomain Событие ResolveAssembly. Код должен выглядеть примерно так:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {

   String resourceName = "AssemblyLoadingAndReflection." +

      new AssemblyName(args.Name).Name + ".dll";

   using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) {

      Byte[] assemblyData = new Byte[stream.Length];

      stream.Read(assemblyData, 0, assemblyData.Length);

      return Assembly.Load(assemblyData);

   }

}; 

теперь, в первый раз, когда поток вызывает метод, который ссылается на тип в зависимый DLL-файл, событие AssemblyResolve будет вызвано и код обратного вызова, показанный выше, найдет требуемый встроенный ресурс DLL и загрузите его, вызвав перегрузку метода загрузки сборки, который принимает Byte[] в качестве аргумента.


использовать Costura.Фоди!--3--> - он доступен как NuGet Pkg для лучшего и простого способа встраивания ресурсов в вашу сборку.

Install-Package Costura.Fody

после добавления его в проект он автоматически вставит все добавленные ссылки на вашу основную сборку.


попробовать .Нец (http://madebits.com/netz/) - это бесплатно (как в пиве) и делает некоторые хорошие вещи, если вы цель exe.


вот измененная версия цитируемого кода от Matthieu, которая не требует знания пространства имен для извлечения кода. Для WPF поместите это в код события запуска приложения.

AppDomain.CurrentDomain.AssemblyResolve += (s, args) =>
{
    // Note: Requires a using statement for System.Reflection and System.Diagnostics.
    Assembly assembly = Assembly.GetExecutingAssembly();
    List<string> embeddedResources = new List<string>(assembly.GetManifestResourceNames());
    string assemblyName = new AssemblyName(args.Name).Name;
    string fileName = string.Format("{0}.dll", assemblyName);
    string resourceName = embeddedResources.Where(ern => ern.EndsWith(fileName)).FirstOrDefault();
    if (!string.IsNullOrWhiteSpace(resourceName))
    {
        using (var stream = assembly.GetManifestResourceStream(resourceName))
        {
            Byte[] assemblyData = new Byte[stream.Length];
            stream.Read(assemblyData, 0, assemblyData.Length);
            var test = Assembly.Load(assemblyData);
            string namespace_ = test.GetTypes().Where(t => t.Name == assemblyName).Select(t => t.Namespace).FirstOrDefault();
#if DEBUG
            Debug.WriteLine(string.Format("\tNamespace for '{0}' is '{1}'", fileName, namespace_));
#endif
            return Assembly.Load(assemblyData);
        }
    }

    return null;
}; 

чтобы сделать их доступными во время компиляции, я создаю папку с именем ExternalDLLs и копирую DLL там и устанавливаю их в EmbeddedResource, как указано выше. Чтобы использовать их в коде, вам все равно нужно установить ссылку на них, но установить Copy local в False. Чтобы получить код для компиляции чисто без ошибок вам также нужно установить с помощью состояний в коде пространства имен DLL.

вот небольшая утилита, которая вращается через внедренные имена ресурсов и отображает их пространства имен в окне вывода.

private void getEmbeddedResourceNamespaces()
{
    // Note: Requires a using statement for System.Reflection and System.Diagnostics.
    Assembly assembly = Assembly.GetExecutingAssembly();
    List<string> embeddedResourceNames = new List<string>(assembly.GetManifestResourceNames());
    foreach (string resourceName in embeddedResourceNames)
    {
        using (var stream = assembly.GetManifestResourceStream(resourceName))
        {
            Byte[] assemblyData = new Byte[stream.Length];
            stream.Read(assemblyData, 0, assemblyData.Length);
            try
            {
                var test = Assembly.Load(assemblyData);
                foreach (Type type in test.GetTypes())
                {
                    Debug.WriteLine(string.Format("\tNamespace for '{0}' is '{1}'", type.Name, type.Namespace));
                }
            }
            catch 
            {
            }
        }
    }
}

  1. добавьте к этому .файл csprofj:

>

<Target Name="AfterResolveReferences">
  <ItemGroup>
    <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
      <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
    </EmbeddedResource>
  </ItemGroup>
</Target>
  1. щелкните правой кнопкой мыши проект / свойства / приложение / объект starup / выберите Sinhro.Программа

  2. добавить в свою программу.cs файл:

    использование системы.Отображение; используя системы.ИО; использование системы.Глобализация;

    [STAThreadAttribute]
    static void Main()
    {
        AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
        ...
    
    
    private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
    {
        Assembly executingAssembly = Assembly.GetExecutingAssembly();
        AssemblyName assemblyName = new AssemblyName(args.Name);
        string path = assemblyName.Name + ".dll";
        if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false)
        {
            path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);
        }
        using (Stream stream = executingAssembly.GetManifestResourceStream(path))
        {
            if (stream == null)
                return null;
            byte[] assemblyRawBytes = new byte[stream.Length];
            stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
            return Assembly.Load(assemblyRawBytes);
        }
    }   
    

источник: http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application