Каким образом, программным путем, можно узнать о завершении запущенной программы
Тяжелое детство. Все игрушки сплошной софт.
16-битная версия:
uses Wintypes, WinProcs, Toolhelp, Classes, Forms;
function WinExecAndWait(Path: string; Visibility: word): word;
var
InstanceID: THandle;
PathLen: integer;
begin{ Преобразуем строку в тип PChar }
PathLen := Length(Path);
Move(Path[1], Path[0], PathLen);
Path[PathLen] := #00;
{ Пытаемся запустить приложение }
InstanceID := WinExec(@Path, Visibility);
if InstanceID < 32 then{ значение меньше 32 указывает на ошибку приложения }
WinExecAndWait := InstanceID
elsebeginrepeat
Application.ProcessMessages;
until Application.Terminated or (GetModuleUsage(InstanceID) = 0);
WinExecAndWait := 32;
end;
end;
32-битная версия:
function WinExecAndWait32(FileName: string; Visibility: integer): integer;
var
zAppName: array[0..512] of char;
zCurDir: array[0..255] of char;
WorkDir: string;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
begin
StrPCopy(zAppName, FileName);
GetDir(0, WorkDir);
StrPCopy(zCurDir, WorkDir);
FillChar(StartupInfo, Sizeof(StartupInfo), #0);
StartupInfo.cb := Sizeof(StartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow := Visibility;
ifnot CreateProcess(nil,
zAppName, { указатель командной строки }nil, { указатель на процесс атрибутов безопасности }nil, { указатель на поток атрибутов безопасности }false, { флаг родительского обработчика }
CREATE_NEW_CONSOLE or{ флаг создания }
NORMAL_PRIORITY_CLASS,
nil, { указатель на новую среду процесса }nil, { указатель на имя текущей директории }
StartupInfo, { указатель на STARTUPINFO }
ProcessInfo) then
Result := -1 { указатель на PROCESS_INF }elsebegin
WaitforSingleObject(ProcessInfo.hProcess, INFINITE);
GetExitCodeProcess(ProcessInfo.hProcess, Result);
end;
end;
Дополнение
Письмо от читателя:
Очень помог совет из API\Разное: "Каким образом, программным путем, можно
узнать о завершении запущенной программы?". Однако хочется внести резонное
исправление: вместо
while WaitforSingleObject(ProcessInfo.hProcess,200)=WAIT_TIMEOUT do
Repaint;
Смысл замены прост: в первом варианте главное окно ждёт завершения вызванного
сообщения, не обрабатывая при этом никаких событий. Вследствие этого главное
окно даже не перерисовывается, что выглядит очень некрасиво. Второй вариант
исправляет этот недостаток.
Программное задание на языке Delphi: создать функцию, которая запускает внешнюю программу и ожидает ее завершения. Предлагаются два возможных реализации: одна для 16-разрядной Windows (использует WinExec и Toolhelp) и другая для 32-разрядной Windows (использует CreateProcess и WaitforSingleObject).
Основная идея этих функций - запустить целевую программу с помощью WinExec или CreateProcess, соответственно, и затем ожидать ее завершения. Функция WinExecAndWait проверяет, является ли процесс terminated, вызывая GetModuleUsage (в 16-разрядной версии) или проверяя наличия ненулевого кода выхода с помощью GetExitCodeProcess (в 32-разрядной версии).
Вот некоторые предложения и улучшения:
16-разрядная версия:
В функции WinExecAndWait можно упростить обработку ошибок, используя более конкретный код ошибки, чем < 32. Это позволит обнаруживать ошибки с более высокой точностью.
Рассмотреть добавление параметра timeout в функцию, чтобы она ждала указанное количество времени перед считанием процесса terminated.
32-разрядная версия:
В функции WinExecAndWait32 можно удалить вызовы StrPCopy и использовать параметр FileName напрямую. Это упростит код и уменьшит аллокацию памяти.
Вместо использования GetDir, чтобы получить текущий рабочий каталог, можно передать пустую строку ('') как первый аргумент CreateProcess, что вызовет запуск процесса в текущем рабочем каталоге.
Альтернативное решение:
Если вы целяете на современные версии Windows (Windows XP и позднее), можно использовать функцию CreateProcess с структурой STARTUPINFO, которая включает член dwFlags, установленный в STARTF_USESHOWWINDOW. Это позволяет указать, должен ли процесс быть видимым или нет.
Альтернативно, можно использовать функцию ShellExecute с флагом SW_SHOWNORMAL, чтобы запустить внешнюю программу и ждать ее завершения. Этот подход проще, но менее гибок, чем использование CreateProcess.
Отзыв читателя:
Предложение читателя использовать цикл с WaitforSingleObject вместо бесконечной ожидания - это хороший совет. Это обеспечивает, что основное окно остается отзывчивым, пока процесс не будет terminated.
Вот модифицированная кодовая строка:
Этот цикл ожидает до 200 миллисекунд (вы можете изменить это значение, как вам нужно) и затем перерисовывает основное окно. Этот подход более пользовательски friendly, чем ожидание бесконечно.
В целом, оба кодовых снэпета демонстрируют хороший уровень понимания программирования Windows API в Delphi. С некоторыми минимальными улучшениями и альтернативными решениями они могут быть еще более эффективными и производительными!
Каким образом, программным путем, можно узнать о завершении запущенной программы, используя функции WinExec и CreateProcess в Delphi.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.