我想以特定顺序和参数运行5个不同的.exe文件。现在我正在尝试使用ShellAPI但它似乎不起作用。另外,我需要在第一个文件完成后执行下一个文件,我可以用ShellAPI吗?我试图使用的代码是
procedure TForm1.Button1Click(Sender: TObject);
begin
ShellExecute(0, 'open',
'C:\Users\ByfyX1\Dropbox\Exjobb\Senaste Fortran 1ajuli\Release\DIG.exe "C:\Users\ByfyX1\Dropbox\Exjobb\V.1 - kopia\Win32\Debug\Indata1.txt"', nil, nil,
SW_SHOWNORMAL);
end;
这里的论点是'Indata1.txt'文件。我在这里说错了吗?这是我在cmd.exe中编写的方式,这就是我走这条路的原因。
答案 0 :(得分:2)
ShellExecute
会立即返回。如果您希望等待该过程完成,则需要采取特定步骤。
在任何情况下,ShellExecute
都是错误的功能。该函数及其无限可用的朋友ShellExecuteEx
旨在对文件执行各种shell操作。您正在寻找创建要使用的API为CreateProcess
的进程。
当您调用CreateProcess
时,将返回新进程及其主线程的句柄。然后,您可以等待进程句柄发出信号。一旦发出信号,您就可以启动下一个流程。等等等等。
这样的事情:
procedure ExecuteAndWait(Command: string; const WorkingDirectory: string);
var
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
begin
ZeroMemory(@StartupInfo, SizeOf(StartupInfo));
StartupInfo.cb := SizeOf(StartupInfo);
StartupInfo.wShowWindow := SW_HIDE;
UniqueString(Command);
Win32Check(CreateProcess(
nil,
PChar(cmd),
nil,
nil,
True,
CREATE_NO_WINDOW or NORMAL_PRIORITY_CLASS,
nil,
PChar(WorkingDirectory),
StartupInfo,
ProcessInfo
));
try
Win32Check(WaitForSingleObject(ProcessInfo.hProcess, INFINITE)=WAIT_OBJECT_0);
finally
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
end;
end;
答案 1 :(得分:1)
为了完整起见,您可以采用的另一种方法是生成批处理(.bat)文件,然后使用您的应用程序将其关闭,然后让CLI执行排序。添加一个最后运行的小应用程序,其行为类似于* nix中的经典“触摸”应用程序,该应用程序在您的应用程序可以检查完成的文件夹中创建一个空文件。
#the batch file
del imdone.txt #or do this inside of your program instead
do_first.exe argfile.txt
do_second.exe argfile2.txt
. . .
do_last.exe argfilen.txt
touch imdone.txt
然后你的程序可以做其他事情并定期轮询寻找imdone.txt
文件的存在。一旦找到,它就知道处理完成了。
或者,您可以使用另一种方法生成批处理文件进程,以便程序等待它完成。
我做了很多这样的事情。它结合了简单的编程要求和同样简单的脚本。
答案 2 :(得分:0)
我使用这些函数异步执行子进程,并在进程终止时回调它。它的工作原理是创建一个等待进程终止的线程,然后通过给定的事件方法回调主程序线程。请注意,您的程序在子进程运行时继续运行,因此您需要某种形式的逻辑来防止产生子进程的无限发生。
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
或者,如果您只是想知道子进程何时终止,则有两个简化版本接受BOOLEAN变量,一旦子程序终止,该变量将设置为TRUE。您不需要先将其设置为FALSE,因为它将自动完成:
ShellExec(ProgramToRun,ChildProcessEnded);
如果您不提供事件处理程序或BOOLEAN变量,则ShellExec过程只是运行/打开给定的文件并且不执行回调。
如果您不提供发件人,则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。如果执行请求失败,这些将引发操作系统错误。