Склеивание .dll и пользовательского .exe - C#

Узнай цену своей работы

Формулировка задачи:

Доброго времени суток ! Вложений всего пять, поэтому выкладываю все одним большим архивом : TEST.rar Зеркало Поставлена такая задача : Есть у меня библиотека Lib с таким кодом :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Lib
{
    public class LibClass
    {
        public delegate void OnKeyPressingContainer(ConsoleKeyInfo Key);
        public static event OnKeyPressingContainer OnKeyPressing;
        public delegate void OnKeyPressedContainer(ConsoleKeyInfo Key);
        public static event OnKeyPressedContainer OnKeyPressed;
        private static void KeyPress(ConsoleKeyInfo Key)
        {
            if (OnKeyPressing != null) OnKeyPressing(Key);
            Console.WriteLine("Key : " + Key.Key + " (\'" + Key.KeyChar + "\')");
            if (OnKeyPressed != null) OnKeyPressed(Key);
        }
        public static void Process()
        {
            ConsoleKeyInfo Key = new ConsoleKeyInfo();
            while (Key.Key != ConsoleKey.Escape)
            {
                Key = Console.ReadKey(true);
                KeyPress(Key);
                Console.WriteLine();
            }
        }
    }
}
Как видно, она в функции Process ожидает нажатия клавиши, затем вызывает событие OnKeyPressing, обрабатывает нажатие и вызывает событие OnKeyPressed. Весь ее проект - Lib.rar во вложении. Есть так же приложение Main с таким кодом :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Lib;
 
namespace Main
{
 
    class Program
    {
        static void Main(string[] args)
        {
            LibClass.OnKeyPressing += KeyPressing;
            LibClass.OnKeyPressed += KeyPressed;
            LibClass.Process();
        }
        static void KeyPressing(ConsoleKeyInfo Key) { Console.WriteLine("KeyPressing : \'" + Key.KeyChar + "\'"); }
        static void KeyPressed(ConsoleKeyInfo Key) { Console.WriteLine("KeyPressed : \'" + Key.KeyChar + "\'"); }
    }
}
Как видно, оно подписывается на события библиотеки и вызывает из нее функцию Process. Весь его проект - Main.rar во вложении. Все работает замечательно. Но ! Необходимо иметь на выходе только Main.exe, т.е. склеить его с библиотекой. __________________________________________________________________________________________________ И тут начались попытки. Пробовал ILMerge : Начал, вооружившись этой статьей на Хабре. Пользовался тем, что есть во вложении. 1. Создал папку TEST. 2. Положил туда ILMerge.exe, Lib.dll и Main.exe. 3. Создал там Merge.bat следующего содержания :
ILMerge.exe /target:Exe /out:Compressed.exe Main.exe /log:Log.txt Lib.dll
4. Запустил его. 5. ILMerge создал Compressed.exe и Compressed.pdb, и вывел в Log.txt следующее :
ILMerge version 2.12.803.0 Copyright (C) Microsoft Corporation 2004-2006. All rights reserved. ILMerge /target:Exe /out:Compressed.exe Main.exe /log:Log.txt Lib.dll Set platform to 'v2', using directory 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727\..\v2.0.50727' for mscorlib.dll Running on Microsoft (R) .NET Framework v2.0.50727 mscorlib.dll version = 2.0.0.0 The list of input assemblies is: Main.exe Lib.dll Trying to read assembly from the file 'D:\Tempo\TEST\Main.exe'. Can not find PDB file. Debug info will not be available for assembly 'Main.exe'. Successfully read in assembly. There were no errors reported in Main's metadata. Trying to read assembly from the file 'D:\Tempo\TEST\Lib.dll'. Can not find PDB file. Debug info will not be available for assembly 'Lib.dll'. Successfully read in assembly. There were no errors reported in Lib's metadata. Checking to see that all of the input assemblies have a compatible PeKind. Main.PeKind = ILonly, Requires32bits, Prefers32bits Lib.PeKind = ILonly All input assemblies have a compatible PeKind value. AssemblyResolver: Assembly 'Main' is referencing assembly 'System'. AssemblyResolver: Attempting referencing assembly's directory. AssemblyResolver: Did not find assembly in referencing assembly's directory. AssemblyResolver: Attempting input directory. AssemblyResolver: Did not find assembly in input directory. AssemblyResolver: Attempting user-supplied directories. AssemblyResolver: No user-supplied directories. AssemblyResolver: Attempting framework directory. Can not find PDB file. Debug info will not be available for assembly 'System'. Resolved assembly reference 'System' to 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727\..\v2.0.50727\System.dll'. (Used framework directory.) Using assembly 'Main' for assembly-level attributes for the target assembly. Merging assembly 'Main' into target assembly. Merging assembly 'Lib' into target assembly. Copying 2 Win32 Resources from assembly 'Main' into target assembly. Transferring entry point 'Main.Program.Main(System.String[])' from assembly 'Main' to assembly 'Compressed'. There were no errors reported in the target assembly's metadata. ILMerge: Writing target assembly 'Compressed.exe'. Location for referenced assembly 'mscorlib' is 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727\mscorlib.dll' There were no errors reported in mscorlib's metadata. Location for referenced assembly 'System' is 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727\system.dll' There were no errors reported in System's metadata. ILMerge: Done.
Судя по надписям "There were no errors reported in" и "Done", ILMerge полагает, что все нормально. Но Compressed.exe при запуске вылетает с APPCRASH (ILMergeCrash.jpg во вложении). Все остальные биения и мучения ни к чему не привели. Итак, с ILMerge покончено. __________________________________________________________________________________________________ Дальнейшие попытки привели меня к такому решению : положить библиотеку во встраиваемые ресурсы. Нарыл немного ссылок : Как объединить exe и Dll в один файл Подключение dll из ресурсов https://geektimes.ru/post/67836/ https://msdn.microsoft.com/ru-ru/library/e2c9s1d7(v=vs.90).aspx https://msdn.microsoft.com/ru-ru/library/7k989cfy(v=vs.90).aspx И, наконец, http://www.codeproject.com/Articles/...edded-Resource. Там есть пример, но если кто-то не зарегистрирован на codeproject и не хочет, то архив есть во вложении. 1. Как там написано, добавляю Lib.dll как файл в проект. 2. Для библиотеки, которая в References, устанавливаю параметр "Копировать локально" в "False", а для той, которая файл - "Действие при сборке" во "Внедренный ресурс". 3. Добавляю в проект EmbeddedAssembly.cs. 4. Добавляю в код Main using System.Reflection; 5. Изменяю код Main следующим образом :
[STAThread]
        static void Main(string[] args)
        {
            EmbeddedAssembly.Load("Main.Lib.dll", "Lib.dll");
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            LibClass.OnKeyPressing += KeyPressing;
            LibClass.OnKeyPressed += KeyPressed;
            LibClass.Process();
        }
        static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            return EmbeddedAssembly.Get(args.Name);
        }
Собираю, запускаю. Получаю FileNotFoundException, говорящий про Lib.dll. По идее, если сборка не найдена, должна вызваться CurrentDomain_AssemblyResolve. Она, в свою очередь, должна загрузить из ресурсов библиотеку и передать её кому нужно. Она этого не делает, потому что если библиотеке в References вернуть параметр "Копировать локально" в "True", то всё будет работать, как раньше. __________________________________________________________________________________________________ Что я делаю не так и есть ли альтернативы ? Заранее благодарен за помощь.

Решение задачи: «Склеивание .dll и пользовательского .exe»

textual
Листинг программы
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.IO;
 
namespace WindowsFormsApplication1 {
    public partial class MainForm : Form {
        public MainForm() {
            InitializeComponent();
            button1.Click += new EventHandler(button1_Click);
        }
 
        void button1_Click(object sender, EventArgs e) {
            Assembly asm = Assembly.Load(Resource1.testlib);
            Type t = asm.GetType("testlib.TestClass");
            dynamic test = Activator.CreateInstance(t);
            MessageBox.Show(test.GetResult(), "test");
        }
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

8   голосов , оценка 3.75 из 5