delphi 如何等待进程树的结束

    等待进程树的结束需要用到windows 2000 的job objects内核对象,默认在delphi windows pas里是没有定义的,所以必须手动引用job相关的定义,下面我把jobs.pas 贴出来

unit Jobs;

{
Interface unit for Windows 2000 Job Objects.

windows 作业对象定义 james
}

interface

Uses Windows;

Type
  TJobObjectInfoClass = Cardinal;

  PJobObjectAssociateCompletionPort = ^TJobObjectAssociateCompletionPort;
  TJobObjectAssociateCompletionPort = Record
    CompletionKey  : Pointer;
    CompletionPort : THandle;
  End;

  PJobObjectBasicLimitInformation = ^TJobObjectBasicLimitInformation;
  TJobObjectBasicLimitInformation = 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
  { for TJobObjectInfoClass }
  JobObjectBasicAccountingInformation         = 1;
  JobObjectBasicLimitInformation              = 2;
  JobObjectBasicProcessIdList                 = 3;
  JobObjectBasicUIRestrictions                = 4;
  JobObjectSecurityLimitInformation           = 5;
  JobObjectEndOfJobTimeInformation            = 6;
  JobObjectAssociateCompletionPortInformation = 7;
  JobObjectBasicAndIoAccountingInformation    = 8;
  JobObjectExtendedLimitInformation           = 9;
  MaxJobObjectInfoClass                       = 10;

  { miscellaneous constants }
  JOB_OBJECT_ASSIGN_PROCESS                   = $0001;
  JOB_OBJECT_SET_ATTRIBUTES                   = $0002;
  JOB_OBJECT_QUERY                            = $0004;
  JOB_OBJECT_TERMINATE                        = $0008;
  JOB_OBJECT_SET_SECURITY_ATTRIBUTES          = $0010;
  JOB_OBJECT_ALL_ACCESS                       = STANDARD_RIGHTS_REQUIRED Or
                                                SYNCHRONIZE Or $1F;
  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;
  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_PROCESS_MEMORY             = $00000100;
  JOB_OBJECT_LIMIT_JOB_MEMORY                 = $00000200;
  JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = $00000400;
  JOB_OBJECT_LIMIT_BREAKAWAY_OK               = $00000800;
  JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK        = $00001000;
  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;

Function AssignProcessToJobObject(hJob,hProcess : THandle) : Bool; StdCall;
           External Kernel32 Name 'AssignProcessToJobObject';

Function CreateJobObject(lpJobAttributes : PSecurityAttributes;
           lpName : PAnsiChar) : THandle; StdCall;
           External Kernel32 Name 'CreateJobObjectA';

Function OpenJobObject(dwDesiredAccess : DWORD; bInheritHandle : Bool;
           lpName : PAnsiChar) : THandle; StdCall;
           External Kernel32 Name 'OpenJobObjectA';

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 TerminateJobObject(hJob : THandle; uExitCode : UINT) : Bool; StdCall;
           External Kernel32 Name 'TerminateJobObject';

implementation

end.

---以下是实现代码,我专门做一个线程来启动进程,这样外部只需要直接调用线程,并绑定线程两个事件便可-----------------------------------------

unit WaitProcessTree;

interface
uses
  windows, classes;
type
//开始运行
  TStartProcessEvent = procedure(sender: Tobject; command: string) of object;
 //结速运行
  TEndProcessEvent = procedure(sender: Tobject; command: string) of object;
type
  TwaitProcessTree = class(tthread)
  private
    fStartProcessEvent: TStartProcessEvent;
    fEndProcessEvent: TEndProcessEvent;
    fCommand: string;
  protected
    procedure WaitProcess; virtual;
    function ExecuteProcess(exe: string): THandle;
    procedure Execute; override;
  public
    constructor Create(CreateSuspended: Boolean; Command: string);
    destructor Destroy; override;
    property OnStartProcess: TStartProcessEvent read fStartProcessEvent write fStartProcessEvent;
    property OnEndProcess: TEndProcessEvent read fEndProcessEvent write fEndProcessEvent;
  end;
implementation
uses
  jobs;
{ TwaitProcessTree }

constructor TwaitProcessTree.Create(CreateSuspended: Boolean; Command: string);
begin
  inherited Create(CreateSuspended);
  self.FreeOnTerminate := true;
  fCommand := Command;

end;

destructor TwaitProcessTree.Destroy;
begin

  inherited;
end;

procedure TwaitProcessTree.Execute;
begin
  inherited;
  if assigned(fStartProcessEvent) then
    fStartProcessEvent(self, fcommand);
  self.WaitProcess;
end;

function TwaitProcessTree.ExecuteProcess(exe: string): THandle;
var
  SI: TStartupInfo;
  PI: TProcessInformation;

begin
  Result := INVALID_HANDLE_VALUE;
  FillChar(SI, SizeOf(SI), 0);
  SI.cb := SizeOf(SI);
  if CreateProcess(nil, PChar(EXE), nil, nil, False, 0, nil, nil, SI, PI) then begin
  {  关闭线程句柄   }
    CloseHandle(PI.hThread);
    Result := PI.hProcess;
  end
  else exit;
end;

procedure TwaitProcessTree.WaitProcess;
var
  Job, pro: Thandle;
  ProList: PJobObjectBasicProcessIDList;
 // jobLimit: PJobObjectBasicLimitInformation;
  len: pDword;
begin
  //创建作业对象
  Job := CreateJobObject(nil, nil);
  try

    new(proList);
   // new(jobLimit);
   // jobLimit^.LimitFlags := jobs.JOB_OBJECT_LIMIT_BREAKAWAY_OK;
      //执行进程
    pro := self.ExecuteProcess(fCommand);
     //if SetInformationJobObject(job, 2, jobLimit, sizeof(TJobObjectBasicLimitInformation)) then
     //begin
    if AssignProcessToJobObject(Job, pro) then
    begin
      while true do
      begin
        QueryInformationJobObject(job, 3, ProList, sizeof(TJobObjectBasicProcessIDList), len);
        if proList^.NumberOfProcessIdsInList <= 0 then
          break;

        sleep(1000);
      end;
      if assigned(fEndProcessEvent) then
        fEndProcessEvent(self, fcommand);
    end;
     //end;
  finally
   // jobs.TerminateJobObject(job, 0);
    closehandle(job);
  end;
end;
end.

----------------下面是外部调用线程方法---------------------------------------------------------------

procedure TForm1.Button6Click(Sender: TObject);
var
 th:TwaitProcessTree;
begin
  th:=TwaitProcessTree.Create(true,edit1.Text);
  th.OnStartProcess:=self.StartProcess;
  th.OnEndProcess:=self.EndProcess;
  th.Resume;
 
end;

posted @ 2011-05-13 12:00  你的影子  阅读(1300)  评论(0编辑  收藏  举报