Решение проблемы ожидания завершения внешней программы с помощью ShellExecuteEx в Delphi
При работе с внешними программами в среде Delphi часто возникает необходимость ожидания их завершения перед продолжением выполнения кода. Одним из способов запуска внешних программ является использование функции ShellExecuteEx. Однако, как отмечено в вопросе пользователя, функция GetExitCodeProcess может возвращать, что программа завершила работу, даже если она все еще выполняется.
Проблема
Пользователь столкнулся с проблемой, когда после сохранения файла на диск и его открытия с помощью ShellExecuteEx, программа не ожидает завершения внешней программы перед продолжением выполнения. Это происходит из-за того, что функция GetExitCodeProcess указывает на завершение работы программы, хотя она все еще активна.
Код, вызывающий проблему
procedure Fire(FileStr: String);
var
SEInfo: TShellExecuteInfo;
ExitCode: DWORD;
ExecuteFile, ParamString, StartInString: string;
begin
// Инициализация переменных и вызов ShellExecuteEx
// ...
if ShellExecuteEx(@SEInfo) then
begin
repeat
Application.ProcessMessages;
GetExitCodeProcess(SEInfo.hProcess, ExitCode);
until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
ShowMessage('App terminated');
end
// Обработка ошибки
end;
Анализ проблемы
В коде используется цикл ожидания с использованием Application.ProcessMessages, который не является лучшей практикой, так как может вызвать проблемы с производительностью и поведением программы. Также, GetExitCodeProcess может возвращать некорректные значения, если hProcess недействителен или если процесс уже завершил передачу управления другому процессу.
Решение проблемы
Для решения проблемы рекомендуется использовать поток. Это позволит избежать блокировки основного потока программы и обеспечит более корректное ожидание завершения внешней программы. Пример реализации потока:
unit uSEWaitThread;
interface
uses
Winapi.Windows, System.Classes;
type
TSEWaitThread = class(TThread)
private
FFile: String;
FSESuccess: Boolean;
FExitCode: DWORD;
FParentWnd: HWND;
protected
procedure Execute; override;
public
constructor Create(const AFile: String; const AParentWindowHandle: HWND);
property ExitCode: DWORD read FExitCode;
property ShellExecuteSuccess: Boolean read FSESuccess;
end;
implementation
uses
Winapi.ShellApi;
constructor TSEWaitThread.Create(const AFile: String; const AParentWindowHandle: HWND);
begin
// Инициализация потока
// ...
end;
procedure TSEWaitThread.Execute;
var
exec_info: TShellExecuteInfo;
begin
// Инициализация информации для ShellExecuteEx
// ...
if ShellExecuteEx(@exec_info) then
begin
FSESuccess := TRUE;
WaitForSingleObject(exec_info.hProcess, INFINITE);
GetExitCodeProcess(exec_info.hProcess, FExitCode);
end;
end;
end.
После завершения потока можно обработать результат его работы в функции SEWaitThreadDone.
Заключение
Использование потока для ожидания завершения внешней программы является предпочтительным методом в сравнении с использованием Application.ProcessMessages. Это позволяет избежать блокировки основного потока и обеспечивает более надежное и предсказуемое поведение программы.
Необходимо решить проблему ожидания завершения внешней программы, запущенной с помощью `ShellExecuteEx` в Delphi, используя потоки для избежания блокировки основного потока и обеспечения корректного завершения процесса.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.