Встраивание одной dll в другую в качестве встроенного ресурса, а затем вызов его из моего кода



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



Это С C# и .NET 3.5.



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



Я первоначально планировалось сделать это путем написания кода, чтобы поместить стороннюю DLL в место, указанное System.Reflection.Assembly.GetExecutingAssembly().Location.ToString()
минус последний /nameOfMyAssembly.dll. Я могу успешно сохранить третью сторону .DLL в этом месте (где заканчивается




C:Documents и настройкиmyUserNameлокальные настройкиприложение
Данныесборкаdl3KXPPAX6Y.ZCYA1MZ1499.\E0115d44 91bb86eb_fe18c901 в 1TR




), но когда я добираюсь до части моего кода, требующей этой DLL, он не может найти оно.



кто-нибудь имеет представление о том, что мне нужно делать по-другому?

1036   6  

6 ответов:

после того, как вы внедрили стороннюю сборку в качестве ресурса, добавьте код для подписки на AppDomain.AssemblyResolve событие текущего домена при запуске приложения. Это событие срабатывает всякий раз, когда подсистеме слияния среды CLR не удается найти сборку в соответствии с действующими политиками зондирования. В обработчике событий для AppDomain.AssemblyResolve загрузите ресурс, используя Assembly.GetManifestResourceStream и передать его содержимое в виде массива байтов в соответствующий Assembly.Load перегрузка. Ниже показано, как одна такая реализация может выглядеть в C#:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    var resName = args.Name + ".dll";    
    var thisAssembly = Assembly.GetExecutingAssembly();    
    using (var input = thisAssembly.GetManifestResourceStream(resName))
    {
        return input != null 
             ? Assembly.Load(StreamToBytes(input))
             : null;
    }
};

здесь StreamToBytes можно определить как:

static byte[] StreamToBytes(Stream input) 
{
    var capacity = input.CanSeek ? (int) input.Length : 0;
    using (var output = new MemoryStream(capacity))
    {
        int readLength;
        var buffer = new byte[4096];

        do
        {
            readLength = input.Read(buffer, 0, buffer.Length);
            output.Write(buffer, 0, readLength);
        }
        while (readLength != 0);

        return output.ToArray();
    }
}

наконец, как некоторые уже упоминали,ILMerge может быть еще один вариант для рассмотрения, хотя и несколько более сложным.

в конце концов я сделал это почти точно так, как предложил raboof (и похоже на то, что предложил dgvid), за исключением некоторых незначительных изменений и некоторых упущений. Я выбрал этот метод, потому что он был ближе всего к тому, что я искал в первую очередь и не требовал использования каких-либо сторонних исполняемых файлов и т. д. Он отлично работает!

вот как выглядел мой код:

EDIT: я решил переместить эту функцию в другую сборку, чтобы я мог повторно использовать ее несколько файлов (я просто передаю в сборке.GetExecutingAssembly()).

Это обновленная версия, которая позволяет передавать в сборку со встроенными DLL.

embeddedResourcePrefix-это строковый путь к встроенному ресурсу, обычно это имя сборки, за которым следует любая структура папок, содержащая ресурс (например, "MyComapny.MyProduct.Моя сборка.Ресурсы", если библиотека dll находится в папке Resources в проекте). Он также предполагает, что библиотека имеет .файл DLL.расширение ресурсов.

   public static void EnableDynamicLoadingForDlls(Assembly assemblyToLoadFrom, string embeddedResourcePrefix) {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // had to add =>
            try {
                string resName = embeddedResourcePrefix + "." + args.Name.Split(',')[0] + ".dll.resource";
                using (Stream input = assemblyToLoadFrom.GetManifestResourceStream(resName)) {
                    return input != null
                         ? Assembly.Load(StreamToBytes(input))
                         : null;
                }
            } catch (Exception ex) {
                _log.Error("Error dynamically loading dll: " + args.Name, ex);
                return null;
            }
        }; // Had to add colon
    }

    private static byte[] StreamToBytes(Stream input) {
        int capacity = input.CanSeek ? (int)input.Length : 0;
        using (MemoryStream output = new MemoryStream(capacity)) {
            int readLength;
            byte[] buffer = new byte[4096];

            do {
                readLength = input.Read(buffer, 0, buffer.Length); // had to change to buffer.Length
                output.Write(buffer, 0, readLength);
            }
            while (readLength != 0);

            return output.ToArray();
        }
    }

есть инструмент под названием IlMerge, который может выполнить это:http://research.microsoft.com / ~mbarnett / ILMerge. aspx

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

Установить Путь="C:\Program Файлы\Microsoft\ILMerge"

ilmerge /out:$(ProjectDir)\Deploy\LevelEditor.exe $(ProjectDir)\bin\Release\release.exe $(ProjectDir)\bin\Release\InteractLib.dll $(ProjectDir)\bin\Release\SpriteLib.файл DLL $(ProjectDir)\bin\Release\LevelLibrary.dll

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

Я получаю встроенную сборку ресурсов в виде массива байтов следующим образом:

        Assembly resAssembly = Assembly.LoadFile(assemblyPathName);

        byte[] assemblyData;
        using (Stream stream = resAssembly.GetManifestResourceStream(resourceName))
        {
            assemblyData = ReadBytesFromStream(stream);
            stream.Close();
        }

затем я загружаю данные с помощью сборки.Нагрузка.)(

наконец, я добавляю обработчик в AppDomain.CurrentDomain.AssemblyResolve возвращает мою загруженную сборку, когда загрузчик типов смотрит на нее.

посмотреть .NET Fusion Workshop для получения дополнительной информации.

вы можете достичь этого удивительно легко с помощью Netz, а .чистый исполняемые файлы компрессора и Пакер.

вместо записи сборки на диск вы можете попробовать сделать сборку.Загрузите (byte[] rawAssembly), где вы создаете rawAssembly из внедренного ресурса.

Comments

    Ничего не найдено.