Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > API de Windows
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 26-01-2011
Flecha Flecha is offline
Miembro
 
Registrado: nov 2006
Posts: 59
Poder: 18
Flecha Va por buen camino
Por suerte, son casos muy rebuscados, pero algunos hay.


Por ejemplo, un caso absurdo, pero que como ejemplo puede valer.
Si queremos ejecutar "notepad.exe", todo funciona OK. Se abre un NotePad con un documento en blanco sin problemas. Pero el programa se queda atrapado en el bucle infinito hasta que cerremos el NotePad.

Como digo, es un caso absurdo, porque el NotePad no da salida a MS-DOS. Pero como ejemplo, puede valer.



Sin embargo hay otros casos nada absurdos y que sí tienen salidas a MS-DOS que, ejecutados desde una ventana de comandos, quedan igualmente atrapados en ese bucle infinito.

Como ejemplo, puedo comentar lo que más me afecta a mí, particularmente. En otro hilo ( http://www.clubdelphi.com/foros/showthread.php?p=387845 ) explico mi necesidad de "reinventar la rueda" para hacer ejecuciones en remoto. Logré localizar por internet un programa (PSExec.exe) capaz de ejecutar cosas en remoto (no me soluciona el problema, pero es lo que tengo).
Por ejemplo..., con ésto se ejecutaría DIR en una máquina remota:
psexec.exe \\DirecciónIP -u usuario -p password cmd /c dir

Esa línea de comando funciona perfectamente desde una ventana de comandos MS-DOS. Pero si la lanzas desde Delphi, e intentas capturar su salida MS-DOS, entra en bucle infinito.



No obstante, otras ejecuciones en remoto con PSExec.exe sí que son capturables sus salidas MS-DOS. Así que el problema no es 100% de PSExec.exe.

Es un caso rebuscado, sí. Pero es el que me afecta.

Muchas gracias.
Un saludo.
Responder Con Cita
  #2  
Antiguo 26-01-2011
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.051
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
¿Un bucle infinito haciendo qué?
Responder Con Cita
  #3  
Antiguo 26-01-2011
Flecha Flecha is offline
Miembro
 
Registrado: nov 2006
Posts: 59
Poder: 18
Flecha Va por buen camino
Cita:
Empezado por Casimiro Notevi Ver Mensaje
¿Un bucle infinito haciendo qué?
Lo explico más arriba.
Es referente a la solución aportada por kurono, y la presente en TrucoManía.
En ambos casos hay un REPEAT UNTIL, dentro del cual se recoge la salida MS-DOS. Se sale del bucle cuando el proceso lanzado deja de estar activo.
Pero en algunos casos, esa señal nunca llega, o no llega cuando se espera que llegue.
Responder Con Cita
  #4  
Antiguo 27-01-2011
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Inténtalo de esta forma:

Código Delphi [-]
function DosCommand(CommandLine: String): String;
var
  cmdBuffer: array [0..MAX_PATH] of char;
  Buffer: array [0..4096] of char;
  pipeRead, pipeWrite: THandle;
  sa: SECURITY_ATTRIBUTES;
  si: STARTUPINFO;
  pi: PROCESS_INFORMATION;
  dwRead: DWORD;
begin
  GetEnvironmentVariable('COMSPEC', cmdBuffer, sizeof(cmdBuffer));
  CommandLine:= String(cmdBuffer) + ' /C ' + CommandLine;
  Result:= '';
  
  sa.nLength:= sizeof(SECURITY_ATTRIBUTES);
  sa.bInheritHandle:= TRUE;
  if CreatePipe(pipeRead, pipeWrite, @sa, 0) then
  begin
    si.cb:= sizeof(STARTUPINFO);
    ZeroMemory(@pi, sizeof(PROCESS_INFORMATION));
    si.hStdOutput:= pipeWrite;
    si.hStdError := pipeWrite;
    si.hStdInput := pipeWrite;
    si.dwFlags:= STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
    si.wShowWindow:= SW_HIDE;
    if CreateProcess(nil, PCHAR(CommandLine), nil, nil, TRUE, 0, nil, nil, si, pi) then
    begin
      CloseHandle(pi.hThread);
      if WaitForSingleObject(pi.hProcess, 9000) = WAIT_OBJECT_0 then
      begin
        dwRead:= 0;
        WriteFile(pipeWrite, '', 1, dwRead, 0);
        repeat
          ZeroMemory(@buffer, sizeof(buffer));
          ReadFile(pipeRead, buffer, sizeof(buffer), dwRead, 0);
          OemToCharBuffA(buffer, buffer, dwRead);
          Result:= Result + #13 + #10 + String(buffer);
        until dwRead < sizeof(buffer);
      end; 
      CloseHandle(pi.hProcess);
    end;
    CloseHandle(pipeRead);
    CloseHandle(pipeWrite);
  end; 
end;

Saludos.
Responder Con Cita
  #5  
Antiguo 27-01-2011
Flecha Flecha is offline
Miembro
 
Registrado: nov 2006
Posts: 59
Poder: 18
Flecha Va por buen camino
Muchas gracias..., pero no funciona.

Da igual lo que intente ejecutar.
CreateProcess() siempre devuelve FALSE, así que nunca llega a ejecutar el comando.
Responder Con Cita
  #6  
Antiguo 27-01-2011
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Cita:
Empezado por Flecha Ver Mensaje
Muchas gracias..., pero no funciona.

Da igual lo que intente ejecutar.
CreateProcess() siempre devuelve FALSE, así que nunca llega a ejecutar el comando.
Pues a mi si. Sólo he encontrado un problemilla en tamaño del buffer del pipe, si lo asignas por defecto a veces falla. Le he dado un valor de 25k.

Ademas, ejecuta y captura comandos difíciles de capturar como el "xcopy".



Cambia la línea:
Código Delphi [-]
if CreatePipe(pipeRead, pipeWrite, @sa, 0) then

por
Código Delphi [-]
if CreatePipe(pipeRead, pipeWrite, @sa, 25*1024) then


Saludos.

Última edición por escafandra fecha: 27-01-2011 a las 16:21:38.
Responder Con Cita
  #7  
Antiguo 27-01-2011
Flecha Flecha is offline
Miembro
 
Registrado: nov 2006
Posts: 59
Poder: 18
Flecha Va por buen camino

A mí me tiene manía. Se niega a funcionar.
¿Podrá ser por la versión del Delphi? Yo trabajo con Delphi 6 (arcaico, sí, pero es lo que hay)
Responder Con Cita
  #8  
Antiguo 27-01-2011
Avatar de Ñuño Martínez
Ñuño Martínez Ñuño Martínez is offline
Moderador
 
Registrado: jul 2006
Ubicación: Ciudad Catedral, Españistán
Posts: 6.000
Poder: 25
Ñuño Martínez Tiene un aura espectacularÑuño Martínez Tiene un aura espectacular
Free Pascal incluye la clase TProcess, que estrictamente hablando crea procesos nuevos y permite la comunicación con estos. Dado que trabaja a nivel de proceso y no de programa, permite ejecutar comandos de consola que no son programas sino funciones dentro de dicha consola (haberlos haylos, como "dir" o "cd"). Además permite capturar mensajes no sólo de la salida "normal" (stdout en POSIX) sino también por otras fuentes (como stderr, variables del sistema, etc.) que no pueden capturarse por ">" ni ">>", además de permitir la redirección de archivos y otras cosas interesantes.

Lo que no sé es si existe esta clase en Delphi, pero por lo que he leído por ahí no hay un equivalente claro.
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi!|MinGRo Game Engine
Responder Con Cita
  #9  
Antiguo 31-01-2011
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.912
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Cita:
Empezado por Ñuño Martínez Ver Mensaje
Free Pascal incluye la clase [url="http://www.freepascal.org/docs-html/fcl/process/tprocess.html"]TProcess[/URL

.....

Lo que no sé es si existe esta clase en Delphi, pero por lo que he leído por ahí no hay un equivalente claro.

Pues mira http://www.elmalabarista.com/es/blog...ti-plataforma/

Asi es como la porte a Delphi

Y asi se usa:

Código Delphi [-]
function TPlugin.RunDosInMemo(DosApp: String; StartDir:String): Boolean;
const
   READ_BYTES = 2048;
var
   AProcess: TProcess;
   AStringList: TStringList;
   n: Integer;
   M: TMemoryStream;
   BytesRead,BytesAvailable : LongInt;
begin
   M:=TMemoryStream.Create;
   AProcess := TProcess.Create(nil);
   AStringList := TStringList.Create;

   try
     AProcess.CommandLine := DosApp;
     AProcess.CurrentDirectory :=  StartDir;
     // We will define an option for when the program
     // is run. This option will make sure that our program
     // does not continue until the program we will launch
     // has stopped running. Also now we will tell it that
     // we want to read the output of the file.
     AProcess.Options := AProcess.Options + [poUsePipes, poNoConsole];
     BytesRead := 0;
     AProcess.Execute;
     LogMsg(IntToStr( AProcess.Handle ), msgStart );

   while AProcess.Running do
   begin
     // make sure we have room
     //M.SetSize(BytesRead + READ_BYTES);
     // try reading it
     BytesAvailable := AProcess.Output.NumBytesAvailable;
     n := AProcess.Output.Read(M.Memory^, BytesRead + BytesAvailable);
     if n > 0
     then begin
       Inc(BytesRead, n);
     end
     else begin
       // no data, wait 100 ms

     end;
       Sleep(250);
   end;
   // read last part
   repeat
     // make sure we have room
      BytesAvailable := AProcess.Output.NumBytesAvailable;
     M.SetSize(BytesRead + BytesAvailable);
     // try reading it
     n := AProcess.Output.Read(M.Memory^, BytesRead + BytesAvailable);
     if n > 0
     then begin
       Inc(BytesRead, n);
     end;
   until n <= 0;
   M.SetSize(BytesRead);

   LogMsg(IntToStr( AProcess.Handle ), msgEnd );

   AStringList.LoadFromStream(M);
      LastOutPut := AStringList.Text;
     AStringList.Clear;
     //Reading errors...
     LastErrors := '';
     AStringList.LoadFromStream(AProcess.Stderr);

     if AStringList.Count>0 then
     begin
      LastErrors := StringReplace( AStringList.Text ,#13+#10,#13,[rfReplaceAll] );
     end;//if

     Result := (AProcess.ExitStatus = 0);
   finally
     AStringList.Free;
     AProcess.Free;
   end;//try
end;

Desafortunadamente tiene un bug: Si el proceso DOS genera un output muy grande muy rapido se queda "colgado". No he podido ver todavia como arreglarlo...
__________________
El malabarista.
Responder Con Cita
  #10  
Antiguo 04-02-2011
Avatar de Ñuño Martínez
Ñuño Martínez Ñuño Martínez is offline
Moderador
 
Registrado: jul 2006
Ubicación: Ciudad Catedral, Españistán
Posts: 6.000
Poder: 25
Ñuño Martínez Tiene un aura espectacularÑuño Martínez Tiene un aura espectacular
Cita:
Empezado por mamcx Ver Mensaje
Desafortunadamente tiene un bug: Si el proceso DOS genera un output muy grande muy rapido se queda "colgado". No he podido ver todavia como arreglarlo...
No lo he estudiado, pero quizá usando varios hilos: uno que es el que ejecuta el proceso y va guardando la salida en un buffer, y otro que es el que va obteniendo los datos desde el buffer y poniéndolos en el memo.

Ya digo que no lo he estudiado, pero se ve bien.
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi!|MinGRo Game Engine
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro


La franja horaria es GMT +2. Ahora son las 01:15:21.


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
Copyright 1996-2007 Club Delphi