2014-01-27 40 views
1

我想从另一个delphi程序编译一个Delphi程序,为此我使用ShellExecuteEx,以便程序等待编译完成。 这工作正常,但我想在.txt文件中的.cmd输出,这是不正常工作。德尔福:ShellExecuteEx到.txt文件

StartAndWait('cmd', '/c c:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild xyz.dproj /t:Build /p:Config=release >> log.txt'); 

StartAndWait用的ShellExecuteEx启动功能,并等待,直到节目结束后,

IF ShellExecuteEx(@SEInfo) THEN 
BEGIN 
    REPEAT 
    Application.ProcessMessages; 
    // Damit die Prozessorauslastung sinkt :-) 
    Sleep(100); 
    GetExitCodeProcess(SEInfo.hProcess, ExitCode); 
    UNTIL (ExitCode <> STILL_ACTIVE) OR Application.Terminated; 
    Result := True; 
END; 

谢谢!

+0

你能指定如何失败。另外,如果没有“睡眠”,写下等待会更好。你需要'MsgWaitForMultipleObjects'。或者运行shell的懒惰方式执行并等待后台线程退出。这样你可以使用'WaitForSingleObject'而不是阻止UI。就个人而言,如果我是你,我会放弃'cmd',并放弃'>>'并使用带管道的'CreateProcess'来读取另一个进程的'stdout'。 –

+0

它没有真正失败,.txt只是保持空白。 你有一个例子如何用管道读取stdout? – user3239791

+0

你喜欢这样做,而不是写入文件? –

回答

4

我个人认为通过致电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,但它是你的选择)。

所以,你不妨调整一下这个,但基本都在这里。

+0

**注意**:检查来自'SetFilePointer'的错误是背后的痛处。所以我只是跳过它。在我自己的代码中,我会调用'SetFilePointerEx',这使得错误检查更容易。但在Win2k上不存在'SetFilePointerEx'。如果有人使用此代码,则应解决该问题。 –

+0

作品像一个魅力,谢谢你! – user3239791

+0

好。如果你想使用'MsgWaitForMultipleObjects',你可以在这里使用我的答案中的代码:http://stackoverflow.com/questions/10334553/processmessages-and-use-of-application/10341681#10341681或这里http:// stackoverflow.com/questions/4871358/let-stay-thread-running-on-form-close –