Как отправить команду в консольное приложение из приложения GUI

У меня есть консольное приложение, которое я запускаю от GUI applicaiton. Консольное приложение берет параметры для имен файлов, чтобы проанализировать и обработать. В настоящее время я в состоянии получить его вывод и отобразить его в приложении GUI, но я хотел бы иметь возможность отправить команды в него, чтобы управлять или даже остановить его выполнение.

Как я могу отправить команду или строку или что-нибудь к консольному приложению, предпочтительно с помощью каналов, которые я открыл для чтения его вывода?

const
  CReadBuffer = 2400;
var
  saSecurity: TSecurityAttributes;
  hRead: THandle;
  hWrite: THandle;
  suiStartup: TStartupInfo;
  piProcess: TProcessInformation;
  pBuffer: array[0..CReadBuffer] of AnsiChar;
  dRead: DWord;
  dRunning: DWord;
  dWritten: DWord;
  Command: String;
  BytesLeft: Integer;
  BytesAvail: Integer;
begin
  saSecurity.nLength := SizeOf(TSecurityAttributes);
  saSecurity.bInheritHandle := True;
  saSecurity.lpSecurityDescriptor := nil;

  if CreatePipe(hRead, hWrite, @saSecurity, 0) then
  begin
    FillChar(suiStartup, SizeOf(TStartupInfo), #0);
    suiStartup.cb := SizeOf(TStartupInfo);
    suiStartup.hStdInput := hRead;
    suiStartup.hStdOutput := hWrite;
    suiStartup.hStdError := hWrite;
    suiStartup.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
    suiStartup.wShowWindow := SW_HIDE;
    Command := 'messageparser.exe c:\messagefile.msg';
    UniqueString(Command);
    if CreateProcess(nil, PChar(Command), @saSecurity,
     @saSecurity, True, NORMAL_PRIORITY_CLASS, nil, nil, suiStartup, piProcess) then
    begin
      repeat
        dRunning  := WaitForSingleObject(piProcess.hProcess, 100);
        Application.ProcessMessages;
        repeat
          dRead := 0;

          if not PeekNamedPipe(hread, @pbuffer, CReadBuffer, @dRead, @BytesAvail, @BytesLeft) then
            RaiseLastOSError;
          if dRead <> 0 then
          begin
            ReadFile(hRead, pBuffer[0], CReadBuffer, dRead, nil);
            pBuffer[dRead] := #0;
            OemToCharA(pBuffer, pBuffer);
            // do something with the data
            // if a condition is present then do the following:
            // WriteFile(hWrite, some_command, size_of_buffer, DWritten, nil);  
          end;
        until (dRead < CReadBuffer);
      until (dRunning <> WAIT_TIMEOUT);
      CloseHandle(piProcess.hProcess);
      CloseHandle(piProcess.hThread);
    end;
    CloseHandle(hRead);
    CloseHandle(hWrite);
  end;

Тогда на консольной стороне, существует поток, ожидающий входа. Вот выполнить метод:

  while not Terminated do
  begin
    ReadLn(Command);
    // process command
    Sleep(10);
  end;

Это плохо мне знакомо поэтому, если существуют подсказки относительно того, как делают его правильно, я приветствую их:). Однако каждый раз, когда я отправляю Команду, она прибывает через как, независимо от того, что я считал в pBuffer из ReadPipe и не, какова команда.

Надежда это помогает.

--

Найденный решением на основе подсказки Nat.

Двунаправленная связь между gui и консолью

9
задан yozey 7 January 2010 в 07:17
поделиться

3 ответа

Вам нужны два канала: один для процесса, отправляющего вам выходные данные ( stdout ), и один для вас, чтобы отправлять входные данные процессу ( stdin ).

Судя по вашему коду, вы помещаете оба конца того же канала в запись TStartupInfo . Таким образом, вы фактически заставляете процесс говорить сам с собой. : -)

Итак, вам нужно дважды вызвать CreatePipe () , чтобы создать два канала, один для stdin , один для stdout stderr ).

Затем поместите дескриптор чтения stdin в suiStartup.hStdInput и дескриптор записи stdout в suiStartup.hStdOutput

Чтобы отправить данные процессу, записать в дескриптор записи канала stdin . Чтобы прочитать вывод процесса, прочтите дескриптор чтения канала stdout .

Изменить: (снова)

Что касается всех дублирующих дескрипторов, а также наследуемого и ненаследуемого материала, описанного на этой странице (особенно в примере кода), вам понадобится чтобы убедиться, что дескрипторы, которые вы отправляете процессу, наследуются (как вы это сделали).

Вы должны также убедиться, что дескрипторы каналов, которые использует родительский процесс, не наследуются . Но у вас нет для этого ... Мне сошло с рук не делать этого раньше.

Вы можете сделать это, либо вызвав DuplicateHandle () для дескрипторов, указав, что они не наследуются и закрыв старые дескрипторы, либо вызвав SetHandleInformation () с 0, указанным для флаги (как описано здесь ).

Прошло много времени с тех пор, как я делал это сам, но я почти уверен, что это так, что счетчик ссылок для дескрипторов связан с вызывающим процессом, а не с дочерним процессом. Это предотвращает закрытие дескриптора, пока вы все еще его используете (например, вызывающий процесс может закрыть 'stdin'). Убедитесь, что вы закрыли ручки, иначе ручки протекут.

HTH.

N @

9
ответ дан 4 December 2019 в 20:24
поделиться

Проверьте это, чтобы увидеть, что вам нужно создать обе трубы (дважды вызывая WINAPI), как повторял Нат, но что насчет наследуемых ручек - не уверен, зачем это нужно?

http://support.microsoft.com/kb/190351.

Я думаю, что также может ввести в заблуждение то, что когда вы создаете трубку, вы создаете ручку для чтения и ручку для записи для этой трубки. В случае с трубкой stdin консоли вы будете использовать только ручку записи. Затем вы создаёте ещё одну трубку для stdout консоли (которая также будет иметь обработчик чтения и записи), но вы будете использовать только обработчик чтения.

Думаю, я правильно понял, но уже поздно и я иду спать.

1
ответ дан 4 December 2019 в 20:24
поделиться

Вместе с выходным трубопроводом есть входной трубопровод. Просто напишите на этот канал, используя WriteFile().

1
ответ дан 4 December 2019 в 20:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: