![]() |
CreateProcess + XCOPY + Pipes = HILFE!!!
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 |
Re: CreateProcess + XCOPY + Pipes = HILFE!!!
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.
|
Re: CreateProcess + XCOPY + Pipes = HILFE!!!
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; |
Re: CreateProcess + XCOPY + Pipes = HILFE!!!
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:
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.
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; Klartext - versuche es mal mit folgender Einfügung:
Delphi-Quellcode:
(vor oder nach:
start.hStdError := tmp;
Delphi-Quellcode:
sollte egal sein)
start.hStdOutput := tmp;
|
Re: CreateProcess + XCOPY + Pipes = HILFE!!!
Zitat:
Delphi-Quellcode:
Ich verwende in leicht modifizierter Form die Routine von Sprint aus
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; ![]() Dabei wird auch geprüft, ob die Pipes erstellt wurden. Und die Konsolenausgabe kann direkt ohne eine temporäre Datei ins Memo eingetragen werden. |
Re: CreateProcess + XCOPY + Pipes = HILFE!!!
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:
{ 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... |
Re: CreateProcess + XCOPY + Pipes = HILFE!!!
Moin Fritz,
Zitat:
Zumindest zu DOS-Zeiten sprach man übrigens von residenten (DIR, COPY...) bzw. transienten (XCOPY...) Befehlen. |
Re: CreateProcess + XCOPY + Pipes = HILFE!!!
Hallo!
Zitat:
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
Delphi-Quellcode:
von OLLI hat GOTTSEIDANK mit XCOPY /? funktioniert(nochmals danke)
procedure TForm1.RunConsoleApp(const CommandLine: String; AStrings: TStrings);
Werde mir die jetzt gedanklich einverleiben.... an OLLI: Mein Haupt in Asche.... |
Re: CreateProcess + XCOPY + Pipes = HILFE!!!
Zitat:
Die fragliche Procedure:
Delphi-Quellcode:
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.
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} Zitat:
__ Nachtrag: War wohl gerade zu lange abgelenkt!? Zitat:
|
Re: CreateProcess + XCOPY + Pipes = HILFE!!!
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:41 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz