¿Es posible incrustar una DLL preexistente en un ejecutable C # compilado (para que solo tenga un archivo para distribuir)? Si es posible, ¿cómo podría uno hacerlo?
Normalmente, me gusta dejar las DLL fuera y hacer que el programa de instalación se encargue de todo, pero ha habido un par de personas en el trabajo que me han preguntado esto y, sinceramente, no lo sé.
Respuestas:
Recomiendo encarecidamente utilizar Costura.Fody : con mucho, la mejor y más fácil forma de integrar recursos en su ensamblaje. Está disponible como paquete NuGet.
Después de agregarlo al proyecto, incorporará automáticamente todas las referencias que se copian al directorio de salida en su ensamblaje principal . Es posible que desee limpiar los archivos incrustados agregando un objetivo a su proyecto:
También podrá especificar si desea incluir los pdb, excluir ciertos ensamblajes o extraer los ensamblajes sobre la marcha. Hasta donde sé, también se admiten ensamblajes no administrados.
Actualizar
Actualmente, algunas personas están tratando de agregar soporte para DNX .
Actualización 2
Para la última versión de Fody, necesitará tener MSBuild 16 (así Visual Studio 2019). Fody versión 4.2.1 hará MSBuild 15. (referencia: Fody solo es compatible con MSBuild 16 y superior. Versión actual: 15 )
fuente
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 siguiente código en su App.xaml.cs o equivalente.
Aquí está mi publicación original del blog: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/
fuente
bytes
es nulo, y si es así, devolver nulo allí. Es posible que el dll no esté en los recursos, después de todo. Dos: esto solo funciona si esa clase en sí misma no tiene un "uso" para nada de ese ensamblado. Para las herramientas de línea de comandos, tuve que mover mi código de programa real a un nuevo archivo, y hacer un pequeño programa principal nuevo que simplemente haga esto y luego llame al principal original en la clase anterior..dll
nombre contiene guiones (es decirtwenty-two.dll
), también se reemplazarán con un guión bajo (es decirtwenty_two.dll
). Puede cambiar esta línea de código a esto:dllName = dllName.Replace(".", "_").Replace("-", "_");
Si en realidad son ensamblados administrados, puede usar ILMerge . Para las DLL nativas, tendrá un poco más de trabajo por hacer.
Consulte también: ¿Cómo se puede combinar un dll de Windows C ++ en un exe de aplicación C #?
fuente
C++
en el enlace. ILMerge también funciona muy fácilmente para VB NET. Ver aquí https://github.com/dotnet/ILMerge . Gracias @ Shog9Sí, es posible combinar ejecutables .NET con bibliotecas. Hay varias herramientas disponibles para hacer el trabajo:
Además, esto se puede combinar con Mono Linker , que elimina el código no utilizado y, por lo tanto, hace que el ensamblaje resultante sea más pequeño.
Otra posibilidad es usar .NETZ , que no solo permite comprimir un ensamblaje, sino que también puede empaquetar los archivos DLL directamente en el exe. La diferencia con las soluciones mencionadas anteriormente es que .NETZ no las combina, permanecen ensamblados separados pero se empaquetan en un solo paquete.
fuente
ILMerge puede combinar ensamblajes en un ensamblaje único, siempre que el ensamblaje solo haya administrado código. Puede usar la aplicación de línea de comandos o agregar una referencia al exe y fusionar mediante programación. Para una versión GUI hay Eazfuscator , y también .Netz, los cuales son gratuitos. Las aplicaciones pagas incluyen BoxedApp y SmartAssembly .
Si tiene que fusionar ensamblados con código no administrado, sugeriría SmartAssembly . Nunca tuve problemas con SmartAssembly sino con todos los demás. Aquí, puede incorporar las dependencias requeridas como recursos a su exe principal.
Puede hacer todo esto manualmente sin tener que preocuparse si el ensamblaje se administra o en modo mixto integrando dll en sus recursos y luego confiando en el ensamblado de AppDomain
ResolveHandler
. Esta es una solución integral al adoptar el peor de los casos, es decir, ensamblajes con código no administrado.La clave aquí es escribir los bytes en un archivo y cargarlos desde su ubicación. Para evitar problemas con el 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 crear una instancia de algo que tenga que ver con el ensamblaje) dentro de la parte de carga (resolución del ensamblaje). También tenga cuidado de asegurarse de
GetMyApplicationSpecificPath()
que no haya ningún 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 bueno 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í.Para los archivos DLL administrados, no necesita escribir bytes, sino cargarlos directamente desde la ubicación del archivo DLL, o simplemente leer los bytes y cargar el ensamblado desde la memoria. Así o más o menos:
Si el ensamblaje no está administrado por completo, puede ver este enlace o este sobre cómo cargar dichos archivos DLL.
fuente
El extracto de Jeffrey Richter es muy bueno. En resumen, agregue la biblioteca como recursos integrados y agregue una devolución de llamada antes que cualquier otra cosa. Aquí hay una versión del código (que se encuentra en los comentarios de su página) que puse al comienzo del método Main para una aplicación de consola (solo asegúrese de que cualquier llamada que use la biblioteca esté en un método diferente al Main).
fuente
Para ampliar en la respuesta de @ Bobby arriba. Puede editar su .csproj para usar IL-Repack para empaquetar automáticamente todos los archivos en un solo ensamblaje cuando compile.
Install-Package ILRepack.MSBuild.Task
Aquí hay una muestra simple que combina ExampleAssemblyToMerge.dll en la salida del proyecto.
fuente
Puede agregar las DLL como recursos incrustados y luego hacer que su programa las descomprima en el directorio de la aplicación al inicio (después de verificar si ya están allí).
Sin embargo, los archivos de instalación son tan fáciles de hacer que no creo que valga la pena.
EDITAR: Esta técnica sería fácil con los ensamblados .NET. Con archivos DLL que no sean .NET sería mucho más trabajo (tendrías que averiguar dónde desempaquetar los archivos y registrarlos, etc.).
fuente
Otro producto que puede manejar esto con elegancia es SmartAssembly, en SmartAssembly.com . Este producto, además de fusionar todas las dependencias en una sola DLL, (opcionalmente) ofuscará su código, eliminará metadatos adicionales para reducir el tamaño del archivo resultante, y también puede optimizar el IL para aumentar el rendimiento del tiempo de ejecución.
También hay algún tipo de función de manejo / informe de excepción global que agrega a su software (si lo desea) que podría ser útil. Creo que también tiene una API de línea de comandos para que pueda hacerla parte de su proceso de compilación.
fuente
Ni el enfoque de ILMerge ni el manejo de Lars Holm Jensen del evento AssemblyResolve funcionarán para un host de complementos. Digamos que el ejecutable H carga el ensamblaje P dinámicamente y accede a él a través de la interfaz IP definida en un ensamblaje separado. Para incrustar IP en H, se necesitará una pequeña modificación al código de Lars:
El truco para manejar los intentos repetidos de resolver el mismo ensamblado y devolver el existente en lugar de crear una nueva instancia.
EDITAR: para que no estropee la serialización de .NET, asegúrese de devolver un valor nulo para todos los ensamblados que no estén integrados en el suyo, por lo que el comportamiento estándar es el predeterminado. Puede obtener una lista de estas bibliotecas al:
y solo devuelve nulo si el ensamblado pasado no pertenece
IncludedAssemblies
.fuente
.NET Core 3.0 admite de forma nativa la compilación en un único .exe
La función se habilita mediante el uso de la siguiente propiedad en su archivo de proyecto (.csproj):
Esto se hace sin ninguna herramienta externa.
Vea mi respuesta a esta pregunta para más detalles.
fuente
Puede parecer simplista, pero WinRar ofrece la opción de comprimir un montón de archivos en un ejecutable autoextraíble.
Tiene muchas opciones configurables: icono final, extraer archivos a la ruta dada, archivo para ejecutar después de la extracción, logotipo / textos personalizados para la ventana emergente que se muestra durante la extracción, ninguna ventana emergente, texto del acuerdo de licencia, etc.
Puede ser útil en algunos casos .
fuente
Uso el compilador csc.exe llamado desde un script .vbs.
En su script xyz.cs, agregue las siguientes líneas después de las directivas (mi ejemplo es para Renci SSH):
Las etiquetas ref, res e ico serán recogidas por el script .vbs a continuación para formar el comando csc.
Luego agregue el llamador de resolución de ensamblaje en Main:
... y agregue el resolutor en algún lugar de la clase:
Nombro el script vbs para que coincida con el nombre de archivo .cs (por ejemplo, ssh.vbs busca ssh.cs); esto hace que ejecutar el script muchas veces sea mucho más fácil, pero si no eres un idiota como yo, entonces un script genérico podría recoger el archivo .cs de destino con una función de arrastrar y soltar:
fuente
Es posible, pero no tan fácil, crear un ensamblado híbrido nativo / administrado en C #. Si utilizabas C ++, sería mucho más fácil, ya que el compilador de Visual C ++ puede crear ensamblajes híbridos tan fácilmente como cualquier otra cosa.
A menos que tenga un requisito estricto para producir un ensamblaje híbrido, estoy de acuerdo con MusiGenesis en que esto realmente no vale la pena hacerlo con C #. Si necesita hacerlo, quizás busque cambiar a C ++ / CLI.
fuente
En general, necesitaría algún tipo de herramienta posterior a la compilación para realizar una fusión de ensamblaje como la que está describiendo. Existe una herramienta gratuita llamada Eazfuscator (eazfuscator.blogspot.com/) que está diseñada para la manipulación de bytecode que también maneja la fusión de ensamblajes. Puede agregar esto en una línea de comando posterior a la compilación con Visual Studio para fusionar sus ensamblajes, pero su kilometraje variará debido a los problemas que surgirán en cualquier escenario de fusión de ensamblajes no trival.
También puede verificar si la creación hace que NANT tenga la capacidad de fusionar ensamblajes después de la construcción, pero no estoy lo suficientemente familiarizado con NANT para decir si la funcionalidad está integrada o no.
También hay muchos complementos de Visual Studio que realizarán la fusión de ensamblajes como parte de la construcción de la aplicación.
Alternativamente, si no necesita que esto se haga automáticamente, hay una serie de herramientas como ILMerge que fusionarán los ensamblados .net en un solo archivo.
El mayor problema que he tenido con la fusión de ensamblajes es si usan espacios de nombres similares. O peor, haga referencia a diferentes versiones de la misma dll (mis problemas fueron generalmente con los archivos dll NUnit).
fuente