Tengo un programa de Windows C # que usa un dll de C++ para la E/S de datos. Mi objetivo es implementar la aplicación como un solo EXE.
¿Cuáles son los pasos para crear tal ejecutable?
Implementación de ensamblaje único de código administrado y no administrado Domingo 4 de febrero de 2007
Los desarrolladores de .NET adoran la implementación de XCOPY. Y aman los componentes individuales de ensamblaje. Al menos siempre me siento un poco incómodo, si tengo que usar algún componente y necesito recordar una lista de archivos para incluir también con el ensamblaje principal de ese componente. Entonces, cuando recientemente tuve que desarrollar un componente de código administrado y tuve que aumentarlo con un código no administrado de un C DLL (¡gracias a Marcus Heege por ayudarme con esto!), Pensé en cómo hacerlo Es más fácil implementar las dos DLL. Si esto fuera solo dos ensamblajes, podría haber usado ILmerge para empaquetarlos en un solo archivo. Pero esto no funciona para componentes de código mixto con archivos DLL administrados y no administrados.
Entonces, esto es lo que se me ocurrió para encontrar una solución:
Incluyo cualquier DLL que quiera implementar con el ensamblaje principal de mi componente como recursos integrados. Luego configuré un constructor de clases para extraer esas DLL como a continuación. La clase ctor se llama solo una vez dentro de cada AppDomain, por lo que es una sobrecarga insignificante, creo.
namespace MyLib
{
public class MyClass
{
static MyClass()
{
ResourceExtractor.ExtractResourceToFile("MyLib.ManagedService.dll", "managedservice.dll");
ResourceExtractor.ExtractResourceToFile("MyLib.UnmanagedService.dll", "unmanagedservice.dll");
}
...
En este ejemplo, incluí dos archivos DLL como recursos, uno es un código DLL no administrado y otro es un código administrado DLL (solo con fines de demostración), para mostrar cómo funciona esta técnica para ambos tipos de código.
El código para extraer las DLL en sus propios archivos es simple:
public static class ResourceExtractor
{
public static void ExtractResourceToFile(string resourceName, string filename)
{
if (!System.IO.File.Exists(filename))
using (System.IO.Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create))
{
byte[] b = new byte[s.Length];
s.Read(b, 0, b.Length);
fs.Write(b, 0, b.Length);
}
}
}
Trabajar con un ensamblado de código administrado como este es lo mismo de siempre, casi. Lo hace referencia (aquí: ManagedService.dll) en el proyecto principal de su componente (aquí: MyLib), pero establece la propiedad Copiar local en falso. Además, se vincula en la Asamblea como un Elemento existente y establece la Acción de compilación en Recurso incrustado.
Para el código no administrado (aquí: UnmanagedService.dll) solo tiene que vincular el DLL como un elemento existente y establecer la acción de compilación como recurso incrustado. Para acceder a sus funciones, use el atributo DllImport como de costumbre, p.
[DllImport("unmanagedservice.dll")] public extern static int Add(int a, int b);
¡Eso es! Tan pronto como cree la primera instancia de la clase con el ctor estático, las DLL incrustadas se extraerán en sus propios archivos y estarán listas para usar como si las implementara como archivos separados. Siempre que tenga permisos de escritura para el directorio de ejecución, esto debería funcionar bien para usted. Al menos para el código prototípico, creo que esta forma de implementación de ensamblaje único es bastante conveniente.
¡Disfrutar!
Utilice Fody.Costura nuget
Eso es !
Fuente: http://www.manuelmeyer.net/2016/01/net-power-tip-10-merging-assemblies/
Pruebe boxedapp ; Permite cargar todas las DLL de la memoria. Además, parece que incluso puedes incrustar .net runtime. Bueno para crear aplicaciones realmente independientes ...
Simplemente haga clic con el botón derecho en su proyecto en Visual Studio, elija Propiedades del proyecto -> Recursos -> Agregar recurso -> Agregar archivo existente ... e incluya el código a continuación en su App.xaml.cs o equivalente.
public App()
{
AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");
dllName = dllName.Replace(".", "_");
if (dllName.EndsWith("_resources")) return null;
System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
byte[] bytes = (byte[])rm.GetObject(dllName);
return System.Reflection.Assembly.Load(bytes);
}
Aquí está mi publicación original del blog: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-Assembly/
¿Has probado ILMerge? http://research.Microsoft.com/~mbarnett/ILMerge.aspx
ILMerge es una utilidad que se puede utilizar para fusionar múltiples ensamblados .NET en un solo ensamblaje. Está disponible gratuitamente para su uso en la página Herramientas y utilidades del Centro de desarrolladores de Microsoft .NET Framework.
Si está compilando el C++ DLL con el indicador /clr
(todo o parcialmente C++/CLI), entonces debería funcionar:
ilmerge /out:Composite.exe MyMainApp.exe Utility.dll
Sin embargo, no funcionará con un Windows ordinario (nativo) DLL.
Smart Assembly puede hacer esto y más. Si su dll tiene código no administrado, no le permitirá fusionar los dlls en un solo ensamblado, sino que puede incorporar las dependencias requeridas como recursos para su exe principal. Su otro lado, no es gratis.
Puede hacerlo manualmente incrustando dll en sus recursos y luego confiando en AppDomain's Assembly ResolveHandler
. Cuando se trata de dlls de modo mixto, encontré que muchas de las variantes y sabores del enfoque ResolveHandler
no funcionan para mí (todos los cuales leen bytes dll a la memoria y leen de él). Todos trabajaron para dlls administrados. Esto es lo que funcionó para mí:
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string assemblyName = new AssemblyName(args.Name).Name;
if (assemblyName.EndsWith(".resources"))
return null;
string dllName = assemblyName + ".dll";
string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);
using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
{
byte[] data = new byte[stream.Length];
s.Read(data, 0, data.Length);
//or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);
File.WriteAllBytes(dllFullPath, data);
}
return Assembly.LoadFrom(dllFullPath);
};
}
La clave aquí es escribir los bytes en un archivo y cargarlos desde su ubicación. Para evitar el problema del huevo y la gallina, debe asegurarse de declarar el controlador antes de acceder al ensamblado y de que no accede a los miembros del ensamblaje (o instanciar nada que tenga que ver con el ensamblaje) dentro de la parte de carga (resolución del ensamblaje). También tenga cuidado de asegurarse de que GetMyApplicationSpecificPath()
no sea un directorio temporal ya que otros archivos o usted mismo podría intentar borrar los archivos temporales (no es que se eliminen mientras su programa accede a la dll, pero al menos es una molestia. AppData es buena ubicación). También tenga en cuenta que debe escribir los bytes cada vez, no puede cargar desde la ubicación solo porque el dll ya reside allí.
Si el ensamblaje no está administrado por completo, puede ver esto enlace o esto sobre cómo cargar dichos archivos DLL.
Thinstall es una solución. Para una aplicación nativa de Windows, sugeriría incrustar el DLL como un objeto de recurso binario, luego extraerlo en tiempo de ejecución antes de que lo necesite.