Desplegando la solución C # con DLL nativa en un solo exe -- # camp Relacionados El problema

Deploying C# Solution with Native Dll into single EXE


3
vote

problema

Español

Tengo una solución C # Visual Studio 2012 que se basa en un DLL nativo que uso PineVoke para acceder. Cuando implemento la aplicación, tendré que asegurarme de que esta DLL esté en la carpeta de la aplicación.

¿Hay de todos modos puedo fusionar esta DLL en el ejecutable?

Tal vez como un recurso?

He oído hablar de Ilmerge, pero me lo dije, no puede hacer frente a código nativo.

Se apreciaría cualquier ayuda.

Original en ingles

I have A C# Visual Studio 2012 Solution that relies on a native dll that I use PInvoke to access. When I deploy the app I will have to ensure that this Dll is in the app folder.

Is there anyway I can merge this Dll into the executable?

perhaps as a resource?

I have heard of ILMerge but I am told it cant cope with native code.

Any help would be appreciated.

  
         
         

Lista de respuestas

6
 
vote
vote
La mejor respuesta
 

Puede crear una Paquete de configuración Proyecto con Visual Studio que implementa todos sus archivos en la ubicación correcta o use otro software de empaque de terceros (como Full InstallShield o alternativas )

Sin embargo, su pregunta me recuerda en la Open Hardware Monitor Monitor Donde incluyen controladores como recurso incrustado y extrajolos Cuando el usuario inicia la aplicación. Funciona así: han agregado WinRing0.sys y WinRing0x64.sys al proyecto y configure su accion de compilación a incorporado , luego tienen un método que extrae el conductor del recurso:

  private static bool ExtractDriver(string fileName) {   string resourceName = "OpenHardwareMonitor.Hardware." +     (OperatingSystem.Is64BitOperatingSystem() ? "WinRing0x64.sys" :      "WinRing0.sys");    string[] names =     Assembly.GetExecutingAssembly().GetManifestResourceNames();   byte[] buffer = null;   for (int i = 0; i < names.Length; i++) {     if (names[i].Replace('\', '.') == resourceName) {       using (Stream stream = Assembly.GetExecutingAssembly().         GetManifestResourceStream(names[i]))        {           buffer = new byte[stream.Length];           stream.Read(buffer, 0, buffer.Length);       }     }   }    if (buffer == null)     return false;    try {     using (FileStream target = new FileStream(fileName, FileMode.Create)) {       target.Write(buffer, 0, buffer.Length);       target.Flush();     }   } catch (IOException) {      // for example there is not enough space on the disk     return false;    }    // make sure the file is actually writen to the file system   for (int i = 0; i < 20; i++) {     try {       if (File.Exists(fileName) &&         new FileInfo(fileName).Length == buffer.Length)        {         return true;       }       Thread.Sleep(100);     } catch (IOException) {       Thread.Sleep(10);     }   }    // file still has not the right size, something is wrong   return false; }   

Están leyendo el recurso en un búfer, escriba ese tampón en el disco y espere hasta que el archivo haya sido enrojecido al disco.

 

You can create a Setup package project with Visual Studio that deploys all your files to the correct location or use other third party packaging software (like full InstallShield or alternatives)

However, your question reminds me on the Open Hardware Monitor project where they include drivers as embedded resource and extract them when the user starts the application. It works like this: they've added WinRing0.sys and WinRing0x64.sys to the project and set their Build Action to Embedded Resource, then they have a method that extracts the driver from the resource:

private static bool ExtractDriver(string fileName) {   string resourceName = "OpenHardwareMonitor.Hardware." +     (OperatingSystem.Is64BitOperatingSystem() ? "WinRing0x64.sys" :      "WinRing0.sys");    string[] names =     Assembly.GetExecutingAssembly().GetManifestResourceNames();   byte[] buffer = null;   for (int i = 0; i < names.Length; i++) {     if (names[i].Replace('\\', '.') == resourceName) {       using (Stream stream = Assembly.GetExecutingAssembly().         GetManifestResourceStream(names[i]))        {           buffer = new byte[stream.Length];           stream.Read(buffer, 0, buffer.Length);       }     }   }    if (buffer == null)     return false;    try {     using (FileStream target = new FileStream(fileName, FileMode.Create)) {       target.Write(buffer, 0, buffer.Length);       target.Flush();     }   } catch (IOException) {      // for example there is not enough space on the disk     return false;    }    // make sure the file is actually writen to the file system   for (int i = 0; i < 20; i++) {     try {       if (File.Exists(fileName) &&         new FileInfo(fileName).Length == buffer.Length)        {         return true;       }       Thread.Sleep(100);     } catch (IOException) {       Thread.Sleep(10);     }   }    // file still has not the right size, something is wrong   return false; } 

They're reading the resource into a buffer, write that buffer to disk and wait until the file has been flushed to disk.

 
 
1
 
vote

Mi solución es conceptualmente similar a la presentada por Wouter .

Es lo que usamos en nuestra propia aplicación, y podemos usar el modo nativo / mixto y C # DLLS todos incrustados en el mismo .exe.

Extrae las DLL en una directa temporada cada vez que se ejecuta la aplicación. Obviamente, es posible que no desee hacer esto en la versión de producción, donde las DLL serán estables; Puede elegir un directorio diferente allí (probablemente en algún lugar en% appData%). Sin embargo, usará un DLL existente con el mismo número de versión (por ejemplo, solo se hace la primera vez al abrir la aplicación varias veces entre el arranque la computadora).

ya que estamos haciendo

  AppDomain.CurrentDomain.AssemblyResolve += (sender, args)   

Esta función se llama donde quiera que el sistema intente resolver una DLL. Y ya que está initalizado en la clase de programa estático, todo funciona automágicamente.

programa.cs:

  namespace MyApp {     internal class Program     {         static Program()         {             LoadAssemblyResource.Initialize("MyApp");         }          //....     } }     

loadassemblyresource.cs

  namespace MyAppStartup {      public static class LoadAssemblyResource     {         private readonly static String _version_string =             Assembly.GetExecutingAssembly().GetName().Version.ToString();          private readonly static String _dll_path = Path.GetTempPath()             + "\MyApp\" + _version_string;          static public String last_error_msg = null;          public static bool WriteBytesToFile(string filename, byte[] bytes)         {             try             {                 var fs = new FileStream(filename, FileMode.Create, FileAccess.Write);                 fs.Write(bytes, 0, bytes.Length);                 fs.Close();                 return true;             }             catch (Exception e)             {                 Console.WriteLine("Writing file failed. Exception: {0}", e.ToString());             }             return false;         }          public static Assembly LoadUnsafe(String assembly_name, Byte[] assembly)         {             if (!Directory.Exists(_dll_path))             {                 Directory.CreateDirectory(_dll_path);                 Console.WriteLine("Created tmp path '" + _dll_path + "'.");             }              String fullpath = _dll_path + "\" + assembly_name;             if (!File.Exists(fullpath))             {                 Console.WriteLine("Assembly location: " + fullpath + ".");                 if (!WriteBytesToFile(fullpath, assembly))                      return null;             }              return Assembly.UnsafeLoadFrom(fullpath);         }          public static void Initialize(String exe_name)         {             AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>             {                 String assembly_name = new AssemblyName(args.Name).Name + ".dll";                 String resource_name = exe_name + "." + assembly_name;                  using (var stream =                      Assembly.GetExecutingAssembly().GetManifestResourceStream(resource_name))                 {                     if (stream == null)                         return null;                      Byte[] assembly_data = new Byte[stream.Length];                     stream.Read(assembly_data, 0, assembly_data.Length);                     try                     {                         Assembly il_assembly = Assembly.Load(assembly_data);                         return il_assembly;                     }                     catch (System.IO.FileLoadException ex)                     {                         // might have failed because it's an mixed-mode dll.                         last_error_msg = ex.Message;                     }                      Assembly mixed_mode_assembly = LoadUnsafe(assembly_name, assembly_data);                     return mixed_mode_assembly;                 }             };         }     }   

}

 

My solution is conceptually similar to the one presented by Wouter.

It's what we use in our own app, and we can use native/mixed-mode and c# dlls all embedded in the same .exe.

It extracts the dlls into a temp dir everytime the application is run. Obviously you might not want to do this in the production version, where the dlls will be stable; you might choose a different directory there (probably somewhere in %AppData%). It will use an existing dll with the same version number, though (e.g. it's only done the first time when opening the app multiple times between booting the computer).

Since we're doing

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) 

this function is getting called wherever the system tries to resolve a dll. And since it's initalised in the static Program class, it all works automagically.

Program.cs:

namespace MyApp {     internal class Program     {         static Program()         {             LoadAssemblyResource.Initialize("MyApp");         }          //....     } }   

LoadAssemblyResource.cs

namespace MyAppStartup {      public static class LoadAssemblyResource     {         private readonly static String _version_string =             Assembly.GetExecutingAssembly().GetName().Version.ToString();          private readonly static String _dll_path = Path.GetTempPath()             + "\\MyApp\\" + _version_string;          static public String last_error_msg = null;          public static bool WriteBytesToFile(string filename, byte[] bytes)         {             try             {                 var fs = new FileStream(filename, FileMode.Create, FileAccess.Write);                 fs.Write(bytes, 0, bytes.Length);                 fs.Close();                 return true;             }             catch (Exception e)             {                 Console.WriteLine("Writing file failed. Exception: {0}", e.ToString());             }             return false;         }          public static Assembly LoadUnsafe(String assembly_name, Byte[] assembly)         {             if (!Directory.Exists(_dll_path))             {                 Directory.CreateDirectory(_dll_path);                 Console.WriteLine("Created tmp path '" + _dll_path + "'.");             }              String fullpath = _dll_path + "\\" + assembly_name;             if (!File.Exists(fullpath))             {                 Console.WriteLine("Assembly location: " + fullpath + ".");                 if (!WriteBytesToFile(fullpath, assembly))                      return null;             }              return Assembly.UnsafeLoadFrom(fullpath);         }          public static void Initialize(String exe_name)         {             AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>             {                 String assembly_name = new AssemblyName(args.Name).Name + ".dll";                 String resource_name = exe_name + "." + assembly_name;                  using (var stream =                      Assembly.GetExecutingAssembly().GetManifestResourceStream(resource_name))                 {                     if (stream == null)                         return null;                      Byte[] assembly_data = new Byte[stream.Length];                     stream.Read(assembly_data, 0, assembly_data.Length);                     try                     {                         Assembly il_assembly = Assembly.Load(assembly_data);                         return il_assembly;                     }                     catch (System.IO.FileLoadException ex)                     {                         // might have failed because it's an mixed-mode dll.                         last_error_msg = ex.Message;                     }                      Assembly mixed_mode_assembly = LoadUnsafe(assembly_name, assembly_data);                     return mixed_mode_assembly;                 }             };         }     } 

}

 
 

Relacionados problema

701  Cómo convertir decimal a doblarse en C #  ( How to convert decimal to double in c sharp ) 
Quiero usar un Track-Bar para cambiar una opacidad double1 . Este es mi código: decimal trans = trackBar1.Value / 5000; this.Opacity = trans; Cuan...

107  ¿Cómo obtengo una lista distinta y ordenada de nombres de un DataQ usando LINQ?  ( How do i get a distinct ordered list of names from a datatable using linq ) 
Tengo un DataTable con una columna Name . Quiero generar una colección de los nombres únicos ordenados alfabéticamente. La siguiente consulta ignora la clá...

1563  Calcular el tiempo relativo en C #  ( Calculate relative time in c sharp ) 
Dado un valor específico double16 , ¿cómo mostrar el tiempo relativo, como: hace 2 horas hace 3 días hace un mes ...

1955  ¿Cómo calculo la edad de alguien en función de un cumpleaños tipo DateTime?  ( How do i calculate someones age based on a datetime type birthday ) 
Dado un Form5 que representa el cumpleaños de una persona, ¿cómo calculo su edad en años? ...

65  Punto flotante Número de análisis: ¿Hay un algoritmo de captura?  ( Floating point number parsing is there a catch all algorithm ) 
Una de las partes divertidas de la programación multicultural son los formatos de números. Los estadounidenses usan 10,000.50 los alemanes usan 10.000,50...

105  Temporizador confiable en una aplicación de consola  ( Reliable timer in a console application ) 
Soy consciente de que en .NET Hay tres tipos de temporizador (consulte Comparando las clases de temporizador en la biblioteca de clase de Framework ). H...

55  Comprimiendo / descomprimiendo carpetas y archivos  ( Compressing decompressing folders files ) 
¿Alguien sabe de una buena manera de comprimir o descomprimir archivos y carpetas en C # rápidamente? Manejo de grandes archivos podría ser necesario. ...

80  ¿Cómo imprimo un documento HTML de un servicio web?  ( How do i print an html document from a web service ) 
Quiero imprimir HTML desde un servicio web C #. El control del navegador web está exagerado, y no funciona bien en un entorno de servicio, ni funciona bien en...

141  Llenando un conjunto de datos o un DataTable desde un conjunto de resultados de consulta LINQ  ( Filling a dataset or a datatable from a linq query result set ) 
¿Cómo expone una consulta LINQ como un servicio web de ASMX? Por lo general, desde el nivel de negocios, puedo devolver un double20 998877766220 998877766...

65  Decodificación T-SQL FUNCIONES EN C # / VB.NET  ( Decoding t sql cast in c vb net ) 
Recientemente, nuestro sitio ha sido desalentado con el resurgimiento de la asprox botnet inyección de SQL Ataque. Sin entrar en detalles, el ataque inten...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos