Открыть список
Как стать автором
Обновить

C# + WPF + сторонние сборки -> один .exe-шник

Программирование
Бывает приходится разработать маленькое приложение на C# и WPF, однако в следствие использования сторонних сборок(например SharpZipLib, Unity) — получается так что на выходе у нас кроме нашего маленького .exe-шника получается ещё и куча .dll-ок, а нам нужно чтобы был именно один .exe-шник.

Немногие знающие люди тут вспомнят про утилиту ILMerge от Microsoft, но к несчастью — есть проблемы с WPF-приложениями из-за особенностей компиляции XAML-файлов.
Так же бывают проблемы с хитрыми сборками, по которым прошлись приличными обфускаторами.

Я предлагаю другой выход который и использую в некоторых своих продуктах — включить все сторонние сборки как встраиваемые ресурсы(embedded resource), а в App.xaml.cs сделать так:

  1. public partial class App : Application
  2. {
  3. //Обработчик события запуска приложения
  4. private void OnStartup(object sender, StartupEventArgs e)
  5. {
  6. //Для текущего домена приложения вешаем свой обработчик в котором и будем вручную подсовывать нужные сборки
  7. AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
  8. }
  9. //Наш обработчик для резолва сборок
  10. static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
  11. {
  12. //Получаем текущую сборку которая выполняется(чтобы из нее брать ресурсы)
  13. Assembly thisAssembly = Assembly.GetExecutingAssembly();
  14. //Формируем имя ресурса
  15. var name = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";
  16. //Находим ресурс по имени
  17. var resourceName = thisAssembly.GetManifestResourceNames().First(s => s.EndsWith(name));
  18. using (Stream stream = thisAssembly.GetManifestResourceStream(resourceName))
  19. {
  20. //Считываем ресурс в массив байтов
  21. byte[] block = new byte[stream.Length];
  22. stream.Read(block, 0, block.Length);
  23. //Загружаем сборку из массива байтов в текущий домен приложения и возвращаем её
  24. return Assembly.Load(block);
  25. }
  26. }
  27. }
* This source code was highlighted with Source Code Highlighter.


Соответственно с таких подходом мы подразумеваем что мы нормально называем файлы сборок.

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

Что ещё можно улучшить — можно уменьшить размер выходного .exe-шника храня сборки сжатыми через DeflateStream и считывая их соответственно распаковывая через него же. Можно периодически проверять не обновилась ли сборка и если обновилась — грузить её из сети (особенно если это чтото мелкое).

И да, важный момент, что скорее всего не будет работать — при такой сборке скорее всего не будут работать сборки с нативными методами, т.е. написанные на C++/CLI. Поправьте меня если я ошибаюсь, но у меня не работали.

[update]
Насчёт C++/CLI — согласно MSDN — выкидывается исключение BadImageFormatException в случае если компилятор C++ удалил .reloc секцию из .exe-шника. Если скомпилировать сборку на C++/CLI с /fixed:no то возможно она будет успешно загружаться
Теги:CWPFILMerge
Хабы: Программирование
Всего голосов 18: ↑14 и ↓4 +10
Просмотры12.8K

Похожие публикации

Лучшие публикации за сутки