Как можно слить DLL С++ в приложение EXE С#?

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

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

Ответ 1

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

Разработчики .NET любят развертывание XCOPY. И они любят отдельные компоненты сборки. По крайней мере, я всегда чувствую себя неловко, если мне нужно использовать какой-то компонент и нужно запомнить список файлов, которые также должны включать в себя основную сборку этого компонента. Поэтому, когда мне недавно приходилось разрабатывать компонент управляемого кода и ему приходилось увеличивать его с помощью некоторого неуправляемого кода из C DLL (спасибо to Marcus Heege за то, что он мне помог!), Я подумал о том, как упростить развертывание двух библиотек 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 файлом, а один из них являлся 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 как на существующий элемент и устанавливаете Build Action to Embedded Resource. Для доступа к его функциям обычно используется атрибут 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

Ответ 2

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

Ответ 3

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

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

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

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

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

Ответ 4

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

Ответ 6

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

Ответ 7

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

Вы можете сделать это вручную, вставив dll в свои ресурсы, а затем опираясь на AppDomain Assembly 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);
    };
}

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

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

Ответ 8

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