Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Получение Stdout дочернего процесса.  (Прочитано 12646 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Sergio
Гость
« : 18-02-2004 10:39 » 

Есть CLX - приложение, требуется запустить с параметрами консольный процесс и получить stdout дочернего процесса в результирующую программу.  
Нужно, чтобы работало и в Windows и в Linux.
Знаю как запустить с параметрами, но не знаю как получить stdout.
В хелпах и сети искал не нашел,  если кто знает подскажите

Sergio.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 18-02-2004 11:16 » 

Расскажу что есть на С, а что есть на Delphi мне не ведомо:
В Win есть ф-ия CreateProcess() запуска дочернего процесса, в которую передаешь HANDLE для stdin/stdout/stderr (через параметер LPSTARTUPINFO lpStartupInfo).
В Linux-е это делается через fork(), заменой stdin/stdout/stderr на нужные и последующим запуском прогрвммы через exec*().
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #2 : 18-02-2004 12:51 » 

RXL, добвить почти нечего Улыбаюсь

но всё-таки. на дельфях поддерживаются практически все функции винды. но, как говорил поручик Ржевский, "есть нюансы". я организовывал вывод в мемо, например, через pipes. сие есть канал, который в состоянии обеспечивать связь между двумя различными процессами через их дескрипторы. т.е. логика работы примерно следующая: создаём pipe, в StartupInfo засовываем хандлы, полученные в результате CreatePipe, запускаем процесс через CreateProcess и ждём, когда он отработает через WaitForSingleObject.  после этого читаем из pipe, который был назначен в hStdInput и кладём в memo. потом всё освобождаем.

короче, проще привести код. вот что у меня вышло:
Код:

procedure RunInMemo;
const
  bufsize = 2000;
var
  sa{ TSecurityAttributes;
  si{ TStartupInfo;
  pi{ TProcessInformation;
  rp, wp{ THandle;
  buf{ pchar;
  ec{ dword;
  bread{ dword;
begin
  with sa do begin
    nLength {= SizeOf )TSecurityAttributes:;
    bInheritHandle {= TRUE;
    lpSecurityDescriptor {= nil;
  end;
  if CreatePipe )rp, wp, @sa, 0: then begin
    FillChar )si, SizeOf )TStartupInfo:, #0:;
    with si do begin
      cb {= SizeOf )si:;
      hStdInput {= rp;
      hStdOutput {= wp;
      dwFlags {= STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
      wShowWindow {= SW_HIDE;
    end;
    buf {= AllocMem )bufsize + 1:;
    try
      if CreateProcess )nil, pchar )Cmd:, @sa, @sa, TRUE, NORMAL_PRIORITY_CLASS, nil, nil, si, pi: then begin
        repeat
          ec {= WaitForSingleObject )pi.hProcess, 500:;
        until ec <> WAIT_TIMEOUT;
        bread {= 0;
        repeat
          ReadFile )rp, buf [0(, bufsize, bread, nil:;
          buf [bread( {= #0;
          OemToAnsi )buf, buf:;
          Memo.Text {= Memo.Text + string )buf:;
          Application.ProcessMessages;
        until bread < bufsize;
      end;
    finally
      FreeMem )buf:;
      CloseHandle)pi.hProcess:;
      CloseHandle)pi.hThread:;
      CloseHandle)rp:;
      CloseHandle)wp:;
    end;
  end;
end;

procedure TForm1.Button1Click)Sender{ TObject:;
begin
  RunInMemo )'C{\WINNT\system32\netstat', Memo1:;
end;


а вот насчёт Linux - сорри.  :oops: я под него на дельфях никогда не писал, но вышеприведённый код там работать не будет однозначно.
Записан

x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #3 : 18-02-2004 13:41 » 

кстати, если код немного изменить,
Код:

        ...
        repeat
          ec {= WaitForSingleObject )pi.hProcess, 500:;
          ReadFile )rp, buf [0(, bufsize, bread, nil:;
          buf [bread( {= #0;
          OemToAnsi )buf, buf:;
          Memo.Text {= Memo.Text + string )buf:;
          Application.ProcessMessages;
        until ec <> WAIT_TIMEOUT;
        ...

то результат будет выводиться в realtime, а не после того, как прога полностью завершит свою работу. частота обновления при этом будет регулироваться последним параметром, передаваемым в WaitForSingleObject.
Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 18-02-2004 14:37 » 

Правда вопрос в том, как сделать это в рамках CLX - чтобы была переносимость.
Правда, я пробовал чуть-чуть разбираться с Kylix2 - оказалось что сие и программы, которые в нем делаешь, работают из под wine! Т.е. через эммулятов win32 API. Как работает более поздние версии я не знаю.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #5 : 18-02-2004 15:10 » 

RXL,  вряд ли. такие модули, как Windows, ToolsApi и пр. не относятся к кроссплатформенным. т.е., если ты включаешь их в проект, чтобы юзать функции виндового api, к примеру, 7-я дельфи сама скажет, что в проекте используются платформенно-зависимые модули. и в линухе такая прога работать не сможет.

я думаю, что надо разобраться с механизмом стандартного ввода/вывода линуха и делать всё через условные опции компилятора, что в дельфи выглядит, как
Код:

  |$IFDEF WINDOWS"
  ...
  |$ENDIF"
  и т.д.
Записан

Sashok
Молодой специалист

us
Offline Offline
Пол: Мужской

« Ответ #6 : 28-03-2004 14:54 » 

Вот, только сейчас наткнулся на эту тему - поэтому такая запоздалая реакция.
Цитата: RXL
Расскажу что есть на С, а что есть на Delphi мне не ведомо:
В Win есть ф-ия CreateProcess() запуска дочернего процесса, в которую передаешь HANDLE для stdin/stdout/stderr (через параметер LPSTARTUPINFO lpStartupInfo).
В Linux-е это делается через fork(), заменой stdin/stdout/stderr на нужные и последующим запуском прогрвммы через exec*().
Если речь идет о запуске дочернего процесса с перехватом его ввода/вывода, то в Юниксе можно использовать popen(). В Linux-е, полагаю, тоже.
Записан

Если бы окружающие нас объекты содержали столько же ошибок, сколько программы, цивилизация обрушилась бы от первого порыва ветра...
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines