Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.119.111.9] |
|
Сообщ.
#1
,
|
|
|
Возник вопрос: как с помощью CreateProcess (или без него) запустить внешнее приложение и получить полный доступ к его консоле.
Поясню. Пусть у меня есть консольная программа Stupid.exe, которая выдает приветствие "Hello" и задумывает случайное число. Затем считывает моё число, сравнивает со своим и выдает "Больше", "Меньше" или "Равно". Цель: написать внешнюю программу, которая будет угадывать это число у консольной программы Stupid.exe. Для этого необходимо работать с входными и выходными потоками консольной программы, однако во всех примерах, которые я нашел в интернете, сначала дают весь входной поток, потом считывают весь выходной, а мне нужно взаимодействие! Спасибо! |
Сообщ.
#2
,
|
|
|
Как вариант отослать программой Stupid.exe, СендМеседжем это число, а другой принять.
|
Сообщ.
#3
,
|
|
|
Цитата meshanya @ Да легко: однако во всех примерах, которые я нашел в интернете, сначала дают весь входной поток, потом считывают весь выходной, а мне нужно взаимодействие! Чуть подробнее: Считывать и записывать можно с помощью функций ReadFile и WriteFile соответственно. Они возвращают управление не только по заполнению собственного буффера, а и в тот момент, когда процесс на другом конце перестает соотвественно писать или читать. Короче, интерактивность как она есть. Посмотри в MSDN поподробнее специфику работы этих функций с pipe. В общем, возьми за основу какой нибудь пример из DRKB и попробуй писать и читать попеременно. Если не получится, то уже тогда выкладывай свой код. Цитата PIKACHU @ Жуть какая Как вариант отослать программой Stupid.exe, СендМеседжем это число, а другой принять. |
Сообщ.
#4
,
|
|
|
Цитата meshanya @ Для этого необходимо работать с входными и выходными потоками консольной программы, однако во всех примерах, которые я нашел в интернете, сначала дают весь входной поток, потом считывают весь выходной, а мне нужно взаимодействие! Хм...может не так/не то смотрел? В нете полно примеров по использованию неименованных пайпов для перехвата ввода/вывода консольной программы. Подсовывая число и считывая ответ - можно (путем перебора) "угадать" задуманное число. |
Сообщ.
#5
,
|
|
|
Ну тогда помогите, пожалуйста, с кодом.
Переписал код с DRKB, процедуру Read оставил без изменений. Программа Stupid при запуске пишет слово "Hello", которое я хотел считать. Вместо этого возвращается пустая строка. В принципе будет быстрее, если кто-нибудь пришлет рабочий код. program Test; {$APPTYPE CONSOLE} {$O-,T+} uses SysUtils, Windows; type Runner=object fChildStdoutRd, fChildStdinWr, fChildStdoutWr, fChildStdinRd:tHandle; procedure ExecConsoleApp(CommandLine: AnsiString); procedure Terminate; function Read(Timeout: Integer): string; function Write(data:String):Boolean; end; var Runner1:Runner; str:String; procedure Runner.ExecConsoleApp(CommandLine: AnsiString); var fsaAttr: TSECURITYATTRIBUTES; tmp1, tmp2:tHandle; function CreateChildProcess(cmd:String; stdin, stdout:tHandle):Boolean; var si: tStartupInfo; pi: TProcessInformation; begin ZeroMemory(@si, SizeOf(TStartupInfo)); si.cb := SizeOf(TStartupInfo); si.hStdInput := StdIn; si.hStdOutput := StdOut; si.dwFlags := STARTF_USESTDHANDLES; Result := CreateProcess(nil, PChar(cmd), nil, nil, TRUE, 0, nil, nil, si, pi); end; begin FsaAttr.nLength := SizeOf(SECURITY_ATTRIBUTES); FsaAttr.bInheritHandle := True; FsaAttr.lpSecurityDescriptor := nil; assert(CreatePipe(FChildStdoutRd, FChildStdoutWr, @FsaAttr, 0), '[STDOUT CREATING FAILED]'); assert(CreatePipe(FChildStdinRd, FChildStdinWr, @FsaAttr, 0), '[STDIN CREATING FAILED]'); assert(DuplicateHandle(GetCurrentProcess(), FChildStdoutRd, GetCurrentProcess(), @Tmp1, 0, False, DUPLICATE_SAME_ACCESS), '[STDOUT DUPLICATE FAILED]'); assert(DuplicateHandle(GetCurrentProcess(), FChildStdinWr, GetCurrentProcess(), @Tmp2, 0, False, DUPLICATE_SAME_ACCESS), '[STDIN DUPLICATE FAILED]'); CloseHandle(fChildStdoutRd); CloseHandle(fChildStdinWr); fChildStdoutRd:=tmp1; fChildStdinWr:=tmp2; CreateChildProcess(CommandLine, FChildStdinRd, FChildStdoutWr); end; procedure Runner.Terminate; begin CloseHandle(fChildStdoutRd); CloseHandle(fChildStdoutWr); CloseHandle(fChildStdinRd); CloseHandle(fChildStdinWr); end; function Runner.Write(data: string):Boolean; var dwWritten, BufSize: DWORD; chBuf: PChar; begin chBuf := PChar(Data + Chr($0D) + Chr($0A)); BufSize := Length(chBuf); Result := WriteFile(FChildStdinWr, chBuf^, BufSize, dwWritten, nil); Result := Result and (BufSize = dwWritten); end; function Runner.Read(Timeout: Integer): string; var i: Integer; dwRead, BufSize, DesBufSize: DWORD; chBuf: PChar; Res: Boolean; begin BufSize := 0; New(chBuf); repeat for i := 0 to 9 do begin Res := PeekNamedPipe(FChildStdoutRd, nil, 0, nil, @DesBufSize, nil); Res := Res and (DesBufSize > 0); if Res then Break; Sleep(Round(Timeout / 10)); end; if Res then begin if DesBufSize > BufSize then begin FreeMem(chBuf); GetMem(chBuf, DesBufSize); BufSize := DesBufSize; end; Res := ReadFile(FChildStdoutRd, chBuf^, BufSize, dwRead, nil); Result := Result + Copy(chBuf, 1, dwRead); end; until not Res; end; begin Runner1.ExecConsoleApp('stupid.exe'); writeln(runner1.Read(10000)); {Возвращает пустую строку!} readln; end. |