2014-01-27 89 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 –