Как библиотека DLL C ++ Windows может быть объединена с EXE-файлом приложения C #?

StackOverflow https://stackoverflow.com/questions/72264

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

Это было полезно?

Решение

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

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

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

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

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

        ...

В этом примере я включил две библиотеки 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 значение 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

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

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

Использование Друзья.Костура самородок

  1. Откройте ваше решение -> Проект -> Управление пакетами Nuget
  2. Поиск Друзья.Костура
  3. Скомпилировать ваш проект.

Вот и все!

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

Вы пробовали Ильмерге? http://research.microsoft.com /~мбарнетт/ILMerge.aspx

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

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

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

Он не будет работать с обычной (основной) Однако в системе Windows файлов.

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

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

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

Вы можете сделать это вручную, внедрив dll в свои ресурсы, а затем полагаясь на сборку AppDomain ResolveHandler.Когда дело доходит до библиотек DLL смешанного режима, я нашел множество вариантов и разновидностей ResolveHandler подход, который не работает для меня (все, которые считывают байты dll в память и считывают из нее).Все они работали с управляемыми библиотеками 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);
    };
}

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

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

PostBuild из Ксенокод может упаковывать как управляемые, так и неуправляемые файлы в один исполняемый файл.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top