it-swarm-ru.tech

Как Windows Cll DLL может быть объединена в C # приложение exe?

У меня есть Windows C # программа, которая использует C++ DLL для ввода/вывода данных. Моя цель - развернуть приложение как один EXE-файл. 

Какие шаги для создания такого исполняемого файла?

32
Noah

Развертывание управляемого и неуправляемого кода в одной сборке. Воскресенье, 4 февраля 2007 г.

Разработчики .NET любят развертывание XCOPY. И они любят отдельные компоненты сборки. По крайней мере, я всегда чувствую себя немного неловко, если мне нужно использовать какой-то компонент и мне нужно запомнить список файлов, которые также нужно включить в основную сборку этого компонента. Поэтому, когда мне недавно пришлось разработать компонент управляемого кода и дополнить его некоторым неуправляемым кодом из C DLL (спасибо Маркусу Хигу за помощь в этом!), Я подумал о том, как сделать его проще. разверните две библиотеки DLL. Если бы это были всего две сборки, я бы использовал ILmerge, чтобы собрать их в один файл. Но это не работает для компонентов смешанного кода с управляемыми и неуправляемыми библиотеками DLL.

Итак, вот что я придумал для решения:

Я включаю все библиотеки DLL, которые я хочу развернуть, с основной сборкой моего компонента в качестве встроенных ресурсов .... Затем я настраиваю конструктор класса для извлечения этих библиотек, как показано ниже. Класс ctor вызывается только один раз в каждом AppDomain, поэтому я думаю, что это незначительные накладные расходы.

namespace MyLib
{
    public class MyClass
    {
        static MyClass()
        {
            ResourceExtractor.ExtractResourceToFile("MyLib.ManagedService.dll", "managedservice.dll");
            ResourceExtractor.ExtractResourceToFile("MyLib.UnmanagedService.dll", "unmanagedservice.dll");
        }

        ...

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

Код для извлечения библиотек DLL в свои файлы прост:

public static class ResourceExtractor
{
    public static void ExtractResourceToFile(string resourceName, string filename)
    {
        if (!System.IO.File.Exists(filename))
            using (System.IO.Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
                using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create))
                {
                    byte[] b = new byte[s.Length];
                    s.Read(b, 0, b.Length);
                    fs.Write(b, 0, b.Length);
                }
    }
}

Работа с управляемым кодом Сборка такая же, как обычно - почти. Вы ссылаетесь на него (здесь: ManagedService.dll) в основном проекте вашего компонента (здесь: MyLib), но для свойства Copy Local установлено значение false. Кроме того, вы связываете сборку как существующий элемент и устанавливаете для действия сборки значение «Встроенный ресурс».

Для неуправляемого кода (здесь: UnmanagedService.dll) вы просто ссылаетесь на DLL как существующий элемент и задаете для параметра «Действия» для «Встроенный ресурс». Чтобы получить доступ к его функциям, используйте атрибут DllImport как обычно, например,.

[DllImport("unmanagedservice.dll")] public extern static int Add(int a, int b);

Это оно! Как только вы создаете первый экземпляр класса со статическим ctor, встроенные библиотеки DLL извлекаются в свои собственные файлы и готовы к использованию, как если бы вы развернули их как отдельные файлы. Если у вас есть права на запись для каталога выполнения, это должно работать нормально. По крайней мере, для прототипного кода, я думаю, этот способ развертывания одной сборки довольно удобен.

Наслаждайтесь!

http://weblogs.asp.net/ralfw/archive/2007/02/04/single-Assembly-deployment-of-managed-and-unmanaged-code.aspx

16
Nick

Попробуйте boxedapp ; это позволяет загружать все библиотеки DLL из памяти. Кроме того, кажется, что вы можете даже встроить .net время выполнения. Хорошо для создания действительно автономных приложений ...

3
Art

Просто щелкните правой кнопкой мыши свой проект в 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/

1
Lars Holm Jensen

Используйте Fody.Costura nuget

  1. Откройте свое решение -> Проект -> Управление пакетами Nuget
  2. Поиск Fody.Costura
  3. Скомпилируйте ваш проект

Это оно !

Источник: http://www.manuelmeyer.net/2016/01/net-power-tip-10-merging-assemblies/

1
automan

Вы пробовали ILMerge? http://research.Microsoft.com/~mbarnett/ILMerge.aspx

ILMerge - это утилита, которая может использоваться для объединения нескольких сборок .NET в одну сборку. Он доступен для свободного использования на странице «Инструменты и утилиты» в Центре разработчиков Microsoft .NET Framework. 

Если вы создаете C++ DLL с флагом /clr (полностью или частично C++/CLI), то он должен работать:

ilmerge /out:Composite.exe MyMainApp.exe Utility.dll

Однако он не будет работать с обычной (родной) Windows DLL. 

1
Raithlin

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

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

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, но, по крайней мере, это создает неудобства. AppData хорошее место). Также обратите внимание, что вы должны записывать байты каждый раз, вы не можете загрузить из местоположения только потому, что dll уже находится там.

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

0
nawfal

Thinstall это одно решение. Для нативного приложения Windows я бы предложил встроить DLL в виде объекта двоичного ресурса, а затем извлечь его во время выполнения до того, как он вам понадобится.

0
titanae