ShellExecute & Co. zum XXX. Mal
-
Dazu brauchst du dann Pipes um stdout und stdin umzubiegen. Ich empfehle dir mal hier zu suchen. Da gibts den Einen oder Andere Beitrag dazu.
-junix
-
@junix
danke für den tip! zu diesem thema hat mir <f> glaub ich auch nen link gepostet. is allerdings noch etwas verwirrend für mich.ich hab mal nach "pipe" gesucht und mir aus den suchergebnissen ein beispiel rausgepickt.
das führt einen createprocess aus. zum beispiel nen ping. das ergebnis wird dann in ner messagebox ausgegeben.
wenn ich das jetzt richtig verstanden habe, ist da jetzt eine pipe mit der ich daten von der dos-konsole empfangen kann. output oder input? aus welcher richtung is das zu sehen?wenn ich jetzt einen befehl an diese dos-konsole senden will, brauche ich jetzt ne zweite pipe, oder?
da kommt noch eine schleife drin vor, bei der ich ein problem sehe:
GetExitCodeProcess(pi.hProcess,&retCode); while (retCode==STILL_ACTIVE) { GetExitCodeProcess(pi.hProcess,&retCode); }
wenn ich plink mit parametern aufrufe findet eine ssh-login statt. danach habe ich den prompt da stehen:
user@machine:~#
das heißt, dass mein returncode immer STILL_ACTIVE sein wird. da ja der prozess noch läuft und eine eingabe erwartet. an dieser stelle will ich ja beim klick auf einen button "exit" schreiben und das wars.
ich nehm am besten diese schleife mal raus.
-
Du musst 2 Pipes eröffnen: Eine die aus Sicht des Konsolenprogramms stdin darstellt (da kannst du reinschreiben mit WriteFile und das programm glaubt, das sind Tastenanschläge) und eine die stdout darstellt (Da wird der Text des Programms ausgegeben)
-junix
-
Vielleicht hilft dir aus das hier aus den FAQ und ggf. WaitForSingleObject
-
hallo!
wollte mich nur bedanken für die hilfe!
mit etwas rumprobieren und der msdn habe ich in etwa rausgefunden wie die pipes funktionieren. ich hoffe ich krieg es jetzt alleine hin.
das beispiel aus der msdn hat mir ziemlich geholfen:
[url] http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/creating_a_child_process_with_redirected_input_and_output.asp [/url]also danke an alle!
gruß
tody
-
War ja auch gar nicht schwer, nichtwahr? (o; Hatte erst auch meine Mühe aber dann... (o;
-junix
-
@junix
es war etwas schwerer als fahrradfahren aber es hielt sich in grenzen.
frauen verstehen is schwerer. ;o))))trotzdem habe ich wieder ein kleines problem. ich hab das ganze in ner win32-anwendung probiert. allerdings wollte ich es dann in mein mfc-projekt einbauen und da startet zwar auf button-klick der prozess aber dann steht meine mfc-anwendung still. ich kann dann keinen button mehr klicken. es wird irgendwie auf ne eingabe in der konsole gewartet.
hat da jemand ne idee???
danke
tody
-
Stand vor dem Selben Problem. Bei mir wars so, dass ReadFile() immer gewartet hat, bis der angeforderte Buffer gefüllt wurde.
Deshalb habe ich dann mit PeekNamedPipe() zunächst die Anzahl Bytes in der Pipe ausgelesn und dann gezielt einen ReadFile() mit der Anzahl Bytes ausgeführt. Das Ganze dann in einer Schleife und zwischen jedem neuen PeekNamedPipe() kam dann wieder eine kleine Routine, welche die Message-Queue (Peekmessage, etc.) abgearbeitet hat.
-junix
-
Was ich vergass: Witzig am Ganzen ist die Tatsache, dass PeekNamedPipe auch unter Windows Playstation-Series (DOS-Basierende Linie) unterstützt ist. Und das obwohl diese Systeme gar keine Named-Pipes unterstützen? Naja, Microsoft war noch nie für Konsistenz berühmt...
-junix
-
*LOL*
Danke schonmal für die Tips. Ich geb mich mal ran.
Aber erstmal mach ich Mittagspause!
-
also hier hänge ich. hab nich ganz verstanden warum er sich bei ReadFile aufhängt. Hängt das damit zusammen, dass ReadFile vielleicht weniger Zeichen liest als ich angegeben hab. Und danach will ReadFile noch weiterlesen bis zu der Anzahl Zeichen, die ich angegeben hab obwohl schon nix mehr in der Pipe steht. (Ich hoffe man versteht was ich meine)
Ich hab auf jeden Fall diese Methode hier, in der ich aus der Pipe lese. BUFSIZE = 4096
BOOL ReadFromPipe() { DWORD dwRead, dwPeekRead, dwWritten, dwAvailable; CHAR chBuf[BUFSIZE]; PeekNamedPipe(hOutReadDpl,chBuf, BUFSIZE, &dwPeekRead, &dwAvailable, NULL); if (dwPeekRead != 0) { // Read output from the child process, and write to parent's STDOUT. ReadFile( hOutReadDpl, chBuf, dwPeekRead, &dwRead, NULL); WriteFile(hStdOut, chBuf, dwRead, &dwWritten, NULL); } return 0; }
in einer win32 funktioniert der Code. Aber in meinem MFC-Prog ist dwPeekRead immer 0.
@junix
den Rest von wegen in Schleife und so weiter habe ich nicht richtig verstanden. Ich bin noch nicht so fit.
-
Also, bei mir siehts so aus: (bei mir gings allerding nur darum die Konsolenausgabe von gunzip "einzufangen" nicht mit dem Programm zu interagieren...)
//-- Irgendwo in der Funktion... /* Puffer initialisieren der so gross ist wie der Puffer der Pipe */ char *Buffer_charp = new char[PIPE_SIZE]; { memset(Buffer_charp, 0, PIPE_SIZE); DWORD BytesRead_DWORD = 0; DWORD BytesToRead_DWORD = 0; /* Solange ausführen, bis das Child-Programm zu Ende ist: */ do { /* Wenns was zu lesen gibt ... */ if (BytesToRead_DWORD) { /* ... werden die anstehenden Bytes gelesen. */ ReadFile(readHandle_HANDLE, Buffer_charp, BytesToRead_DWORD, &BytesRead_DWORD, NULL); /* Was auch immer mit dem gelesenen Wert zu tun ist, kann man hier erledigen... */ ProcessMessages(); /* globale funktion, siehe weiter unten. */ } /* Die Anzahl der anstehenden Bytes ermitteln. Da wir nur die Anzahl bytes wissen wollen, brauchen wir nichts zu Lesen und entsprechend auch keine Puffer zu übergeben. */ PeekNamedPipe(readHandle_HANDLE, NULL, /* Kein Puffer nötig, denn */ 0, /* wir lesen 0 Bytes, wodurch */ NULL, /* auch kein BytesRead nötig ist aber */ &BytesToRead_DWORD, /* Die anzahl verfügbarer bytes schon */ NULL); } while (BytesToread_DWORD > 0); } delete [] Buffer_charp; //-- Irgendwie gehts dann hier in der Funktion wohl weiter... //-- Eine neue Funktion... /* Leert die komplette MessageQueue und verarbeitet die Messages. Sonst erweckt die Applikation den Eindruck "abgestürzt" zu sein, da weder Interaktion möglich ist, noch ein Refresh/repaint stattfindet (Achtung, nur mit MFC) Das Listing hab ich irgendwo aus de Knowledgebase... */ void ProcessMessages(void) { MSG message_MSG; // überprüft ob die Queue noch eine Nachricht enthält. while (::PeekMessage(&message_MSG, NULL, 0, 0, PM_NOREMOVE)) { if (!AfxGetThread()->PumpMessage()) return; } }
Das Obige Beispiel liest einfach unersättlich alles ein, was das Child so den ganzen Tag von sich gibt. Gibts nichts zu lesen, springts raus.
Vielleicht wird dir mein Gefasel jetzt etwas klarer. Das hat bei mir in der MFC-Anwendung eigentlich bestens funktioniert...
-junix
[ Dieser Beitrag wurde am 01.07.2003 um 15:16 Uhr von junix editiert. ]
-
ja danke! es wird mir schon etwas klarer. ich muss halt sehen wie ich das so hinbekomme, dass ich eine art dialog führen kann mit meiner konsole.
ich bin zudem noch unsicher welche variablen ich nachher killen muss. klar die handles schließe ich alle mit closehandle(); und den pointer den du erstellst muss man mit delete putzen. aber erledigt sich der rest von selbst?
und den inhalt der pipes sollte man doch nach einem "wortwechsel" (a sagt b hört) leeren. machst du das mit peekmessage() ?gut gut, ich werde dann nochmal etwas basteln.
danke für die geduld!
-
ReadFile() entfernt die Anzahl bytes die du gelesen hast aus der Pipe.. Ausser den von dir mit new erstellten Variablen und den Handles musst du nichts freigeben.
-junix
-
Hi junix,
mir ist soweit klar was in deinem Code passiert. Bis auf PumpMessage.
Ich gehe eigentlich genauso vor wie du, nur, dass ich nich in einer Schleife lese.
Mein Problem ist, dass mir PeekNamedPipe immer 0 zurückgibt. Warum?
Nachdem ich CreateProcess ausgeführt hab, läuft mein Programm und wartet auf ne eingabe.
Wenn ich dann beenden will schreibe ich mit WriteFile den Befehl "exit\r\n" in StdIn. (Im Win32-Prog kommt das auch an)
Danach lese ich im Win32-Prog den StdOut und bekomm "exit" und die Antwort darauf angezeigt.Soweit kommt es im MFC-Prog erst garnich. Wenn ich mit WriteFile "exit" schreibe passiert überhauptnix.
Das klingt sicher alles sehr verwirrend! Ich bin halt der meinung, dass ich das mache was du tust und es trotzdem nich funktioniert.
Vielleicht weißt du ja noch was?
Ich such mal weiter...
-
Huhu,
wenn ich mir das MFC-Prog beim debuggen so angucke, laufen ein paar Dinge anders als im Win32-Prog.
Als erstes bekommen meine Handles zu STDIN und STDOUT schonmal den gleichen Wert:
hStdIn = 0x00000000
hStdOut = 0x00000000und wenn ReadFile aufgerufen wird, setzt er den Parameter dwRead nicht.
ReadFile(hOutReadDpl, chBuf, dwAvailable, &dwRead, NULL);
das gleiche bei WriteFile. Der Parameter dwWritten wird auch nicht gesetzt.
WriteFile(hInWriteDpl, chBuf, dwRead, &dwWritten, NULL);
In der Win32-Anwendung funktioniert das. Ich bin echt am verzweifeln.
Das mit dem STDIN un STDOUT kann ich mir ja noch erklären, weil es ja ne MFC-Anwendung ist... aber das andere.
-
Hi ...
Habs jetzt mit Hilfe von nem Ex-Dozenten rausbekommen. Der meinte es läge an der fehlenden Konsole im MFC-Prog.
Jetzt lege ich mir in der InitInstance ne Konsole an und verstecke sie.BOOL res = AllocConsole(); if (res) { HWND hwnd = GetConsoleWindow(); ShowWindow(hwnd, SW_HIDE); }
Der Rest funktioniert dann eigentlich auch wie beim Win32-Prog.
Hab gedacht es wäre vielleicht interessant. Aus dem WinAPI-Thread hat sich zwar am Ende ein MFC_Thread entwickelt aber nimmt mir hoffentlich keiner krumm.
Gruß Tody