¿Cómo se puede fusionar una dll de windows de C++ en una aplicación exe de C#?


Tengo un programa de Windows C# que utiliza una dll de C++ para e/s de datos. Mi objetivo es implementar la aplicación como un solo EXE.

¿Cuáles son los pasos para crear un ejecutable de este tipo?

 32
Author: Noah, 2008-09-16

8 answers

Implementación de Ensamblado Único de Código Administrado y No Administrado Domingo, 4 de febrero de 2007

A los desarrolladores de.NET les encanta la implementación de XCOPY. Y les encantan los componentes de ensamblaje individuales. 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. Así que cuando recientemente tuve que desarrollar un componente de código administrado y tuve que aumentarlo con un código no administrado de una DLL C (thx a Marcus Heege por ayudarme ¡con esto!), pensé en cómo hacer más fácil el despliegue de los 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 DLL administrados y no administrados.

Así que he aquí lo que se me ocurrió para una solución:

Incluyo las DLL que quiero implementar con el ensamblaje principal de mis componentes como recursos incrustados. Luego configuré un constructor de clase para extraer esos archivos DLL como a continuación. El la clase ctor se llama solo una vez dentro de cada AppDomain, por lo que creo que es una sobrecarga neglible.

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 DLL como recursos, uno es una DLL de código no administrado y otro es una DLL de código administrado (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 archivos propios 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. Usted referencia (aquí: ManagedService.dll) en su proyecto principal de componentes (aquí: MyLib), pero establezca la propiedad Copiar local en false. Además, se enlaza en el ensamblado como un Elemento Existente y se establece la Acción de compilación en Recurso incrustado.

Para el código no administrado (aquí: UnmanagedService.dll) simplemente se enlaza en el DLL como un Elemento Existente y se establece la Acción de compilación en Recurso Incrustado. Para acceder a sus funciones utilice el atributo DllImport como de costumbre, por ejemplo

[DllImport("unmanagedservice.dll")] public extern static int Add(int a, int b);

Eso es todo! Tan pronto como crea la primera instancia de la clase con el ctor estático las DLL incrustadas se extraen en archivos propios y están listas para usar como si las desplegara como archivos separados. Mientras 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 ensamblado único es bastante conveniente.

Disfrute!

Http://weblogs.asp.net/ralfw/archive/2007/02/04/single-assembly-deployment-of-managed-and-unmanaged-code.aspx

 16
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-28 21:26:32

Try boxedapp; permite cargar todas las DLL de la memoria. Además, parece que incluso puede incrustar. net runtime. Bueno para crear una aplicaciones realmente independientes...

 3
Author: CharlesB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-23 09:38:22

¿Has probado ILMerge? http://research.microsoft.com / ~ mbarnett / ILMerge. aspx

ILMerge es una utilidad que se puede usar para combinar múltiples ensamblados.NET en un solo ensamblado. Está disponible gratuitamente para su uso en la página Herramientas y Utilidades en el Centro de Desarrolladores de Microsoft. NET Framework.

Si está construyendo la DLL de C++ con la bandera /clr (todo o parcialmente C++ / CLI), entonces debería funcionar:

ilmerge /out:Composite.exe MyMainApp.exe Utility.dll

No funcionará con un ordinario (nativo) DLL de Windows sin embargo.

 1
Author: Raithlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 13:59:28

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 incluye el siguiente código en tu 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 entrada de blog original: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly /

 1
Author: Lars Holm Jensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-15 18:25:39

Use Fody.Costura nuget

  1. Abra su solución -> Proyecto - > Administrar paquetes Nuget
  2. Busca Fody.Costura
  3. Compilatu proyecto.

¡Eso es !

Fuente: http://www.manuelmeyer.net/2016/01/net-power-tip-10-merging-assemblies /

 1
Author: automan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-30 20:32:10

Thinstall es una solución. Para una aplicación nativa de Windows, sugeriría incrustar el DLL como un objeto de recurso binario, y luego extraerlo en tiempo de ejecución antes de que lo necesite.

 0
Author: titanae,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 13:40:44

Smart Assembly puede hacer esto y más. Si su dll tiene código no administrado, no le permitirá fusionar las DLL en un solo ensamblado, sino que puede incrustar las dependencias requeridas como recursos en su exe principal. Su otro lado, no es libre.

Puede hacer esto manualmente incrustando dll en sus recursos y luego confiando en el Ensamblado de AppDomain ResolveHandler. Cuando se trata de dlls de modo mixto, encontré que muchas de las variantes y sabores de ResolveHandler no funcionan para mí (todos los cuales leen dll bytes a la memoria y leer de ella). Todos trabajaban para dll gestionados. 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 de la gallina y el huevo, debe asegurarse de declarar el controlador antes de acceder al ensamblado y que no accede a los miembros del ensamblado (o instanciar nada que tenga que lidiar con el ensamblado) dentro de la parte de carga (resolución del ensamblado). También tenga cuidado de asegurarse de GetMyApplicationSpecificPath() no es cualquier temp directorio puesto que los archivos temporales se podrían intentar conseguir borrados por otros programas o por usted mismo (no que conseguirá suprimido mientras que su programa está accediendo al dll, pero por lo menos su una molestia. AppData es buena ubicación). También tenga en cuenta que usted tiene que escribir los bytes cada vez, usted no puede cargar desde la ubicación solo 'porque el dll ya reside allí.

Si el ensamblado no está completamente administrado, puede ver este enlace o este en cuanto a cómo cargar tales archivos DLL.

 0
Author: nawfal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:32:23

PostBuild de Xenocode puede empaquetar tanto administrado como sin cambiar en un solo exe.

 -2
Author: Joel Lucsy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-10 19:58:15