Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Запустить с Delphi консольное приложение и считать его вывод / 25 сообщений из 25, страница 1 из 1
14.10.2011, 17:20
    #37482921
Zmiy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Добрый день.

Столкнулся с непонятной проблемой. Из дельфи вызываю консольное приложение и считываю его вывод. Проблема в том, что в компилированной версии работает не стабильно, случается что программа просто зависает и дальше не идет. Если запускаю напрямую из дельфи, то при работе консольной программы выходит сообщение отладчика в асемблере и после последующего нажати Run все продолжается как и должно.

С консоли читаю так:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
class function TIDCard.readData(DosApp: string): string;
const
  ReadBuffer = 2400;
var
  Security : TSecurityAttributes;
  ReadPipe,WritePipe : THandle;
  start : TStartUpInfo;
  ProcessInfo : TProcessInformation;
  Buffer : Pchar;
  BytesRead : DWord;
  Apprunning : DWord;
begin
  with Security do begin
   nlength := SizeOf(TSecurityAttributes) ;
   binherithandle := true;
   lpsecuritydescriptor := nil;
  end;
  if Createpipe (ReadPipe, WritePipe, @Security, 0) then begin
    Buffer := AllocMem(ReadBuffer + 1) ;
    FillChar(Start,Sizeof(Start),#0) ;
    start.cb := SizeOf(start) ;
    start.hStdOutput := WritePipe;
    start.hStdInput := ReadPipe;
    start.dwFlags := STARTF_USESTDHANDLES +  STARTF_USESHOWWINDOW;
    start.wShowWindow := SW_HIDE;
    if CreateProcess(nil,                            //Тут окно с ассемблером
              PChar(DosApp),
              @Security,
              @Security,
              true,
              NORMAL_PRIORITY_CLASS,
              nil,
              nil,
              start,
              ProcessInfo)
    then begin
      repeat
       Apprunning := WaitForSingleObject
                    (ProcessInfo.hProcess,100) ;
       Application.ProcessMessages;
      until (Apprunning <> WAIT_TIMEOUT) ;
      Repeat
         BytesRead := 0;
         ReadFile(ReadPipe,Buffer[0],
         ReadBuffer,BytesRead,nil) ;
         Buffer[BytesRead]:= #0;
         OemToAnsi(Buffer,Buffer) ;
         Result := Result + String(Buffer) ;
      until (BytesRead < ReadBuffer) ;
    end;
    FreeMem(Buffer) ;
    CloseHandle(ProcessInfo.hProcess) ;
    CloseHandle(ProcessInfo.hThread) ;
    CloseHandle(ReadPipe) ;
    CloseHandle(WritePipe) ;
  end;
end;


В коде вызываю метод таким образом:
Код: pascal
1.
2.
3.
            Application.ProcessMessages;
            Self.loggedIdCode := TIDCard.getPersonalCode;
            Application.ProcessMessages;



Так же впомогательный методы:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
class function TIDCard.getPersonalCode: string;
begin
  Result := getValue('Personal ID code');
end;

class function TIDCard.getValue(name: string): string;
var
  src: string;
  startIdx: integer;
begin
  src := readData('idcard/eidenv.exe');
  startIdx := Pos(name, src);
  if (startIdx > 0) then begin
    Result := Copy(src, startIdx + length(name) + 2, 11);
  end else begin
    Result := '';
  end;
end;



Может кто-нибудь подскажет в какую сторону копать?

Заранее благодарен.
...
Рейтинг: 0 / 0
14.10.2011, 18:07
    #37482989
demian111
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Zmiyслучается что программа просто зависает и дальше не идет
как минимум два места вижу:
1. консольная прога не умирает, и ты в вечном цикле с вечной Application.ProcessMessages.
2. цикл чтения из пайпы, если начитывается не меньше чем размер буфера, то повторное чтение, а там уже нету байтов и висим ...
OemToAnsi - Obsolete.

з.ы.
ну и я бы в потоке начитывал.
...
Рейтинг: 0 / 0
14.10.2011, 22:56
    #37483220
bk0010
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Пример из DelphiWorld:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
function ExecuteFile(FileName, StdInput: string;
  TimeOut: integer;
  var StdOutput: string): boolean;

label
  Error;

type
  TPipeHandles = (IN_WRITE, IN_READ,
    OUT_WRITE, OUT_READ,
    ERR_WRITE, ERR_READ);

type
  TPipeArray = array[TPipeHandles] of THandle;

var
  i: integer;
  ph: TPipeHandles;
  sa: TSecurityAttributes;
  Pipes: TPipeArray;
  StartInf: TStartupInfo;
  ProcInf: TProcessInformation;
  Buf: array[0..1024] of byte;
  TimeStart: TDateTime;

  function ReadOutput: string;
  var
    i: integer;
    s: string;
    BytesRead: longint;

  begin
    Result := '';
    repeat

      Buf[0] := 26;
      WriteFile(Pipes[OUT_WRITE], Buf, 1, BytesRead, nil);
      if ReadFile(Pipes[OUT_READ], Buf, 1024, BytesRead, nil) then
      begin
        if BytesRead > 0 then
        begin
          buf[BytesRead] := 0;
          s := StrPas(@Buf[0]);
          i := Pos(#26, s);
          if i > 0 then
            s := copy(s, 1, i - 1);
          Result := Result + s;
        end;
      end;

      if BytesRead1024 then
        break;
    until false;
  end;

begin
  Result := false;
  for ph := Low(TPipeHandles) to High(TPipeHandles) do
    Pipes[ph] := INVALID_HANDLE_VALUE;

  // Создаем пайпы
  sa.nLength := sizeof(sa);
  sa.bInheritHandle := TRUE;
  sa.lpSecurityDescriptor := nil;

  if not CreatePipe(Pipes[IN_READ], Pipes[IN_WRITE], @sa, 0) then
    goto Error;
  if not CreatePipe(Pipes[OUT_READ], Pipes[OUT_WRITE], @sa, 0) then
    goto Error;
  if not CreatePipe(Pipes[ERR_READ], Pipes[ERR_WRITE], @sa, 0) then
    goto Error;

  // Пишем StdIn
  StrPCopy(@Buf[0], stdInput + ^Z);
  WriteFile(Pipes[IN_WRITE], Buf, Length(stdInput), i, nil);

  // Хендл записи в StdIn надо закрыть - иначе выполняемая программа
  // может не прочитать или прочитать не весь StdIn.

  CloseHandle(Pipes[IN_WRITE]);

  Pipes[IN_WRITE] := INVALID_HANDLE_VALUE;

  FillChar(StartInf, sizeof(TStartupInfo), 0);
  StartInf.cb := sizeof(TStartupInfo);
  StartInf.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;

  StartInf.wShowWindow := SW_SHOW; // SW_HIDE если надо запустить невидимо

  StartInf.hStdInput := Pipes[IN_READ];
  StartInf.hStdOutput := Pipes[OUT_WRITE];
  StartInf.hStdError := Pipes[ERR_WRITE];

  if not CreateProcess(nil, PChar(FileName), nil,
    nil, True, NORMAL_PRIORITY_CLASS,
    nil, nil, StartInf, ProcInf) then
    goto Error;

  TimeStart := Now;

  repeat
    Application.ProcessMessages;
    i := WaitForSingleObject(ProcInf.hProcess, 100);
    if i = WAIT_OBJECT_0 then
      break;
    if (Now - TimeStart) * SecsPerDay > TimeOut then
      break;
  until false;

  if iWAIT_OBJECT_0 then
    goto Error;
  StdOutput := ReadOutput;

  for ph := Low(TPipeHandles) to High(TPipeHandles) do
    if Pipes[ph]INVALID_HANDLE_VALUE then
      CloseHandle(Pipes[ph]);

  CloseHandle(ProcInf.hProcess);
  CloseHandle(ProcInf.hThread);
  Result := true;
  Exit;

  Error:

  if ProcInf.hProcessINVALID_HANDLE_VALUE then

  begin
    CloseHandle(ProcInf.hThread);
    i := WaitForSingleObject(ProcInf.hProcess, 1000);
    CloseHandle(ProcInf.hProcess);
    if iWAIT_OBJECT_0 then

    begin
      ProcInf.hProcess := OpenProcess(PROCESS_TERMINATE,
        FALSE,
        ProcInf.dwProcessId);

      if ProcInf.hProcess 0 then
      begin
        TerminateProcess(ProcInf.hProcess, 0);
        CloseHandle(ProcInf.hProcess);
      end;
    end;
  end;

  for ph := Low(TPipeHandles) to High(TPipeHandles) do
    if Pipes[ph]INVALID_HANDLE_VALUE then
      CloseHandle(Pipes[ph]);
end;

...
Рейтинг: 0 / 0
17.10.2011, 11:07
    #37484712
Zmiy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
demian111,

То есть ее надо самому убивать?
...
Рейтинг: 0 / 0
17.10.2011, 11:28
    #37484747
Zmiy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
bk0010,

В 7й версии дельфи не билдится. Говорит
Types of actual and formal var parameters must be identical

В строке:
Код: plaintext
1.
WriteFile(Pipes[OUT_WRITE], Buf,  1 , BytesRead,  nil );
...
Рейтинг: 0 / 0
17.10.2011, 11:39
    #37484765
Anatoly Podgoretsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Разве nil var параметр?
...
Рейтинг: 0 / 0
17.10.2011, 12:41
    #37484926
Zmiy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
В статье по крайней мере такой код. Кажется он не для 7й версии.
...
Рейтинг: 0 / 0
17.10.2011, 14:15
    #37485089
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Zmiy,

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

Как Вам такой вариантец?
...
Рейтинг: 0 / 0
17.10.2011, 14:27
    #37485113
Zmiy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Можно и в файл, но тогда встает вопрос как определить что запись в файл прошла успешно?
...
Рейтинг: 0 / 0
17.10.2011, 15:04
    #37485184
чччД
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Zmiy,

Ну, раз есть возможность выбора вариантов взаимодействия - это ж супер!
:)
Можно задействовать различные варианты ipc, начиная с обмена сообщениями и dde. А если объем данных велик - можно в к-н субд писать. Вопросы синхронизации в последнем случае решаются автоматически, механизмом транзакций.
...
Рейтинг: 0 / 0
17.10.2011, 15:06
    #37485188
чччД
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
ZmiyМожно и в файл, но тогда встает вопрос как определить что запись в файл прошла успешно?
Методом попытки открытия файла в режиме эксклюзивного доступа.
...
Рейтинг: 0 / 0
17.10.2011, 22:51
    #37485857
bk0010
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Zmiybk0010,

В 7й версии дельфи не билдится. Говорит
Types of actual and formal var parameters must be identical

В строке:
Код: plaintext
1.
WriteFile(Pipes[OUT_WRITE], Buf,  1 , BytesRead,  nil );

Заведите переменную типа POverlapped, присвойте ей nil и замените nil в функции на нее
...
Рейтинг: 0 / 0
18.10.2011, 06:12
    #37486014
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
ZmiyМожно и в файл, но тогда встает вопрос как определить что запись в файл прошла успешно?
Zmiy, запись в файл пройдёт успешно, не переживайте, потому что не Вы будете писать в файл, а система. Т.е. вывод будет перенаправлен с консоли в файл. Вам-же нужно просто дождаться завершения исполнения консольного приложения и считать полученный файл. Надеюсь Вы знаете КАК нужно написать строку исполнения, чтобы вывод пошёл в файл ;-)
...
Рейтинг: 0 / 0
18.10.2011, 12:38
    #37486561
Човайохоя
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
А можно ли получить вывод из программы с псевдографическим интерфейсом, таких как FAR Manager ?
...
Рейтинг: 0 / 0
18.10.2011, 12:52
    #37486609
Човайохоя
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
ЧовайохояА можно ли получить вывод из программы с псевдографическим интерфейсом, таких как FAR Manager ?Если просто перенаправить вывод в файл, то файл создается пустой
...
Рейтинг: 0 / 0
18.10.2011, 13:53
    #37486747
Zmiy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Спасибо всем, в итоге заработал такой вариант:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
class procedure TIDCard.CaptureConsoleOutput(DosApp : string; cpt : TCaption);
const
  ReadBuffer = 1048576;  // 1 MB Buffer
var
  Security            : TSecurityAttributes;
  ReadPipe,WritePipe  : THandle;
  start               : TStartUpInfo;
  ProcessInfo         : TProcessInformation;
  Buffer              : Pchar;
  TotalBytesRead,
  BytesRead           : DWORD;
  Apprunning,n,
  BytesLeftThisMessage,
  TotalBytesAvail : integer;
begin
  with Security do
  begin
    nlength              := SizeOf(TSecurityAttributes);
    binherithandle       := true;
    lpsecuritydescriptor := nil;
  end;

  if CreatePipe (ReadPipe, WritePipe, @Security, 0) then
  begin
    // Redirect In- and Output through STARTUPINFO structure

    Buffer  := AllocMem(ReadBuffer + 1);
    FillChar(Start,Sizeof(Start),#0);
    start.cb          := SizeOf(start);
    start.hStdOutput  := WritePipe;
    start.hStdInput   := ReadPipe;
    start.dwFlags     := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
    start.wShowWindow := SW_HIDE;

    // Create a Console Child Process with redirected input and output

    if CreateProcess(nil      ,PChar(DosApp),
                     @Security,@Security,
                     true     ,CREATE_NO_WINDOW or NORMAL_PRIORITY_CLASS,
                     nil      ,nil,
                     start    ,ProcessInfo) then
    begin
      n:=0;
      TotalBytesRead:=0;
      repeat
        // Increase counter to prevent an endless loop if the process is dead
        Inc(n,1);
        
        // wait for end of child process
        Apprunning := WaitForSingleObject(ProcessInfo.hProcess,100);
        Application.ProcessMessages;

        // it is important to read from time to time the output information
        // so that the pipe is not blocked by an overflow. New information
        // can be written from the console app to the pipe only if there is
        // enough buffer space.

        if not PeekNamedPipe(ReadPipe        ,@Buffer[TotalBytesRead],
                             ReadBuffer      ,@BytesRead,
                             @TotalBytesAvail,@BytesLeftThisMessage) then break
        else if BytesRead > 0 then
          ReadFile(ReadPipe,Buffer[TotalBytesRead],BytesRead,BytesRead,nil);
        TotalBytesRead:=TotalBytesRead+BytesRead;
      until (Apprunning <> WAIT_TIMEOUT) or (n > 150);

      Buffer[TotalBytesRead]:= #0;
      OemToChar(Buffer,Buffer);
      cpt := cpt + StrPas(Buffer);
    end;
    FreeMem(Buffer);
    CloseHandle(ProcessInfo.hProcess);
    CloseHandle(ProcessInfo.hThread);
    CloseHandle(ReadPipe);
    CloseHandle(WritePipe);
  end;
end;

...
Рейтинг: 0 / 0
Период между сообщениями больше года.
30.12.2013, 12:10
    #38515759
dima70
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
function CaptureConsoleOutput(DosApp : string):AnsiString;
const
  ReadBuffer = 1048576;  // 1 MB Buffer
var
  Security            : TSecurityAttributes;
  ReadPipe,WritePipe  : THandle;
  start               : TStartUpInfo;
  ProcessInfo         : TProcessInformation;
  Buffer              : PAnsiChar;
  TotalBytesRead,
  BytesRead           : DWORD;
  Apprunning,n,
  BytesLeftThisMessage,
  TotalBytesAvail : integer;
begin
  with Security do
  begin
    nlength              := SizeOf(TSecurityAttributes);
    binherithandle       := true;
    lpsecuritydescriptor := nil;
  end;

  if CreatePipe (ReadPipe, WritePipe, @Security, 0) then
  begin
    // Redirect In- and Output through STARTUPINFO structure

    Buffer  := AllocMem(ReadBuffer + 1);
    FillChar(Start,Sizeof(Start),#0);
    start.cb          := SizeOf(start);
    start.hStdOutput  := WritePipe;
    start.hStdInput   := ReadPipe;
    start.dwFlags     := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
    start.wShowWindow := SW_HIDE;

    // Create a Console Child Process with redirected input and output

    if CreateProcess(nil      ,PChar(DosApp),
                     @Security,@Security,
                     true     ,CREATE_NO_WINDOW or NORMAL_PRIORITY_CLASS,
                     nil      ,nil,
                     start    ,ProcessInfo) then
    begin
      n:=0;
      TotalBytesRead:=0;
      repeat
        // Increase counter to prevent an endless loop if the process is dead
        Inc(n,1);

        // wait for end of child process
        Apprunning := WaitForSingleObject(ProcessInfo.hProcess,100);
        Application.ProcessMessages;

        // it is important to read from time to time the output information
        // so that the pipe is not blocked by an overflow. New information
        // can be written from the console app to the pipe only if there is
        // enough buffer space.

        if not PeekNamedPipe(ReadPipe        ,@Buffer[TotalBytesRead],
                             ReadBuffer      ,@BytesRead,
                             @TotalBytesAvail,@BytesLeftThisMessage) then break
        else if BytesRead > 0 then
          ReadFile(ReadPipe,Buffer[TotalBytesRead],BytesRead,BytesRead,nil);
        TotalBytesRead:=TotalBytesRead+BytesRead;
      until (Apprunning <> WAIT_TIMEOUT) or (n > 150);

      Buffer[TotalBytesRead]:= #0;
     // OemToChar(Buffer,Buffer);
      Result := Result + StrPas(Buffer);
    end;
    FreeMem(Buffer);
    CloseHandle(ProcessInfo.hProcess);
    CloseHandle(ProcessInfo.hThread);
    CloseHandle(ReadPipe);
    CloseHandle(WritePipe);
  end;
end;



Подправит чуток для XE3...
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
22.09.2018, 15:08
    #39706418
avlaxoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
dima70,

Последний пример не работает на Delphi Tokyo 10.2, валится на "if CreateProcess..."
...
Рейтинг: 0 / 0
22.09.2018, 23:01
    #39706476
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
avlaxoft,

естественно падает. Ведь DosApp объявлен как string, т.е. в Delphi 10.2 это unicode-строка (1 символ - 2 байта).
А в строке "if CreateProcess" идет приведение DosApp к PChar (1 символ - 1 байт).

Доработайте немного код и он заработает :-)
...
Рейтинг: 0 / 0
22.09.2018, 23:05
    #39706478
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Хотя конечно я погорячился, не подумав. pchar это же PWideChar)))
...
Рейтинг: 0 / 0
22.09.2018, 23:09
    #39706480
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
asutp2PChar (1 символ - 1 байт).

Не хочу тебя разочаровывать, но PChar там тоже юникодский, 1 символ = 2 байта. И что хуже
всего: CreateProcess должен бы использоваться в юникодной версии (АКА CreateProcessW), так
что проблема не в нём.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
23.09.2018, 01:35
    #39706485
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Dimitry Sibiryakov,

это я понял через минуту после написания своего поста)))) прочитай пост выше своего)))
...
Рейтинг: 0 / 0
23.09.2018, 12:25
    #39706521
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
asutp2это я понял через минуту после написания своего поста)))) прочитай пост выше своего)))

Да, да, видел. Я тоже не чемпион мира по скоростному набору текста.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
23.09.2018, 13:32
    #39706534
schi
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Обработку ошибок в примерах Пушкин конечно же выполняет.
...
Рейтинг: 0 / 0
02.11.2018, 13:05
    #39727189
avlaxoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Запустить с Delphi консольное приложение и считать его вывод
Если кому ещё интересно: вот работающий пример (сорри за лишние комментарии, некогда было код причёсывать...):

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
unit uMain;

interface

uses
   Vcl.Forms, Vcl.Controls, Vcl.StdCtrls, System.Classes, Vcl.ExtCtrls,
   Windows, StrUtils, SysUtils;

type
  //TAttachConsole = function (dwProcessId: DWORD): LongBOOL stdcall;

  TfmMain = class(TForm)
    btMyButton: TButton;
    edText: TEdit;
    btClear: TButton;
    memOut: TMemo;
    procedure btMyButtonClick(Sender: TObject);
    procedure btClearClick(Sender: TObject);
  private
    { Private declarations }
    function GetDosOutput(const CommandLine: string): string;
  public
    { Public declarations }
  end;

var
  fmMain: TfmMain;

const
  C_EXE_CMD = 'c:\Program Files\SlikSvn\bin\svn.exe log -r '; //'c:\Program Files\SlikSvn\bin\svn.exe';
  C_WORKING_DIR = 'c:\Users\ALEX\Documents\MxLib\';
  C_BUF_SIZE = 1024;
  //Вова "c:\Program Files\SlikSvn\bin\svn.exe"

implementation

{$R *.dfm}

var stopfunc: Integer;

function DosToWin(ASource: AnsiString): AnsiString;
 var
   Ch: PAnsiChar;
 begin
   Ch := AnsiStrAlloc(Length(ASource) + 1);
   OemToAnsi(PAnsiChar(ASource), Ch);
   Result := StrPas(Ch);
   StrDispose(Ch);
 end;

procedure TfmMain.btClearClick(Sender: TObject);
begin
  edText.Clear;
  memOut.Clear;
end;

function TfmMain.GetDosOutput(const CommandLine: string): string;
var
  SA: TSecurityAttributes;
  SI: TStartupInfoA;
  PI: TProcessInformation;
  StdOutPipeRead, StdOutPipeWrite: THandle;
  WasOK: Boolean;
  Buffer: array[0..C_BUF_SIZE - 1] of AnsiChar;
  BytesRead: Cardinal;
  WorkDir, Line: AnsiString;
  i:Integer;
begin
//stopfunc:=0;
  Application.ProcessMessages;
  with SA do
  begin
    nLength := SizeOf(SA);
    bInheritHandle := True;
    lpSecurityDescriptor := nil;
  end;

  CreatePipe(StdOutPipeRead,
             StdOutPipeWrite,
             @SA,
             0
             );
  try

    with SI do
    begin
      FillChar(SI, SizeOf(SI), 0);
      cb := SizeOf(SI);
      dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
      wShowWindow := SW_HIDE;
      hStdInput := GetStdHandle(STD_INPUT_HANDLE);
      hStdOutput := StdOutPipeWrite;
      hStdError := StdOutPipeWrite;
    end;

    WorkDir := C_WORKING_DIR; //ExtractFilePath(CommandLine);

    WasOK := CreateProcessA(nil, PAnsiChar(AnsiString(CommandLine)), nil, nil, True, 0, nil, PAnsiChar(WorkDir{'C:\WINDOWS\system32\'}), SI, PI);
    //WasOK := CreateProcess(nil, PChar('C:\WINDOWS\system32\cmd.exe'), nil, nil, True, 0, nil, PChar(WorkDir), SI, PI);

    CloseHandle(StdOutPipeWrite);

    if not WasOK then
      raise Exception.Create('Could not execute command line!')
    else
      try

        Line := '';
        repeat

          WasOK := ReadFile(StdOutPipeRead, Buffer, C_BUF_SIZE, BytesRead, nil);
          if BytesRead > 0 then

          begin

            Buffer[BytesRead] := #0;
            Line := Line + Buffer;
            {if (Copy(Form1.Edit1.text,1,4) = 'ping') then
            begin
            }
             //Memo1.text := DosToWin(Line); // конвертим вывод в мемо, с ОЕМ в Анси
             //Perform(EM_LINESCROLL,0,Memo1.Lines.Count-1); // автопрокрутка мемо вниз
               //////////////////////////  пауза, чтоб не висло окно при пинге и множественных выводов консоли

              {i := 0;
               while i<100 do begin
              sleep(12);
              Application.ProcessMessages;
              inc(i);
              end;
              }
              Application.ProcessMessages;

                //// убиваем процессы
              if stopfunc = 1 then
               begin
               CloseHandle(PI.hThread);
               CloseHandle(PI.hProcess);
               //shellexecute(0,'Open',Pchar('taskkill'),'/im cmd.exe /f',0,SW_HIDE);
               //shellexecute(0,'Open',Pchar('taskkill'),'/im ping.exe /f',0,SW_HIDE);
              Exit;
             end;
            //end;


          end;
        until not WasOK or (BytesRead = 0);
        WaitForSingleObject(PI.hProcess, INFINITE);
      finally
        CloseHandle(PI.hThread);
        CloseHandle(PI.hProcess);
      end;
  finally
      result:=Line;
      CloseHandle(StdOutPipeRead);
  end;
end;

procedure TfmMain.btMyButtonClick(Sender: TObject);
begin
  memOut.Lines.Text := GetDosOutput(C_EXE_CMD + Trim(edText.Text));
end;

end. 

...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Запустить с Delphi консольное приложение и считать его вывод / 25 сообщений из 25, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]