На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! user posted image
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Соблюдайте общие правила форума

Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как запустить программу/файл? (и дождаться ее завершения)
5. Как перехватить API-функции, поставить hook? (перехват сообщений от мыши, клавиатуры - внедрение в удаленное адресное прстранство)
... (продолжение следует) ...

Внимание:
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки - бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Rouse_, user posted image Krid

Модераторы: Rouse_, Krid
  
> Перенаправление потоков , Запускаем внешнее приложение и перенаправляем потоки по-особенному
    Возник вопрос: как с помощью CreateProcess (или без него) запустить внешнее приложение и получить полный доступ к его консоле.
    Поясню.
    Пусть у меня есть консольная программа Stupid.exe, которая выдает приветствие "Hello" и задумывает случайное число.
    Затем считывает моё число, сравнивает со своим и выдает "Больше", "Меньше" или "Равно".
    Цель: написать внешнюю программу, которая будет угадывать это число у консольной программы Stupid.exe. Для этого необходимо работать с входными и выходными потоками консольной программы, однако во всех примерах, которые я нашел в интернете, сначала дают весь входной поток, потом считывают весь выходной, а мне нужно взаимодействие!

    Спасибо!
      Как вариант отослать программой Stupid.exe, СендМеседжем это число, а другой принять.
        Цитата meshanya @
        однако во всех примерах, которые я нашел в интернете, сначала дают весь входной поток, потом считывают весь выходной, а мне нужно взаимодействие!
        Да легко:
        1. Создаешь pipe
        2. Создаешь дочерний процесс
        3. Считываешь строчку из дочернего процесса
        4. Записываешь свой ответ в поток дочернего процесса
        5. Пока не угадаем goto 3

        Чуть подробнее:
        Считывать и записывать можно с помощью функций ReadFile и WriteFile соответственно. Они возвращают управление не только по заполнению собственного буффера, а и в тот момент, когда процесс на другом конце перестает соотвественно писать или читать. Короче, интерактивность как она есть.
        Посмотри в MSDN поподробнее специфику работы этих функций с pipe.
        В общем, возьми за основу какой нибудь пример из DRKB и попробуй писать и читать попеременно. Если не получится, то уже тогда выкладывай свой код.


        Цитата PIKACHU @
        Как вариант отослать программой Stupid.exe, СендМеседжем это число, а другой принять.
        Жуть какая :)
          Цитата meshanya @
          Для этого необходимо работать с входными и выходными потоками консольной программы, однако во всех примерах, которые я нашел в интернете, сначала дают весь входной поток, потом считывают весь выходной, а мне нужно взаимодействие!

          Хм...может не так/не то смотрел? В нете полно примеров по использованию неименованных пайпов для перехвата ввода/вывода консольной программы. Подсовывая число и считывая ответ - можно (путем перебора) "угадать" задуманное число. :wacko:
            Ну тогда помогите, пожалуйста, с кодом.
            Переписал код с DRKB, процедуру Read оставил без изменений.

            Программа Stupid при запуске пишет слово "Hello", которое я хотел считать. Вместо этого возвращается пустая строка.

            В принципе будет быстрее, если кто-нибудь пришлет рабочий код.

            ExpandedWrap disabled
              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.
            Сообщение отредактировано: meshanya -
            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
            0 пользователей:


            Рейтинг@Mail.ru
            [ Script execution time: 0,0316 ]   [ 16 queries used ]   [ Generated: 28.04.24, 00:46 GMT ]