2008-09-16 34 views
31

Tengo un programa Windows C# que usa un dll C++ para datos de E/S. Mi objetivo es implementar la aplicación como un único EXE.¿Cómo se puede combinar un archivo DLL de Windows C++ en un exe de aplicación C#?

¿Cuáles son los pasos para crear dicho ejecutable?

+0

Debe utilizar BoxedAppPacker o BoxedApp SDK. Debe ayudar. – MastAvalons

+1

Duplicado de http://stackoverflow.com/questions/666799/embedding-unmanaged-dll-into-a-managed-c-sharp-dll/11038376#11038376 –

Respuesta

14

individual Asamblea Despliegue de Código administrados y no administrados Domingo, 04 de febrero 2007

.NET desarrolladores aman implementación XCOPY. Y aman 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 algún código no administrado de una DLL de C (gracias a Marcus Heege por ayudarme con esto), pensé en cómo facilitar el despliegue de las dos DLL . Si esto fuera solo dos ensamblajes, podría haber usado ILmerge para empacarlos en un solo archivo. Pero esto no funciona para los componentes de código mixto con DLL administrados y no administrados.

Así tope aquí tienes lo que se le ocurrió una solución:

que incluyen lo DLL que desea implementar con mis component's conjunto principal como recursos incrustados. Luego configuré un constructor de clase para extraer esos archivos DLL como a continuación. El ctor de clase se llama solo una vez dentro de cada dominio de aplicación, así 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 he incluido dos DLL como recursos, uno de ellos una DLL de código no administrado, y uno de ellos un DLL de código administrado (sólo para fines de demostración), para mostrar, cómo esta técnica funciona para ambos tipos de código .

El código para extraer los archivos DLL en los archivos de su propio 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 conjunto de código administrado como este es el mismo de siempre - casi. Usted lo referencia (aquí: ManagedService.dll) en el proyecto principal de su componente (aquí: MyLib), pero establece la propiedad Copy Local en false. Además, se vincula en el conjunto como un elemento existente y establece la acción de compilación en el recurso incrustado.

Para el código no administrado (aquí: UnmanagedService.dll) solo vincula en la DLL como un elemento existente y establece la acción de compilación para el 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 todo! Tan pronto como cree la primera instancia de la clase con el ctor estático, las DLL incorporadas se extraen en sus propios archivos y están listas para usar como si las hubiera desplegado 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.

¡Disfrútalo!

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

+1

El enlace está muerto. Es por eso que debe ** siempre ** [citar las partes más relevantes de la página vinculada] (http://stackoverflow.com/help/how-to-answer) en lugar de publicar una respuesta de solo enlace. – BackSlash

0

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

+2

Thinstall es ridículamente costoso y tiene problemas con algunas instalaciones de Windows y extensiones de shell de terceros. lo usamos con éxito limitado para códigos que no son .Net, pero encontramos que ClickOnce y MSI instalan lo mejor para .Net. – user7116

+2

Si su instalación está buscando principalmente, recomendaría Inno Setup, dejamos InstallShield hace unos años y nunca miramos hacia atrás. http://www.innosetup.com/isinfo.php – titanae

1

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

ILMerge es una utilidad que se puede utilizar para unir varios ensamblados .NET en un solo ensamblaje. Está disponible de forma gratuita para su uso desde la página de Herramientas & en el Microsoft .NET Framework Developer Center.

Si usted 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 va a funcionar con un ordinario (nativo) de Windows DLL sin embargo.

+1

Bastante seguro requiere '/ clr: pure' o superior en la DLL. –

3

Probar boxedapp; permite cargar todas las DLL desde la memoria. Además, parece que incluso puedes incrustar el tiempo de ejecución .net. Bueno para crear aplicaciones realmente independientes ...

+0

great sdk. Yo también lo uso –

-2

PostBuild de Xenocode puede empaquetar administrado y no gestionado en un solo exe.

1

Simplemente haga clic derecho en su proyecto en Visual Studio, seleccione Propiedades del proyecto -> Recursos -> Agregar recurso -> Agregar archivo existente ... E incluya el código siguiente 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í es mi post original del blog: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/

+2

por favor no publique la misma publicación varias veces, especialmente si va a publicarla en preguntas muy antiguas. Si es la misma respuesta exacta que una publicación anterior, marque la pregunta como un duplicado. Si continúa publicando ese enlace de blog con el mismo texto que lo acompaña, podría atraer algunas banderas de spam. – Mat

+0

Ok ... Gracias. –

0

Smart Assembly puede hacer esto y mucho más. Si su dll tiene un código no administrado, no le permitirá fusionar los dlls en un único ensamblado, sino que puede incorporar las dependencias requeridas como recursos a su exe principal. Es flip-side, no es gratis.

Puede hacerlo manualmente insertando dll en sus recursos y luego confiando en el conjunto ResolveHandler de AppDomain. Cuando se trata de dlls de modo mixto, encontré que muchas de las variantes y los sabores del enfoque ResolveHandler no funcionan para mí (todos los cuales leen dll bytes a la memoria y leen). Todos trabajaron para dlls 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 la carga de su ubicación. Para evitar el problema del huevo y la gallina, debe asegurarse de declarar el controlador antes de acceder al ensamblaje y de no acceder a los miembros del ensamblaje (o crear una instancia de todo lo que tenga que ver con el ensamblaje) dentro de la pieza de carga (resolución de ensamblaje). Además, asegúrese de que GetMyApplicationSpecificPath() no sea un directorio temporal, ya que los archivos temporales pueden ser borrados por otros programas o por usted mismo (no es que se eliminen mientras su programa está accediendo al dll, pero al menos es una molestia). 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á completamente administrado, puede ver este link o this en cuanto a cómo cargar dichos archivos.

Cuestiones relacionadas