delphi – 如何调用应用程序并等待它退出的高质量代码示例
使用:Delphi XE2;
Windows 32位VCL应用程序
在我的Delphi应用程序中,我需要使用ShellExecute调用一个应用程序并等到它完成后再继续. 我在ShellExecute的SO上看到了很多关于MsgWaitForMultipleObjects的例子,但是不知道哪一个是最好的,因为他们大多是做不推荐的事情,即.还使用了很多人不推荐的Application.ProcessMessages. 我在post中看到了NFX的答案,它没有使用Application.ProcessMessages,但我不确定它是否正确或最佳,因此这个问题. 如果您能提供高质量的代码示例,我们将非常高兴. 任何答案的TIA. 解决方法
我使用这些函数异步执行子进程,并在进程终止时回调它.它的工作原理是创建一个等待进程终止的线程,然后通过给定的事件方法回调主程序线程.请注意,您的程序在子进程运行时继续运行,因此您需要某种形式的逻辑来防止产生子进程的无限发生.
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,EndedFlag) END END; FUNCTION ShellExec(CONST FileName,Tail : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL) : BOOLEAN; BEGIN Result:=ShellExec(FileName,Tail,Sender,NIL) END; FUNCTION ShellExec(CONST FileName : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL) : BOOLEAN; BEGIN Result:=ShellExec(FileName,'',Sender) END; FUNCTION ShellExec(CONST FileName,Tail : String ; VAR EndedFlag : BOOLEAN) : BOOLEAN; BEGIN Result:=ShellExec(FileName,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,Sender) THEN RaiseLastOSError END; PROCEDURE ShellExecExcept(CONST FileName,Tail : String ; Event : TSpawnEvent = NIL ; Sender : TObject = NIL); BEGIN IF NOT ShellExec(FileName,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,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,Sender) 要么 ShellExec(ProgramToRunOrFileToOpen,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 或者,如果您只是想知道子进程何时终止,则有两个简化版本接受BOOLEAN变量,一旦子程序终止,该变量将设置为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 PROCEDURE而不是ShellExec FUNCTION.如果执行请求失败,这些将引发操作系统错误. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |