2012-01-11 2 views
7

Мое приложение (main.exe) выполняет детский процесс (child.exe) с использованием ShellExecuteEx.Как создать дочерний процесс в зависимости от его родителя?

Но когда я закрываю (через Process-Explorer) main.exe, дочерний процесс остается активным.

Как изящно справиться с этим, когда main.exe завершает child.exe прекращает также?

+0

Получить главный исполняемый файл, чтобы отправить сообщение для дочернего исполняемого файла, когда основной исполняемый закрывается. –

+1

не тогда, когда главный исполняемый файл убит – ZigiZ

+1

Работа представляется изящным решением. Кроме того, вы можете наследовать дескриптор родительского процесса и ждать, пока он будет передан по завершении. – OnTheFly

ответ

13

Вам необходимо использовать jobs. Основной исполняемый файл должен быть create a job object, тогда вам нужно указать set флаг JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE для вашего объекта задания.

uses 
    JobsApi; 
//... 
var 
    jLimit: TJobObjectExtendedLimitInformation; 

    hJob := CreateJobObject(nil, PChar('JobName'); 
    if hJob <> 0 then 
    begin 
    jLimit.BasicLimitInformation.LimitFlags := JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 
     SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, @jLimit, 
     SizeOf(TJobObjectExtendedLimitInformation)); 
    end; 

Затем нужно выполнить другой процесс с CreateProcess функции, где dwCreationFlags должен быть установлен в CREATE_BREAKAWAY_FROM_JOB. Если этой функции удается выполнить вызов AssignProcessToJobObject.

function ExecuteProcess(const EXE : String; const AParams: string = ''; AJob: Boolean = True): THandle; 
var 
    SI : TStartupInfo; 
    PI : TProcessInformation; 
    AFlag: Cardinal; 
begin 
    Result := INVALID_HANDLE_VALUE; 
    FillChar(SI,SizeOf(SI),0); 
    SI.cb := SizeOf(SI); 

    if AJob then 
    AFlag := CREATE_BREAKAWAY_FROM_JOB 
    else 
    AFlag := 0; 


    if CreateProcess(
    nil, 
    PChar(EXE + ' ' + AParams), 
    nil, 
    nil, 
    False, 
    AFlag, 
    nil, 
    nil, 
    SI, 
    PI 
    ) then 
    begin 
    { close thread handle } 
    CloseHandle(PI.hThread); 
    Result := PI.hProcess; 
    end; 
end; 
//... 
    hApp := ExecuteProcess('PathToExecutable'); 

    if hApp <> INVALID_HANDLE_VALUE then 
    begin 
    AssignProcessToJobObject(hJob, hApp); 
    end; 

Когда все это выполнено, все дочерние процессы будут автоматически завершены, даже если основной исполняемый файл был убит. Вы можете получить блок JobsApi here. Примечание. Я не тестировал его с помощью Delphi 7.

EDIT: Here вы можете скачать рабочий демонстрационный проект.

+0

Я проверил ваш код. Я использовал CreateJobObject в моей форме. добавлена ​​кнопка «ExecuteProcess». дочерний процесс работает нормально, 'AssignProcessToJobObject' возвращает True. но когда я закрываю родительское приложение, дочерний процесс остается в живых. – ZigiZ

+0

@ zigi70 Возможно, вы делаете что-то неправильно. Мы успешно используем этот метод в нашем мультимодульном программном обеспечении.Я отредактировал свой ответ и включил ссылку на исходный код моего рабочего проекта. – Linas

+0

Я загрузил свой проект [здесь] (http://www.4shared.com/zip/1yveHVAO/Jobs.html). вы бы так любезны взглянуть. – ZigiZ

3

Попробуйте использовать Job Objects, проверьте эти функции CreateJobObject и AssignProcessToJobObject.

Объект задания позволяет управлять группами процессов как единое целое. Задачи - это объекты, которые можно идентифицировать, защищать, совместно использовать объекты, которые управляют атрибутами связанных с ними процессов . Выполненные операции объекта задания влияют на все процессы, связанные с объектом задания. Примеры включают принудительные ограничения, такие как размер рабочего набора и процесс приоритет или завершение всех процессов, связанных с заданием.

0

Я думаю, это очень классный код. Он работает для меня, но я добавляю некоторые изменения, чтобы иметь возможность устанавливать флажки окна show для дочерних процессов, таких как SW_SHOW/SW_HIDE.

...

function ExecuteProcess(const EXE : String; const AParams: string = ''; 
    const nCmdShow: Integer = SW_SHOW; AJob: Boolean = True): THandle; 
var 
    SI : TStartupInfo; 
    PI : TProcessInformation; 
    AFlag: Cardinal; 
begin 
    Result := INVALID_HANDLE_VALUE; 
    FillChar(SI,SizeOf(SI),0); 
    SI.cb := SizeOf(SI); 
    SI.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; 
    SI.wShowWindow := nCmdShow; 

    if AJob then 
    AFlag := CREATE_BREAKAWAY_FROM_JOB 
    else 
    AFlag := 0; 

...

Смежные вопросы