Нужно при старте Win-приложения загружать dll, но делать это необходимо изнутри сборки (именно потому статическая загрузка)!
Частичное решение уже есть: https://stackoverflow.com/questions/23971418/c-sharp-embed-dll-in-exe-filenotfoundexception
Но, что и закономерно, в моем случае также вылетает это же исключение:
An unhandled exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.dll
Additional information: Не удалось загрузить файл или сборку "SevenZipSharp, Version=0.64.3890.29348, Culture=neutral, PublicKeyToken=20de82c62b055c88" либо одну из их зависимостей. Не удается найти указанный файл.
Пробовал добавлять эту dll и через ресурсы (тогда программа даже отказывается стартовать из-за того, что не находит в нужном месте эту dll, а именно в папке "bin/Debug/...") и через "Сборка - Add - Existing Item..." (так стартует, но до загрузки формы получаю вышеописанное исключение).
Код, находящийся в файле Program.cs, имеет вид (практически идентичен тому, который рассматривается по ссылке и оставлен без ответа; также я пробовал изменять его, следуя указаниям из различных источников):
namespace WindowsFormsApplication1
{
static class Program
{
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string assemblyName = args.Name.Split(',').First();
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("WindowsFormsApplication1." + assemblyName + ".dll"))
{
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}
}
}
Также пробовал в свойствах dll (добавленной через "Existing Item...") выбирать различные варианты "Build Action". Результат отрицательный.
Также вариант с программой ILMerge (http://habrahabr.ru/post/126089/) не подходит.
Как указать системе, что я хочу обратиться и загрузить dll по пути изнутри сборки, а не извне?
Ответ
Вот полные шаги:
Добавить SevenZipSharp.dll в проект через Add Existing Item, выставить Build Type = Embedded Resource
Добавить SevenZipSharp.dll в References. Выставить у референса Copy Local = false - чтобы избежать копирования в bin.
Упомнятуть класс где-то в Form_Load (чтобы произошла попытка подгрузки dll) - у вас это явно сделано:
private void Form1_Load(object sender, EventArgs e)
{
SevenZip.SevenZipCompressor c = new SevenZip.SevenZipCompressor();
}
Аккуратно обработать CurrentDomain_AssemblyResolve
using System;
using System.Reflection;
using System.Windows.Forms;
namespace WindowsFormsApplication7
{
static class Program
{
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var assemblyName = new AssemblyName(args.Name).Name;
if (assemblyName == "SevenZipSharp")
{
using (var stream = typeof(Program).Assembly.GetManifestResourceStream(
"WindowsFormsApplication7." + assemblyName + ".dll"))
{
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}
else
{
return null;
}
}
}
}
Это минимальный рабочий пример. Если не работает - запускайте под отладчиком. Скорее всего вы не угадали с именем ресурса, и GetManifestResourceStream возвращает null. Убедитесь, что тип у айтема выставлен именно в Embedded Resource (а не просто в Resource). Просмотреть имена всех доступных ресурсов можно прямо в отладчике, вызовом
typeof(Program).Assembly.GetManifestResourceNames()
Проект целиком на гитхабе: https://github.com/PashaPash/SevenZipSharp-Embedded
Комментариев нет:
Отправить комментарий