Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   API de Windows (https://www.clubdelphi.com/foros/forumdisplay.php?f=7)
-   -   Enviar "parámetro" a una aplicación ya abierta. (https://www.clubdelphi.com/foros/showthread.php?t=94233)

MaxiDucoli 09-10-2019 03:17:45

Enviar "parámetro" a una aplicación ya abierta.
 
Hola, buenas noches.
Estoy tratando de hacer algo muy difícil para mi entender de Delphi.
Lo que pretendo hacer es una aplicación tipo "mensajeador" que iría buscando los HANDLE de ventanas externas y mediante PostMessage (Lo hago así por que de otra manera no sé hacerlo) enviarle o eventos de teclado o bien cerrar las ventanas o traerlas al frente.

Mi problemas por ahora es que en un evento no me envía o no lo envío yo bien a un evento de la tecla espacio a un programa previamente abierto con mi aplicación.
Les paso a explicar a ver si me entienden:

Abro mi aplicación, esta lanza un programa externo de linea de comandos (FFPLAY.EXE) y ejecuta un video, cuando el video se cierra o lo cierro presionando una tecla, inmediatamente arranca otro programa externo que quedaría "de fondo" pasando música (Fmedia.exe) y además lanza un programa más que queda como pantalla principal (EmulationStation).

Hasta ahí todo bien. Esta aplicación se que de fondo esperando que se le envíen mensajes con otra aplicación que se ejecutaría cuando el usuario lo requiera, que le envía un código + una linea de comandos que se vería así:

EMUamiga||"D:\RetroLife\emulators\amiga\launcher.exe -config:floppy-drive-count=1 "d:\RetroLife\roms\amiga\GalaxyBlast_v1.1.zip"||

Hasta ahí todo va bien, funciona a la perfección.
El problema viene ahora.

Ese código de arriba lo proceso con una aplicación también mia llamada RELExecutor.exe que le envía los mensajes a la primer aplicación hasta no necestar más de RELExecutor.exe, y cerrarlo.

Yo necesito enviar a la aplicación Fmedia.exe un evento de teclado que sería la barra espaciadora presionada, para que este quede en PAUSA, con la línea de comandos de allá arriba (sin el EMUamiga y los ||) ejecuto el emulador de CommodoreAmiga y una vez que se me cierre el emulador, volver a enviar la barra espaciadora para quitar la PAUSA,

Bueno, todo este proceso de poner la PAUSA, cerrar el RLExecutor.exe y quitar la PAUSA no me funciona en este código que les voy a poner por acá.

Alguien podría darle una mirada y decirme qué puedo agregarle o por qué no me funciona, por favor?

Muchas gracias!!!!!

Código Delphi [-]
unit RetroLauncher;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, MisFunciones, jpeg, Vcl.ExtCtrls,
  JvExExtCtrls, JvImage, shellapi, MMSYSTEM, Vcl.MPlayer,strutils, JvBackgrounds;

type
  TFrmLauncher = class(TForm)
    Timer1: TTimer;
    Splash: TJvBackground;
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormDestroy(Sender: TObject);
    procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;
    procedure LoadIMG (Splash : TJvBackGround;Ruta:String);
  private
    { Private declarations }
  public
    { Public declarations }

  end;




var
  FrmLauncher: TFrmLauncher;
  contador, contador2 : integer;
  LAUNCHERPATH : String;
  HWindow : HWND;



implementation

{$R *.dfm}

procedure TFrmLauncher.LoadIMG (Splash : TJvBackGround;Ruta:String);
begin
 Splash.Image.Picture.LoadFromFile(ruta); // Carga una imagen que se le envía mediante los mensajes de RELExecutor.exe
end;

procedure TFrmLauncher.FormClose(Sender: TObject; var Action: TCloseAction);
var
H, J : HWND;
begin

//AL CERRAR LA APLICACION, CERRAMOS FMEDIA Y RELEXECUTOR SI ES QUE SE ESTAN EJECUTANDO.

H := FindWindowExtd('fmedia.exe');
J := FindWindowExtd('RLExecutor');

if IsWindow(H) then
begin
PostMessage(H, WM_CLOSE, 0, 0);
end;

if IsWindow(J) then
begin
PostMessage(J, WM_CLOSE, 0, 0);
end;


end;

procedure TFrmLauncher.FormCreate(Sender: TObject);
var
Fondo : TPicture;
begin
FrmLauncher.Width := Screen.Width;
FrmLauncher.Height := Screen.Height;
contador := 0;
contador2 := 0;
Timer1.Enabled := true;
end;

procedure TFrmLauncher.FormDestroy(Sender: TObject);
var
H : HWND;
begin

H := FindWindowExtd('fmedia.exe');

if IsWindow(H) then
begin
PostMessage(H, WM_CLOSE, 0, 0);
end;


end;

procedure TFrmLauncher.FormResize(Sender: TObject);

begin
LAUNCHERPATH := ExtractFilePath(Application.ExeName);
Splash.Image.Picture.LoadFromFile(LauncherPath + '\Launcher\RLLogo.jpg' ) // CARGAMOS IMAGEN DESDE RELEXECUTOR.EXE
end;

procedure TFrmLauncher.FormShow(Sender: TObject);
begin
//MUSICPATH := ExtractFilePath(Application.ExeName) + '\music\';
end;

procedure TFrmLauncher.Timer1Timer(Sender: TObject);
var
i : integer;
Lista : TStringList;
Ruta,ffplay,Fmedia : String;
begin
Ruta := ExtractFilePath(Application.ExeName) + 'music\';
ffplay := '"' +LAUNCHERPATH + 'Launcher\ffplay.exe' + '"';
Inc(Contador);
if contador = 5 then
begin
Lista := TStringList.Create;

FindFiles(Ruta,'*.*',false,Lista);
// EJECUTAMOS EL VIDEO Y ESPERAMOS A QUE TERMINE EL PROCESO PARA PODER CONTINUAR.
  if EjecutarYEsperar (LAUNCHERPATH + 'Launcher\ffplay.exe -fs -autoexit -exitonkeydown -exitonmousedown -infbuf ' +
  '"' + LAUNCHERPATH + '\intro\intro.mp4"',SW_HIDE)= 0 then
  begin
  //  Timer1.Enabled := False;
  //Timer1.Enabled := True;
  Randomize;
  i := Random(Lista.Count - 1 );
  Ruta := LAUNCHERPATH + 'Launcher\playlist.m3u';
  Fmedia := ExtractFilePath(Application.ExeName) + 'tools\fmedia\fmedia.exe';
  Lista.SaveToFile(Ruta);

  //Ruta :='"' + Lista[i] + '"';

  lista.Free;


// COMO YA TERMINO EL VIDEO EJECUTAMOS EL PROGRAMA PARA QUE QUEDE DE FONDO TOCANDO MUSICA.

  ShellExecute(0,nil, PWideChar(Fmedia),
  PWideChar(' --random "' + Ruta + '"' ),PWIDECHAR(ExtractFilePAth(Fmedia)),SW_MINIMIZE);


// EJECUTAMOS EL PROGRAMA PRINCIPAL Y ESPERAMOS A QUE TERMINE.
  if EjecutarYEsperar (LAUNCHERPATH + '\RLLauncher.bat',SW_NORMAL) = 0 then
  begin
//  Timer1.Enabled := False;
  FrmLauncher.Close;
  //keybd_event(VK_SPACE,0,0,0);
//  CloseWindow(H);
  end;
        End else
        Begin
        ShowMessage('RetroLife: - No RLLauncher.bat present');
      End;
//keybd_event(
end;
//H := FindWindowByName(
end;





// PROCEDIMIENTO QUE RECIBE LOS MENSAJES DE LA OTRA APLICACION (RLEXECUTOR.EXE)
procedure TFrmLauncher.WMCopyData(var Msg: TWMCopyData);
var
MESSG,LoadIMGs,CMDLN,EMULATOR : String;
WindowLauncher,WindowExecutor, WindowFrontEnd : HWND;
TerminarVuelta : integer;
CONST RUTA = '/RetroLife\LaunchIMGS\';
begin
TerminarVuelta := 1;
MESSG := '';
  MESSG := PChar(Msg.CopyDataStruct.lpData); // MENSAJE RECIBIDO
  Msg.Result := 1; //Valor de respuesta para indicar que se ha
                  //recibido correctamente la información
//  ShowMessage(MESSG);
//  MessageDlg ('Mensaje recibido correctamente de aplicación externa.',
//      mtInformation, [mbok], 0);
LoadIMGs := ExtractTextBetween(MESSG,'|','|'); // CARGAMOS UNA IMAGEN COMO FONDO DE LA APLICACION.

//if AnsiContainsText(MESSG,'LineaDeComando') then CMDLN := ExtractTextBetween(MESSG,'||','||');

if AnsiContainsText(MESSG,'CONSOLA') then
begin
  LoadIMG(Splash,RUTA + LowerCase(LoadIMGs) + '.jpg'); //CARGAMOS LA IMAGEN
end;


//ACA VIENE EL CODIGO QUE NO ME ESTARIA FUNCIOANADO.
      if AnsiContainsText(MESSG,'EMUamiga') then
       begin
//             MensajeFMedia('fmedia.exe');
              CMDLN := ExtractTextBetween(MESSG,'||','||');

              if EjecutarYPrimerPlano(CMDLN,SW_NORMAL,'FS-UAE') = 0 then // EJECUTAMOS EL PROGAMA Y ESPERAMOS A QUE TERMINE
              begin

              //MensajeFMedia('fmedia.exe');


//COMO EL PROGRAMA QUE EJECUTAMOS TIENE UN LAUNCHER, ESTE SE CIERRA Y NO QUEDA DE FONDO, SI NO QUE LANZA OTRO PROGRAMA QUE VA A SER BUSCADO EN EL REPEAT HASTA QUE LO CERREMOS.

                    Repeat
                    WindowLauncher := FindWindowExtd('FS-UAE'); // BUSCO EL PROGRAMA QUE ABRIO EL LAUNCHER
                        If WindowLauncher = 0 then // SI EL PROGRAMA SE CERRO HAGO LOS PASOS ARRIBA EXPLICADOS
                        begin
                        LoadIMG(Splash,LauncherPath + '\Launcher\RLLogo.jpg');
                        TerminarVuelta := 0;
                        WindowExecutor := FindWindowExtd('RLExecutor'); // BUSCO RLEXECUTOR
                            if IsWindow(WindowExecutor) then
                              begin
                              PostMessage(WindowExecutor,WM_CLOSE,0,0); // SI LO ENCUENTRO LO CIERRO PERO NO CIERRA
                              MensajeFmedia('fmedia.exe');  // CON ESTE PROCEDIMIENTO BUSCO EL FMEDIA y SI ESTA ABIERTO LE ENVIO PAUSA, PERO NO ME FUNCIONA
                            end;
                        end;
                    Until TerminarVuelta = 0; // COMO EL EMULADOR SE CERRO, TERMINO EL LOOP DE REPEAT.
              end;
//              MensajeFMedia('fmedia.exe'); // QUITO LA PAUSA (NO FUNCIONA)

              Repeat
                WindowFrontEnd := FindWindowExtd('EmulationStation'); / BUSCO LA VENTANA DEL PROGRAMA PRINCIPAL POR QUE AL EJECUTAR EL EMULADOR SE "ESCONDE" Y NO APARECE ENTRE LAS VENTANAS ABIERTAS
              until WindowFrontEnd <> 0; // ENCUENTRO EL PROGRAMA Y CAPTURO SU HANDLE.

              if isWindow(WindowFrontEnd) then 
              begin
              SetWindowPos(WindowFrontEnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE);  // ENVIO EL PROGRAMA AL PRIMER PLANO.
              end;


       end;

// OTRO MENSAJE PARA HACER OTRA COSA QUE SI ANDA.
    if MESSG = 'Normal' then
    begin
    FrmLauncher.FormStyle := FsNormal;
    end;

end; // FIN


end.


Bueno, ojalá lo hayan entendido y puedan ayudarme.

SALUDOS!!!!!

escafandra 10-10-2019 08:02:25

Debes concretar alguna cosa en tu pregunta y tenes en cuenta que para cerrar una aplicación puede no ser efectivo el envío de WM_CLOSE. Este mensaje cierra una ventana. de forma que eso hará. Puede ser que la ventana en cuestión no sea la principal, o que la aplicación no tenga ventanas. El Mensaje WM_QUIT puede ser mandado al hilo principal mediante PostThreadMessage pero tampoco es seguro que. Finalmente puedes usar TerminateProcess Esta opción acaba con el proceso sobre el que se tiene permisos pero no de forma natural con lo que no podrá tomar las acciones previstas para su cierre.

Por otro lado preguntas como controlar otro proceso mediante la tecla espacio y muestras un código en el que esa tarea la realiza un procedimiento llamado MensajeFmedia pero cuyo código no muestras. Difícil poder analizarlo en esta condiciones ¿no crees? Revisa este tema: ¿Cómo simular de "verdad" las teclas SHIFT+TAB?
seguro que te va a ayudar.


Saludos.

MaxiDucoli 11-10-2019 00:28:01

Cita:

Empezado por escafandra (Mensaje 533900)
Debes concretar alguna cosa en tu pregunta y tenes en cuenta que para cerrar una aplicación puede no ser efectivo el envío de WM_CLOSE. Este mensaje cierra una ventana. de forma que eso hará. Puede ser que la ventana en cuestión no sea la principal, o que la aplicación no tenga ventanas. El Mensaje WM_QUIT puede ser mandado al hilo principal mediante PostThreadMessage pero tampoco es seguro que. Finalmente puedes usar TerminateProcess Esta opción acaba con el proceso sobre el que se tiene permisos pero no de forma natural con lo que no podrá tomar las acciones previstas para su cierre.

Por otro lado preguntas como controlar otro proceso mediante la tecla espacio y muestras un código en el que esa tarea la realiza un procedimiento llamado MensajeFmedia pero cuyo código no muestras. Difícil poder analizarlo en esta condiciones ¿no crees? Revisa este tema: ¿Cómo simular de "verdad" las teclas SHIFT+TAB?
seguro que te va a ayudar.


Saludos.

Hola, gracias por la respuesta.
Disculpa, es que ese precedimiento lo tengo en otra unit y por eso no me di cuenta de ponerlo.

No hace más que esto:

Esto es el que manda el espacio a Fmedia.exe
Código Delphi [-]
procedure MensajeFMedia (WindowCaption : String);
var
WindowFmedia : HWND;
begin
WindowFmedia := FindWindowExtd(WindowCaption);
                  if IsWindow(WindowFmedia) then
                  begin
                  PostMessage(WindowFMedia, WM_KEYDOWN, VK_SPACE, 0);
                 // h := 0;
                  end;
end;


Esto es lo que me busca la ventana de Fmedia.exe y obtiene su Handle.
Código Delphi [-]
function FindWindowExtd(partialTitle: string): HWND;
var
  hWndTemp: hWnd;
  iLenText: Integer;
  cTitletemp: array [0..254] of Char;
  sTitleTemp: string;
begin
  hWndTemp := FindWindow(nil, nil);
  while hWndTemp <> 0 do begin
    iLenText := GetWindowText(hWndTemp, cTitletemp, 255);
    sTitleTemp := cTitletemp;
    sTitleTemp := UpperCase(copy( sTitleTemp, 1, iLenText));
    partialTitle := UpperCase(partialTitle);
    if pos( partialTitle, sTitleTemp ) <> 0 then
      Break;
    hWndTemp := GetWindow(hWndTemp, GW_HWNDNEXT);
  end;
  result := hWndTemp;
end;

La verdad es que no entiendo como hacerlo. Hace rato que estoy con esto y de a poco voy aprendiendo cosas nuevas que nunca he usado.

Mi idea es Ejecutar un emulador, que se pause el Fmedia, que al cerrarse el emulador, se quite la pausa del Fmedia y se cierren las ejecuciones de fondo que se largaron con el emulador.

Quizás ni se pueda hacer lo que quiero, pero no pierdo nada con tratar.

Muchas gracias!!!!!

escafandra 11-10-2019 07:01:51

Para la simulación del teclado debes poner el foco en la ventana que te interesa (SetFocus) y luego usar SimKey que te describí en el hilo que te recomendé.

Saludos.

MaxiDucoli 12-10-2019 21:22:13

Enviar "parámetro" a una aplicación ya abierta.
 
Buenas tardes.
Estoy buscando por internet y por el foro (que también es internet :p ) a ver si existe algo parecido a lo que necesito, pero no encuentro guía al respecto.

La cosa es esta:

Si yo hago una aplicación de Windows en Delphi, hay manera de poder, por ejemplo con un ShellExecute volver a tratar de ejecutar mi aplicación, pero que en vez de ejecutarse, esta solo tome los parámetros que le paso como para poder procesarlos como yo quiera en la aplicación ya abierta??????

Por ejemplo:

Tengo una aplicación que está de fondo, la cual me ejecuta a otra aplicación también hecha por mi que es la que le envía los parámetros cada vez que se ejecuta.

El problema es que yo la ejecuto mediante otro programa que es un frontEnd de emuladores, el cual abre una ventana de consola al ejecutarse por lo que queda abierta la ventana que ejecuto para mandar los parámetros a la aplicación ya abierta y la de consola y esto me genera el problema de que no puedo cerrrar mi programa, sin antes cerrar la ventana de consola por que si no me dá error y no puedo lograr hacer esto por medio de código.


Mi idea es solamente ejecutar la aplicación que recibe los mensajes, mediante el frontend volver a llamar a esa aplicación y en vez de que se abra otra ventana, solo tome la linea de comandos con los parámetros que le pase, para ejecutar el emulador mediante mi programa.

Ojalá lo hayan entendido.

Y les quería hacer una petición para los expertos: Dónde tengo que leer o sacar los datos para cosas como estas? No me gusta estar preguntando tanto y que me resuelvan todo sin yo entender nada. Por que solo copio y pego código que no entiendo y así nunca voy a aprender a progamar realmente.

Muchas gracias!!!!!

MaxiDucoli 12-10-2019 23:44:16

Enviar parámetros a una aplicación ya abierta.
 
Buenas tardes.
Estoy buscando por internet y por el foro (que también es internet ) a ver si existe algo parecido a lo que necesito, pero no encuentro guía al respecto.

La cosa es esta:

Si yo hago una aplicación de Windows en Delphi, hay manera de poder, por ejemplo con un ShellExecute volver a tratar de ejecutar mi aplicación, pero que en vez de ejecutarse, esta solo tome los parámetros que le paso como para poder procesarlos como yo quiera en la aplicación ya abierta??????

Por ejemplo:

Tengo una aplicación que está de fondo, la cual me ejecuta a otra aplicación también hecha por mi que es la que le envía los parámetros cada vez que se ejecuta.

El problema es que yo la ejecuto mediante otro programa que es un frontEnd de emuladores, el cual abre una ventana de consola al ejecutarse por lo que queda abierta la ventana que ejecuto para mandar los parámetros a la aplicación ya abierta y la de consola y esto me genera el problema de que no puedo cerrrar mi programa, sin antes cerrar la ventana de consola por que si no me dá error y no puedo lograr hacer esto por medio de código.


Mi idea es solamente ejecutar la aplicación que recibe los mensajes, mediante el frontend volver a llamar a esa aplicación y en vez de que se abra otra ventana, solo tome la linea de comandos con los parámetros que le pase, para ejecutar el emulador mediante mi programa.

Ojalá lo hayan entendido.

Y les quería hacer una petición para los expertos: Dónde tengo que leer o sacar los datos para cosas como estas? No me gusta estar preguntando tanto y que me resuelvan todo sin yo entender nada. Por que solo copio y pego código que no entiendo y así nunca voy a aprender a progamar realmente.

Muchas gracias!!!!!

engranaje 13-10-2019 11:41:18

No te creas que tengo claro haberte entendido bien, pero voy a arriesgarme. Lo que entiendo es que necesitas que dos aplicaciones desarrolladas por tí se comuniquen entre sí. No sé con que versión de delphi estás trabajando o si es con Lazarus, ni tampoco en que SO se ejecutaran estas aplicaciones por lo que igual mi recomendación no es aplicable. Puedes intentar utilizar la API de windows (creo que por eso estará la pregunta en este foro) y utilizar la función SendMessage. No me gusta mucho poner enlaces externos porque no sé cuanto tiempo estarán operativos, pero dejo aquí uno en el que se explica el sistema que que te planteo a ver si te sirve como punto de partida.

http://www.ajpdsoft.com/modules.php?...oenviarmensaje

Casimiro Notevi 13-10-2019 12:52:10

Cita:

Empezado por MaxiDucoli (Mensaje 533950)
Buenas tardes.

Por favor, deja de crear hilos repetidos, este es el tercero igual, los he unido. Gracias, y no olvides nuestra guía de estilo.

MaxiDucoli 22-10-2019 08:43:30

Cita:

Empezado por Casimiro Notevi (Mensaje 533953)
Por favor, deja de crear hilos repetidos, este es el tercero igual, los he unido. Gracias, y no olvides nuestra guía de estilo.

Si, pero no fue algo mío.
Respondí un comentario y después cuando fui a hacer otro post nuevo, me hizo un post exactamente igual a mi conemtario y no el post que yo había escrito.
Traté de borrarlo y no supe como,perdón.
Lo que menos quiero es incumplir las normas del foro del que tanto aprendí.
Muchas gracias!!!!!

MaxiDucoli 22-10-2019 08:48:55

Cita:

Empezado por engranaje (Mensaje 533952)
No te creas que tengo claro haberte entendido bien, pero voy a arriesgarme. Lo que entiendo es que necesitas que dos aplicaciones desarrolladas por tí se comuniquen entre sí. No sé con que versión de delphi estás trabajando o si es con Lazarus, ni tampoco en que SO se ejecutaran estas aplicaciones por lo que igual mi recomendación no es aplicable. Puedes intentar utilizar la API de windows (creo que por eso estará la pregunta en este foro) y utilizar la función SendMessage. No me gusta mucho poner enlaces externos porque no sé cuanto tiempo estarán operativos, pero dejo aquí uno en el que se explica el sistema que que te planteo a ver si te sirve como punto de partida.

http://www.ajpdsoft.com/modules.php?...oenviarmensaje

Hola, es exactamente lo que estoy usando.

El programa emisor le envía cierto mensaje al programa receptor y este hace ejecuciones de emuladores según lo que se le haya enviado en el mensaje.

Ya solucioné el problema del envío de la tecla ESPACIO ejecutando el programa que la recibe con TJvCreateProcess y manejando desde ahí todo.
Ahora más o menos lo que estoy haciendo haca algo de lo que realmente quiero hacer, será cuestión de tiempo seguro.

Muchas gracias!!!!!

Ah!!!!! Uso Embarcadero Delphi Community Edition 10.3.2 en Windows 10 con la última actualización.

Casimiro Notevi 22-10-2019 09:38:34

Cita:

Empezado por MaxiDucoli (Mensaje 534042)
Si, pero no fue algo mío.
Respondí un comentario y después cuando fui a hacer otro post nuevo, me hizo un post exactamente igual a mi conemtario y no el post que yo había escrito.
Traté de borrarlo y no supe como,perdón.
Lo que menos quiero es incumplir las normas del foro del que tanto aprendí.
Muchas gracias!!!!!




Gracias, amigo ^\||/
Es que soy un poco insoportable :D


La franja horaria es GMT +2. Ahora son las 16:43:01.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi