我使用这些函数异步执行子进程,并在进程终止时回调它。它通过创建一个线程来工作,该线程等待进程终止,然后通过给定的事件方法回调主程序线程。请注意,您的程序会在子进程运行时继续运行,因此您需要某种形式的逻辑来防止生成子进程的无限发生。
UNIT SpawnFuncs;
INTERFACE
{$IF CompilerVersion >= 20 }
{$DEFINE ANONYMOUS_METHODS }
{$ELSE }
{$UNDEF ANONYMOUS_METHODS }
{$ENDIF }
TYPE
TSpawnAction = (saStarted,saEnded);
TSpawnArgs = RECORD
Action : TSpawnAction;
FileName : String;
PROCEDURE Initialize(Act : TSpawnAction ; CONST FN : String); INLINE;
CLASS FUNCTION Create(Act : TSpawnAction ; CONST FN : String) : TSpawnArgs; static;
END;
{$IFDEF ANONYMOUS_METHODS }
TSpawnEvent = REFERENCE TO PROCEDURE(Sender : TObject ; CONST Args : TSpawnArgs);
{$ELSE }
TSpawnEvent = PROCEDURE(Sender : TObject ; CONST Args : TSpawnArgs) OF OBJECT;
{$ENDIF }
FUNCTION ShellExec(CONST FileName,Tail : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL) : BOOLEAN; OVERLOAD;
FUNCTION ShellExec(CONST FileName : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL) : BOOLEAN; OVERLOAD;
FUNCTION ShellExec(CONST FileName : String ; VAR EndedFlag : BOOLEAN) : BOOLEAN; OVERLOAD;
FUNCTION ShellExec(CONST FileName,Tail : String ; VAR EndedFlag : BOOLEAN) : BOOLEAN; OVERLOAD;
PROCEDURE ShellExecExcept(CONST FileName : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL); OVERLOAD:
PROCEDURE ShellExecExcept(CONST FileName,Tail : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL); OVERLOAD;
PROCEDURE ShellExecExcept(CONST FileName : String ; VAR EndedFlag : BOOLEAN); OVERLOAD;
PROCEDURE ShellExecExcept(CONST FileName,Tail : String ; VAR EndedFlag : BOOLEAN); OVERLOAD;
IMPLEMENTATION
USES Windows,SysUtils,Classes,ShellApi;
TYPE
TWaitThread = CLASS(TThread)
CONSTRUCTOR Create(CONST FileName : String ; ProcessHandle : THandle ; Event : TSpawnEvent ; Sender : TObject); REINTRODUCE; OVERLOAD;
CONSTRUCTOR Create(CONST FileName : String ; ProcessHandle : THandle ; EndedFlag : PBoolean); OVERLOAD;
PROCEDURE Execute; OVERRIDE;
PROCEDURE DoEvent(Action : TSpawnAction);
PRIVATE
Handle : THandle;
Event : TSpawnEvent;
EndedFlag : PBoolean;
FN : String;
Sender : TObject;
{$IFNDEF ANONYMOUS_METHODS }
Args : TSpawnArgs;
PROCEDURE RunEvent;
{$ENDIF }
END;
CONSTRUCTOR TWaitThread.Create(CONST FileName : String ; ProcessHandle : THandle ; Event : TSpawnEvent ; Sender : TObject);
BEGIN
INHERITED Create(TRUE);
Handle:=ProcessHandle; Self.Event:=Event; FN:=FileName; Self.Sender:=Sender; FreeOnTerminate:=TRUE;
Resume
END;
{$IFNDEF ANONYMOUS_METHODS }
PROCEDURE TWaitThread.RunEvent;
BEGIN
Event(Sender,Args)
END;
{$ENDIF }
CONSTRUCTOR TWaitThread.Create(CONST FileName : String ; ProcessHandle : THandle ; EndedFlag : PBoolean);
BEGIN
INHERITED Create(TRUE);
Handle:=ProcessHandle; EndedFlag^:=FALSE; Self.EndedFlag:=EndedFlag; FreeOnTerminate:=TRUE;
Resume
END;
PROCEDURE TWaitThread.DoEvent(Action : TSpawnAction);
BEGIN
IF Assigned(EndedFlag) THEN
EndedFlag^:=(Action=saEnded)
ELSE BEGIN
{$IFDEF ANONYMOUS_METHODS }
Synchronize(PROCEDURE BEGIN Event(Sender,TSpawnArgs.Create(Action,FN)) END)
{$ELSE }
Args:=TSpawnArgs.Create(Action,FN);
Synchronize(RunEvent)
{$ENDIF }
END
END;
PROCEDURE TWaitThread.Execute;
BEGIN
DoEvent(saStarted);
WaitForSingleObject(Handle,INFINITE);
CloseHandle(Handle);
DoEvent(saEnded)
END;
FUNCTION ShellExec(CONST FileName,Tail : String ; Event : TSpawnEvent ; Sender : TObject ; EndedFlag : PBoolean) : BOOLEAN; OVERLOAD;
VAR
Info : TShellExecuteInfo;
PTail : PChar;
BEGIN
ASSERT(NOT (Assigned(Event) AND Assigned(EndedFlag)),'ShellExec called with both Event and EndedFlag!');
IF Tail='' THEN PTail:=NIL ELSE PTail:=PChar(Tail);
FillChar(Info,SizeOf(TShellExecuteInfo),0);
Info.cbSize:=SizeOf(TShellExecuteInfo);
Info.fMask:=SEE_MASK_FLAG_NO_UI;
Info.lpFile:=PChar(FileName);
Info.lpParameters:=PTail;
Info.nShow:=SW_SHOW;
IF NOT (Assigned(Event) OR Assigned(EndedFlag)) THEN
Result:=ShellExecuteEx(@Info)
ELSE BEGIN
Info.fMask:=Info.fMask OR SEE_MASK_NOCLOSEPROCESS;
Result:=ShellExecuteEx(@Info) AND (Info.hProcess>0);
IF Result THEN
IF Assigned(Event) THEN
TWaitThread.Create(FileName,Info.hProcess,Event,Sender)
ELSE
TWaitThread.Create(FileName,Info.hProcess,EndedFlag)
END
END;
FUNCTION ShellExec(CONST FileName,Tail : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL) : BOOLEAN;
BEGIN
Result:=ShellExec(FileName,Tail,Event,Sender,NIL)
END;
FUNCTION ShellExec(CONST FileName : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL) : BOOLEAN;
BEGIN
Result:=ShellExec(FileName,'',Event,Sender)
END;
FUNCTION ShellExec(CONST FileName,Tail : String ; VAR EndedFlag : BOOLEAN) : BOOLEAN;
BEGIN
Result:=ShellExec(FileName,Tail,NIL,NIL,@EndedFlag)
END;
FUNCTION ShellExec(CONST FileName : String ; VAR EndedFlag : BOOLEAN) : BOOLEAN;
BEGIN
Result:=ShellExec(FileName,'',EndedFlag)
END;
PROCEDURE ShellExecExcept(CONST FileName : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL);
BEGIN
IF NOT ShellExec(FileName,Event,Sender) THEN RaiseLastOSError
END;
PROCEDURE ShellExecExcept(CONST FileName,Tail : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL);
BEGIN
IF NOT ShellExec(FileName,Tail,Event,Sender) THEN RaiseLastOSError
END;
PROCEDURE ShellExecExcept(CONST FileName : String ; VAR EndedFlag : BOOLEAN);
BEGIN
IF NOT ShellExec(FileName,EndedFlag) THEN RaiseLastOSError
END;
PROCEDURE ShellExecExcept(CONST FileName,Tail : String ; VAR EndedFlag : BOOLEAN);
BEGIN
IF NOT ShellExec(FileName,Tail,EndedFlag) THEN RaiseLastOSError
END;
{ TSpawnArgs }
CLASS FUNCTION TSpawnArgs.Create(Act : TSpawnAction ; CONST FN : String) : TSpawnArgs;
BEGIN
Result.Initialize(Act,FN)
END;
PROCEDURE TSpawnArgs.Initialize(Act : TSpawnAction ; CONST FN : String);
BEGIN
Action:=Act; FileName:=FN
END;
END.
如下使用:
USES SpawnFuncs;
ShellExec(ProgramToRun,CommandLineArgs,Event,Sender)
或
ShellExec(ProgramToRunOrFileToOpen,Event,Sender)
在哪里
ProgramToRun = Name of program to run
ProgramToRunOrFileToOpen = Program to run, or file to open (f.ex. a .TXT file)
CommandLineArgs = Command line parameters to pass to the program
Event = The (perhaps anonymous) method to run upon start and termination of program
Sender = The Sender parameter to pass to the method
或者,如果您只是想知道子进程何时终止,则有两个简化版本可以接受一个布尔变量,该变量将在子程序终止时立即设置为 TRUE。您无需先将其设置为 FALSE,因为它会自动完成:
ShellExec(ProgramToRun,ChildProcessEnded);
如果您不提供事件处理程序或 BOOLEAN 变量,ShellExec 过程只会运行/打开给定的文件并且不执行回调。
如果您不提供 Sender,则 Sender 参数将在事件处理程序中未定义。
事件处理程序必须是具有以下签名的方法(匿名或其他):
PROCEDURE SpawnEvent(Sender : TObject ; CONST Args : TSpawnArgs);
其中 Args 包含以下字段:
Action = either saStarted or saEnded
FileName = the name of the file that passed to ShellExec
如果您更喜欢使用 SEH(结构化异常处理)而不是错误返回值,您可以使用 ShellExecExcept PROCEDUREs 而不是 ShellExec FUNCTIONs。如果执行请求失败,这些将引发操作系统错误。