Redirect Output von Konsolenprogramm an Winapi Anwendung
-
Hallo ich hab mir hier versucht eine Funktion zu basteln die mir die Ausgabe eines Konsolenfensters umleitet. Leider bleibt der Code an folgender Stelle stehen:
if((ReadFile(hOutputRead, lpBuffer, sizeof(lpBuffer) - 1, &nBytesRead, NULL) == FALSE) || (nBytesRead == 0)){ if(GetLastError() == ERROR_BROKEN_PIPE){ break; } }
Hier jetzt mal die ganze Funktion, wobei "void (*ptrOutPut)(char *text)" die Funktion ist die die Ausgabe in einem Multiline Editfeld ausgibt. Zur Ausgabe ist zu sagen, dass der Text auch korrekt ausgegeben wird, nur nach oben genanter Stelle im Programm ist dann Feierabend und der nachfolgende Teil im Code wird nicht ausgeführt. Was mach ich falsch? Wer kann helfen?
boolean ExecProggyWithRedirectOutput(char *appname, char *cmdline, char *workingdir, boolean showwnd, int *returncode, void (*ptrOutPut)(char *text)){ STARTUPINFO si ={0}; PROCESS_INFORMATION pi ={0}; SECURITY_ATTRIBUTES sa ={0}; HANDLE hOutputReadTmp = 0, hInputWriteTmp = 0; HANDLE hOutputWrite = 0, hInputWrite = 0, hErrorWrite = 0; HANDLE hOutputRead = 0, hInputRead = 0; boolean back = TRUE; si.cb = sizeof( STARTUPINFO); if(ptrOutPut){ sa.nLength= sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; if(!CreatePipe(&hOutputReadTmp, &hOutputWrite, &sa,0)){ return FALSE; } if(!DuplicateHandle(GetCurrentProcess(), hOutputWrite, GetCurrentProcess(),&hErrorWrite,0, TRUE, DUPLICATE_SAME_ACCESS)){ back = FALSE; goto END; } if(!CreatePipe(&hInputRead, &hInputWriteTmp, &sa,0)){ back = FALSE; goto END; } if(!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp, GetCurrentProcess(), &hOutputRead, 0, FALSE, DUPLICATE_SAME_ACCESS)){ back = FALSE; goto END; } if(!DuplicateHandle(GetCurrentProcess(), hInputWriteTmp, GetCurrentProcess(), &hInputWrite, 0, FALSE, DUPLICATE_SAME_ACCESS)){ back = FALSE; goto END; } CloseHandle(hOutputReadTmp); CloseHandle(hInputWriteTmp); si.dwFlags |= STARTF_USESTDHANDLES; si.hStdOutput = hOutputWrite; si.hStdError = hErrorWrite; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); } if(showwnd == FALSE){ si.dwFlags |= STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; } if(CreateProcess(appname, cmdline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, workingdir, &si, &pi) == 0){ int i = GetLastError(); back = FALSE; goto END; } WaitForInputIdle(pi.hProcess, INFINITE); if(ptrOutPut){ char lpBuffer[1024]; DWORD nBytesRead; while(TRUE){ memset(&lpBuffer, 0, sizeof(lpBuffer)); if((ReadFile(hOutputRead, lpBuffer, sizeof(lpBuffer) - 1, &nBytesRead, NULL) == FALSE) || (nBytesRead == 0)){ if(GetLastError() == ERROR_BROKEN_PIPE){ break; } } lpBuffer[nBytesRead] = '\0'; ptrOutPut(lpBuffer); nBytesRead = 0; } } WaitForSingleObject(pi.hProcess, INFINITE); if(returncode){ GetExitCodeProcess(pi.hProcess, returncode); } END:; if(ptrOutPut){ CloseHandle(hOutputReadTmp); CloseHandle(hInputWriteTmp); CloseHandle(hOutputWrite); CloseHandle(hInputWrite); CloseHandle(hErrorWrite); CloseHandle(hOutputRead); CloseHandle(hInputRead); } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return back; }
-
Kanns sein dass deine Zielanwendung einfach nichts ausgibt?
-
Nein, die Zielanwendung gibt genau das in dem Redirected Fenster aus, was sie auch in der Konsole ausgibt. Aber wenn die Ausgabe rum ist geht es in meiner Funktion laut Debugger nicht weiter. An genau der Codestelle, die ich in meinem Post als erstes aufgeführt habe.
-
Hat niemand eine Ahnung was falsch sein könnte?
-
In der Pipe kommt von Deiner Anwendnung nichts an. Punkt. Vermutlich gibt die andere Anwendung nichts aus...
-
Was soll denn das WaitForInputIdle?
Deine Lösung ist auch nicht korrekt. Je nachdem wie viele Daten ausgegeben werden, kann es bei Dir zu einen Dead-Lock kommen. Du musst einen eigenen Therad verwenden um die Ausgabe zu lesen.Eine korrekte Implementierung findest Du hier:
http://support.microsoft.com/kb/190351Beachte auch, dass die Anwendung es explizit verhindern kann, dass die Ausgaben umgeleitet werden. SIehe auch obiger Link.
Probiere es zuerst in der Commandozeile via < / > aus. Wenn es da geht, dann geht es auch mit der Lösung im Link.
-
Martin Richter schrieb:
In der Pipe kommt von Deiner Anwendnung nichts an. Punkt. Vermutlich gibt die andere Anwendung nichts aus...
Du hast schon beide Posts von mir gelesen? Auf Anmerkung von dot habe ich bereits explizit gesagt, dass das Fenster das die Redirect Nachrichten erhalten soll, diese auch erhält und ausgibt. Lediglich, wenn das Child Programm fertig ist werden keine Nachrichten mehr ausgegeben (was ja logisch ist) , aber an besagter Codestelle guggst du oben verliert sich die Ausführung des Codes.
@Jochen Kalmbach
danke, der Beispielcode der auf der von dir verlinkten Seite steht funktioniert einwandfrei. Ich werde versuchen mir daraus eine entsprechende Funktion zu schreiben. good job!
-
CloseHandle wird an falscher Stelle ausgeführt, dadurch läuft dein ReadFile nach Beenden des Child Processes ins Leere. Führe
CloseHandle(hOutputReadTmp); CloseHandle(hInputWriteTmp); CloseHandle(hOutputWrite); CloseHandle(hErrorWrite); CloseHandle(hInputRead);
vor
if((ReadFile(hOutputRead, lpBuffer, sizeof(lpBuffer) - 1, &nBytesRead, NULL) == FALSE) || (nBytesRead == 0)){ if(GetLastError() == ERROR_BROKEN_PIPE){ break; } }
aus