Ir al contenido


Foto

Capturar la salida de consola: DosCommand


  • Por favor identifícate para responder
19 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 27 enero 2011 - 06:27

Este tema no es nuevo, se han publicado numerosos trucos que tratan de realizar esta tarea. Algunos códigos no capturan o no ejecutan todos los comandos, como puede ser el problema que algunos tienen con "xcopy".

Propongo otra versión, DosCommand:



delphi
  1. function DosCommand(CommandLine: String): String;
  2. var
  3.   Buffer: array [0..4096] of char;
  4.   pipeRead, pipeWrite: THandle;
  5.   sa: SECURITY_ATTRIBUTES;
  6.   si: STARTUPINFO;
  7.   pi: PROCESS_INFORMATION;
  8.   dwRead: DWORD;
  9. begin
  10.   Result:= '';
  11.   GetEnvironmentVariable('COMSPEC', Buffer, sizeof(Buffer));
  12.   CommandLine:= String(Buffer) + ' /C ' + CommandLine;
  13.  
  14.   ZeroMemory(@sa, sizeof(SECURITY_ATTRIBUTES));
  15.   sa.nLength:= sizeof(SECURITY_ATTRIBUTES);
  16.   sa.bInheritHandle:= TRUE;
  17.   if CreatePipe(pipeRead, pipeWrite, @sa, 25*1024) then
  18.   begin
  19.     si.cb:= sizeof(STARTUPINFO);
  20.     ZeroMemory(@pi, sizeof(PROCESS_INFORMATION));
  21.     si.hStdOutput:= pipeWrite;
  22.     si.hStdError := pipeWrite;
  23.     si.hStdInput := pipeWrite;
  24.     si.dwFlags:= STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
  25.     si.wShowWindow:= SW_HIDE;
  26.     if CreateProcess(nil, PCHAR(CommandLine), nil, nil, TRUE, 0, nil, nil, si, pi) then
  27.     begin
  28.       CloseHandle(pi.hThread);
  29.       if WaitForSingleObject(pi.hProcess, 9000) = WAIT_OBJECT_0 then
  30.       begin
  31.         dwRead:= 0;
  32.         Buffer[0]:= ' ';
  33.         WriteFile(pipeWrite, Buffer, 1, dwRead, 0);
  34.         repeat
  35.           ZeroMemory(@buffer, sizeof(buffer));
  36.           ReadFile(pipeRead, buffer, sizeof(buffer), dwRead, 0);
  37.           OemToCharBuffA(buffer, buffer, dwRead);
  38.           Result:= Result + #13 + #10 + String(buffer);
  39.         until dwRead < sizeof(buffer);
  40.       end;
  41.       CloseHandle(pi.hProcess);
  42.     end;
  43.     CloseHandle(pipeRead);
  44.     CloseHandle(pipeWrite);
  45.   end;
  46. end;


Un ejemplo de uso:

delphi
  1. Memo1.Text:= DosCommand(Edit1.Text);




Saludos.

PD.
Modifico el código:


delphi
  1. // cambio
  2. WriteFile(pipeWrite, '', 1, dwRead, 0);
  3. // por
  4. Buffer[0]:= ' '; //un espacio.
  5. WriteFile(pipeWrite, Buffer, 1, dwRead, 0);


Para evitar problemas con programas que no devuelvan nada a la consola.
  • 0

#2 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 27 enero 2011 - 06:51

A ver si entendí, ese código sirve para utilizar comandos DOS desde Delphi??.
  • 0

#3 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 27 enero 2011 - 06:59

A ver si entendí, ese código sirve para utilizar comandos DOS desde Delphi??.


Exacto, ejecutarlo y obtener la salida en un String.  :)


Saludos.
  • 0

#4 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 27 enero 2011 - 01:30

Lo probé y obtuve un "Acces Violation", ejemplo, si uso el comando "dir", veo que en la variable CommandLine aparece "C:\WINDOWS\system32\cmd.exe /C dir"


Saludos!
  • 0

#5 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.460 mensajes
  • LocationMéxico

Escrito 27 enero 2011 - 01:38

Lo probé y obtuve un "Acces Violation", ejemplo, si uso el comando "dir", veo que en la variable CommandLine aparece "C:\WINDOWS\system32\cmd.exe /C dir"


Saludos!


No amigo felipe.co  ese código es para cosas más complejas, no intentes observarnos el rostro :D :D :D

Salud OS
  • 0

#6 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 27 enero 2011 - 02:02


Lo probé y obtuve un "Acces Violation", ejemplo, si uso el comando "dir", veo que en la variable CommandLine aparece "C:\WINDOWS\system32\cmd.exe /C dir"


Saludos!


No amigo felipe.co  ese código es para cosas más complejas, no intentes observarnos el rostro :D :D :D

Salud OS


:D :D :D jaja... bueno no tenía más opción, a este equipo le pasa algo raro y hace mucho dejaron de funcionar los comandos importantes, creo que desde la última actualización  ^o|


Saludos!
  • 0

#7 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.460 mensajes
  • LocationMéxico

Escrito 27 enero 2011 - 02:10

Bueno, creo que es tu maquina mi amigo, he hecho la misma prueba y a mi no me da error



DIR E:

********************************************
El volumen de la unidad E es RODGAB
El número de serie del volumen es: 31F4-0BF5

Directorio de E:\

22/01/2011  14:14    <DIR>          VIDEO
22/01/2011  14:14    <DIR>          AUDIO
              0 archivos              0 bytes
              2 dirs              0 bytes libres
********************************************


Salud OS
  • 0

#8 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 27 enero 2011 - 02:13

Bueno, creo que es tu maquina mi amigo, he hecho la misma prueba y a mi no me da error
...
Salud OS


Creería lo mismo, lo tendré que probar en otra máquina.


Saludos!
  • 0

#9 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 27 enero 2011 - 02:20


Lo probé y obtuve un "Acces Violation", ejemplo, si uso el comando "dir", veo que en la variable CommandLine aparece "C:WINDOWSsystem32cmd.exe /C dir"

Claro, se ejecuta una consola invisible, se le pasa el comando y se captura el resultado.
Subo un ejemplo.Imagen Enviada



Saludos.
  • 0

#10 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 27 enero 2011 - 02:47

Claro, se ejecuta una consola invisible, se le pasa el comando y se captura el resultado.


Sí, y efectivamente quería mostrar eso, porque si lo uso desde el editor de comandos normalmente no me da ningún problema, pero si lo uso desde esta función obtengo un Access violation:

Access violation at address 784966C3 in module "ntdll.dll". Read of address FFFFFFFF.


Pero como dice egostar y cuya idea apoyo es que posiblemente este equipo tenga problemas.


Saludos!
  • 0

#11 madiazg

madiazg

    Member

  • Miembros
  • PipPip
  • 28 mensajes

Escrito 30 enero 2011 - 08:52

Hola,he intentado combinar el código descrito con el siguiente código que ejecuta una aplicación y espera a que termine el proceso pero no lo he conseguido (entre otras cosas porque mis conocimientos de delphi no son suficientes para comprender el código).



delphi
  1. function WinExecAndWait32(FileName:String; Visibility:integer):integer;
  2. var
  3.   zAppName:array[0..512] of char;
  4.   zCurDir:array[0..255] of char;
  5.   WorkDir:String;
  6.   StartupInfo:TStartupInfo;
  7.   ProcessInfo:TProcessInformation;
  8.   Resultado,exitCode: DWord;
  9. begin
  10.   StrPCopy(zAppName,FileName);
  11.   GetDir(0,WorkDir);
  12.   StrPCopy(zCurDir,WorkDir);
  13.   FillChar(StartupInfo,Sizeof(StartupInfo),#0);
  14.   StartupInfo.cb := Sizeof(StartupInfo);
  15.   StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  16.   StartupInfo.wShowWindow := Visibility;
  17.   CreateProcess(nil,
  18.     zAppName,                      { pointer to command line string }
  19.     nil,                          { pointer to process security attributes}
  20.     nil,                          { pointer to thread security attributes}
  21.     false,                        { handle inheritance flag }
  22.     CREATE_NEW_CONSOLE or          { creation flags }
  23.     NORMAL_PRIORITY_CLASS,
  24.     nil,                          { pointer to new environment block }
  25.     nil,                          { pointer to current directory name }
  26.     StartupInfo,                  { pointer to STARTUPINFO }
  27.     ProcessInfo);
  28.   {Espera a que termine la ejecucion}
  29.   {Wait until execution finish}
  30.   Repeat
  31.     exitCode := WaitForSingleObject( ProcessInfo.hProcess,1000);
  32.     Application.ProcessMessages;
  33.   Until (exitCode <> WAIT_TIMEOUT);
  34.   GetExitCodeProcess(ProcessInfo.hProcess,Resultado);
  35.   CloseHandle(ProcessInfo.hProcess );  Result:=Resultado;
  36. end;


(No recuerdo donde obtuve este código)

¿Alguien puede ayudarme a adaptar el DosCommand para que espere a que termine el proceso?

Saludos...Miguel Angel
  • 0

#12 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 30 enero 2011 - 11:07

¿Alguien puede ayudarme a adaptar el DosCommand para que espere a que termine el proceso?


La API que provoca la espera es WaitForSingleObject. Si te fijas, en la función DosCommand encuentras:



delphi
  1. if WaitForSingleObject(pi.hProcess, 9000) = WAIT_OBJECT_0 then
  2. .....



Esto significa que va a esperar hasta 9 segundos a que termine, si se cumple este timeout, la función continúa, y si si termina antes, también continuará. Si quieres que no tenga timeout, entonces:



delphi
  1. if WaitForSingleObject(pi.hProcess, INFINITE) = WAIT_OBJECT_0 then
  2. .....



Pero no es muy recomendable.


Saludos.
  • 0

#13 madiazg

madiazg

    Member

  • Miembros
  • PipPip
  • 28 mensajes

Escrito 30 enero 2011 - 12:48

Pues no me funciona como yo querría. Lo que yo hago es ejecutar un programa DOS con la función:


delphi
  1. WinExecAndWait32(NombrePrograma,True);


Esta función muestra una ventana DOS y ejecuta el programa. Cuando termina la ejecución se cierra la ventana DOS y pasa a la siguiente línea de código de mi programa. En cambio, con la función:


delphi
  1. Memo1.Text:= DosCommand(NombrePrograma);



no ocurre lo mismo y no espera a que termine la ejecución del programa y se ejecuta la siguiente línea de código inmediatamente.

Saludos...
Miguel Angel

  • 0

#14 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 30 enero 2011 - 05:06

Pues no se que modificación hiciste a la función...

Prueba esta modificación, en la que se espera no 9 segundos, sino hasta que termine y visualizando la consola para ver que pasa con ella. Cuando termine la aplicación se cierra la consola y continua con la linea siguiente, si no termina, DosCommand queda bloqueado.



delphi
  1. function DosCommand(CommandLine: String): String;
  2. var
  3.   Buffer: array [0..4096] of char;
  4.   pipeRead, pipeWrite: THandle;
  5.   sa: SECURITY_ATTRIBUTES;
  6.   si: STARTUPINFO;
  7.   pi: PROCESS_INFORMATION;
  8.   dwRead: DWORD;
  9. begin
  10.   Result:= '';
  11.   GetEnvironmentVariable('COMSPEC', Buffer, sizeof(Buffer));
  12.   CommandLine:= String(Buffer) + ' /C ' + CommandLine;
  13.  
  14.   ZeroMemory(@sa, sizeof(SECURITY_ATTRIBUTES));
  15.   sa.nLength:= sizeof(SECURITY_ATTRIBUTES);
  16.   sa.bInheritHandle:= TRUE;
  17.   if CreatePipe(pipeRead, pipeWrite, @sa, 25*1024) then
  18.   begin
  19.     si.cb:= sizeof(STARTUPINFO);
  20.     ZeroMemory(@pi, sizeof(PROCESS_INFORMATION));
  21.     si.hStdOutput:= pipeWrite;
  22.     si.hStdError := pipeWrite;
  23.     si.hStdInput := pipeWrite;
  24.     si.dwFlags:= STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
  25. //    si.wShowWindow:= SW_HIDE;
  26.     si.wShowWindow:= SW_SHOW;
  27.     if CreateProcess(nil, PCHAR(CommandLine), nil, nil, TRUE, 0, nil, nil, si, pi) then
  28.     begin
  29.       CloseHandle(pi.hThread);
  30.       if WaitForSingleObject(pi.hProcess, INFINITE) = WAIT_OBJECT_0 then
  31.       begin
  32.         dwRead:= 0;
  33.         Buffer[0]:= ' ';
  34.         WriteFile(pipeWrite, Buffer, 1, dwRead, 0);
  35.         repeat
  36.           ZeroMemory(@Buffer, sizeof(Buffer));
  37.           ReadFile(pipeRead, buffer, sizeof(buffer), dwRead, 0);
  38.           OemToCharBuffA(buffer, buffer, dwRead);
  39.           Result:= Result + #13 + #10 + String(buffer);
  40.         until dwRead < sizeof(buffer);
  41.       end; //WaitForSingleObject
  42.       CloseHandle(pi.hProcess);
  43.     end; //CreateProcess
  44.     CloseHandle(pipeRead);
  45.     CloseHandle(pipeWrite);
  46.   end; //CreatePipe
  47. end;





Saludos.
  • 0

#15 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.460 mensajes
  • LocationMéxico

Escrito 17 noviembre 2017 - 02:10

Hola amigo

 

Vaya, después de 6 años he requerido utilizar éste proceso :)

 

Bueno, estoy intentando utilizar este truco en Delphi 10.2 Tokyo Starter, pero en la siguiente línea:


delphi
  1. OemToCharBuffA(buffer, buffer, dwRead);

Me salta el siguiente error:

 

 

 

[dcc32 Error] Unit1.pas(61): E2010 Incompatible types: 'PAnsiChar' and 'array[0..4096] of Char'

 

 

Pensé en hacer un Cast a la variable Buffer:


delphi
  1. OemToCharBuffA(PAnsiChar(buffer), buffer, dwRead);

Pero no acepta el Cast :(

 

 

 

[dcc32 Error] Unit1.pas(61): E2089 Invalid typecast

 

 

¿Algo que pueda hacer para solucionarlo?

 

 

Saludos.

 

 


  • 0

#16 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.460 mensajes
  • LocationMéxico

Escrito 17 noviembre 2017 - 04:31

Me respondo.

 

Así me ha compilado:


php
  1. OemToCharBuffA(PAnsiChar(String(buffer)), PAnsiChar(String(buffer)), dwRead);

Solo que no lo he podido probar porque no estoy ejecutando un comando DOS, pensé que era para obtener la salida de cualquier programa en la Consola :(

 

Salta un error en la siguiente línea


delphi
  1. if CreateProcess(nil, PCHAR(CommandLine), nil, nil, TRUE, 0, nil, nil, si, pi) then

 

---------------------------
Project1
---------------------------
Access violation at address 77C88100 in module 'ntdll.dll'. Read of address 0036005F.
---------------------------
Aceptar   
---------------------------
 

 

 

Saludos


  • 0

#17 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 18 noviembre 2017 - 09:22

El problema es el unicode si quieres usas el antiguo CHAR deber tipificarlo cono AnsiCHAR y PCHAR como PAnsiChar, pues el compilador ahora asume que CHAR = WCHAR y PCHAR = PWCHAR

 

Revisa esta pregunta

 

 

Saludos.


  • 1

#18 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 18 noviembre 2017 - 10:34

También te puede ser de utilidad este hilo donde se trata de ejecutar comandos de consola encadenados
 
Saludos.
  • 1

#19 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.460 mensajes
  • LocationMéxico

Escrito 19 noviembre 2017 - 12:11

Muchas gracias amigo escafandra, vaya que la edad no me perdona, ya no me acordaba de ese hilo.

 

Finalmente utilicé la rutina de esperar a que termine un programa, 

 

http://delphiallimit...sperar-que.html

 

 

Saludos


  • 0

#20 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 19 noviembre 2017 - 10:54

Muchas gracias amigo escafandra, vaya que la edad no me perdona, ya no me acordaba de ese hilo.
 
Finalmente utilicé la rutina de esperar a que termine un programa, 
 
http://delphiallimit...sperar-que.html
 
 
Saludos


También te hubiese servido alguna de las propuestas de este otro hilo: Ejecutar un programa y esperar hasta recibir su respuesta   ;)

 

Saludos.


  • 0




IP.Board spam blocked by CleanTalk.