我个人认为通过致电CreateProcess
来做到这一点更容易。您需要创建一个文件句柄,并将其传递给CreateProcess
以用作stdout。有几个细节需要注意,主要涉及句柄继承。你可以把它全部用这个函数来完成:
procedure ExecuteCommandAndAppendToFile(
const Executable: string;
const Arguments: string;
const WorkingDir: string;
const OutputFile: string
);
const
sa: TSecurityAttributes = (nLength: SizeOf(sa); bInheritHandle: True);
var
hstdout: THandle;
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
cmd: string;
begin
hstdout := CreateFile(PChar(OutputFile), GENERIC_WRITE, 0, @sa, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0);
Win32Check(hstdout<>INVALID_HANDLE_VALUE);
try
//move to end of file since we wish to append
SetFilePointer(hstdout, 0, nil, FILE_END);
ZeroMemory(@StartupInfo, SizeOf(StartupInfo));
StartupInfo.cb := SizeOf(StartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
StartupInfo.wShowWindow := SW_HIDE;
StartupInfo.hStdOutput := hstdout;
StartupInfo.hStdError := hstdout;
cmd := Executable + ' ' + Arguments;
UniqueString(cmd);//not needed but let's be explicit
if not CreateProcess(nil, PChar(cmd), nil, nil, True,
CREATE_NO_WINDOW or NORMAL_PRIORITY_CLASS, nil, PChar(WorkingDir),
StartupInfo, ProcessInfo) then
begin
RaiseLastOSError;
end;
try
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
finally
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
end;
finally
CloseHandle(hstdout);
end;
end;
这使用WaitForSingleObject
等待完成。这将阻止运行此代码的线程。如果您有不希望阻止的GUI,可以将此代码移动到另一个线程中。或者你可以使用MsgWaitForMultipleObjects
。或者你可以使用基于Sleep
的循环,如果你必须的话(我并不在乎Sleep
,但它是你的选择)。
所以,你不妨调整一下这个,但基本都在这里。
你能指定如何失败。另外,如果没有“睡眠”,写下等待会更好。你需要'MsgWaitForMultipleObjects'。或者运行shell的懒惰方式执行并等待后台线程退出。这样你可以使用'WaitForSingleObject'而不是阻止UI。就个人而言,如果我是你,我会放弃'cmd',并放弃'>>'并使用带管道的'CreateProcess'来读取另一个进程的'stdout'。 –
它没有真正失败,.txt只是保持空白。 你有一个例子如何用管道读取stdout? – user3239791
你喜欢这样做,而不是写入文件? –