ShellExecute & Co. zum XXX. Mal
-
kannst du ihn nicht einfach casten?
-
ich mache folgendes:
if(sei.hProcess) { LPDWORD code; GetExitCodeProcess(sei.hProcess, code); ExitProcess((UINT)code); CloseHandle(sei.hProcess); }
sei ist vom Typ SHELLEXECUTEINFO
ShellExecute wurde aufgerufenIch bekomme beim Erstellen 2 Warnungen:
Typumwandlung: Zeigerverkürzung von LPDWORD zu UINT
Die Variable code wurde ohne Initialisierung übernommenIch glaub ich bring da was durcheinander. LPDWORD ist doch ein 32Bit signed Integer und UINT spricht wohl für sich.
Und der Parameter lpExitCode von GetExitCodeProcess ist doch ein Ausgabeparameter. Was muss ich da vorher initialisieren?Wenn ich debugge, hängt er an der Stelle mit der nicht initialisierten Variablen code.
-
Versuch's mal so:
if(sei.hProcess) { DWORD code; GetExitCodeProcess(sei.hProcess, &code); ExitProcess((UINT)code); CloseHandle(sei.hProcess); }
-
klar sollte ja ein Pointer rein. wer lesen kann...
naja mir sind da so manche Sachen nicht klar.Allerdings löst sich jetzt mein MFC_Prog in Luft auf und die DOS-Box bleibt nach wie vor da.
Auf jeden Fall vielen Dank schonmal!
Tody
-
Öhm... ExitProcess beendet DEINEN PROZESS!
Was Du dort tust, ist den Status des DOS-Prozesses abfragen (wird STILL_ACTIVE sein) und beendest dann deinen eigenen Prozeß mit Exitcode STILL_ACTIVE...
-
@hepi
dann habe ich wohl wieder nich ganz aufgepasst.ich dachte damit beende ich den dos-prozess. darum geht es mir ja. dass ich mit buttonA ein shellexecute ausführe und mit buttonB diese dadurch entstandene dos-box wieder schließe, bzw. das programm beende welches in der dos-box läuft.
sowas muss doch möglich sein.
ich stelle mit das so vor:
buttonA:
shellexecute("Programm-Start", SW_HIDE);buttonB:
shellexecute("Programm-Stop", AusführenInVerstecktemFenster);aber beides spielt sich in der selben dos-box ab.
außerdem wenn ich ein programm gestartet habe, muss ich es erst beenden bevor ich ein neues starten kann. aber das hab ich schon hingekriegt.
vielleicht weiß ja jemand nen lösungsansatz?!
danke schonmal für alle antworten!
tody
-
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