![]() |
mit der console interaktiv komunizieren
ich habe zwar schon mal dies bezüglich im DF gepostet (
![]() also ich habe folgends problem: mein programm soll ein doscommand an die console übergeben. soweit ist das ja auch kein problem. code dazu findet man ja genug. nur leider ist das was man findet, ein klein wenig an meinem problem vorbei, weil der command ausgeführt wird und das ergebnis in einem memo ausgegeben wird und die console wird dann wieder geschlossen. und genau da sitzt mein problem. die console soll sich nicht schliessen, sondern auf weitere anweisungen warten, eben interaktiv komunizieren, mit meinem programm. bei dem code welchen man findet ist zum beispiel ein cd oder cd.. nicht möglich genausowenig kann man laufende prozeße unterbrechen. wenn ich jetzt zb. in die richtig console eingebe ping -t ![]() ich hoffe mir kann jemand helfen. |
Re: mit der console interaktiv komunizieren
Kommunizier mit der Konsole über Pipes.
|
Re: mit der console interaktiv komunizieren
Zitat:
Also ich hatte so ein Problem noch nie, ich weiß aber, das man ein CMD starten kann und auf Pipes umleiten, schau dir mal das hier an, vielleicht hilft das irgendwie: Zitat:
Bye |
Re: mit der console interaktiv komunizieren
das es an den "Pipes" liegen könnte, konnte ich mir schon denken nur leider versteh ich nicht viel davon. hast du da nicht ein code beispiel für mich (unfähigen api programmierer)?
das was Kedariodakon geschrieben hat hilft mir nicht wirklich weiter, denke ich weil ich ja nicht die "echte" console benutze sondern alles über meine programm laufen lass in und output |
Re: mit der console interaktiv komunizieren
Zitat:
Bye |
Re: mit der console interaktiv komunizieren
Zitat:
doch mit paramter /k gehts !!! den code stelle ich gleich noch vor wo bei ich dazusagen muß, das die eigendliche funktion aus dem delphi-treff ist... |
Re: mit der console interaktiv komunizieren
Hallo
Hm, was ist eine regestrierten Pipe und wie greifst Du daruf zu (Codebeispiel). Wie kann man eigentlich auf eine Eingabaufforderung reagieren. Oder wie bekommt man überhaupt mit, das ein Dos Programm auf eine Eingabe wartet? // Martin |
Re: mit der console interaktiv komunizieren
ich doch noch mal was berichtigen.... es wird nur 1x ein verzeichniswechsel aus geführt wenn ich zweimal cd.. cd.. mache gehts nicht. da ich aber insgesamt 4 code beispiele habe werde ich jetzt mal alle durchtesten...
Zitat:
|
Re: mit der console interaktiv komunizieren
Naja die Konsole hat ja nen Output als pipe, der ja nur ausgegeben wird, war irgendwie sowas wie STDOut und ERROut, da muß es auch ein *In* geben :roll:
Nur brauch man die Pipe von der CMD die man gestartet hat ^^ Einzelne befehle kann man sich ja auch auf pips, bzw. datein ausgeben lassen: dir c:\gibtsnet.haumichtod 1>>STDOut.txt 2>>ErrOut.txt Normale Ausgabe in STDOut.txt und ERRor Ausgabe in ErrOut.txt... Bye Edit zur not die gedrückten Tasten dem CMD zusenden ^^ |
Re: mit der console interaktiv komunizieren
also wenn ich eingebe "cd.." und lasse mir dann mit "dir" den verzeichnisinhalt anzeigen zeigt er zwar an da er das verzeichnis gewechselt hat aber dir liefert immer noch den alte verzeichnis inhalt
|
Re: mit der console interaktiv komunizieren
|
Re: mit der console interaktiv komunizieren
ich habe jetzt von den 4 codebeispielen das beste rausgesucht wo ein verzeichniswechsel möglich ist:
(ich glaube der war von den schweitzern)
Delphi-Quellcode:
aber auch hier gibt es das problem das wenn ich eingebe cd verzeichnis wechselt er zwar aber wenn ich dann wieder "dir" eingebe zeigt er wieder den inhalt von c:\ an. dies liegt daran das ich als arbeitsverzeichnis "c:\" im Button1Click-Ereigeniss übergebe. kann den code jemand umbauen, weil ich kann es nicht....
{ Public-Deklarationen }
function RunCaptured(const _dirName, _exeName, _cmdLine: string): Boolean; 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 } { Set a temporary 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; { Starte das Programm } { Start the program } if CreateProcess(nil, PChar(_exeName + ' ' + _cmdLine), nil, nil, True, 0, nil, PChar(_dirName), start, procInfo) 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 } { Add the output } 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; procedure TForm1.Button1Click(Sender: TObject); begin RunCaptured('C:\', 'cmd.exe', '/K '+Edit1.Text); end; und diesen code habe ich im delphi-treff gefunden
Delphi-Quellcode:
bei diesem kann ich zwar ein cd.. machen aber wenn ich mir denn verzeichnis inhalt anzeigen lasse, zeigt er nicht das übergeordnete verzeichnis
function GetConsoleOutput(const Command: String; var Output, Errors: TStringList): Boolean;
var StartupInfo: TStartupInfo; ProcessInfo: TProcessInformation; SecurityAttr: TSecurityAttributes; PipeOutputRead: THandle; PipeOutputWrite: THandle; PipeErrorsRead: THandle; PipeErrorsWrite: THandle; Succeed: Boolean; Buffer: array [0..255] of Char; NumberOfBytesRead: DWORD; Stream: TMemoryStream; begin //Initialisierung ProcessInfo FillChar(ProcessInfo, SizeOf(TProcessInformation), 0); //Initialisierung SecurityAttr FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0); SecurityAttr.nLength := SizeOf(SecurityAttr); SecurityAttr.bInheritHandle := true; SecurityAttr.lpSecurityDescriptor := nil; //Pipes erzeugen CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0); CreatePipe(PipeErrorsRead, PipeErrorsWrite, @SecurityAttr, 0); //Initialisierung StartupInfo FillChar(StartupInfo, SizeOf(TStartupInfo), 0); StartupInfo.cb:=SizeOf(StartupInfo); StartupInfo.hStdInput := 0; StartupInfo.hStdOutput := PipeOutputWrite; StartupInfo.hStdError := PipeErrorsWrite; StartupInfo.wShowWindow := sw_Hide; StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; if CreateProcess(nil, PChar(command), nil, nil, true, CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo) then begin result:=true; //Write-Pipes schließen CloseHandle(PipeOutputWrite); CloseHandle(PipeErrorsWrite); //Ausgabe Read-Pipe auslesen Stream := TMemoryStream.Create; try while true do begin succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil); if not succeed then break; Stream.Write(Buffer, NumberOfBytesRead); end; Stream.Position := 0; Output.LoadFromStream(Stream); finally Stream.Free; end; CloseHandle(PipeOutputRead); //Fehler Read-Pipe auslesen Stream := TMemoryStream.Create; try while true do begin succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil); if not succeed then break; Stream.Write(Buffer, NumberOfBytesRead); end; Stream.Position := 0; Errors.LoadFromStream(Stream); finally Stream.Free; end; CloseHandle(PipeErrorsRead); WaitForSingleObject(ProcessInfo.hProcess, INFINITE); CloseHandle(ProcessInfo.hProcess); end else begin result:=false; CloseHandle(PipeOutputRead); CloseHandle(PipeOutputWrite); CloseHandle(PipeErrorsRead); CloseHandle(PipeErrorsWrite); end; end; procedure TForm1.Button1Click(Sender: TObject); var output, errors: TStringList; begin output:=TStringList.Create; try errors:=TStringList.Create; if GetConsoleOutput('cmd /K '+Edit1.Text, output, errors) then Memo1.Lines.AddStrings(output); finally output.free; errors.free; end; end; dieser code kommt von supermuckel ein mitglied der DP
Delphi-Quellcode:
wenn ich hier die console mit dem parameter "/K" starte, hängt sich das programm auf. es läuft nur sauber mit dem "/C"
function IsWinNT: boolean;
var osv : OSVERSIONINFO; begin result := false; try osv.dwOSVersionInfoSize := sizeof(osv); GetVersionEx(osv); result := (osv.dwPlatformId = VER_PLATFORM_WIN32_NT); except end; end; procedure TForm1.GetConsoleOutput(const Command: String); var si: TStartupInfo; pi: TProcessInformation; sa: TSecurityAttributes; sd: TSECURITYDESCRIPTOR; newstdin,newstdout,read_stdout,write_stdin:Thandle; Succeed: Boolean; Buffer: array [0..1024] of Char; NumberOfBytesRead: DWORD; BytesAvailable: DWORD; //Stream: TMemoryStream; app_spawn: string; exitcode : cardinal; begin //Initialisierung ProcessInfo FillChar(pi, SizeOf(TProcessInformation), 0); //Initialisierung SecurityAttr FillChar(sa, SizeOf(TSecurityAttributes), 0); if IsWinNT then begin InitializeSecurityDescriptor(@sd,SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(@sd, true, nil, false); sa.lpSecurityDescriptor := @sd; end else begin sa.lpSecurityDescriptor := nil; end; sa.nLength := SizeOf(sa); sa.bInheritHandle := true; if (not CreatePipe(newstdin,write_stdin,@sa,0)) then begin CloseHandle(newstdin); CloseHandle(write_stdin); exit; //create stdin pipe end; if (not CreatePipe(read_stdout,newstdout,@sa,0)) then begin //create stdout pipe CloseHandle(read_stdout); CloseHandle(newstdout); exit; end; GetStartupInfo(si); //set startupinfo for the spawned process { The dwFlags member tells CreateProcess how to make the process. STARTF_USESTDHANDLES validates the hStd* members. STARTF_USESHOWWINDOW validates the wShowWindow member. } si.dwFlags := STARTF_USESTDHANDLES OR STARTF_USESHOWWINDOW; si.wShowWindow := SW_HIDE; si.hStdOutput := newstdout; si.hStdError := newstdout; //set the new handles for the child process si.hStdInput := newstdin; app_spawn := 'c:\\window3\\system32\\cmd.exe'; //spawn the child process // if (not CreateProcess(pchar(app_spawn),nil,nil,nil,TRUE,CREATE_NEW_CONSOLE,nil,nil,si,pi)) then begin if (not CreateProcess(nil, PChar(command), nil, nil, true,CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil,si,pi)) then begin CloseHandle(newstdin); CloseHandle(newstdout); CloseHandle(read_stdout); CloseHandle(write_stdin); end else begin //fillchar(buffer,sizeof(buffer),0); // main loop exitcode := 0; while true do begin GetExitCodeProcess(pi.hProcess,exitcode); //while the process is running if (exitcode <> STILL_ACTIVE) then break; BytesAvailable := 0; PeekNamedPipe(read_stdout,pchar(buffer[0]),1023,@NumberOfBytesRead,@BytesAvailable,nil); //check to see if there is any data to read from stdout if (NumberOfBytesRead <> 0) then begin if (BytesAvailable > 1023) then begin while (NumberOfBytesRead >= 1023) do begin fillchar(buffer,sizeof(buffer),0); ReadFile(read_stdout,buffer,1023,NumberOfBytesRead,nil); //read the stdout pipe memo1.Lines.Add(buffer); end; end else begin fillchar(buffer,sizeof(buffer),0); ReadFile(read_stdout,buffer,1023,NumberOfBytesRead,nil); //read the stdout pipe memo1.Lines.Add(buffer); end; end; end; // main loop CloseHandle(pi.hThread); CloseHandle(pi.hProcess); CloseHandle(newstdin); //clean stuff up CloseHandle(newstdout); CloseHandle(read_stdout); CloseHandle(write_stdin); end; // process created end; procedure TForm1.Button1Click(Sender: TObject); begin GetConsoleOutput('cmd /C '+edit1.Text); end; |
Re: mit der console interaktiv komunizieren
Zitat:
also scheint es wohl nur abgestürzt zu sein.. ich bin da auch kein experte ! |
Re: mit der console interaktiv komunizieren
Zitat:
MfG Binärbaum |
Re: mit der console interaktiv komunizieren
Zitat:
|
Re: mit der console interaktiv komunizieren
Liste der Anhänge anzeigen (Anzahl: 1)
ich glaube das hier könnte die lösung sein. ich bin nicht mehr sicher wo ich es gestern gefunden habe, ich glaube bei torry... ich häge es einfach mal an.
|
Re: mit der console interaktiv komunizieren
Moin, moin
1. Der Glaube ist wieder im Kommen, aber bei mir kommt bei dem Click auf 'Run' nur ein leidiges 'Error creating Pipe A'. 2. Wie man eine Eingabe abfängt ist nicht gelöst. 3. Soweit war ich vor längerem schon mal und die Lösung liegt in der DP unter ![]() Man kann damit Befehle ausfürhen, die nur Anzeigen. Das Eingabeproblem blieb damals auch schon offen. Schönes Wochenende // Martin |
Re: mit der console interaktiv komunizieren
also bei mir funzt es bis jetzt hervorranged. es tretten genau(!!!) die gleichen oder selben fehler auf wie bei "professionellen" löungen die man kaufen kann. zb. wenn ich dort dos ftp nehmen will, geht das nicht so richrig. wenn ich es in einem script ausführe weden mir zwar fehler angezeigt, aber das get bzw put hat funktioniert. ich habe versucht ein ping -t
![]() |
Re: mit der console interaktiv komunizieren
Moin, moin
Hm, war ein ME-Rechner. Vielleicht liegt es daran. Grüße // Martin |
Re: mit der console interaktiv komunizieren
möglich. ich habe win2kpro drauf und es läuft einwandfrei (bis auf eben die fehler welche in komerzieller software auch sind) hast du "cmd.exe" gegen "command.com" ausgetauscht und den phat angepasst? übrigends: die unit RedirectConsole.pas enthält eine funktion "function IsWinNT" hast du dir das schonmal angesehen?
|
Re: mit der console interaktiv komunizieren
Moin, ziemlich Spätmoin
Delphi-Quellcode:
Jo das wars dann doch,
if IsWinNT then begin
InitializeSecurityDescriptor(@sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(@sd, true, nil, false); sa.lpSecurityDescriptor:=@sd; end else sa.lpSecurityDescriptor:=nil; { <-- das ist es unter Win9.x } da ist die Erklärung: Geht nur unter NT.x So long für heute abend... // Martin |
Re: mit der console interaktiv komunizieren
Zitat:
Es funktioniert auch bei allen Anwendungen, nur bei einer nicht. Die Anwendung läuft in der Konsole ohne Probleme aber wenn ich sie mit dem Tool starte bekomme ich andauernd(mind 100x in der Sekunde) die Meldung, dass der Befehl von dem Programm nicht erkannt wird. Heißt für mich, dass das Programm irgendwie glaubt es wären Daten eingegeben (wenn auch fehlerhafte) worden - sind es aber nicht. Hat jemand vielleicht ein ähnliches Problem, oder weiss wie ich das beheben kann? Jan |
Re: mit der console interaktiv komunizieren
Mit einen Debugger, Tasse Kaffee viel Geduld und tiefergreifenden Delphi-Verständniss :lol:
|
Re: mit der console interaktiv komunizieren
Zitat:
Es funktioniert nichtmal, wenn ich in deinem tool cmd.exe starte und damit das Programm öffne *grummel* Das ist kein delphi-verständnis mehr ... das ist Windows API :(. |
Re: mit der console interaktiv komunizieren
Verstehe ich jetzt richtig das es nicht möglich ist mit einer consolenanwendung hin UND her, mit dynamischer ein- und ausgabe, OHNE auf das beenden des consoleapps gewartet wird, zu kommunizieren ?
gruß. |
Re: mit der console interaktiv komunizieren
Zitat:
Schöne Grüße, Jan |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:24 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