Помогите пожалуйсто, бъюсь целый месяц, ни на одном форуме не смогли помочь. Задача програмы выполнять консольные комманды и захватывать их вывод. вот мой код PHP: program Project1; {$APPTYPE CONSOLE} uses SysUtils,Windows; var SecurityAttributes: TSecurityAttributes; ProcessInfo: TProcessInformation; StartUpInfo: TStartupInfo; newstdin,newstdout,read_stdout,write_stdin,hConsoleInput: THandle; Buffer1,Buffer2: array[0..1033] of Char; BytesRead,BytesAvail,NumRead: Cardinal; InputRec: TInputRecord; BuffLen: Integer; begin SecurityAttributes.nLength:=SizeOf(TStartUpInfo); SecurityAttributes.bInheritHandle:=True; SecurityAttributes.lpSecurityDescriptor:=nil; CreatePipe(newstdin,write_stdin,@SecurityAttributes,0); CreatePipe(read_stdout,newstdout,@SecurityAttributes,0); ZeroMemory(@StartUpInfo,SizeOf(TStartUpInfo)); StartUpInfo.cb:=SizeOf(TStartUpInfo); StartUpInfo.dwFlags:=STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; StartUpInfo.hStdInput:=newstdin; StartUpInfo.hStdOutput:=newstdout; StartUpInfo.hStdError:=newstdout; CreateProcess('C:\\Windows\\System32\\cmd.exe',nil,nil,nil,True,0,nil,nil,StartUpInfo,ProcessInfo); hConsoleInput:=GetStdHandle(STD_INPUT_HANDLE); while True do begin PeekNamedPipe(read_stdout,@Buffer1,1023,@BytesRead,@BytesAvail,nil); if BytesRead <> 0 then begin ZeroMemory(@Buffer1,SizeOf(Buffer1)); if BytesAvail > 1023 then begin while BytesRead >= 1023 do begin ReadFile(read_stdout,Buffer1,SizeOf(Buffer1),BytesRead,nil); Buffer1[BytesRead]:=#13; Buffer1[BytesRead]:=#10; Write(Buffer1); ZeroMemory(@Buffer1,SizeOf(Buffer1)); end; end else begin ReadFile(read_stdout,Buffer1,1023,BytesRead,nil); Buffer1[BytesRead]:=#13; Buffer1[BytesRead+1]:=#10; Write(Buffer1); ZeroMemory(@Buffer1,SizeOf(Buffer1)); end; end; if PeekConsoleInput(hConsoleInput,InputRec,1,NumRead) and (NumRead >=1) then begin if (InputRec.EventType = KEY_EVENT) and InputRec.Event.KeyEvent.bKeyDown then begin Read(Buffer2); Bufflen:=Length(Buffer2); Buffer2[Bufflen]:=#13; Buffer2[Bufflen+1]:=#10; WriteFile(write_stdin,Buffer2,Length(Buffer2),BytesRead,nil); end else begin ReadConsoleInput(hConsoleInput, InputRec, 1,NumRead); ZeroMemory(@Buffer2,SizeOf(Buffer2)); end; end; end; CloseHandle(ProcessInfo.hThread); CloseHandle(ProcessInfo.hProcess); CloseHandle(newstdin); CloseHandle(newstdout); CloseHandle(read_stdout); CloseHandle(write_stdin); end. Проблемма со вводом в консоль, пробовал много вариантов. Проблема наверно в этом куске кода PHP: if (InputRec.EventType = KEY_EVENT) and InputRec.Event.KeyEvent.bKeyDown then begin Read(Buffer2); Bufflen:=Length(Buffer2); Buffer2[Bufflen]:=#13; Buffer2[Bufflen+1]:=#10; WriteFile(write_stdin,Buffer2,Length(Buffer2),BytesRead,nil); end else begin ReadConsoleInput(hConsoleInput, InputRec, 1,NumRead); ZeroMemory(@Buffer2,SizeOf(Buffer2)); end; end; программа не корректо работает, не принимает ввод, тоесть принимает но както через жопу ,выполняет токо первую комманду и то через попу, а потом вообще пише "Продолжить?" и виснет. скриншот прилагаю п.с. надеюсь slesh поможет.))
Я вот чтото недопер одного. А зачем такая сложность? Тыбы лучше описал что тебе именно надо. Зачем пайпы юзать? Винда и так делает напрямую передачу данных между хендлами. Пайпы нужны тока для того, когда ты будешь делать ввод и вывод в приложение которое не имеет собственных хендлов ввода-вывода т.е. не консольное. Или когда тебе программно надо посылать данные, то тоже надо их юзать. А когда у тебя есть уже консоль, то её хендлы ты можеш юзать для этих целей. Проще говоря это выглядит так: Code: program Project2; {$APPTYPE CONSOLE} uses Windows; function RunCMD(stdin, stdout, stderr: THandle) : THandle; var pi : TProcessInformation; si : TStartupInfo; begin ZeroMemory(@si, SizeOf(TStartupInfo)); si.cb := SizeOf(TStartupInfo); // зададим хендлы ввода/вывода si.hStdInput := stdin; si.hStdOutput := stdout; si.hStdError := stderr; si.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW; si.wShowWindow := SW_HIDE; // запустим процесс if (CreateProcess(nil, 'cmd.exe', nil, nil, true, 0, nil, nil, si, pi)) then begin result := pi.hProcess; // если запустился то вернем хендл процесса end else begin result := INVALID_HANDLE_VALUE; // если не запустился то ошибку end; end; var ph : THandle; stdin : THandle; stdout : THandle; stderr : THandle; begin stdin := GetStdHandle(STD_INPUT_HANDLE); // хендл ввода stdout := GetStdHandle(STD_OUTPUT_HANDLE); // хендл вывода stderr := GetStdHandle(STD_ERROR_HANDLE); // хендл ошибки writeln('Start Process'); ph := RunCMD(stdin, stdout, stderr); // запускаем процесс if (ph <> INVALID_HANDLE_VALUE) then // если запустился нормально begin WaitForSingleObject(ph, INFINITE); // ждем пока процесс работает end; writeln('Stop Process'); readln; end.
На дельфях не пишу, на вб 6.0(на котором я писАл) работа с хендлами тоже из разряда научной фантастики, поэтому это было реализовано через маленький финт: всю выводимую на экран инфу после выполнения команды - записываешь в текстовый файл путем добавления к команде > Путь_к_файлу\файл, затем просто считываешь его в текстбокс или еще куда... P.S. Подводные грабли - обязательно будут глюки с кодировкой, но это решается... chcp 866
slesh, спасибо за ответ. Но я в упор не вижу где происходит ввод/вывод. Мне надо. Запустить процесс, получить вывод. Потом сделать ввод, затем считать вывод. и так постоянно. объясните пожалуйсто как это реализовать.
Дескрипторы, возвращенные функцией GetStdHandle, могут быть использованы программой для чтения или записи в консоль функциями ReadFile и WriteFile, или любой из консольных функций, которые обращаются к консольному буферу ввода или экранному буферу (например, функциям ReadConsoleInput, WriteConsole, или GetConsoleScreenBufferInfo). Вот и используй дескрипторы stdin, stdout, stderr для чтения\записи при успешном создании процесса.
slesh, alexey - спасибо! всё работает, просто я не протестировал был! Slesh, а почему консоль дублируется??? как это убрать? Посоветуйте плиз как доделать прогу под сетевое использование. т.е. клиент посылвает серверу команды, а сервер отсылает вывод. Токо не надо предлогать юзать сокеты как пайпы.
короче мне надо удалённо выполнять команды и получать вывод! slesh, я тебя умалаю, помогите пожалуйсто. ты один на этом свете кто может помочь! я шас б**ть провалюсь! ни**я не получается!!! это пи**ец просто какойто. у меня уже истерека месяц над этим е**сь.... блин (((((((((((((((((((((((((((((((((((((((((((( форум пхпшиников недотраханых, никто ничего не знает...