AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi CreateProcess + XCOPY + Pipes = HILFE!!!
Thema durchsuchen
Ansicht
Themen-Optionen

CreateProcess + XCOPY + Pipes = HILFE!!!

Ein Thema von FritzAT · begonnen am 25. Aug 2007 · letzter Beitrag vom 26. Aug 2007
Antwort Antwort
Seite 1 von 2  1 2      
FritzAT
(Gast)

n/a Beiträge
 
#1

CreateProcess + XCOPY + Pipes = HILFE!!!

  Alt 25. Aug 2007, 22:36
Hallo Leute!

Ich suche eine möglichkeit(seit 4 Tagen) mithilfe von pipes die ausgabe von
XCOPY /? in ein memo zu "schieben".
Es funktionieren dir /?, set /?, copy /?,...

WARUM funktioniert das mit XCOPY nicht?

Benutze folgenden code:

Delphi-Quellcode:
if CreateProcess
        (nil, // pointer to name of executable module
// FUNKTIONIERT
// PChar('cmd.exe /c copy /?), // pointer to command line string
// FUNKIONIERT NICHT(WAAARUM???)
         PChar('cmd.exe /c xcopy /?), // pointer to command line string
nil, // pointer to process security attributes
nil, // pointer to thread security attributes
True, // handle inheritance flag
0, // creation flags
nil, // pointer to new environment block
nil, // pointer to current directory name
start, // pointer to STARTUPINFO
procInfo) // pointer to PROCESS_INFORMATION
  Mit Zitat antworten Zitat
Olli
(Gast)

n/a Beiträge
 
#2

Re: CreateProcess + XCOPY + Pipes = HILFE!!!

  Alt 25. Aug 2007, 22:52
STDOUT, STDIN und STDERR ... an welche hängst du deine Pipes und in welche gibt XCOPY die Ausgabe aus? Das wird aus deinem Code nicht ersichtlich, daher die Frage.
  Mit Zitat antworten Zitat
FritzAT
(Gast)

n/a Beiträge
 
#3

Re: CreateProcess + XCOPY + Pipes = HILFE!!!

  Alt 25. Aug 2007, 23:18
Hallo!

Danke für die antwort, aber wie geschreiben funktionieren die anderen commandos
einwandfrei(dir /?,...).
Soweit muesste die funktion eigentlich mit XCOPY auch funktionieren.
Ich glaube bald es liegt an XCOPY selbst...
Zu deiner frage.
Die umleitung erfolg über eine temporäre datei...

Delphi-Quellcode:
function TForm1.RunCaptured(const _dirName, _exeName, _cmdLine: string): Boolean;
var
  start: TStartupInfo;
  procInfo: TProcessInformation;
  tmpName: string;
  tmp: Windows.THandle;
  tmpSec: TSecurityAttributes;
  res: TStringList;
  return: Cardinal;
begin
  Result := False;
  try
    { Setze ein Temporäres File }
    tmpName := 'Test.tmp';
    FillChar(tmpSec, SizeOf(tmpSec), #0);
    tmpSec.nLength := SizeOf(tmpSec);
    tmpSec.bInheritHandle := True;
    tmp := Windows.CreateFile(PChar(tmpName),
           Generic_Write, File_Share_Write,
           @tmpSec, Create_Always, File_Attribute_Normal, 0);
    try
      FillChar(start, SizeOf(start), #0);
      start.cb := SizeOf(start);
      start.hStdOutput := tmp;
      start.dwFlags := StartF_UseStdHandles or StartF_UseShowWindow;
      start.wShowWindow := SW_Minimize;
      { bsp. RunCaptured('C:\', 'cmd.exe', '/c dir /?'); }
      if CreateProcess
        (nil, // pointer to name of executable module
         PChar(_exeName+' '+_cmdLine), // pointer to command line string
         nil, // pointer to process security attributes
         nil, // pointer to thread security attributes
         True, // handle inheritance flag
         0, // creation flags
         nil, // pointer to new environment block
         PChar(_dirName), // pointer to current directory name
         start, // pointer to STARTUPINFO
         procInfo) // pointer to PROCESS_INFORMATION
      then
      begin
        SetPriorityClass(procInfo.hProcess, Idle_Priority_Class);
        WaitForSingleObject(procInfo.hProcess, Infinite);
        GetExitCodeProcess(procInfo.hProcess, return);
        Result := (return = 0);
        CloseHandle(procInfo.hThread);
        CloseHandle(procInfo.hProcess);
        Windows.CloseHandle(tmp);
        { Die Ausgaben hinzufügen }
        res := TStringList.Create;
        try
          res.LoadFromFile(tmpName);
          Memo1.Lines.AddStrings(res);
        finally
          res.Free;
        end;
        Windows.DeleteFile(PChar(tmpName));
      end
      else
      begin
        Application.MessageBox(PChar(SysErrorMessage(GetLastError())),
          'RunCaptured Error', MB_OK);
      end;
    except
      Windows.CloseHandle(tmp);
      Windows.DeleteFile(PChar(tmpName));
      raise;
    end;
  finally
  end;
end;
--------------------------------------
Delphi-Quellcode:
procedure TForm1.Button3Click(Sender: TObject);
begin
  RunCaptured('C:\', 'cmd.exe', '/c copy /?');
end;
  Mit Zitat antworten Zitat
Olli
(Gast)

n/a Beiträge
 
#4

Re: CreateProcess + XCOPY + Pipes = HILFE!!!

  Alt 26. Aug 2007, 00:32
Eigentlich irrelevant, ob Pipe oder Datei. Aber der zuletzt gepostete Code bringt u.U. des Rätsels Lösung.

Wie oben schon erwähnt, gibt es verschiedene "Kanäle" auf denen Ein- und Ausgaben von/in die Konsole stattfinden. Die komplette Struktur, welche du als Variable "start" ansprichst, sieht in C so aus:

Code:
typedef struct _STARTUPINFO {
  DWORD cb;
  LPTSTR lpReserved;
  LPTSTR lpDesktop;
  LPTSTR lpTitle;
  DWORD dwX;
  DWORD dwY;
  DWORD dwXSize;
  DWORD dwYSize;
  DWORD dwXCountChars;
  DWORD dwYCountChars;
  DWORD dwFillAttribute;
  DWORD dwFlags;
  WORD wShowWindow;
  WORD cbReserved2;
  LPBYTE lpReserved2;
  [color=darkred]HANDLE hStdInput;
  HANDLE hStdOutput;
  [b]HANDLE hStdError;[/b][/color]
} STARTUPINFO, *LPSTARTUPINFO;
Die Kanäle habe ich mal hervorgehoben. Da du nur den Ausgabekanal "STDOUT" überwachst, kann es sein, daß dir Ausgaben auf "STDERR" (fett hervorgehoben) verloren gehen. Das war mein Punkt. Daher solltest du entweder - noch nie probiert ob das geht - die Datei so öffnen, daß sie von mehreren "Benutzern" zum Schreiben verwendet werden kann (i.e. FILE_SHARE_WRITE mit angeben), oder eine zweite Datei für diesen Ausgabekanal bereitstellen um ihn abzufangen. Wenn es dann immernoch nicht geht, liegt ein anderes Problem vor, aber eigentlich sollte es das lösen.

Klartext - versuche es mal mit folgender Einfügung:

start.hStdError := tmp; (vor oder nach:
start.hStdOutput := tmp; sollte egal sein)
  Mit Zitat antworten Zitat
Benutzerbild von Garfield
Garfield

Registriert seit: 9. Jul 2004
Ort: Aken (Anhalt-Bitterfeld)
1.335 Beiträge
 
Delphi XE5 Professional
 
#5

Re: CreateProcess + XCOPY + Pipes = HILFE!!!

  Alt 26. Aug 2007, 10:48
Zitat von Olli:
Die komplette Struktur, welche du als Variable "start" ansprichst, sieht in C so aus:
Unit Windows:
Delphi-Quellcode:
type
  PStartupInfoA = ^TStartupInfoA;
  PStartupInfoW = ^TStartupInfoW;
  PStartupInfo = PStartupInfoA;
  _STARTUPINFOA = record
    cb: DWORD;
    lpReserved: PAnsiChar;
    lpDesktop: PAnsiChar;
    lpTitle: PAnsiChar;
    dwX: DWORD;
    dwY: DWORD;
    dwXSize: DWORD;
    dwYSize: DWORD;
    dwXCountChars: DWORD;
    dwYCountChars: DWORD;
    dwFillAttribute: DWORD;
    dwFlags: DWORD;
    wShowWindow: Word;
    cbReserved2: Word;
    lpReserved2: PByte;
    hStdInput: THandle;
    hStdOutput: THandle;
    hStdError: THandle;
  end;
  _STARTUPINFOW = record
    cb: DWORD;
    lpReserved: PWideChar;
    lpDesktop: PWideChar;
    lpTitle: PWideChar;
    dwX: DWORD;
    dwY: DWORD;
    dwXSize: DWORD;
    dwYSize: DWORD;
    dwXCountChars: DWORD;
    dwYCountChars: DWORD;
    dwFillAttribute: DWORD;
    dwFlags: DWORD;
    wShowWindow: Word;
    cbReserved2: Word;
    lpReserved2: PByte;
    hStdInput: THandle;
    hStdOutput: THandle;
    hStdError: THandle;
  end;
  _STARTUPINFO = _STARTUPINFOA;
  TStartupInfoA = _STARTUPINFOA;
  TStartupInfoW = _STARTUPINFOW;
  TStartupInfo = TStartupInfoA;
  {$EXTERNALSYM STARTUPINFOA}
  STARTUPINFOA = _STARTUPINFOA;
  {$EXTERNALSYM STARTUPINFOW}
  STARTUPINFOW = _STARTUPINFOW;
  {$EXTERNALSYM STARTUPINFO}
  STARTUPINFO = STARTUPINFOA;
Ich verwende in leicht modifizierter Form die Routine von Sprint aus http://www.softgames.de/forum/viewtopic.php?t=24225

Dabei wird auch geprüft, ob die Pipes erstellt wurden. Und die Konsolenausgabe kann direkt ohne eine temporäre Datei ins Memo eingetragen werden.
Gruss Garfield
Ubuntu 22.04: Laz2.2.2/FPC3.2.2 - VirtBox6.1+W10: D7PE, DXE5Prof
  Mit Zitat antworten Zitat
FritzAT
(Gast)

n/a Beiträge
 
#6

Re: CreateProcess + XCOPY + Pipes = HILFE!!!

  Alt 26. Aug 2007, 13:19
Hallo!

Danke für die antworten...

Mein gedanke...
vielleicht funktioniert es nicht weil xcopy kein 'interner befehl' wie zb. dir, copy,...
usw. ist, den die 'echten internen befehle' funktionieren ALLE optimal.
Könnte es nicht sein das XCOPY anders 'gestarted' werden muß um die ausgabe zu erhalten?

zu Olli:
natürlich nur den Ausgabekanal, denn ich will ja nur die ausgabe sehen(xcopy /?)...
und warum Fehler..(bei xcopy /?)

Zitat:
Das war mein Punkt. Daher solltest du entweder - noch nie probiert ob das geht - die Datei so öffnen,
daß sie von mehreren "Benutzern" zum Schreiben verwendet werden kann (i.e. FILE_SHARE_WRITE mit angeben).
try
{ Setze ein Temporäres File }
tmpName := 'Test.tmp';
FillChar(tmpSec, SizeOf(tmpSec), #0);
tmpSec.nLength := SizeOf(tmpSec);
tmpSec.bInheritHandle := True;
tmp := Windows.CreateFile(PChar(tmpName),
Generic_Write, File_Share_Write,
@tmpSec, Create_Always, File_Attribute_Normal, 0);

zu Garfiel:
danke für den link, aber der führt ins nirwana...
hast du einen aktuellen?

Danke ihr beiden...
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.117 Beiträge
 
Delphi 11 Alexandria
 
#7

Re: CreateProcess + XCOPY + Pipes = HILFE!!!

  Alt 26. Aug 2007, 13:45
Moin Fritz,

Zitat von FritzAT:
Mein gedanke...
vielleicht funktioniert es nicht weil xcopy kein 'interner befehl' wie zb. dir, copy,...
usw. ist, den die 'echten internen befehle' funktionieren ALLE optimal.
Könnte es nicht sein das XCOPY anders 'gestarted' werden muß um die ausgabe zu erhalten?
das liesse sich ja recht einfach herausfinden, indem Du statt der cmd.exe einfach mal die xcopy.exe mittels CreateProcess startest.

Zumindest zu DOS-Zeiten sprach man übrigens von residenten (DIR, COPY...) bzw. transienten (XCOPY...) Befehlen.
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
FritzAT
(Gast)

n/a Beiträge
 
#8

Re: CreateProcess + XCOPY + Pipes = HILFE!!!

  Alt 26. Aug 2007, 14:06
Hallo!

Zitat:
das liesse sich ja recht einfach herausfinden, indem Du statt der cmd.exe
einfach mal die xcopy.exe mittels CreateProcess startest.

Zumindest zu DOS-Zeiten sprach man übrigens von residenten (DIR, COPY...)
bzw. transienten (XCOPY...) Befehlen.
Hab ich natürlich schon probiert...
Dachte mir es müsste anders gestartet werden...

Mit intern hatte ich gemeint, das die befehle innerhalb von command.com waren.
Den dir, copy usw. wurden eigentlich von command.com ausgeführt...

Trotzdem DANKE

Die procedure TForm1.RunConsoleApp(const CommandLine: String; AStrings: TStrings); von OLLI hat GOTTSEIDANK mit XCOPY /? funktioniert(nochmals danke)

Werde mir die jetzt gedanklich einverleiben....

an OLLI: Mein Haupt in Asche....
  Mit Zitat antworten Zitat
Benutzerbild von Garfield
Garfield

Registriert seit: 9. Jul 2004
Ort: Aken (Anhalt-Bitterfeld)
1.335 Beiträge
 
Delphi XE5 Professional
 
#9

Re: CreateProcess + XCOPY + Pipes = HILFE!!!

  Alt 26. Aug 2007, 14:50
Zitat von FritzAT:
zu Garfiel:
danke für den link, aber der führt ins nirwana...
hast du einen aktuellen?
Bei mir funktioniert er.

Die fragliche Procedure:

Delphi-Quellcode:
procedure RunConsoleApp(const CommandLine: String; AStrings: TStrings);
type
  TCharBuffer = array[0..MaxInt - 1] of Char;
const
  MaxBufSize = 1024;
var
  I: Longword;
  SI: TStartupInfo;
  PI: TProcessInformation;
  SA: PSecurityAttributes;
  SD: PSECURITY_DESCRIPTOR;
  NewStdIn: THandle;
  NewStdOut: THandle;
  ReadStdOut: THandle;
  WriteStdIn: THandle;
  Buffer: ^TCharBuffer;
  BufferSize: Cardinal;
  Last: WideString;
  Str: WideString;
  ExitCode: DWORD;
  Bread: DWORD;
  Avail: DWORD;
begin
  GetMem(SA, SizeOf(TSecurityAttributes));

  case Win32Platform of
    VER_PLATFORM_WIN32_NT:
      begin
        GetMem(SD, SizeOf(SECURITY_DESCRIPTOR));
        Win32Check(InitializeSecurityDescriptor(SD, SECURITY_DESCRIPTOR_REVISION));
        Win32Check(SetSecurityDescriptorDacl(SD, True, nil, False));
        SA.lpSecurityDescriptor := SD;
      end; {end VER_PLATFORM_WIN32_NT}
    else
      SA.lpSecurityDescriptor := nil;
  end; {end case}

  SA.nLength := SizeOf(SECURITY_ATTRIBUTES);
  SA.bInheritHandle := True;

  Win32Check(CreatePipe(NewStdIn, WriteStdIn, SA, 0));

  if not CreatePipe(ReadStdOut, NewStdOut, SA, 0) then
  begin
    CloseHandle(NewStdIn);
    CloseHandle(WriteStdIn);
    RaiseLastWin32Error;
  end; {end if}

  GetStartupInfo(SI);
  SI.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
  SI.wShowWindow := SW_SHOWNORMAL;
  SI.hStdOutput := NewStdOut;
  SI.hStdError := NewStdOut;
  SI.hStdInput := NewStdIn;

  if not CreateProcess(nil, PChar(CommandLine), nil, nil, True,
    CREATE_NEW_CONSOLE, nil, nil, SI, PI) then
  begin
    CloseHandle(NewStdIn);
    CloseHandle(NewStdOut);
    CloseHandle(ReadStdOut);
    CloseHandle(WriteStdIn);
    RaiseLastWin32Error;
  end; {end if}

  Last := '';
  BufferSize := MaxBufSize;
  Buffer := AllocMem(BufferSize);

  try
    repeat
      Win32Check(GetExitCodeProcess(PI.hProcess, ExitCode));
      PeekNamedPipe(ReadStdOut, Buffer, BufferSize, @Bread, @Avail, nil);

      if (Bread <> 0) then
      begin
        if (BufferSize < Avail) then
        begin
          BufferSize := Avail;
          ReallocMem(Buffer, BufferSize);
        end; {end if}
        FillChar(Buffer^, BufferSize, #0);
        ReadFile(ReadStdOut, Buffer^, BufferSize, Bread, nil);
        Str := Last;
        I := 0;

        while (I < Bread) do
        begin

          case Buffer^[I] of
            #0: inc(I);

            #10:
              begin
                inc(I);
                AStrings.Add(Str);
                Str := '';
              end; {end #10}

            #13:
              begin
                inc(I);
                if (I < Bread) and (Buffer^[I] = #10) then
                  inc(I);
                AStrings.Add(Str);
                Str := '';
              end; {end #13}

            else
              begin
                Str := Str + Buffer^[I];
                inc(I);
              end; {end else}

          end; {end case}
        end; {end while}
        Last := Str;
      end; {end if}
      Sleep(1);
      Application.ProcessMessages;
    until (ExitCode <> STILL_ACTIVE);

    if Last <> 'then
      AStrings.Add(Last);

  finally
    FreeMem(Buffer);
  end; {end try/finally}

  CloseHandle(PI.hThread);
  CloseHandle(PI.hProcess);
  CloseHandle(NewStdIn);
  CloseHandle(NewStdOut);
  CloseHandle(ReadStdOut);
  CloseHandle(WriteStdIn);

end; {end procedure}
Ich habe beispielsweise 'AStrings: TStrings' in 'Memo: TMemo' und 'AStrings.Add(Str);' in 'Memo.Lines.Add(Str);' geändert. Eventuell muss beim Memo wegen der Umlaute das Charset vom Standard Ansi_CharSet auf OEM_CharSet geändert werden.

Zitat von FritzAT:
Mein gedanke...
vielleicht funktioniert es nicht weil xcopy kein 'interner befehl' wie zb. dir, copy,...
usw. ist, den die 'echten internen befehle' funktionieren ALLE optimal.
Könnte es nicht sein das XCOPY anders 'gestarted' werden muß um die ausgabe zu erhalten?
Dein Befehl hat bei mir vorhin funktioniert.
__

Nachtrag:

War wohl gerade zu lange abgelenkt!?

Zitat von FritzAT:
Die procedure TForm1.RunConsoleApp(const CommandLine: String; AStrings: TStrings); von OLLI hat GOTTSEIDANK mit XCOPY /? funktioniert(nochmals danke)
Von OLLI???
Gruss Garfield
Ubuntu 22.04: Laz2.2.2/FPC3.2.2 - VirtBox6.1+W10: D7PE, DXE5Prof
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#10

Re: CreateProcess + XCOPY + Pipes = HILFE!!!

  Alt 26. Aug 2007, 14:52
Zitat:
Ich habe beispielsweise 'AStrings: TStrings' in 'Memo: TMemo' und 'AStrings.Add(Str);' in 'Memo.Lines.Add(Str);' geändert. Eventuell muss beim Memo wegen der Umlaute das Charset vom Standard Ansi_CharSet auf OEM_CharSet geändert werden.
Aua TMemo.Lines ist vom Typ TStrings. Das heißt du hättest einfach "Memo.Lines" an die Funktion übergeben müssen.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:25 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz