[SOLUCIONADO] Ejecutar recurso embedido del programa?

Iniciado por Eleкtro, 17 Enero 2013, 07:26 AM

0 Miembros y 1 Visitante están viendo este tema.

Eleкtro

Tengo 4 recursos en mi APP:
Splitty_WinRar.exe
Splitty_7zip.exe
Default.SFX
rarreg.key


Al compilar el proyecto, los recursos se copian a la carpeta:
...\Debug\Resources\APPS\*
Y para ejecutar los exe debo usar un:
process.Start(".\Resources\APPS\Programa.exe")

* Lo que quiero es no depender de esa carpeta llena de recursos.

He intentado cambiar el tipo de recurso a "Resource", "Embeded resource", "Content", pero al hacerlo no encuentro la forma de ejecutar los EXE porque no encuentra la ruta (Están embedidos dentro del EXE) La ruta que utilizo en la CMD es la del directorio de trabajo principal:
process.Start(".\Programa.exe")

Y también he probado a juntar los recursos con .NET Shrink e ILMerge, pero solo me permite juntar recursos en formato DLL...

¿Alguna ayuda?

EDITO: Sería factible usar un Joiner para esto? :-/








kub0x

Lo que pides es embedir un ensamblado .NET dentro de otro. La clase Assembly te permite cargar ensamblados .NET en la memoria del programa y ejecutarlos en tiempo de ejecucción, sin tener que ejecutarlo en un proceso separado. Puedes escoger como vas a cargar el ensamblado, si está fuera del proyecto lo cargas como un archivo indicando la ruta. Lo normal sería añadirlo a los recursos del programa y cargarlo dinámicamente desde ahí mediante un Array de Bytes. El resto del trabajo es pan comido, solo tienes que llamar a su método de entrada, es decir, a Main().

Te dejo un fragmento de code, si lo quieres probar inicia un proyecto en modo consola y lo copias tal cual pero cambiando el path del ensamblado que quieres cargar :)

Código (VB.NET) [Seleccionar]

Imports System.Reflection
Module Module1

    Sub Main()
'Cargamos el ensamblado desde un archivo
'En tu caso podrias hacerlo desde los recursos del proyecto
        Dim Ensamblado As Assembly = Assembly.LoadFile("C:\POC.exe")
'Apuntamos hacia el método de entrada, método principal que será llamado al ejecutarse el ensamblado
        Dim EntryPoint As MethodInfo = Ensamblado.EntryPoint
'Lo invocamos pasandole un Array de Strings vacío ya que éste indica los Argumentos (args) y no le quiero pasar ninguno
        EntryPoint.Invoke(Nothing, New Object() {New String() {}})
'Se ejecuta la PoC :)
    End Sub

End Module


Saludos!
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


Eleкtro

#2
Tus respuestas son alucinantes Kubox (y dificiles),
pero de poco me va a servir, porque lo que quiero ejecutar es el Winrar y el 7zip, que no son ensamblados .NET... xD

A ver, lo voy a explicar de otra manera...

Hice una función para ejecutar procesos, con argumentos:

Código (vbnet) [Seleccionar]
   Private Function Run_Process(ByVal Process_Name As String, Optional Process_Arguments As String = Nothing, Optional Read_Output As Boolean = False, Optional Process_Hide As Boolean = False)
           Dim My_Process As New Process()
           Dim My_Process_Info As New ProcessStartInfo()
           bla bla bla
           bla bla
           My_Process.Start() ' Run the process NOW
   end function


Y entonces en el código hago por ejemplo esto:
Código (vbnet) [Seleccionar]
Run_Process(".\Apps\Splitty_winrar.exe", argumentos, false)

Como ves uso la ruta ".\apps\" así que la estructura del directorio de mi programa debe ser así:

.\Mi_Programa.exe
.\apps
.\apps\splitty_winrar.exe


Yo lo que quiero es embedir el "splitty_winrar.exe" dentro de "mi_programa.exe", para poder usar la función sin depender de la carpeta "apps", llamando al "splitty_winrar.exe" que está embedido dentro de mi programa.así:
Código (vbnet) [Seleccionar]
Run_Process("Splitty_winrar.exe", argumentos, false)

Es decir, quiero que todo quede en un solo ejecutable distribuible, sin la carpeta "apps", y pudiendo usar la función.

Eso ya lo he intentado, el EXE queda dentro de mi programa, como un recurso más, pero no funciona la orden, no encuentra el executable "splitty_winrar.exe".

Ni siquiera sé si esto es posible hacerlo...

¿Alguna otra ayuda?








Danyfirex

También podrías meterlos como una cadena y correrlos on the fly con algun "RunPE" que acepte parámetros. Bueno creo que eso se podria.  ;D

$Edu$

Me parece que tenes que sacarlo del recurso y luego ejecutarlo si o si, no puedes hacer eso de que se ejecute directamente del recurso, por lo menos yo nunca lo he hecho.
Por eso que mucha gente usa el directorio %temp% para dejar cosas ahi temporales y luego se borran cuando terminas tu app.

kub0x

Advertencia - mientras estabas escribiendo, fueron publicadas 2 respuestas. Probablemente desees revisar tu mensaje.

Ahí me has pillado pues no he tenido experiencia en lo que se refiere a cargar código no administrado desde .NET . Se me ocurre que puedes embedir el ejecutable dentro de la lista de recursos y desde ahí crear un archivo temporal en el que escribes los Bytes del ejecutable embedido en recursos, ya que My.Resources."recurso" nos devolvería un Array de Bytes.

Luego cuando cierras la App podrías llamar a una rutina que limpiara esos archivos temporales de la ruta donde los creaste, o bien, podrías eliminarlos cuando el proceso temporal finalice. A ver si alguien nos da algun consejo más práctico de como implementar esto.

Lo que hago a continuación es cargar el TCPOptimicer desde un Array de Bytes de la lista de recursos. Creo un archivo temporal de éste, lo inicializo mediante la clase Process() y asocio el evento Exited de Process() a un método que será llamado cuando el archivo sea cerrado. Dentro de este método se ejecutará la instrucción de borrado del archivo temporal, de esta manera te libras del Process.WaitForExit(), recuerda, queremos rendimiento en nuestra aplicación.

Código (VB.NET) [Seleccionar]

Imports System.IO
Module Module1
  Dim ExePath As String = "C:\TempTCPOptimicer.exe"
  Sub Main()
        If Not File.Exists(ExePath) Then
'Obtenemos los Bytes del archivo a través de la lista de recursos
        Dim Buffer As Byte() = My.Resources.TCPOptimizer
'Creamos un nuevo ejecutable en el que introduciremos los Bytes del archivo
        Dim Fs As New FileStream(ExePath, FileMode.Create, FileAccess.Write)
        Fs.Write(Buffer, 0, Buffer.Length)
        Fs.Close()
'Ejecutamos el proceso temporal
        Dim p As Process = Process.Start(ExePath)
'Activamos el evento Exited, que se encargará de manejar el cierre de la aplicación
        p.EnableRaisingEvents = True
'Asociamos el evento Exited al método FileExitedEvent
        AddHandler p.Exited, AddressOf FileExitedEvent
'No queremos que se cierra la instancia de la consola
        Else
        Console.WriteLine("El Archivo temporal {0} ya existe",ExePath)
        End If
     Console.Read()
    End Sub

    Private Sub FileExitedEvent(ByVal sender As Object, ByVal e As EventArgs)
'Si has llegado hasta aquí es que el proceso finalizó
'Procedemos a eliminar el archivo temporal del disco
        File.Delete(ExePath)
    End Sub
End Module


Saludos!
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


seba123neo

los cargas como recursos, y cuando lo quieras usar los escribis al disco y ejecutas, asi de facil.

en ves de hacerlo a la carpeta temp, podes ponerlos en la carpeta de appdata de tu aplicacion (por las dudas tengas problema de permisos).

una ves que ya los pasas a esa carpeta no hace falta que lo pases de nuevo, para eso deberias chequear si existe antes de ecribirlo al disco de esa forma solo lo harias una sola ves.
La característica extraordinaria de las leyes de la física es que se aplican en todos lados, sea que tú elijas o no creer en ellas. Lo bueno de las ciencias es que siempre tienen la verdad, quieras creerla o no.

Neil deGrasse Tyson

Eleкtro

@Seba

Te refieres a la carpeta de appdata donde se genera el "user.config"?
Me gustaría hacer las cosas bien, pero creo que el nombre que se genera es aleatorio, como por ejemplo ".\roaming\Programa.exe_Url_ktb5duwkcuyoinv5ivsuakbcdmye00nf\user.config", ¿entonces como obtengo la ruta? ni siquiera sé si ese número es una GUID única, o que es.




@Kubox

Código (vbnet) [Seleccionar]
Dim Buffer As Byte() = My.Resources.Splitty_7zip
Dim Fs As New IO.FileStream(TempDir & "Splitty_7zip.exe", IO.FileMode.Create, IO.FileAccess.Write)
Fs.Write(Buffer, 0, Buffer.Length)
Fs.Close()


Te lo digo muy en serio, eres mi pu** ídolo, ¿diosss pero como lo haces para resolverlo todo!?,
PD: Algunos no tenemos la suerte de aprender programación con un profesor en la uni :(.

Desde luego eso de sacar los bytes va para mi colección de snippets/apuntes xD

Un saludo!








seba123neo

Cita de: EleKtro H@cker en 17 Enero 2013, 19:44 PM
Te refieres a la carpeta de appdata donde se genera el "user.config"?
Me gustaría hacer las cosas bien, pero creo que el nombre que se genera es aleatorio, como por ejemplo ".\roaming\Programa.exe_Url_ktb5duwkcuyoinv5ivsuakbcdmye00nf\user.config", ¿entonces como obtengo la ruta? ni siquiera sé si ese número es una GUID única, o que es.

ahi guardan los datos y configuraciones las aplicaciones, por ejemplo, firefox guarda todo ahi.

asi lo obtenes:
Código (vbnet) [Seleccionar]
MsgBox(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData))

y yo no veo ninguno con guid.

La característica extraordinaria de las leyes de la física es que se aplican en todos lados, sea que tú elijas o no creer en ellas. Lo bueno de las ciencias es que siempre tienen la verdad, quieras creerla o no.

Neil deGrasse Tyson

Eleкtro

#9
Lo de obtener la ruta de APPDATA, y que los programas (suelen) guardan sus datos ahí, ya lo sabía, pero te lo agradezco.

Lo que pasa es que todos los programas que yo compilo (con settings) generan una carpeta en Local con una GUID o algo que parece ser una GUID, como en este ejemplo:
C:\Users\Administrador\AppData\Local\Microsoft\PlayDir.exe_Url_lnflzfdwlfhy5awswiu4l03ntux3k2vh\1.0.0.0\user.config

por eso me parecía impredecible saber el nombre de esa carpeta a menos que hubiera algún método para obtener esa guid... pero por lo que dices parece que no xD.
No sé, quizas es cosa del VS2012...

EDITO: O del ILMerge o el .Net Shrink, ahora que lo pienso...

¿En la IDE se puede cambiar la ruta donde se almacena el archivo de configuración para quitarle la GUID?

Un saludo!