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
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
  #2  
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
  #3  
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
  #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
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
  #5  
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
  #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

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)
No, no te tiene manía, ha sido un pequeño error mio al inicializar la estructura SECURITY_ATTRIBUTES, se bebe poner a cero. El no hacerlo provoca errores erráticos en la API CreatePipe que te tomaron manía .

Coloco el código de nuevo para dejarlo mas claro y optimizarlo un poco:

Código Delphi [-]
function DosCommand(CommandLine: String): String;
var
  Buffer: array [0..4096] of char;
  pipeRead, pipeWrite: THandle;
  sa: SECURITY_ATTRIBUTES;
  si: STARTUPINFO;
  pi: PROCESS_INFORMATION;
  dwRead: DWORD;
begin
  Result:= '';
  GetEnvironmentVariable('COMSPEC', Buffer, sizeof(Buffer));
  CommandLine:= String(Buffer) + ' /C ' + CommandLine;

  ZeroMemory(@sa, sizeof(SECURITY_ATTRIBUTES));
  sa.nLength:= sizeof(SECURITY_ATTRIBUTES);
  sa.bInheritHandle:= TRUE;
  if CreatePipe(pipeRead, pipeWrite, @sa, 25*1024) 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
  #7  
Antiguo 27-01-2011
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
¿Que este ejemplo no es básicamente lo mismo que en el mensaje #5?

Lo comento no por demeritar éste, sino porque ya el compañero mencionaba que le fallaba con algunos programas.

// Saludos
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 07:47:17.


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