Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

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

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 07-09-2020
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
¿Podrías mostrarnos un poco más de código? Incluyendo el código de read_stdout (sea variable, función...) y la declaración de Buffer (sea variable, parámetro...). Gracias.
Responder Con Cita
  #2  
Antiguo 07-09-2020
Avatar de JoAnCa
JoAnCa JoAnCa is offline
Miembro
 
Registrado: jul 2005
Ubicación: Cuba
Posts: 435
Poder: 19
JoAnCa Va por buen camino
Cita:
Empezado por Al González Ver Mensaje
¿Podrías mostrarnos un poco más de código? Incluyendo el código de read_stdout (sea variable, función...) y la declaración de Buffer (sea variable, parámetro...). Gracias.

En realidad no puse el codigo completo porque puse el enlace en el primer post, pero de igual forma aqui lo tienes

Código Delphi [-]
function IsWinNT: boolean;
var
  OSV: OSVERSIONINFO;
begin
  OSV.dwOSVersionInfoSize := sizeof(osv);
  GetVersionEx(OSV);
  result := OSV.dwPlatformId = VER_PLATFORM_WIN32_NT;
end;

function CmdExec(Cmd: string): string;
var
  Buffer: array[0..4096] of Char;
  si: STARTUPINFO;
  sa: SECURITY_ATTRIBUTES;
  sd: SECURITY_DESCRIPTOR;
  pi: PROCESS_INFORMATION;
  newstdin, newstdout, read_stdout, write_stdin: THandle;
  exitcod, bread, avail: Cardinal;
begin
  Result:= '';
  if IsWinNT then
  begin
    InitializeSecurityDescriptor(@sd, SECURITY_DESCRIPTOR_REVISION);
    SetSecurityDescriptorDacl(@sd, true, nil, false);
    sa.lpSecurityDescriptor := @sd;
  end
  else sa.lpSecurityDescriptor := nil;
  sa.nLength := sizeof(SECURITY_ATTRIBUTES);
  sa.bInheritHandle := TRUE;
  if CreatePipe(newstdin, write_stdin, @sa, 0) then
  begin
    if CreatePipe(read_stdout, newstdout, @sa, 0) then
    begin
      GetStartupInfo(si);
      with si do
      begin
        dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
        wShowWindow := SW_HIDE;
        hStdOutput := newstdout;
        hStdError := newstdout;
        hStdInput := newstdin;
      end;
      Fillchar(Buffer, SizeOf(Buffer), 0);
      GetEnvironmentVariable('COMSPEC', @Buffer, SizeOf(Buffer) - 1);
      StrCat(@Buffer,PChar(' /c ' + Cmd));
      if CreateProcess(nil, @Buffer, nil, nil, TRUE, CREATE_NEW_CONSOLE, nil, nil, si, pi) then
      begin
        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);
            Result:= Result + String(PChar(@Buffer));
          end;
          Application.ProcessMessages;
          GetExitCodeProcess(pi.hProcess, exitcod);
        until (exitcod <> STILL_ACTIVE) and (bread = 0);
      end;
      CloseHandle(read_stdout);
      CloseHandle(newstdout);
    end;
    CloseHandle(newstdin);
    CloseHandle(write_stdin);
  end;
end;

Forma de uso:

Código Delphi [-]
ShowMessage(CmdExec('dir c:\'));
__________________
La hora de acción no es hora de aprender, es necesario haber aprendido antes
Responder Con Cita
  #3  
Antiguo 08-09-2020
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por JoAnCa Ver Mensaje
no puse el codigo completo porque puse el enlace en el primer post
Oh, es verdad.

Revisando el código, da la impresión de que podría funcionar si cambias esta línea:
Código Delphi [-]
Result:= Result + String(PChar(@Buffer));
por:
Código Delphi [-]
Result:= Result + ANSIString(PANSIChar(@Buffer));
o simplemente:
Código Delphi [-]
Result := Result + PANSIChar (@Buffer);

Última edición por Al González fecha: 08-09-2020 a las 06:30:00.
Responder Con Cita
  #4  
Antiguo 09-09-2020
Avatar de JoAnCa
JoAnCa JoAnCa is offline
Miembro
 
Registrado: jul 2005
Ubicación: Cuba
Posts: 435
Poder: 19
JoAnCa Va por buen camino
Pues con el cambio que me indicas ya sale bien, con las dos opciones

Muchas gracias
__________________
La hora de acción no es hora de aprender, es necesario haber aprendido antes
Responder Con Cita
  #5  
Antiguo 09-09-2020
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
¡De nada!

Me alegra en verdad haberte podido ayudar.

Por lo visto esta sentencia
Código Delphi [-]
ReadFile(read_stdout, Buffer, bread, bread, nil);
lee caracteres ANSI (de un byte) y los mete a la variable Buffer. Esta tiene la declaración
Código Delphi [-]
Buffer: array[0..4096] of Char;
, que en su momento era una matriz de 4097 bytes. Pero ahora el tipo Char es Unicode y tiene un tamaño de dos bytes, por lo que la matriz duplica su tamaño en las versiones modernas de Delphi. Este cambio no parece dar problema con el resto de las funciones donde se utiliza la variable Buffer. GetEnvironmentVariable, por ejemplo, fue en su momento actualizada para Unicode. Sin embargo la lectura con ReadFile de lo que arroja el comando ejecutado depende de cómo trabaje la consola de Windows (al parecer sigue siendo ANSI).

Así, cuando se realiza la concatenación
Código Delphi [-]
Result:= Result + String(PChar(@Buffer));
en Delphi 2009 o superior, se toman los bytes de Buffer de dos en dos, siendo cada par, es decir, cada Char moderno, interpretado como un carácter Unicode.

Digamos que en un String ANSI 'Hola', donde el valor como Byte de esos cuatro caracteres es 72, 111, 108 y 97, unir por pares dichos valores nos daría (por su conformación binaria) los valores Word 28488 (111 desplazado ocho bits a la izquierda más 72) y 24940 (97 desplazado ocho bits a la izquierda más 108). Si buscamos en Google los caracteres Unicode de valor decimal 28488 y 24940, aparece que estos son y , respectivamente. No tengo la más remota idea de qué significan; no vayan a decir hola de esa manera cuando viajen por oriente.

El efecto del problema que se producía puede ser comprobado con un código como este:
Código Delphi [-]
procedure TfmMain.Button1Click(Sender: TObject);
Var
  A :ANSIString;
begin
  A := 'Hola';
  ShowMessage (PChar (A));  // W1044 Suspicious typecast of AnsiString to PWideChar
end;

Me gustaría hacer un reconocimiento al autor de la útil función CmdExec, Domingo Seoane. Tengo buenos recuerdos de él como miembro de este club. Durante años hizo innumerables aportaciones técnicas en materia de Delphi que hasta la fecha siguen sirviendo a programadores como JoAnCa. Mi respeto absoluto para Domingo, ojalá lo leamos por acá nuevamente.

Un abrazo caracterizado.

Al González.
Responder Con Cita
  #6  
Antiguo 09-09-2020
Avatar de JoAnCa
JoAnCa JoAnCa is offline
Miembro
 
Registrado: jul 2005
Ubicación: Cuba
Posts: 435
Poder: 19
JoAnCa Va por buen camino
Cita:
Empezado por Al González Ver Mensaje
¡De nada!

Me alegra en verdad haberte podido ayudar.

Por lo visto esta sentencia Código Delphi [-]ReadFile(read_stdout, Buffer, bread, bread, nil);

lee caracteres ANSI (de un byte) y los mete a la variable Buffer. Esta tiene la declaración Código Delphi [-]Buffer: array[0..4096] of Char;

, que en su momento era una matriz de 4097 bytes. Pero ahora el tipo Char es Unicode y tiene un tamaño de dos bytes, por lo que la matriz duplica su tamaño en las versiones modernas de Delphi. Este cambio no parece dar problema con el resto de las funciones donde se utiliza la variable Buffer. GetEnvironmentVariable, por ejemplo, fue en su momento actualizada para Unicode. Sin embargo la lectura con ReadFile de lo que arroja el comando ejecutado depende de cómo trabaje la consola de Windows (al parecer sigue siendo ANSI).

Así, cuando se realiza la concatenación Código Delphi [-]Result:= Result + String(PChar(@Buffer));

en Delphi 2009 o superior, se toman los bytes de Buffer de dos en dos, siendo cada par, es decir, cada Char moderno, interpretado como un carácter Unicode.

Digamos que en un String ANSI 'Hola', donde el valor como Byte de esos cuatro caracteres es 72, 111, 108 y 97, unir por pares dichos valores nos daría (por su conformación binaria) los valores Word 28488 (111 desplazado ocho bits a la izquierda más 72) y 24940 (97 desplazado ocho bits a la izquierda más 108). Si buscamos en Google los caracteres Unicode de valor decimal 28488 y 24940, aparece que estos son y , respectivamente. No tengo la más remota idea de qué significan; no vayan a decir hola de esa manera cuando viajen por oriente.

El efecto del problema que se producía puede ser comprobado con un código como este:
Código Delphi [-]procedure TfmMain.Button1Click(Sender: TObject); Var A :ANSIString; begin A := 'Hola'; ShowMessage (PChar (A)); // W1044 Suspicious typecast of AnsiString to PWideChar end;


Me gustaría hacer un reconocimiento al autor de la útil función CmdExec, Domingo Seoane. Tengo buenos recuerdos de él como miembro de este club. Durante años hizo innumerables aportaciones técnicas en materia de Delphi que hasta la fecha siguen sirviendo a programadores como JoAnCa. Mi respeto absoluto para Domingo, ojalá lo leamos por acá nuevamente.

Un abrazo caracterizado.

Al González.

Vaya, muy buena explicación, muy instructiva para mi, ya que siempre me gusta saber el por qué las "cosas" no funcionan
__________________
La hora de acción no es hora de aprender, es necesario haber aprendido antes
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

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Ejecutar comando PowerShell windows Parsec Windows 2 03-10-2019 08:52:01
Ejecutar comando y capturar su salida seoane Trucos 10 07-11-2017 12:08:28
Capturar la salida de un comando dos. spab API de Windows 26 04-02-2011 13:05:08
Ejecutar comando remoto papulo Linux 5 27-11-2008 18:41:46
Capturar salida de comando linux pkbza Lazarus, FreePascal, Kylix, etc. 5 13-01-2006 01:45:32


La franja horaria es GMT +2. Ahora son las 20:34:22.


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