PDA

Ver la Versión Completa : Leer texto de otra aplicación


erika.martinez
26-03-2007, 20:32:17
Hola

Mi problema es el siguiente, tengo que ejecutar desde Delphi una aplicación que corre bajo DOS,
la entrada a esta aplicación es solamente por teclado y lo que me devuelve lo hace en pantalla.
Consultando acá en el foro ya encontré la solución a los primeros puntos, es decir ya ejecuté
esta aplicación desde Delphi y envié los datos mediante simulación de teclado. Lo que me falta
es traerme lo que esta aplicación me devuelve a Delphi, lo que me devuelve es texto, sería
básicamente poder traerme a Delphi la líneas que hay dentro de la pantalla de command.com
¿Hay alguna forma de hacer esto? Si alguien puede ayudarme realmente estaré muy agradecida.

seoane
26-03-2007, 20:37:01
Prueba con algo como esto:

http://www.clubdelphi.com/foros/showpost.php?p=190345&postcount=6

erika.martinez
27-03-2007, 15:52:37
Gracias seoane por tu respuesta. Lamentablemente no consigo adaptar el ejemplo que me diste a mi aplicación. Creo que el tema tiene que ver con el programita que yo ejecuto. Por ejemplo, para ejecutar este programita directamente desde command.com, tengo que poner todo el path: c:\vienna.rnafold.exe, no es una simple "instrucción?" como 'time', entonces en el ejemplo que me das en la instrucción:

GetEnvironmentVariable('COMSPEC', @Buffer, SizeOf(Buffer) - 1);

lo que obtengo en Buffer es: 'C:\windows\system32\cmd.exe'

La verdad es que soy principiante en esto de programar en Delphi y no manejo mucho el tema de las funciones de la API de Windows. Si alguien puede darme una mano, GRACIAS!

DTAR
27-03-2007, 17:47:54
hola... no es una solucion elegante,pero creo que puede funcionar...
lo que habria que hacer seria...
al ejecutar tu programa con los parametros correspondientes enviar todo eso a tu archivo de texto y despues levantarlo...
nose que funcion estaras utilizando para ejecutar tu aplicacion externa pero te doy un ejemplo ilustrativo...

ShellExecute('c:\MyDirectorio\MyAplicacion.exe','Parametro 1','> resultado.txt')
despues levantas el txt y recuperas los datos que a ejecutado esa apliacion...
espero que te sirvar de algo...:)

ArdiIIa
27-03-2007, 17:57:14
Si la salida del programa es la estandar, debería utilizar un procedimiento tal cual se describe en este hilo (http://www.clubdelphi.com/foros/showthread.php?t=41660)
CreateDOSProcessRedirected

Además cito otro procedimiento con el cual podría controlar el programa sin necesidad de enviarle teclas, eso en el caso de que tuviera la entrada estandar.

erika.martinez
27-03-2007, 18:33:31
Tal vez si conocen el código que estoy usando sea más fácil para ustedes entender mi problema. el código es el siguiente:


procedure TForm1.PostKeyEx32(key: Word; const shift: TShiftState; specialkey: Boolean);
{Este código lo obtuve en el Club Delphi}
{************************************************************
* Procedure PostKeyEx32
*
* Parameters:
* key : virtual keycode of the key to send. For printable
* keys this is simply the ANSI code (Ord(character)).
* shift : state of the modifier keys. This is a set, so you
* can set several of these keys (shift, control, alt,
* mouse buttons) in tandem. The TShiftState type is
* declared in the Classes Unit.
* specialkey: normally this should be False. Set it to True to
* specify a key on the numeric keypad, for example.
* Description:
* Uses keybd_event to manufacture a series of key events matching
* the passed parameters. The events go to the control with focus.
* Note that for characters key is always the upper-case version of
* the character. Sending without any modifier keys will result in
* a lower-case character, sending it with [ssShift] will result
* in an upper-case character!
*Created: 17.7.98 by P. Below
************************************************************}
Type
TShiftKeyInfo = Record
shift: Byte;
vkey : Byte;
End;
byteset = Set of 0..7;
Const
shiftkeys: Array [1..3] of TShiftKeyInfo =
((shift: Ord(ssCtrl); vkey: VK_CONTROL ),
(shift: Ord(ssShift); vkey: VK_SHIFT ),
(shift: Ord(ssAlt); vkey: VK_MENU ));
Var
flag: DWORD;
bShift: ByteSet absolute shift;
i: Integer;
Begin
For i := 1 To 3 Do Begin
If shiftkeys[i].shift In bShift Then
keybd_event( shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0), 0, 0);
End; { For }

If specialkey Then
flag := KEYEVENTF_EXTENDEDKEY
Else
flag := 0;

keybd_event( key, MapvirtualKey( key, 0 ), flag, 0 );
flag := flag or KEYEVENTF_KEYUP;
keybd_event( key, MapvirtualKey( key, 0 ), flag, 0 );

For i := 3 DownTo 1 Do Begin
If shiftkeys[i].shift In bShift Then
keybd_event( shiftkeys[i].vkey, MapVirtualKey(shiftkeys[i].vkey, 0), KEYEVENTF_KEYUP, 0);
End; { For }
End; { PostKeyEx32 }

function TForm1.WinExecAndWait32(FileName: String; Visibility: Integer): Integer;
{Esta función la utilicé hace tiempo para otra aplicación y creo que el código lo saqué
del Club Delphi}
var
zAppName: Array[0..512] of Char;
zCurDir: Array[0..255] of Char;
WorkDir: String;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
Resultado, ExitCode: DWord;
begin
StrPCopy(zAppName, FileName);
GetDir(0, WorkDir);
StrPCopy(zCurDir, WorkDir);
FillChar(StartupInfo, Sizeof(StartupInfo), #0);
StartupInfo.cb := SizeOf(StartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow := Visibility;
CreateProcess(nil, zAppName, nil, nil, False, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS,
nil, nil, StartupInfo, ProcessInfo);

repeat
exitCode := WaitForSingleObject(ProcessInfo.hProcess,1000);
Application.ProcessMessages;
until (exitCode <> WAIT_OBJECT_0);

GetExitCodeProcess(ProcessInfo.hProcess,Resultado);
MessageBeep(0);
CloseHandle(ProcessInfo.hProcess);
Result := Resultado;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
F: TextFile;
H: HWND;
I, J: Integer;
C: Char;
Genoma: Array of Char;
begin
WinExecAndWait32(PChar('C:\VIENNA\RNAfold.exe'),SW_SHOWNORMAL);
for J := 1 to 1443 do
begin
AssignFile(F, 'C:\GenomasGenerados\SinGenes\' + IntToStr(J) + '\GenomaInicial.txt');
{Acá tengo la información que tengo que pasarle al programita RNAfold.exe, y que la paso
mediante simmulación de teclado. Esta información la tengo guardada en archivos de texto,
después la cargo a un array of char: Genoma, y mientras recorro este array simulo presión de
teclas}
try
Reset(F);
except
CloseFile(F);
Exit;
end;
SetLength(Genoma, 0);
while not Eof(F) do
begin
Read(F, C);
SetLength(Genoma, Length(Genoma) + 1);
Genoma[High(Genoma)] := C;
end;
CLoseFile(F);
H := FindWindow(Nil,'C:\VIENNA\RNAfold.exe');
if H = 0 then ShowMessage('No se encontro la Aplicacion')
else
begin
SetForegroundWindow(H);
for I := Low(Genoma) to High(Genoma) do
PostKeyEx32(Ord(Genoma[I]), [], False);
repeat
Application.ProcessMessages;
until FileExists('C:\Erika\ICBME\Delphi y Vienna\rna.ps');
{Esto es porque el programita me genera una gráfica en un erchivo de tipo ps. De todas
formas no es esta la información que me interesa, lo que a mi me interesa es lo que el
programa devuelve en PANTALLA}
end;;
LeerPantallaRNAFold {ESTO ES LO QUE ME FALTA Y NO SÉ COMO HACER!!!}
end;
H := FindWindow(Nil,'C:\VIENNA\RNAfold.exe');
if H = 0 then ShowMessage('No se encontro la Aplicacion');
SendMessage(H, WM_CLOSE, 0, 0);
end;

y lo que no puedo hacer es capturar los datos de salida que me da la aplicación rnafold.exe. Esta salida es de tipo stdout, es decir no me genera ningún archivo de salida.

Gracias por su ayuda!!!

ArdiIIa
27-03-2007, 18:51:53
y lo que no puedo hacer es capturar los datos de salida que me da la aplicación rnafold.exe. Esta salida es de tipo stdout, es decir no me genera ningún archivo de salida.
Gracias por su ayuda!!!

Pues el tema es complicado si no tienes salida nada más que por pantalla...

erika.martinez
27-03-2007, 18:58:56
Entonces, ¿no hay forma de resolver esto con Delphi?

ArdiIIa
27-03-2007, 19:26:45
Yo solamente he tratado los ficheros con salida/entrada standar mediante pipes.

En tu caso creo que esto no es posible. Tal vez leyendo la memoria de video, ni siquiera sabría como hacerlo y luego caso de que fuera posible, tendrías que procesar todos los caracteres de la pantalla... A lo mejor con la función CreateFile --> Console, pero no se si es posible.
Seguro que este tema supone un reto para alguien y aporta alguna solución...

seoane
27-03-2007, 19:53:38
Gracias seoane por tu respuesta. Lamentablemente no consigo adaptar el ejemplo que me diste a mi aplicación. Creo que el tema tiene que ver con el programita que yo ejecuto. Por ejemplo, para ejecutar este programita directamente desde command.com, tengo que poner todo el path: c:\vienna.rnafold.exe, no es una simple "instrucción?" como 'time'


:confused: Y probaste a pasarle todo el path a la función que te pase como ejemplo ???

erika.martinez
27-03-2007, 20:24:34
Si, le pasé todo el path, y lo que obtengo es lo que puse en el mensaje #3

seoane
27-03-2007, 20:27:44
Buffer es una variable interna, entiendo entonces que colocas un breakpoint y examinas su contenido ¿cuando lo haces? ¿en que instrucción lo haces?

ArdiIIa
27-03-2007, 20:32:44
seoane:
Lo que veo es que en CreateProcess le asignas la salida al primer pipe.
Pena; no tengo ningún programa DOS a mano para probarlo.

seoane
27-03-2007, 20:36:48
Perdona, ahora que leo mejor el mensaje 3 intuyo que miras el valor de la variable buffer justo después de llamar a la función:

GetEnvironmentVariable('COMSPEC', @Buffer, SizeOf(Buffer) - 1);

Pero si te fijas en la siguiente instrucción, después de la ruta del cmd.exe le "pegamos" el parámetro "/c" y la ruta entera de tu programa. Es decir le estamos diciendo al cmd que ejecute tu programa. Así que no entiendo cual es el problema :confused:

erika.martinez
27-03-2007, 20:58:12
Haciendo esto que decís:

GetEnvironmentVariable('COMSPEC', @Buffer, SizeOf(Buffer) - 1);
StrCat(@Buffer,PChar(' /c ' + FileName)); {donde FileName = 'C:\Vienna\RnaFold.exe'}
if CreateProcess(nil, @Buffer, nil, nil, TRUE, CREATE_NEW_CONSOLE, nil, nil, si, pi) then

repeat
PeekNamedPipe(read_stdout, @Buffer, SizeOf(Buffer) - 1, @bread, @avail, nil);
if bread > 0 then
begin
Fillchar(Buffer, SizeOf(Buffer), 0);
ReadFile(read_stdout, Buffer, bread, bread, nil);
Rdo:= Rdo + String(PChar(@Buffer));
end;
GetExitCodeProcess(pi.hProcess, exitcod);
until (exitcod <> STILL_ACTIVE) and (bread = 0);

Cuando entro al repeat, la variable bread = 0 por lo que el programa no lee nada.

ZRR
26-04-2007, 01:09:02
Esto podria ayudarte:
http://www.clubdelphi.com/trucos/index.php?id=54

Saludos

cHackAll
04-05-2007, 00:39:56
Hola amigos, algunos comentarios:

ScreenBuffer no es nada más que el buffer en memoria convencional (así se llamaba), que tenemos desde las primeras PCs compatibles. 80 es la cantidad máxima de caracteres que se podían utilizar horizontalmente, y 50 es la cantidad máxima soportada al cambiar el modo (int 10h, 0).

CreateProcess es desde mi punto de vista (fuera de cualquier discusión del foro), la mejor función para correr programas. Si no utilizan Güindos eQuispe la carpeta es 'windows\command', y el eula.txt no se dónde andará.

CreateFont la use, pues es la forma mas simple de crear el font que requiero para mostrar a los antiguos caracteres 8:12 del CLI

Colors contiene la RGB de los colores que se ven en consola (modo texto). No hice el blink pues creo no es aplicable.

Toolhelp32ReadProcessMemory es una hermosa función que nos sirve para curiosear en procesos ajenos :). Lo lindo del caso es que podemos acceder al primer mega de memoria que nos dejaron los programas en DOS, en éste encontraremos cosillas muuuy interesantes.

SetBkColor API que permite definir el color de fondo (background) del texto en un determinado lienzo.

SetTextColor API define el color del texto (foreground en este caso).

0j0: el Timer llama a OnPaint para hacer 'refresh'

Lo que requieres es leer la matriz que te dejé, con esto encontrarás lo que buscas tal y como lo ve el usuario... si quieres métele todo a un PaintBox para que muestres otras cosillas también en tu formulario...

PD: El resto como ya se imaginaran es cosecha de mi ocio
Espero nos cuentes que es lo que querías hacer en concreto.

Suerte!

cHackAll
04-05-2007, 00:45:15
Espero que tu programa DOS sea CLI (Command Line Interface), si no debemos ver otras alternativas, pero igual nos servirá la idea de leer del de otro proceso.

Saludos