Страницы

Поиск по вопросам

суббота, 7 декабря 2019 г.

Можно ли добавить библиотеку в exe? [дубликат]

#c_sharp #dll #visual_studio_2013


        
             
                
                    
                        
                            This question already has answers here:
                            
                        
                    
                
                        
                            Как скомпилировать все проекты солюшена в один .EXE?
                                
                                    (3 ответа)
                                
                        
                                Closed 2 года назад.
            
                    
Я написал небольшой проект в VS 2013, используя стороннюю библиотеку (DLL). Теперь
рядом с экзешником приходится постоянно держать эту библиотеку. Нельзя ли встроить
эту библиотеку в проект или хотя бы необходимую часть кода, что бы не приходилось повсюду
таскать эту dllку?
    


Ответы

Ответ 1



Да, можно. Зависимую библиотеку можно встроить в ресурсы и подгружать оттуда вручную. Предполагается, что ваша библиотека уже находится в References проекта, проект собирается, программа успешно запускается. Для начала добавьте в проект библиотеку как ресурс: Меню Project -> Add Existing Item... - выбираете вашу сборку (dll, в диалоге открытия выберите тип файлов Executable Files). Библиотека появится в списке файлов проекта. Вызовите контекстное меню на добавленном файле, выберите Properties. Затем установите в открывшемся окне Build Actions -> Embedded Resource. Добавьте в ваш проект следующий класс: public static class Resolver { private static volatile bool _loaded; public static void RegisterDependencyResolver() { if (!_loaded) { AppDomain.CurrentDomain.AssemblyResolve += OnResolve; _loaded = true; } } private static Assembly OnResolve(object sender, ResolveEventArgs args) { Assembly execAssembly = Assembly.GetExecutingAssembly(); string resourceName = String.Format("{0}.{1}.dll", execAssembly.GetName().Name, new AssemblyName(args.Name).Name); using (var stream = execAssembly.GetManifestResourceStream(resourceName)) { int read = 0, toRead = (int)stream.Length; byte[] data = new byte[toRead]; do { int n = stream.Read(data, read, data.Length - read); toRead -= n; read += n; } while (toRead > 0); return Assembly.Load(data); } } } Этот класс загрузит зависимую сборку из ресурса, как только основная программа обратится к ней, используя обработчик события AppDomain.AssemblyResolve. В классе, где находится точка входа программы, добавьте статический конструктор и вызовите метод RegisterDependencyResolver. Для примера, пусть у вас имеется консольное приложение: class Program { static Program() { Resolver.RegisterDependencyResolver(); } static void Main(string[] args) { // ... } } Заботиться о выгрузке сборки не надо, т.к. это все равно невозможно (можно выгрузить только домен целиком). Пример подсмотрен в книге Дж. Рихтера "CLR via C#".

Ответ 2



Еще один вариант - использовать ILMerge. Но писать скрипт для "склеивания" придется вручную, интеграции со студией из коробки нет. Также такой вариант будет работать не для любой библиотеки; если библиотека активно использует рефлексию - возможно потребуется написать свой обработчик AssemblyResolve: var assembly = typeof(Program).Assembly; AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { if (args.Name == "имя внедренной сборки") return assembly; return null; }; Главное достоинство варианта с ILMerge при работе с несколькими проектами - не требуется помещать один и тот же код загрузчика в каждый проект; поскольку обработчик AssemblyResolve нужен только для рефлексии - можно поместить его в общую библиотеку.

Ответ 3



Используйте утилиту ILMerge, а точнее ILMergeGUI Отличная утилита, упаковывает все DLL в EXE

Комментариев нет:

Отправить комментарий