Встраивание DLL в скомпилированный исполняемый файл

Можно ли встроить уже существующую DLL в скомпилированный исполняемый файл C# (чтобы у вас был только один файл для распространения)? Если возможно, как бы это сделать?

Обычно мне нравится просто оставлять библиотеки DLL снаружи, а программа установки все обрабатывает, но на работе было несколько человек, которые спрашивали меня об этом, а я, честно говоря, не знаю.

Это возможно, но вы получите большой исполняемый файл (Base64 будет использоваться для кодирования вашей dll).

Paweł Dyda 28.10.2010 17:56

@ PawełDyda: Вы можете встроить необработанные двоичные данные в PE-образ (см. RCDATA). Никаких преобразований не требуется (или рекомендуется).

IInspectable 26.02.2017 22:53

Помимо ILMerge, если вы не хотите возиться с переключателями командной строки, я действительно рекомендую ILMerge-Gui. Это действительно хороший проект с открытым исходным кодом!

tyron 19.12.2012 16:45

Я бы порекомендовал вам попробовать утилиту .NETZ, которая также сжимает сборку по выбранной вами схеме: http://madebits.com/netz/help.php#single

Nathan Baulch 10.10.2008 03:28
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
656
4
418 224
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

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

Однако файлы установки создать настолько легко, что я не думаю, что это того стоит.

Обновлено: этот метод будет легко использовать со сборками .NET. С библиотеками DLL, отличными от .NET, было бы намного больше работы (вам нужно было бы выяснить, где распаковать файлы, зарегистрировать их и т. д.).

Вот отличная статья, объясняющая, как это сделать: codeproject.com/Articles/528178/Load-DLL-From-Embedded-Resou‌ rce

bluish 09.09.2015 17:44

Если они действительно управляемые сборки, вы можете использовать ILMerge. Для собственных DLL вам придется немного поработать.

Смотрите также:Как можно объединить dll Windows C++ с exe-файлом приложения C#?

Меня интересует слияние Native DLL, есть ли материалы?

baye 05.03.2009 05:45

См. Также: stackoverflow.com/questions/108971/…

Milan Gardian 10.04.2012 00:56

@BaiyanHuang посмотрите на github.com/boxedapp/bxilmerge, идея состоит в том, чтобы сделать "ILMerge" для нативных Dll.

Artem Razin 17.02.2020 18:47

Разработчики VB NET вроде меня не пугаются этого C++ по ссылке. ILMerge также очень легко работает с VB NET. Смотрите здесь https://github.com/dotnet/ILMerge. Спасибо @ Shog9

Ivan Ferrer Villa 25.05.2020 11:55

Возможно, но не так просто, создать гибридную собственную / управляемую сборку на C#. Если бы вы использовали C++ вместо этого, было бы намного проще, поскольку компилятор Visual C++ может создавать гибридные сборки так же легко, как и все остальное.

Если у вас нет строгих требований к созданию гибридной сборки, я согласен с MusiGenesis, что на самом деле это не стоит того, чтобы делать с C#. Если вам нужно это сделать, возможно, лучше подумайте о переходе на C++ / CLI.

Еще один продукт, который может с этим элегантно справиться - SmartAssembly, по адресу SmartAssembly.com. Этот продукт, помимо слияния всех зависимостей в единую DLL, (необязательно) обфусцирует ваш код, удаляет лишние метаданные, чтобы уменьшить итоговый размер файла, а также может фактически оптимизировать IL для повышения производительности во время выполнения.

Существует также какая-то функция глобальной обработки исключений / отчетов, которую он добавляет в ваше программное обеспечение (при желании), что может быть полезно. Я считаю, что у него также есть API командной строки, поэтому вы можете сделать его частью процесса сборки.

Как правило, для выполнения слияния сборок, как вы описываете, вам понадобится какой-то инструмент для пост-сборки. Существует бесплатный инструмент под названием Eazfuscator (eazfuscator.blogspot.com/), предназначенный для изменения байт-кода, который также обрабатывает слияние сборок. Вы можете добавить это в командную строку после сборки с помощью Visual Studio, чтобы объединить ваши сборки, но ваш опыт будет варьироваться из-за проблем, которые возникнут в любых сценариях слияния нетривиальных сборок.

Вы также можете проверить, имеет ли NANT возможность объединять сборки после сборки, но я недостаточно хорошо знаком с NANT, чтобы сказать, встроена ли эта функция или нет.

Также существует множество подключаемых модулей Visual Studio, которые будут выполнять слияние сборок как часть сборки приложения.

В качестве альтернативы, если вам не нужно, чтобы это выполнялось автоматически, существует ряд инструментов, таких как ILMerge, которые объединят сборки .net в один файл.

Самая большая проблема, с которой я столкнулся при слиянии сборок, - это то, используют ли они какие-либо похожие пространства имен. Или, что еще хуже, ссылаться на разные версии одной и той же dll (мои проблемы обычно были с файлами dll NUnit).

Eazfuscator просто позвонит IlMerge, AFAIK.

Bobby 28.10.2010 18:03

+1 Бобби. Я должен был помнить об этом. Практически все, что делает для вас Eazfucator, - это абстрагирование фактических вызовов ILMerge с помощью более общего файла конфигурации.

wllmsaccnt 29.10.2010 16:30

Да, можно объединять исполняемые файлы .NET с библиотеками. Для выполнения этой работы доступно несколько инструментов:

  • ILMerge - это служебная программа, которую можно использовать для объединения нескольких сборок .NET в одну сборку.
  • Моно mkbundle, упаковывает exe и все сборки с libmono в один двоичный пакет.
  • Ил-Репак является альтернативой ILMerge FLOSS с некоторыми дополнительными функциями.

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

Другая возможность - использовать .NETZ, который не только позволяет сжимать сборку, но также может упаковывать библиотеки DLL прямо в exe. Отличие от вышеупомянутых решений в том, что .NETZ не объединяет их, они остаются отдельными сборками, а упаковываются в один пакет.

.NETZ is a open source tool that compresses and packs the Microsoft .NET Framework executable (EXE, DLL) files in order to make them smaller.

NETZ, кажется, ушел

Rbjz 10.06.2016 13:20

Вау - я думал, что наконец нашел, потом прочитал этот комментарий. Кажется, он полностью ушел. Есть ли вилки?

Mafii 08.10.2016 19:19

Ну, он только что переместился на GitHub, и на него больше нет ссылок на веб-сайте ... так что "полностью исчез" - это преувеличение. Скорее всего, он больше не поддерживается, но он все еще есть. Обновил ссылку.

Bobby 08.10.2016 21:55

Просто щелкните свой проект в Visual Studio правой кнопкой мыши, выберите «Свойства проекта» -> «Ресурсы» -> «Добавить ресурс» -> «Добавить существующий файл…». И включите приведенный ниже код в свой App.xaml.cs или аналогичный.

public App()
{
    AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");

    dllName = dllName.Replace(".", "_");

    if (dllName.EndsWith("_resources")) return null;

    System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());

    byte[] bytes = (byte[])rm.GetObject(dllName);

    return System.Reflection.Assembly.Load(bytes);
}

Вот мой оригинальный пост в блоге: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/

Вы можете настроить такое поведение прямо из коробки. Посмотрите мой ответ stackoverflow.com/a/20306095/568266

Matthias 01.12.2013 01:57

Также важно отметить НЕВЕРОЯТНО полезный комментарий к вашему блогу от AshRowe: если у вас установлена ​​настраиваемая тема, она попытается разрешить сборку PresentationFramework.Theme, которая вылетает и горит! Согласно предложению AshRowe, вы можете просто проверить, содержит ли dllName PresentationFramework следующим образом: if (dllName.ToLower (). Contains ("presentationframework")) return null;

YasharBahman 31.01.2014 10:45

Два комментария по этому поводу. Первый: вы должны проверить, является ли bytes нулевым, и если да, вернуть там ноль. В конце концов, возможно, что dll - это нет в ресурсах. Два: это работает только в том случае, если сам класс не имеет «использования» для чего-либо из этой сборки. Для инструментов командной строки мне пришлось переместить реальный программный код в новый файл и создать небольшую новую основную программу, которая просто делает это, а затем вызывает исходный основной код в старом классе.

Nyerguds 26.05.2014 11:41

В связи с этим, это можно использовать для компиляции решения с двумя проектами в один exe-файл ... все, что вам нужно сделать, это сделать так, чтобы сценарии предварительной сборки проекта встраивания перезаписывали dll, используемую в качестве ресурса, со встроенной dll из встроенный проект, и заставьте сценарии после сборки внедренного проекта удалить библиотеки DLL из выходной папки решения.

Nyerguds 26.05.2014 12:26

Еще одно полезное замечание: если вы используете byte[] bytes = rm.GetObject(dllName) as byte[];, вы не можете получить там ошибки приведения, опять же, если система каким-то образом случайно выбрала существующий ресурс другого типа.

Nyerguds 04.06.2014 11:06

Где я могу найти App.xaml.cs или аналогичный в Winforms? Это файл, который мне нужно создать?

Dan W 29.06.2015 12:40

Итак, ваш ответ предназначен для WPF. У меня получилось работать с Winforms. После добавления ресурса, как вы сказали, просто поместите строку AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(CurrentDomain_AssemblyResolve); перед строкой InitializeComponent(); в конструкторе формы. Затем поместите весь метод System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) куда угодно. Скомпилируйте и запустите. Вот и все. Это делает ваше решение даже проще, чем ответ с наивысшей оценкой, поскольку нет сторонней утилиты для загрузки.

Dan W 29.06.2015 13:33

@DanW: В приложениях с нормальной формой просто есть файл program.cs, который создает фактический объект формы и запускает его. Вы можете просто поместить его туда перед созданием объекта формы. В любом случае, там больше ничего не должно быть. Ваше решение может не работать, поскольку фактический класс, содержащий этот код, не может использовать загруженный таким образом материал сборки, поскольку разрешение сборки выполняется до выполнения конструктора.

Nyerguds 24.08.2015 10:24

Достоинством этого подхода является то, что он не полагается на установку каких-либо внешних библиотек для достижения желаемой функциональности. Обратной стороной этого подхода является то, что он полезен только когда дело доходит до управляемых библиотек DLL - библиотеки взаимодействия (по крайней мере, в рамках моего тестирования) не запускают событие assemblyresolve, и даже если они выполнили Assembly.Load (<bytes of some interop .dll>) не дает желаемого эффекта в будущем. stackoverflow.com/questions/13113131/… Просто мой 2с по этому поводу

XDS 28.08.2015 14:53

На всякий случай, если кто-нибудь столкнется с моей проблемой: если имя .dll содержит дефисы (например, twenty-two.dll), они также будут заменены подчеркиванием (например, twenty_two.dll). Вы можете изменить эту строку кода на это: dllName = dllName.Replace(".", "_").Replace("-", "_");

Micah Vertal 14.07.2016 04:03

Когда я это сделаю, мое решение не будет компилироваться. Выдает ошибку везде, где я использовал класс из dll

Notts90 supports Monica 03.12.2019 13:08

@ Notts90 Вам все равно нужно ссылаться на библиотеку для компиляции решения

Lars Holm Jensen 06.12.2019 16:45

ILMerge может объединять сборки в одну сборку при условии, что сборка имеет только управляемый код. Вы можете использовать приложение командной строки или добавить ссылку на exe и программно слить. Для версии с графическим интерфейсом есть Eazfuscator, а также .Netz, оба из которых бесплатны. Платные приложения включают BoxedApp и SmartAssembly.

Если вам нужно объединить сборки с неуправляемым кодом, я бы предложил SmartAssembly. У меня никогда не было икоты с SmartAssembly, но со всеми остальными. Здесь он может встроить необходимые зависимости в качестве ресурсов в ваш основной исполняемый файл.

Вы можете сделать все это вручную, не беспокоясь о том, управляется ли сборка или в смешанном режиме, путем встраивания dll в свои ресурсы и последующего использования сборки ResolveHandler AppDomain. Это универсальное решение, основанное на худшем случае, то есть сборках с неуправляемым кодом.

static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
    {
        string assemblyName = new AssemblyName(args.Name).Name;
        if (assemblyName.EndsWith(".resources"))
            return null;

        string dllName = assemblyName + ".dll";
        string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);

        using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
        {
            byte[] data = new byte[stream.Length];
            s.Read(data, 0, data.Length);

            //or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);

            File.WriteAllBytes(dllFullPath, data);
        }

        return Assembly.LoadFrom(dllFullPath);
    };
}

Ключевым моментом здесь является запись байтов в файл и загрузка из его местоположения. Чтобы избежать проблем с курицей и яйцом, вы должны убедиться, что вы объявили обработчик перед доступом к сборке и что вы не имеете доступа к элементам сборки (или не создаете экземпляры чего-либо, что имеет дело со сборкой) внутри части загрузки (разрешения сборки). Также убедитесь, что GetMyApplicationSpecificPath() не является временным каталогом, поскольку временные файлы могут быть удалены другими программами или вами (не то, чтобы они были удалены, пока ваша программа обращается к dll, но, по крайней мере, это неприятно. хорошее расположение). Также обратите внимание, что вам нужно записывать байты каждый раз, вы не можете загружать из местоположения только потому, что dll уже находится там.

Для управляемых dll вам нужно не записывать байты, а загружать напрямую из местоположения dll или просто читать байты и загружать сборку из памяти. Примерно так:

    using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
    {
        byte[] data = new byte[stream.Length];
        s.Read(data, 0, data.Length);
        return Assembly.Load(data);
    }

    //or just

    return Assembly.LoadFrom(dllFullPath); //if location is known.

Если сборка полностью неуправляемая, вы можете увидеть этот связь или это относительно того, как загружать такие библиотеки DLL.

Обратите внимание, что для ресурса «Build Action» необходимо установить значение «Embedded Resource».

Mavamaarten 18.01.2014 19:57

@Mavamaarten Не обязательно. Если он заранее добавлен в файл Resources.resx проекта, в этом нет необходимости.

Nyerguds 26.05.2014 12:22

EAZfuscator теперь коммерческий.

Telemat 12.06.2014 21:44

Ни подход ILMerge, ни обработка события AssemblyResolve Ларсом Холмом Дженсеном не будут работать для хоста плагина. Скажем, исполняемый файл ЧАС динамически загружает сборку п и обращается к ней через интерфейс IP, определенный в отдельной сборке. Чтобы встроить IP в ЧАС, потребуется небольшая модификация кода Ларса:

Dictionary<string, Assembly> loaded = new Dictionary<string,Assembly>();
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{   Assembly resAssembly;
    string dllName = args.Name.Contains(",") ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");
    dllName = dllName.Replace(".", "_");
    if ( !loaded.ContainsKey( dllName ) )
    {   if (dllName.EndsWith("_resources")) return null;
        System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
        byte[] bytes = (byte[])rm.GetObject(dllName);
        resAssembly = System.Reflection.Assembly.Load(bytes);
        loaded.Add(dllName, resAssembly);
    }
    else
    {   resAssembly = loaded[dllName];  }
    return resAssembly;
};  

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

Обновлено: Чтобы не испортить сериализацию .NET, убедитесь, что возвращено значение null для всех сборок, не встроенных в вашу, что приведет к стандартному поведению по умолчанию. Вы можете получить список этих библиотек:

static HashSet<string> IncludedAssemblies = new HashSet<string>();
string[] resources = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();
for(int i = 0; i < resources.Length; i++)
{   IncludedAssemblies.Add(resources[i]);  }

и просто верните null, если переданная сборка не принадлежит IncludedAssemblies.

Извините за то, что разместил это как ответ, а не как комментарий. Я не имею права комментировать чужие ответы.

Ant_222 09.10.2013 15:27

отрывок Джеффри Рихтера очень хорошо. Короче говоря, добавьте библиотеку как встроенные ресурсы и добавьте обратный вызов прежде всего. Вот версия кода (найдена в комментариях к его странице), которую я поместил в начале метода Main для консольного приложения (просто убедитесь, что все вызовы, использующие библиотеку, находятся в другом методе, чем Main).

AppDomain.CurrentDomain.AssemblyResolve += (sender, bargs) =>
        {
            String dllName = new AssemblyName(bargs.Name).Name + ".dll";
            var assem = Assembly.GetExecutingAssembly();
            String resourceName = assem.GetManifestResourceNames().FirstOrDefault(rn => rn.EndsWith(dllName));
            if (resourceName == null) return null; // Not found, maybe another handler will find it
            using (var stream = assem.GetManifestResourceStream(resourceName))
            {
                Byte[] assemblyData = new Byte[stream.Length];
                stream.Read(assemblyData, 0, assemblyData.Length);
                return Assembly.Load(assemblyData);
            }
        };

Немного изменил, сделал работу, приятель!

Sean Ed-Man 21.11.2014 19:00

Проект libz.codeplex.com использует этот процесс, но он также будет делать некоторые другие вещи, например, управлять обработчиком событий для вас и некоторым специальным кодом, чтобы не нарушать "Каталоги управляемой платформы расширяемости" (который сам по себе этот процесс сломал бы)

Scott Chamberlain 23.02.2015 22:53

Замечательно!! Спасибо @Steve

Ahmer Afzal 03.08.2019 12:39
Ответ принят как подходящий

Я настоятельно рекомендую использовать Costura.Fody - безусловно, лучший и простой способ встраивать ресурсы в вашу сборку. Он доступен как пакет NuGet.

Install-Package Costura.Fody

После добавления его в проект он автоматически вставит все ссылки, которые копируются в выходной каталог, в вашу сборку основной. Возможно, вы захотите очистить встроенные файлы, добавив цель в свой проект:

Install-CleanReferencesTarget

Вы также сможете указать, следует ли включать pdb, исключать определенные сборки или извлекать сборки на лету. Насколько мне известно, поддерживаются и неуправляемые сборки.

Обновлять

В настоящее время некоторые люди пытаются добавить поддержка DNX.

Обновление 2

Для последней версии Fody вам потребуется MSBuild 16 (то есть Visual Studio 2019). Fody версии 4.2.1 поддерживает MSBuild 15. (ссылка: Fody поддерживается только в MSBuild 16 и выше. Текущая версия: 15)

Спасибо за это замечательное предложение. Установите пакет, и все готово. По умолчанию он даже сжимает сборки.

Daniel 19.12.2013 19:40

Ненавижу быть «я тоже», но и я тоже - это избавило меня от головной боли! Спасибо за рекомендацию! Это позволило мне упаковать все, что мне нужно для распространения, в один exe, и теперь он меньше, чем исходный exe и библиотеки, которые были объединены ... Я использую это всего несколько дней, поэтому я не могу сказать, что я ' Я прошел через это испытание, но если не произойдет чего-нибудь плохого, я вижу, что это стало обычным инструментом в моем наборе инструментов. Просто работает!

mattezell 12.06.2014 23:27

Это круто. Но есть недостаток: сборка, созданная в Windows, больше не двоично совместима с моно Linux. Это означает, что вы не можете развернуть сборку в Linux mono напрямую.

Tyler Long 17.06.2014 16:40

У Costura, похоже, нет крючков для автоматического обновления через Интернет. См. Мой вопрос: stackoverflow.com/questions/28323709/…

Pompair 04.02.2015 17:55

Создание чистого выходного каталога Существует также командлет PowerShell для автоматической установки этой цели в ваш проект. В консоли диспетчера пакетов введите: PM> Install-CleanReferencesTarget

Siva 23.07.2015 04:16

Он отлично работал с Visual Studio 2013, но я больше не работаю с VS 2015 (Enterprise) - у кого-нибудь такая же проблема!?!?

CeOnSql 28.07.2015 16:47

@CeOnSql У меня такая же проблема в Windows 8.1 и 10 с сообществом VS 2015. Если у кого-то есть решение, дайте мне знать!

alexyorke 03.08.2015 22:34

@ alexy13: Поскольку у меня такая репутация благодаря этому посту, я чувствую ответственность за его обновление. К сожалению, сейчас я не могу это проверить. Я был бы очень признателен, если бы один из вас создал здесь проблему github.com/Fody/Costura/issues.

Matthias 03.08.2015 23:55

@Siva: Спасибо за подсказку. Добавил в пост.

Matthias 06.08.2015 01:57

Могу ли я включить текстовый файл в exe ?? У меня тоже есть родная библиотека dll и txt. Могу ли я сделать с помощью Costura.Fody только один exe-файл ??

Md. Yusuf 08.02.2016 15:12

Я нашел эти два: exepack.codeplex.com И visualstudiogallery.msdn.microsoft.com/…

zero.zero.seven 27.03.2016 22:29

@Ciprian на самом деле я не использовал костуру.

Md. Yusuf 10.10.2016 09:00

Кто-нибудь хотел бы предоставить образец того, как вы сливаете это запутанным образом? Я имею в виду, что .exe запутывается перед слиянием.

newbieguy 01.04.2017 03:25

Просто попробовал с VS 2015 R3 и сработал. Уменьшение общего размера файла для загрузки на 40%. Жаль, что имя NuGet так сложно запомнить (никогда бы не нашел его, если бы не этот ответ).

Gone Coding 26.04.2017 13:40

Просто голова вверх .. У меня были серьезные проблемы с установкой Costura.Fody с использованием всех обновлений VS 2013. Очевидно, последняя сборка 1.4.1 не работает с 2013 годом. Я успешно установил 1.4 из консоли nuget, но у меня были ошибки компилятора. Я закончил тем, что вручную добавил их в качестве ресурсов проекта, поскольку подход Fody в конце концов потратил мое время. Я могу обновить его, как только закончу свой проект, потому что простота и сжатие звучат УДИВИТЕЛЬНО

waltmagic 18.05.2017 23:14

Кстати ... У меня был проект с использованием Fody в Visual Studio 2012. Все работало КРАСИВО! Теперь я обновился до Visual Studio 2017, и Fody полностью разочаровался; Совсем не работает.

eidylon 25.05.2017 00:16

@CeOnSql, а alexy13 отлично работает в VS2015 обновление 3, 14.0.254431.01

Mehdi Dehghani 11.09.2017 21:31

Спасатель. Для людей, которые не знают, как установить Costura.Fody, просто зайдите в VS, в Инструменты-> Диспетчер пакетов NuGet-> Консоль диспетчера пакетов. Итак, вы переходите к команде «Install-Package Costura.Fody». Перестройте приложение, и все будет хорошо. Просто как тот! Не будучи здесь высокомерным, мне тоже пришлось разобраться в себе.

Eldoïr 22.09.2017 15:51

он не встраивает "SQLite.Interop.dll" из библиотеки System.Data.SQLite.Core

Gene R 12.02.2018 17:52

Это прекрасно! Если вы используете vs2018, не забудьте, что файл FodyWeavers.xml должен находиться в корне вашего проекта.

Alan Deep 14.04.2018 08:15

Это действительно прекрасно и в 2018 году! :) Очень полезно!

rigerta 07.06.2018 12:35

В качестве дополнения к последнему комментарию: добавьте в свой проект файл FodyWeavers.xml следующего содержания: <? Xml version = "1.0" encoding = "utf-8"?> <Weavers VerifyAssembly = "true"> <Costura /> </Weavers>

HHenn 29.08.2018 17:13

Все еще работает в 2018 году, но вам нужно следовать руководству из readme.md здесь github.com/Fody/Costura

super sahar 27.11.2018 12:10

это работа со ссылками, добавленными из NUGETPackages. Но не работает, если я добавлю решение существующего проекта в качестве ссылки на него. Может кто-нибудь помочь, почему это?

nsds 07.02.2019 10:51

Для тех, у кого ошибка MSBuild: stackoverflow.com/a/55843973/6674014

DCOPTimDowd 06.05.2019 23:09

Для меня это не решение - Symantec пометила этот пакет Nuget как вирус и автоматически удалила его.

DAG 10.01.2020 18:41

Команда консоли диспетчера пакетов Install-CleanReferencesTarget больше недействительна и завершится ошибкой. В текущих версиях это автоматизировано. Также для Visual Studio 2017 (с использованием MSBuild 15) установите Nugets Fody 4.2.1 и Costura.Fody 3.3.3 для успешной компиляции.

Arvo Bowen 21.02.2020 21:27

Это может показаться упрощенным, но WinRar дает возможность сжать кучу файлов в самораспаковывающийся исполняемый файл. Он имеет множество настраиваемых параметров: конечный значок, извлечение файлов по заданному пути, файл для выполнения после извлечения, собственный логотип / тексты для всплывающих окон во время извлечения, отсутствие всплывающих окон, текст лицензионного соглашения и т. д. Может быть полезно в некоторых случаях.

В самой Windows есть аналогичный инструмент под названием iexpress. Вот учебник

Ivan Ferrer Villa 20.01.2015 12:22

Чтобы развернуть на @ Ответ Бобби выше. Вы можете отредактировать свой .csproj, чтобы использовать Ил-Репак для автоматической упаковки всех файлов в одну сборку при сборке.

  1. Установите пакет nuget ILRepack.MSBuild.Task с Install-Package ILRepack.MSBuild.Task
  2. Отредактируйте раздел AfterBuild вашего .csproj

Вот простой пример, который объединяет ExampleAssemblyToMerge.dll с выходными данными вашего проекта.

<!-- ILRepack -->
<Target Name = "AfterBuild" Condition = "'$(Configuration)' == 'Release'">

   <ItemGroup>
    <InputAssemblies Include = "$(OutputPath)$(AssemblyName).exe" />
    <InputAssemblies Include = "$(OutputPath)\ExampleAssemblyToMerge.dll" />
   </ItemGroup>

   <ILRepack 
    Parallel = "true"
    Internalize = "true"
    InputAssemblies = "@(InputAssemblies)"
    TargetKind = "Exe"
    OutputFile = "$(OutputPath)$(AssemblyName).exe"
   />
</Target>

Синтаксис IL-Repack изменился, проверьте README.md, который находится в связанном репозитории github (github.com/peters/ILRepack.MSBuild.Task). Этот способ был единственным, который у меня сработал, и я смог использовать подстановочный знак, чтобы сопоставить все библиотеки DLL, которые я хотел включить.

Seabass77 26.07.2019 15:29

Я использую компилятор csc.exe, вызываемый из сценария .vbs.

В вашем скрипте xyz.cs добавьте следующие строки после директив (мой пример для Renci SSH):

using System;
using Renci;//FOR THE SSH
using System.Net;//FOR THE ADDRESS TRANSLATION
using System.Reflection;//FOR THE Assembly

//+ref>"C:\Program Files (x86)\Microsoft\ILMerge\Renci.SshNet.dll"
//+res>"C:\Program Files (x86)\Microsoft\ILMerge\Renci.SshNet.dll"
//+ico>"C:\Program Files (x86)\Microsoft CAPICOM 2.1.0.2 SDK\Samples\c_sharp\xmldsig\resources\Traffic.ico"

Теги ref, res и ico будут взяты приведенным ниже сценарием .vbs для формирования команды csc.

Затем добавьте вызывающий преобразователь сборки в Main:

public static void Main(string[] args)
{
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    .

... и добавьте сам резолвер где-нибудь в классе:

    static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        String resourceName = 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);
        }

    }

Я называю сценарий vbs, чтобы он соответствовал имени файла .cs (например, ssh.vbs ищет ssh.cs); это многократно упрощает выполнение сценария, но если вы не такой идиот, как я, то общий сценарий может выбрать целевой файл .cs путем перетаскивания:

    Dim name_,oShell,fso
    Set oShell = CreateObject("Shell.Application")
    Set fso = CreateObject("Scripting.fileSystemObject")

    'TAKE THE VBS SCRIPT NAME AS THE TARGET FILE NAME
    '################################################
    name_ = Split(wscript.ScriptName, ".")(0)

    'GET THE EXTERNAL DLL's AND ICON NAMES FROM THE .CS FILE
    '#######################################################
    Const OPEN_FILE_FOR_READING = 1
    Set objInputFile = fso.OpenTextFile(name_ & ".cs", 1)

    'READ EVERYTHING INTO AN ARRAY
    '#############################
    inputData = Split(objInputFile.ReadAll, vbNewline)

    For each strData In inputData

        if left(strData,7) = "//+ref>" then 
            csc_references = csc_references & " /reference:" &         trim(replace(strData,"//+ref>","")) & " "
        end if

        if left(strData,7) = "//+res>" then 
            csc_resources = csc_resources & " /resource:" & trim(replace(strData,"//+res>","")) & " "
        end if

        if left(strData,7) = "//+ico>" then 
            csc_icon = " /win32icon:" & trim(replace(strData,"//+ico>","")) & " "
        end if
    Next

    objInputFile.Close


    'COMPILE THE FILE
    '################
    oShell.ShellExecute "c:\windows\microsoft.net\framework\v3.5\csc.exe", "/warn:1 /target:exe " & csc_references & csc_resources & csc_icon & " " & name_ & ".cs", "", "runas", 2


    WScript.Quit(0)

.NET Core 3.0 изначально поддерживает компиляцию в один EXE-файл.

Эта функция включается при использовании следующего свойства в файле проекта (.csproj):

    <PropertyGroup>
        <PublishSingleFile>true</PublishSingleFile>
    </PropertyGroup>

Это делается без каких-либо внешних инструментов.

См. Мой ответ на этот вопрос для получения дополнительной информации.

Следующий метод НЕ используйте внешние инструменты и АВТОМАТИЧЕСКИ включить все необходимые DLL (никаких ручных действий не требуется, все делается при компиляции)

Я читал здесь много ответов, в которых говорилось об использовании метода ILMerge, ILRepack или Джеффри Ритчер, но ни один из них не работал с Приложения WPF и не был простым в использовании.

Когда у вас много DLL, может быть сложно вручную включить ту, которая вам нужна в исполняемый файл. Лучший метод, который я нашел, был объяснен Wegged здесь, в StackOverflow.

Скопируйте сюда его ответ для ясности (все кредиты Wegged)


1) Добавьте это в свой файл .csproj:

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

Другие вопросы по теме