You need to use jobs. Main executable should create a job object, then you'll need to set JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag to your job object.
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;Then you need to execute another process with CreateProcess function where dwCreationFlags must be set to CREATE_BREAKAWAY_FROM_JOB. If this function succeeds call 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;When all of this done all the child processes will be automatically terminated even if the main executable has been killed. You can get the JobsApi unit here.
If you nee add some changes to be able user to set show window flags for child processes like 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; ........Demo Project can be downloaded here.
Or For JobsApi Take a look here:
unit JobsApi; interface uses Windows; type TJobObjectInfoClass = Cardinal; PJobObjectAssociateCompletionPort = ^TJobObjectAssociateCompletionPort; TJobObjectAssociateCompletionPort = Record CompletionKey : Pointer; CompletionPort : THandle; End; PJobObjectBasicLimitInformation = ^TJobObjectBasicLimitInformation; TJobObjectBasicLimitInformation = packed Record PerProcessUserTimeLimit : TLargeInteger; PerJobUserTimeLimit : TLargeInteger; LimitFlags : DWORD; MinimumWorkingSetSize : DWORD; MaximumWorkingSetSize : DWORD; ActiveProcessLimit : DWORD; Affinity : DWORD; PriorityClass : DWORD; SchedulingClass : DWORD; End; PJobObjectBasicUIRestrictions = ^TJobObjectBasicUIRestrictions; TJobObjectBasicUIRestrictions = Record UIRestrictionsClass : DWORD; End; PJobObjectEndOfJobTimeInformation = ^TJobObjectEndOfJobTimeInformation; TJobObjectEndOfJobTimeInformation = Record EndOfJobTimeAction : DWORD; End; TIOCounters = Record { all fields should be actually unsigned int64 's } ReadOperationCount : Int64; WriteOperationCount : Int64; OtherOperationCount : Int64; ReadTransferCount : Int64; WriteTransferCount : Int64; OtherTransferCount : Int64; End; PJobObjectExtendedLimitInformation = ^TJobObjectExtendedLimitInformation; TJobObjectExtendedLimitInformation = Record BasicLimitInformation : TJobObjectBasicLimitInformation; IoInfo : TIOCounters; ProcessMemoryLimit : DWORD; JobMemoryLimit : DWORD; PeakProcessMemoryUsed : DWORD; PeakJobMemoryUsed : DWORD; End; PJobObjectSecurityLimitInformation = ^TJobObjectSecurityLimitInformation; TJobObjectSecurityLimitInformation = Record SecurityLimitFlags : DWORD; JobToken : THandle; SidsToDisable : PTokenGroups; PrivilegesToDelete : PTokenPrivileges; RestrictedSids : PTokenGroups; End; PJobObjectBasicAccountingInformation = ^TJobObjectBasicAccountingInformation; TJobObjectBasicAccountingInformation = Record TotalUserTime : TLargeInteger; TotalKernelTime : TLargeInteger; ThisPeriodTotalUserTime : TLargeInteger; ThisPeriodTotalKernelTime : TLargeInteger; TotalPageFaultCount : DWORD; TotalProcesses : DWORD; ActiveProcesses : DWORD; TotalTerminatedProcesses : DWORD; End; PJobObjectBasicAndIOAccountingInformation = ^TJobObjectBasicAndIOAccountingInformation; TJobObjectBasicAndIOAccountingInformation = Record BasicInfo : TJobObjectBasicAccountingInformation; IoInfo : TIOCounters; End; PJobObjectBasicProcessIDList = ^TJobObjectBasicProcessIDList; TJobObjectBasicProcessIDList = Record NumberOfAssignedProcesses : DWORD; NumberOfProcessIdsInList : DWORD; ProcessIdList : Array[0..0] of ULONG; End; const {$IFDEF UNICODE} AWSuffix = 'W'; {$ELSE} AWSuffix = 'A'; {$ENDIF UNICODE} const {for TJobObjectInfoClass } JobObjectBasicAccountingInformation = 1; JobObjectBasicLimitInformation = 2; JobObjectBasicProcessIdList = 3; JobObjectBasicUIRestrictions = 4; JobObjectSecurityLimitInformation = 5; JobObjectEndOfJobTimeInformation = 6; JobObjectAssociateCompletionPortInformation = 7; JobObjectBasicAndIoAccountingInformation = 8; JobObjectExtendedLimitInformation = 9; MaxJobObjectInfoClass = 10; JOB_OBJECT_ASSIGN_PROCESS = $0001; {$EXTERNALSYM JOB_OBJECT_ASSIGN_PROCESS} JOB_OBJECT_SET_ATTRIBUTES = $0002; {$EXTERNALSYM JOB_OBJECT_SET_ATTRIBUTES} JOB_OBJECT_QUERY = $0004; {$EXTERNALSYM JOB_OBJECT_QUERY} JOB_OBJECT_TERMINATE = $0008; {$EXTERNALSYM JOB_OBJECT_TERMINATE} JOB_OBJECT_SET_SECURITY_ATTRIBUTES = $0010; {$EXTERNALSYM JOB_OBJECT_SET_SECURITY_ATTRIBUTES} JOB_OBJECT_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $1F ; {$EXTERNALSYM JOB_OBJECT_ALL_ACCESS} JOB_OBJECT_TERMINATE_AT_END_OF_JOB = 0; JOB_OBJECT_POST_AT_END_OF_JOB = 1; JOB_OBJECT_MSG_END_OF_JOB_TIME = 1; JOB_OBJECT_MSG_END_OF_PROCESS_TIME = 2; JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT = 3; JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO = 4; { where 's 5? } JOB_OBJECT_MSG_NEW_PROCESS = 6; JOB_OBJECT_MSG_EXIT_PROCESS = 7; JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS = 8; JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT = 9; JOB_OBJECT_MSG_JOB_MEMORY_LIMIT = 10; JOB_OBJECT_LIMIT_WORKINGSET = $00000001; JOB_OBJECT_LIMIT_PROCESS_TIME = $00000002; JOB_OBJECT_LIMIT_JOB_TIME = $00000004; JOB_OBJECT_LIMIT_ACTIVE_PROCESS = $00000008; JOB_OBJECT_LIMIT_AFFINITY = $00000010; JOB_OBJECT_LIMIT_PRIORITY_CLASS = $00000020; JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = $00000040; JOB_OBJECT_LIMIT_SCHEDULING_CLASS = $00000080; JOB_OBJECT_LIMIT_RESERVED1 = $00002000; JOB_OBJECT_LIMIT_RESERVED2 = $00004000; JOB_OBJECT_LIMIT_RESERVED3 = $00008000; JOB_OBJECT_LIMIT_RESERVED4 = $00010000; JOB_OBJECT_LIMIT_RESERVED5 = $00020000; JOB_OBJECT_LIMIT_RESERVED6 = $00040000; JOB_OBJECT_LIMIT_VALID_FLAGS = $0007FFFF; JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS = $000000FF; JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS = $00001FFF; JOB_OBJECT_RESERVED_LIMIT_VALID_FLAGS = $0007FFFF; JOB_OBJECT_UILIMIT_NONE = $00000000; JOB_OBJECT_UILIMIT_HANDLES = $00000001; JOB_OBJECT_UILIMIT_READCLIPBOARD = $00000002; JOB_OBJECT_UILIMIT_WRITECLIPBOARD = $00000004; JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS = $00000008; JOB_OBJECT_UILIMIT_DISPLAYSETTINGS = $00000010; JOB_OBJECT_UILIMIT_GLOBALATOMS = $00000020; JOB_OBJECT_UILIMIT_DESKTOP = $00000040; JOB_OBJECT_UILIMIT_EXITWINDOWS = $00000080; JOB_OBJECT_UILIMIT_ALL = $000000FF; JOB_OBJECT_UI_VALID_FLAGS = $000000FF; JOB_OBJECT_SECURITY_NO_ADMIN = $00000001; JOB_OBJECT_SECURITY_RESTRICTED_TOKEN = $00000002; JOB_OBJECT_SECURITY_ONLY_TOKEN = $00000004; JOB_OBJECT_SECURITY_FILTER_TOKENS = $00000008; JOB_OBJECT_SECURITY_VALID_FLAGS = $0000000F; CREATE_BREAKAWAY_FROM_JOB = $01000000; // // Extended Limits // JOB_OBJECT_LIMIT_PROCESS_MEMORY = $00000100; {$EXTERNALSYM JOB_OBJECT_LIMIT_PROCESS_MEMORY} JOB_OBJECT_LIMIT_JOB_MEMORY = $00000200; {$EXTERNALSYM JOB_OBJECT_LIMIT_JOB_MEMORY} JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = $00000400; {$EXTERNALSYM JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION} JOB_OBJECT_LIMIT_BREAKAWAY_OK = $00000800; {$EXTERNALSYM JOB_OBJECT_LIMIT_BREAKAWAY_OK} JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = $00001000; {$EXTERNALSYM JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK} JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = $00002000; {$EXTERNALSYM JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE} function CreateJobObjectA(lpJobAttributes: PSecurityAttributes; lpName: LPCSTR): THANDLE; stdcall; {$EXTERNALSYM CreateJobObjectA} function CreateJobObjectW(lpJobAttributes: PSecurityAttributes; lpName: LPCWSTR): THANDLE; stdcall; {$EXTERNALSYM CreateJobObjectW} function CreateJobObject(lpJobAttributes: PSecurityAttributes; lpName: LPCTSTR): THANDLE; stdcall; {$EXTERNALSYM CreateJobObject} function OpenJobObjectA(dwDesiredAccess: DWORD; bInheritHandle: BOOL; lpName: LPCSTR): THANDLE; stdcall; {$EXTERNALSYM OpenJobObjectA} function OpenJobObjectW(dwDesiredAccess: DWORD; bInheritHandle: BOOL; lpName: LPCWSTR): THANDLE; stdcall; {$EXTERNALSYM OpenJobObjectW} function OpenJobObject(dwDesiredAccess: DWORD; bInheritHandle: BOOL; lpName: LPCTSTR): THANDLE; stdcall; {$EXTERNALSYM OpenJobObject} function AssignProcessToJobObject(hJob, hProcess: THANDLE): BOOL; stdcall; {$EXTERNALSYM AssignProcessToJobObject} function TerminateJobObject(hJob: THANDLE; uExitCode: UINT): BOOL; stdcall; {$EXTERNALSYM TerminateJobObject} function IsProcessInJob(ProcessHandle, JobHandle: THANDLE; var Result_: BOOL): BOOL; stdcall; {$EXTERNALSYM IsProcessInJob} Function QueryInformationJobObject(hJob : THandle; JobObjectInformationClass : TJobObjectInfoClass; lpJobObjectInformation : Pointer; cbJobObjectInformationLength : DWORD; lpReturnLength : PDWORD) : Bool; StdCall; External Kernel32 Name 'QueryInformationJobObject'; Function SetInformationJobObject(hJob : THandle; JobObjectInformationClass : TJobObjectInfoClass; lpJobObjectInformation : Pointer; cbJobObjectInformationLength : DWORD): BOOL; StdCall; External Kernel32 Name 'SetInformationJobObject'; function CreateJobObjectA; external kernel32 name 'CreateJobObjectA'; function CreateJobObjectW; external kernel32 name 'CreateJobObjectW'; function CreateJobObject; external kernel32 name 'CreateJobObject' + AWSuffix; function OpenJobObjectA; external kernel32 name 'OpenJobObjectA'; function OpenJobObjectW; external kernel32 name 'OpenJobObjectW'; function OpenJobObject; external kernel32 name 'OpenJobObject' + AWSuffix; function AssignProcessToJobObject; external kernel32 name 'AssignProcessToJobObject'; function TerminateJobObject; external kernel32 name 'TerminateJobObject'; function IsProcessInJob; external kernel32 name 'IsProcessInJob'; implementation end.
All credits go to Linas, - StackOverFlaw, the original creator
0 comments:
Post a Comment