Объединение библиотек DLL в одну.exe с wpf
в настоящее время я работаю над проектом, в котором у нас много зависимостей. Я хотел бы скомпилировать все ссылки dll в .exe так же, как вы сделали бы со встроенными ресурсами. Я пробовал ILMerge но он не может справиться .ресурсы xaml.
Итак, мой вопрос: есть ли способ объединить проект WPF с несколькими зависимостями в один .exe?
9 ответов
это работает как шарм для меня :) и совершенно бесплатно.
добавление кода в случае, если блог не исчезает.
1) Добавьте это в ваш :
<Target Name="AfterResolveReferences">
<ItemGroup>
<EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
<LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Target>
2) Сделайте свой основной Program.cs
выглядит так:
[STAThreadAttribute]
public static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
App.Main();
}
3) Добавить OnResolveAssembly
способ:
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
var path = assemblyName.Name + ".dll";
if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false) path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);
using (Stream stream = executingAssembly.GetManifestResourceStream(path))
{
if (stream == null) return null;
var assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
return Assembly.Load(assemblyRawBytes);
}
}
Costura Fody-это инструмент с открытым исходным кодом, предназначенный для обработки слияния сборок wpf.
{smartassembly} является одним из таких продуктов. Он может obsfucate или встраивать ваши DLL.
попробуйте это: http://www.smartassembly.com/
вы также можете сделать много улучшений в своем приложении, чтобы он работал быстрее.
и да. Вы можете использовать его для WPF.
обновление 8/06/2015: ILRepack 2.0.0 (который является альтернативой ILMerge с открытым исходным кодом) теперь поддерживает большинство случаев слияния WPF: https://twitter.com/Gluckies/status/607680149157462016
на сайт ILMerge, рассматривайте эти библиотеки как ресурсы, от Джеффри Рихтера здесь :
многие приложения состоят из EXE-файла, который зависит от многих DLL файлы. При развертывании этого приложения, все файлы должны быть развертываемый. Однако, существует метод, который можно использовать для развертывания просто один EXE файл. Во-первых, определите все DLL-файлы, которые EXE-файл зависит от того, что не поставляются в составе Microsoft .ЧИСТЫЙ Сама структура. Затем добавьте эти библиотеки DLL в проект Visual Studio. Для каждого добавляемого DLL-файла отобразите его свойства и измените его "Build Action" to " встроенный ресурс."Это заставляет компилятор C# вставьте DLL-файл (ы) в EXE-файл, и вы можете развернуть его файл EXE. Во время выполнения среда CLR не сможет найти зависимой Сборки DLL, что является проблемой. Чтобы исправить это, когда ваше приложение инициализирует, регистрирует метод обратного вызова с помощью AppDomain Событие ResolveAssembly. Код должен выглядеть примерно так:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
String resourceName = "AssemblyLoadingAndReflection." +
new AssemblyName(args.Name).Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) {
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
теперь, в первый раз, когда поток вызывает метод, который ссылается на тип в зависимый DLL-файл, событие AssemblyResolve будет вызвано и код обратного вызова, показанный выше, найдет требуемый встроенный ресурс DLL и загрузите его, вызвав перегрузку метода загрузки сборки, который принимает Byte[] в качестве аргумента.
использовать Costura.Фоди!--3--> - он доступен как NuGet Pkg для лучшего и простого способа встраивания ресурсов в вашу сборку.
Install-Package Costura.Fody
после добавления его в проект он автоматически вставит все добавленные ссылки на вашу основную сборку.
попробовать .Нец (http://madebits.com/netz/) - это бесплатно (как в пиве) и делает некоторые хорошие вещи, если вы цель exe.
вот измененная версия цитируемого кода от Matthieu, которая не требует знания пространства имен для извлечения кода. Для WPF поместите это в код события запуска приложения.
AppDomain.CurrentDomain.AssemblyResolve += (s, args) =>
{
// Note: Requires a using statement for System.Reflection and System.Diagnostics.
Assembly assembly = Assembly.GetExecutingAssembly();
List<string> embeddedResources = new List<string>(assembly.GetManifestResourceNames());
string assemblyName = new AssemblyName(args.Name).Name;
string fileName = string.Format("{0}.dll", assemblyName);
string resourceName = embeddedResources.Where(ern => ern.EndsWith(fileName)).FirstOrDefault();
if (!string.IsNullOrWhiteSpace(resourceName))
{
using (var stream = assembly.GetManifestResourceStream(resourceName))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
var test = Assembly.Load(assemblyData);
string namespace_ = test.GetTypes().Where(t => t.Name == assemblyName).Select(t => t.Namespace).FirstOrDefault();
#if DEBUG
Debug.WriteLine(string.Format("\tNamespace for '{0}' is '{1}'", fileName, namespace_));
#endif
return Assembly.Load(assemblyData);
}
}
return null;
};
чтобы сделать их доступными во время компиляции, я создаю папку с именем ExternalDLLs и копирую DLL там и устанавливаю их в EmbeddedResource, как указано выше. Чтобы использовать их в коде, вам все равно нужно установить ссылку на них, но установить Copy local в False. Чтобы получить код для компиляции чисто без ошибок вам также нужно установить с помощью состояний в коде пространства имен DLL.
вот небольшая утилита, которая вращается через внедренные имена ресурсов и отображает их пространства имен в окне вывода.
private void getEmbeddedResourceNamespaces()
{
// Note: Requires a using statement for System.Reflection and System.Diagnostics.
Assembly assembly = Assembly.GetExecutingAssembly();
List<string> embeddedResourceNames = new List<string>(assembly.GetManifestResourceNames());
foreach (string resourceName in embeddedResourceNames)
{
using (var stream = assembly.GetManifestResourceStream(resourceName))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
try
{
var test = Assembly.Load(assemblyData);
foreach (Type type in test.GetTypes())
{
Debug.WriteLine(string.Format("\tNamespace for '{0}' is '{1}'", type.Name, type.Namespace));
}
}
catch
{
}
}
}
}
- добавьте к этому .файл csprofj:
>
<Target Name="AfterResolveReferences">
<ItemGroup>
<EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
<LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Target>
щелкните правой кнопкой мыши проект / свойства / приложение / объект starup / выберите Sinhro.Программа
-
добавить в свою программу.cs файл:
использование системы.Отображение; используя системы.ИО; использование системы.Глобализация;
[STAThreadAttribute] static void Main() { AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly; ... private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); AssemblyName assemblyName = new AssemblyName(args.Name); string path = assemblyName.Name + ".dll"; if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false) { path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path); } using (Stream stream = executingAssembly.GetManifestResourceStream(path)) { if (stream == null) return null; byte[] assemblyRawBytes = new byte[stream.Length]; stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); return Assembly.Load(assemblyRawBytes); } }