Склеивание .dll и пользовательского .exe - C#
Формулировка задачи:
Доброго времени суток !
Вложений всего пять, поэтому выкладываю все одним большим архивом : TEST.rar Зеркало
Поставлена такая задача :
Есть у меня библиотека Lib с таким кодом :
Как видно, она в функции Process ожидает нажатия клавиши, затем вызывает событие OnKeyPressing, обрабатывает нажатие и вызывает событие OnKeyPressed.
Весь ее проект - Lib.rar во вложении.
Есть так же приложение Main с таким кодом :
Как видно, оно подписывается на события библиотеки и вызывает из нее функцию Process.
Весь его проект - Main.rar во вложении.
Все работает замечательно. Но !
Необходимо иметь на выходе только Main.exe, т.е. склеить его с библиотекой.
__________________________________________________________________________________________________
И тут начались попытки.
Пробовал ILMerge :
Начал, вооружившись этой статьей на Хабре.
Пользовался тем, что есть во вложении.
1. Создал папку TEST.
2. Положил туда ILMerge.exe, Lib.dll и Main.exe.
3. Создал там Merge.bat следующего содержания :
4. Запустил его.
5. ILMerge создал Compressed.exe и Compressed.pdb, и вывел в Log.txt следующее :
Судя по надписям "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 следующим образом :
Собираю, запускаю. Получаю FileNotFoundException, говорящий про Lib.dll.
По идее, если сборка не найдена, должна вызваться CurrentDomain_AssemblyResolve.
Она, в свою очередь, должна загрузить из ресурсов библиотеку и передать её кому нужно.
Она этого не делает, потому что если библиотеке в References вернуть параметр "Копировать локально" в "True", то всё будет работать, как раньше.
__________________________________________________________________________________________________
Что я делаю не так и есть ли альтернативы ?
Заранее благодарен за помощь.
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(); } } } }
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 + "\'"); } } }
ILMerge.exe /target:Exe /out:Compressed.exe Main.exe /log:Log.txt Lib.dll
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.
[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); }
Решение задачи: «Склеивание .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"); } } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д