Гость
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Вернуть результат работы приложения / 21 сообщений из 21, страница 1 из 1
24.01.2022, 10:29
    #40128937
antox
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
Хочу одним приложением, запускать второе и ждать его завершения, но не просто окончания, а с каким-то результатом.

Как что-то вернуть из подопытного главному,? :)

Хотя бы код той же ошибки или путь к файлу с детальной информацией
...
Рейтинг: 0 / 0
24.01.2022, 10:36
    #40128942
cptngrb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
antox, второе приложение твоё?
...
Рейтинг: 0 / 0
24.01.2022, 10:45
    #40128944
AWSVladimir
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
Exit(IntegerCodeResult) не вариант ?
...
Рейтинг: 0 / 0
24.01.2022, 12:45
    #40128974
shalamyansky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
antox,

Функция написана давно, уже не помню всех нюансов. Но она работает(ла). Основной смысл в том, что кроме запущенного процесса надо и о своем родном не забывать, обрабатывать очередь сообщений. Вижу там внутри пару других личных функций, они очевидны по названию, свои напишете.


Код: 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.
{ Starts a process and waits for its ending. Returns the process exit code }

function WaitProcess( FileName:AnsiString; CommandLine:AnsiString = ''; CurrentDir:AnsiString = ''; pExitCode:PDWORD = nil ):BOOLEAN;
var
    StartupInfo : _STARTUPINFOA;
    ProcessInfo : TProcessInformation;
    pDir        : PAnsiChar;
    WaitRes     : DWORD;
    Msg         : TMsg;
    Done        : BOOLEAN;
begin
    Result := FALSE;
    if( pExitCode <> nil )then begin
        pExitCode^ := 0;
    end;
    if( 0 < Pos( ' ', FileName ) )then begin
        FileName := Enquote( FileName );
    end;
    if( CommandLine <> '' )then begin
        CommandLine := ' ' + CommandLine;
    end;
    if( CurrentDir <> '' )then begin
        pDir := PAnsiChar( CurrentDir );
    end else begin
        pDir := nil;
    end;
    try
        FillChar( StartupInfo, SizeOf( StartupInfo ), 0 );
        StartupInfo.cb := SizeOf( StartupInfo );
        FillChar( ProcessInfo, SizeOf( ProcessInfo ), 0 );
        Result := CreateProcessA(
              nil
            , PAnsiChar( FileName + CommandLine )
            , nil, nil, FALSE, 0, nil
            , pDir
            , StartupInfo
            , ProcessInfo
        );
        if( Result )then begin
            Done := FALSE;
            while( not Done )do begin
                WaitRes := MsgWaitForMultipleObjects( 1, ProcessInfo.hProcess, FALSE, INFINITE, QS_ALLINPUT );
                case WaitRes of
                    WAIT_OBJECT_0 : begin
                        if( pExitCode <> nil )then begin
                            if( not GetExitCodeProcess( ProcessInfo.hProcess, pExitCode^ ) )then begin
                                pExitCode^ := 0;
                            end;
                        end;
                        Done := TRUE;
                    end;
                    WAIT_OBJECT_0 + 1 : begin
                        while( PeekMessage( Msg, 0, 0, 0, PM_REMOVE ) )do begin
                            case Msg.message of
                                WM_PAINT,
                                WM_CLOSE,
                                WM_SYSCOMMAND  : DispatchMessage( Msg );
                                WM_QUIT        : begin
                                    PostMessage( Msg.hwnd, Msg.message, Msg.wParam, Msg.lParam );
                                    Done := TRUE;
                                    break;
                                end;
                            end;
                        end;
                    end;
                    else begin
                        break;
                    end;
                end;
            end;
            PostThreadMessage( ProcessInfo.dwThreadID, WM_QUIT, 0, 0 );
        end;
    finally
        SafeCloseHandle( ProcessInfo.hThread );
        SafeCloseHandle( ProcessInfo.hProcess );
    end;
end;{ WaitProcess }


...
Рейтинг: 0 / 0
24.01.2022, 13:49
    #40128999
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
antox
Как что-то вернуть из подопытного главному,? :)
Зависит от того, что нужно вернуть
antox
код той же ошибки
Exit(Code)/Halt(Code)/ExitCode := Code
antox
путь к файлу с детальной информацией
Проще всего в само приложение передать имя файла, в которое оно должно писать лог
...
Рейтинг: 0 / 0
24.01.2022, 17:26
    #40129115
shalamyansky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
_Vasilisk_
Проще всего в само приложение передать имя файла

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

Интересно, кстати, вот присутствующие здесь разработчики выставляют в ExitCode когда-нибудь что-нибудь отличное от нуля?
...
Рейтинг: 0 / 0
24.01.2022, 17:43
    #40129129
YuRock
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
shalamyansky
Интересно, кстати, вот присутствующие здесь разработчики выставляют в ExitCode когда-нибудь что-нибудь отличное от нуля?
Когда это важно и анализируется - ставим.
...
Рейтинг: 0 / 0
24.01.2022, 17:47
    #40129134
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
YuRock
Когда это важно и анализируется - ставим.
+1

У нас система обновления основана на кодах возврата и чтении логов.
...
Рейтинг: 0 / 0
25.01.2022, 07:30
    #40129195
antox
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
Спасибо, работает :)

Пускач:

Код: 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.
function ExecAndWait(const FileName,
                     Params: ShortString;
                     const WinState: Word; var reslt: Integer): boolean; export;
var
  StartInfo: TStartupInfo;
  ProcInfo: TProcessInformation;
  CmdLine: ShortString;
  i: Cardinal;
begin
  { Помещаем имя файла между кавычками, с соблюдением всех пробелов в именах Win9x }
  CmdLine := '"' + Filename + '" ' + Params;
  FillChar(StartInfo, SizeOf(StartInfo), #0);
  with StartInfo do
  begin
    cb := SizeOf(StartInfo);
    dwFlags := STARTF_USESHOWWINDOW;
    wShowWindow := WinState;
  end;
  Result := CreateProcess(nil, PChar( String( CmdLine ) ), nil, nil, false,
                          CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil,
                          PChar(ExtractFilePath(Filename)),StartInfo,ProcInfo);
  { Ожидаем завершения приложения }
  if Result then
  begin
    WaitForSingleObject(ProcInfo.hProcess, INFINITE);
    GetExitCodeProcess(ProcInfo.hProcess, i);
    reslt := i; //Код завершения дочернего процесса
    { Free the Handles }
    CloseHandle(ProcInfo.hProcess);
    CloseHandle(ProcInfo.hThread);
  end;
end;

function AppStart(fn: string): Integer;
var
  code: Integer; //для получения кода завершния дочернего
begin
  //Если файла нет
  if not FileExists(fn) then
  begin
    ShowMessage('Файл не найден (' + fn +')');
    Exit(-1);
  end                   else
    ExecAndWait( fn, '', SW_SHOW, code); //в code будет значение код завершения дочернего процесса

  //Возврат кода завершения приложения
  Result := code;
end;

procedure TForm1.btnStartAppClick(Sender: TObject);
var
  i: Integer;
begin
  //Запуск приложения и получение кода его завершения
  i := AppStart(edtFileName.Text);

  //Отображение события завершения работы дочернего с кодом его завершения
  ShowMessage('Завершилось: ' + i.ToString);
end;



Дочерний:

Код: pascal
1.
2.
3.
4.
5.
procedure TForm2.btnCloseClick(Sender: TObject);
begin
  ExitCode := 5;
  Close;
end;
...
Рейтинг: 0 / 0
25.01.2022, 13:43
    #40129269
Кроик Семён
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
...
Рейтинг: 0 / 0
25.01.2022, 15:17
    #40129303
shalamyansky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
antox

Спасибо, работает


Не за что. Потому что вы не использовали основную идею, ради которой применена именно функция MsgWaitForMultipleObjects , и уходите в глухое ожидание. Это было бы допустимо, если ваше вызывающее приложение тоже было бы консольным, как и вызываемое, однако, судя по примеру, это вполне себе оконное приложение. Для системы и для пользователя оно будет "зависшим", неуправляемое неотрисованное окно, которое пользователь, не понимая, что это за хрень, в конце концов прибьет через менеджер процессов. А в случае завершения сеанса прибьет система, но не сразу, а задав пугающий, но справедливый вопрос о несохраненных данных.
...
Рейтинг: 0 / 0
25.01.2022, 15:47
    #40129314
antox
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
Хм, буду дорабатывать...
...
Рейтинг: 0 / 0
25.01.2022, 16:28
    #40129332
antox
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
shalamyansky
antox

Спасибо, работает


Не за что. Потому что вы не использовали основную идею, ради которой применена именно функция MsgWaitForMultipleObjects , и уходите в глухое ожидание. Это было бы допустимо, если ваше вызывающее приложение тоже было бы консольным, как и вызываемое, однако, судя по примеру, это вполне себе оконное приложение. Для системы и для пользователя оно будет "зависшим", неуправляемое неотрисованное окно, которое пользователь, не понимая, что это за хрень, в конце концов прибьет через менеджер процессов. А в случае завершения сеанса прибьет система, но не сразу, а задав пугающий, но справедливый вопрос о несохраненных данных.


При MsgWaitForMultipleObjects процесс не блокируется, удобно :)

Код: 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.
function ExecAndWait(const FileName,
                     Params: ShortString;
                     const WinState: Word; var reslt: Integer): boolean; export;
var
  StartInfo: TStartupInfo;
  ProcInfo: TProcessInformation;
  M:TMsg;
  CmdLine: ShortString;
  i: Cardinal;
  R:DWord;
begin
  { Помещаем имя файла между кавычками, с соблюдением всех пробелов в именах Win9x }
  CmdLine := '"' + Filename + '" ' + Params;
  FillChar(StartInfo, SizeOf(StartInfo), #0);
  with StartInfo do
  begin
    cb := SizeOf(StartInfo);
    dwFlags := STARTF_USESHOWWINDOW;
    wShowWindow := WinState;
  end;
  Result := CreateProcess(nil, PChar( String( CmdLine ) ), nil, nil, false,
                          CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil,
                          PChar(ExtractFilePath(Filename)),StartInfo,ProcInfo);
  { Ожидаем завершения приложения }
  if Result then
  begin
     {1. С блокировкой основного процесса}
     //WaitForSingleObject(ProcInfo.hProcess, INFINITE);

     {2. Без блокировки основного процесса}
     repeat
       R := MsgWaitForMultipleObjects(1, 
       ProcInfo.hProcess,
       FALSE, 
       INFINITE, 
       QS_ALLINPUT); 
       if R>WAIT_OBJECT_0 then begin
         M.Message := 0;
         while PeekMessage(M,0,0,0,PM_REMOVE) do begin
           TranslateMessage(M);
           DispatchMessage(M);
         end
       end;

     until R=WAIT_OBJECT_0;

    GetExitCodeProcess(ProcInfo.hProcess, i);

    reslt := i; //Код завершения дочернего процесса
    { Free the Handles }
    CloseHandle(ProcInfo.hProcess);
    CloseHandle(ProcInfo.hThread);
  end;
end;
...
Рейтинг: 0 / 0
25.01.2022, 16:42
    #40129338
shalamyansky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
antox,

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

И еще вы понимаете, что если вдруг получите WM_QUIT, то до конца процедуры код никогда не дойдет, приложение умрет где-то в глубине DispatchMessage. А так все хорошо, прекрасная маркиза, все хорошо, все хорошо.
...
Рейтинг: 0 / 0
25.01.2022, 16:57
    #40129341
antox
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
shalamyansky
antox,

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

И еще вы понимаете, что если вдруг получите WM_QUIT, то до конца процедуры код никогда не дойдет, приложение умрет где-то в глубине DispatchMessage. А так все хорошо, прекрасная маркиза, все хорошо, все хорошо.


Я так понимаю, что можно просто кнопку запуска дочернего перевести в disable, в этом случае как-бы будет доступен только тот же выход? Надо только иметь возможность при закрытии формы, из которой запускается процесс, убить этот дочерний процесс

А по WM_QUIT не совсем понятно, при каком раскладе это может произойти и как отловить?
...
Рейтинг: 0 / 0
25.01.2022, 17:25
    #40129351
Fr0sT-Brutal
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
shalamyansky
antox,

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

И чего только не придумают, лишь бы в тред не выносить...
...
Рейтинг: 0 / 0
25.01.2022, 17:59
    #40129363
shalamyansky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
Fr0sT-Brutal

И чего только не придумают, лишь бы в тред не выносить...

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

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

antox

А по WM_QUIT не совсем понятно, при каком раскладе это может произойти и как отловить?

Это и есть просьба системы или пользователя закрыться, см. выше. Требование даже, просьбы раньше были.

Кнопка disabled, это всего лишь кнопка disabled, второй раз эту кнопку не нажмут. Но есть еще много других кнопок и крестиков...
...
Рейтинг: 0 / 0
26.01.2022, 06:50
    #40129457
antox
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
shalamyansky
Fr0sT-Brutal

И чего только не придумают, лишь бы в тред не выносить...

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

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

antox

А по WM_QUIT не совсем понятно, при каком раскладе это может произойти и как отловить?

Это и есть просьба системы или пользователя закрыться, см. выше. Требование даже, просьбы раньше были.

Кнопка disabled, это всего лишь кнопка disabled, второй раз эту кнопку не нажмут. Но есть еще много других кнопок и крестиков...


Тогда на закрытие формы в основном приложении повешу функцию по уничтожению дочернего

Код: pascal
1.
2.
3.
4.
function processKill(ProcInfo: TProcessInformation): Integer;
begin
 TerminateProcess(ProcInfo.hProcess, 2);
end;
...
Рейтинг: 0 / 0
26.01.2022, 14:22
    #40129597
shalamyansky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
antox

Код: pascal
1.
TerminateProcess(ProcInfo.hProcess, 2);



Жестко, как серпом по яйцам. Мягче надо бы, мягче...

Но речь шла не о том, как закрыть дочерний процесс, а как первичный процесс должен правильно отреагировать на полученный WM_QUIT. Посмотрите на свой код. Если вы во время ожидания получите WM_QUIT, вы его выберете из очереди, выйдете из цикла ожидания и вернетесь в главный цикл приложения, как будто ничего не произошло. Должны были закрыться, а вы не закрылись. Потому что для главного цикла в очереди уже не осталось никакого WM_QUIT.

Я в таком случае отправлял дополнительный WM_QUIT в хвост очереди. Процедура аккуратно завершается, код выходит в основной цикл, а там его уж поджидает WM_QUIT и все происходит стандартным образом. Можно, конечно, придумать и другие схемы, вольному воля. Главное - аккуратно.
...
Рейтинг: 0 / 0
26.01.2022, 18:20
    #40129725
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
shalamyansky
Я в таком случае отправлял дополнительный WM_QUIT в хвост очереди.
Достаточно вызвать Application.Terminate
...
Рейтинг: 0 / 0
26.01.2022, 18:37
    #40129736
shalamyansky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вернуть результат работы приложения
_Vasilisk_,

Это если в области видимости есть Application, да и вообще, если он есть и цикл сообщений крутится через Application.Run, что необязательно.

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


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