Как можно объединить dll Windows C ++ в exe приложения C #? - PullRequest
32 голосов
/ 16 сентября 2008

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

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

Ответы [ 8 ]

16 голосов
/ 16 сентября 2008

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

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

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

Я включаю все библиотеки 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-файлов в собственные файлы прост:

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

3 голосов
/ 30 июня 2017

Использование Fody.Costura nuget

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

Вот и все!

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

3 голосов
/ 25 сентября 2008

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

1 голос
/ 15 июня 2011

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

Вы пробовали 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.

0 голосов
/ 15 мая 2012

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 голосов
/ 10 апреля 2010

PostBuild из Xenocode может упаковать как управляемые, так и неуправляемые в один exe.

0 голосов
/ 16 сентября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...