powered by simpleCommunicator - 2.0.36     © 2025 Programmizd 02
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Вернуть результат работы приложения
21 сообщений из 21, страница 1 из 1
Вернуть результат работы приложения
    #40128937
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хочу одним приложением, запускать второе и ждать его завершения, но не просто окончания, а с каким-то результатом.

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

Хотя бы код той же ошибки или путь к файлу с детальной информацией
...
Рейтинг: 0 / 0
Вернуть результат работы приложения
    #40128942
cptngrb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox, второе приложение твоё?
...
Рейтинг: 0 / 0
Вернуть результат работы приложения
    #40128944
AWSVladimir
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Exit(IntegerCodeResult) не вариант ?
...
Рейтинг: 0 / 0
Вернуть результат работы приложения
    #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
Вернуть результат работы приложения
    #40128999
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox
Как что-то вернуть из подопытного главному,? :)
Зависит от того, что нужно вернуть
antox
код той же ошибки
Exit(Code)/Halt(Code)/ExitCode := Code
antox
путь к файлу с детальной информацией
Проще всего в само приложение передать имя файла, в которое оно должно писать лог
...
Рейтинг: 0 / 0
Вернуть результат работы приложения
    #40129115
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
Проще всего в само приложение передать имя файла

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

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

У нас система обновления основана на кодах возврата и чтении логов.
...
Рейтинг: 0 / 0
Вернуть результат работы приложения
    #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
Вернуть результат работы приложения
    #40129269
Фотография Кроик Семён
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Вернуть результат работы приложения
    #40129303
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox

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


Не за что. Потому что вы не использовали основную идею, ради которой применена именно функция MsgWaitForMultipleObjects , и уходите в глухое ожидание. Это было бы допустимо, если ваше вызывающее приложение тоже было бы консольным, как и вызываемое, однако, судя по примеру, это вполне себе оконное приложение. Для системы и для пользователя оно будет "зависшим", неуправляемое неотрисованное окно, которое пользователь, не понимая, что это за хрень, в конце концов прибьет через менеджер процессов. А в случае завершения сеанса прибьет система, но не сразу, а задав пугающий, но справедливый вопрос о несохраненных данных.
...
Рейтинг: 0 / 0
Вернуть результат работы приложения
    #40129314
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хм, буду дорабатывать...
...
Рейтинг: 0 / 0
Вернуть результат работы приложения
    #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
Вернуть результат работы приложения
    #40129338
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox,

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

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

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

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


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

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

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

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

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

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

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

antox

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

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

Кнопка disabled, это всего лишь кнопка disabled, второй раз эту кнопку не нажмут. Но есть еще много других кнопок и крестиков...
...
Рейтинг: 0 / 0
Вернуть результат работы приложения
    #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
Вернуть результат работы приложения
    #40129597
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox

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



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

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

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

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

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


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