Remote Shell
-
Jo dann funktioniert es auch. Wenn ich das Programm starte bekomme ich die ersten Zeilen von der cmd... Cool
Aber ich glaube irgendwie es ist nicht so optimal direkt den buf in printf zu übergeben.....
Wie dem auch sei. Wie kann ich jetzt "lauschen", also warten ob die cmd was zu sagen hat?
-
Hab es so gelöst:
[cpp]
while(true)
{
if(ReadFile(hReadPipe,buf,99,&reDword,0)!=0)
printf(buf,"\n");
}[code]Allerdings nicht sehr performant... Wenn ich das Fenster rumziehe, dann zieht es schlieren nach sich. Gibts da evtl. was besseres, als so eine Endloschleife?
Achja, und wenn ich ne andre CMD starte und befehle eingebe, dann kommt nichts an bei meinem Programm. Liegt das daran, dass die cmd die ich öffne ein ganz neues Handle bekommt und keinen Einfluss haben kann auf mein per CreateProcess geöffnetes cmd?
-
Ganz kurz noch (ich muß langsam schlafen gehen):
Du kannst Dich nicht darauf verlassen, daß Dein ReadFile auch wirklich 99 Byte bekommt, ergo solltest Du beim printf nicht blind den ganzen buf ausgeben.
Selbstverständlich bekommt eine weitere cmd, die Du zB per Hand öffnest, eigene Bereiche für STDIN und STDOUT.
Die von Deinem Programm geöffnete bekommt ja dafür eigens die Enden der Pipes. Das ist natürlich nicht der Fall, wenn Du eine Konsole ohne entsprechende Vorbereitung öffnest.
Endlosschleife muß ja nicht sein, da ReadFile nur zurückkehrt, wenn es etwas gelesen hat, oder ein Fehler aufgetreten ist.Also so:
while(ReadFile((HANDLE)pipe,buffer,255,&x,NULL) && GetLastError() != ERROR_BROKEN_PIPE) { ...
Damit Du die Kontrolle über Dein Programm behältst, solltest Du das eventuell in einen eigenen Thread verlagern.
Du könntest dann im Hauptthread über eine Pipe (die Du bisher in Deinem Beispiel noch nicht hast), Befehle an die Konsole senden (dir, type xxx.dat, wasweißichnochwas), und über die bereits vorhandene Pipe die Ausgabe abholen(was Du ja auch schon tust).
Ich hab da in grauer Vorzeit schon mal ein prima Beispiel (sogar mit deutschen Kommentaren im Netz gefunden), das poste ich hier einfach mal so, wie ich es entdeckt habe:#include <stdio.h> #include <windows.h> #include <stdlib.h> // ReadData // Diese Funktion wird anschliessen als eigener Thread gestarted und liest Daten aus // der mit stdout und stderr verbundenen Pipeline und gibt sie einfach auf der // Konsole aus. unsigned long __stdcall ReadData(void *pipe) { DWORD x; // Anzahl der gelesenen Bytes char buffer[255]; // Puffer // Solange lesen, bis die Pipeline von der anderen Seite geschlossen wird while(ReadFile((HANDLE)pipe,buffer,255,&x,NULL) && GetLastError() != ERROR_BROKEN_PIPE) fwrite(buffer,x,1,stdout); fflush(stdout); // eigenes Handle schliessen CloseHandle((HANDLE)pipe); return 0; } // WriteData // Diese Funktion wird anschliessend als eigener Thread gestarted und schreibt ein // paar Befehle auf stdin des Kommandointerpreters cmd. Diese werden in einer Art // Batchbetrieb abgearbeitet. unsigned long __stdcall WriteData(void *pipe) { DWORD ignore; // Ein paar Daten schreiben (es ist sicherlich ein wenig overkill, diese paar // Zeichen durch einen eigenen Thread schreiben zu lassen - ich moechte // hier nur das Prinzip demonstrieren) WriteFile((HANDLE)pipe,"dir /s *.exe\n",13,&ignore,NULL); WriteFile((HANDLE)pipe,"cd /d C:\\\n",10,&ignore,NULL); WriteFile((HANDLE)pipe,"type autoexec.bat\n",18,&ignore,NULL); // Pipeline schliessen - damit wird der anderen Seite EOF signalisiert CloseHandle((HANDLE)pipe); return 0; } int main() { // Handles fuer die beiden Pipelines HANDLE hClientOut_rd,hClientOut_wr; HANDLE hClientIn_rd,hClientIn_wr; // Erzeugen der beiden Pipelines - ich gebe NULL fuer den Zeiger auf // die SECURITY_ATTRIBUTES an. Dadurch werden beide Handles als nicht // vererbbar gekennzeichnet. if(!CreatePipe(&hClientOut_rd,&hClientOut_wr,NULL,0)) { printf("Can not create PIPE!\n"); exit(5); } if(!CreatePipe(&hClientIn_rd,&hClientIn_wr,NULL,0)) { printf("Can not create PIPE!\n"); exit(5); } // Die Handles, die der Kindprozess benoetigt werden als vererbbar // gekennzeichnet. Dies kann entweder unter NT ueber SetHandleInformation // erfolgen oder unter Windows 95 ueber DuplicateHandle #ifdef NT SetHandleInformation(hClientOut_wr,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT); SetHandleInformation(hClientIn_rd,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT); #else DuplicateHandle(GetCurrentProcess(),/*source*/hClientOut_wr, GetCurrentProcess(),/*dest*/&hClientOut_wr,0,/*bInheritHandle*/TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); DuplicateHandle(GetCurrentProcess(),hClientIn_rd,GetCurrentProcess(), &hClientIn_rd,0,/*bInheritHandle*/TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); #endif STARTUPINFO si; memset(&si,0,sizeof(STARTUPINFO)); // stdin, stdout und stderr des Kindes in STARTUPINFO eintragen si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = hClientIn_rd; si.hStdOutput = hClientOut_wr; si.hStdError = hClientOut_wr; PROCESS_INFORMATION pi; // cmd als Kindprozess ohne eigene Konsole starten if(!CreateProcess(NULL,"cmd",NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS | DETACHED_PROCESS, NULL,NULL,&si,&pi)) { printf("Kein Process??\n"); exit(5); } // um die Systemresourcen zu schonen koennen wir das nicht benotigte // Thread Handle gleich wieder schliessen CloseHandle(pi.hThread); // Schliessen der nicht mehr benoetigten Handles, die ich an den Prozess // uebergeben habe. Nur so kann ich eine 'broken pipe' feststellen, wenn // der Kind-Prozess beendet wird. CloseHandle(hClientIn_rd); CloseHandle(hClientOut_wr); HANDLE threads[3]; unsigned long ignore; // Starten des Lese- und Schreibthreads threads[0] = CreateThread(NULL,0,WriteData,(void *)hClientIn_wr,0,&ignore); threads[1] = CreateThread(NULL,0,ReadData,(void *)hClientOut_rd,0,&ignore); // Prozess ebenfalls in Warteliste eintragen threads[2] = pi.hProcess; // Warten bis alle fertig sind WaitForMultipleObjects(3,threads,TRUE,INFINITE); // und tschuess... exit(0); }
-
verstehe. Ich brauche also eine zweite Pipe um Signale an die cmd zu senden. Werde mir das ganze nochmal genauer Ansehen
Aber im Großen und Ganzen hab ichs verstanden (denke ich ;)). Danke für das coole Beispiel!!!
PS: Da ich noch am C/C++ lernen bin, meint ihr, dass der C++ Primer eine gute Wahl ist (wird da auch Netwerkkram beschrieben und etwas Windoof Programmierung?
Grüße. brownie
-
Genau. Weil man bei einer anonymous Pipe an einem Ende nur lesen und am anderen Ende nur schreiben kann. Es gibt daneben noch named Pipes, dort kann man an beiden Enden lesen und schreiben, ist aber für Deine Zwecke untauglich.
Das von Dir erwähnte Buch kenne ich nicht, wird aber von vielen empfohlen.
Für die reine Windows-Programmierung empfehle ich Windows-Programmierung von Charles Petzold, das ist zwar schon ziemlich betagt, aber imho noch immer sehr gut, wenn es darum geht, das Message-System und die Programmierung von Windows-Elementen zu verstehen.
Ich halte es aber für besser, zuerst mal C++ unabhängig von einem OS zu lernen, wenn man sich da einigermaßen bewegen kann, ist es noch Zeit genug, sich um ein bestimmtes OS zu kümmern.Übrigens: Mit den Pipes bist Du schon mittendrin in der Windowsprogrammierung!