ShellExecute & Co. zum XXX. Mal
-
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