Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to redirect large amount of output from command executed by CreateProcess?
    text
    copied!<p>I need to run a sqlite backup command from the command line. I don't want to use "cmd /c". The command is:</p> <blockquote> <p>sqlite3.exe MYDB.db .dump > MYDB.bak</p> </blockquote> <p>I could not find any example on SO that shows how to do this. </p> <p>Code that I have so far, collected from various SO posts is this, but is very much incomplete:</p> <pre><code>function StartProcess(const ACommandLine: string; AShowWindow: boolean = True; AWaitForFinish: boolean = False): Integer; var CommandLine: string; StartupInfo: TStartupInfo; ProcessInformation: TProcessInformation; StdOutPipeRead, StdOutPipeWrite: THandle; Handle: boolean; begin Result := 0; FillChar(StartupInfo, SizeOf(TStartupInfo), 0); FillChar(ProcessInformation, SizeOf(TProcessInformation), 0); StartupInfo.cb := SizeOf(TStartupInfo); StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE); StartupInfo.hStdOutput := StdOutPipeWrite; StartupInfo.hStdError := StdOutPipeWrite; if not(AShowWindow) then begin StartupInfo.dwFlags := STARTF_USESHOWWINDOW; StartupInfo.wShowWindow := SW_SHOWNORMAL; end; CommandLine := ACommandLine; UniqueString(CommandLine); Handle := CreateProcess(nil, PChar(CommandLine), nil, nil, False, CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInformation); CloseHandle(StdOutPipeWrite); if Handle then Result := ProcessInformation.dwProcessId; if AWaitForFinish then WaitForSingleObject(ProcessInformation.hProcess, INFINITE); CloseHandle(ProcessInformation.hProcess); CloseHandle(ProcessInformation.hThread); end; </code></pre> <p>Since the output from the dump command is very large, I'm not sure how to capture the output from stdout and then redirect it. Redirect it to what? COPY CON? or to a TFileStream.Write?</p> <p>I've seen this <a href="https://stackoverflow.com/questions/2971266/how-to-get-the-dos-output-in-delphi2009-with-vista">post</a>, but its incomplete with regard to implementing the redirection to the output file. I guess I should ask "What is the most efficient way to implement this?"</p> <p>If anyone has done this before, please post a code sample illustrating how I can do it. </p> <p>TIA.</p> <p>EDIT: </p> <p>Based on David Heffernan's answer, here is my revised code that indeed works properly:</p> <pre><code>function StartProcessWithRedirectedOutput(const ACommandLine: string; const AOutputFile: string; AShowWindow: boolean = True; AWaitForFinish: boolean = False): Integer; var CommandLine: string; StartupInfo: TStartupInfo; ProcessInformation: TProcessInformation; StdOutFileHandle: THandle; ProcessResult: boolean; begin Result := 0; StdOutFileHandle := CreateFile(PChar(AOutputFile), GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); Win32Check(StdOutFileHandle &lt;&gt; INVALID_HANDLE_VALUE); Win32Check(SetHandleInformation(StdOutFileHandle, HANDLE_FLAG_INHERIT, 1)); try FillChar(StartupInfo, SizeOf(TStartupInfo), 0); FillChar(ProcessInformation, SizeOf(TProcessInformation), 0); StartupInfo.cb := SizeOf(TStartupInfo); StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESTDHANDLES; StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE); StartupInfo.hStdOutput := StdOutFileHandle; StartupInfo.hStdError := StdOutFileHandle; if not(AShowWindow) then begin StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESHOWWINDOW; StartupInfo.wShowWindow := SW_HIDE; end; CommandLine := ACommandLine; UniqueString(CommandLine); ProcessResult := Win32Check(CreateProcess(nil, PChar(CommandLine), nil, nil, True, CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInformation)); if ProcessResult then begin try Result := ProcessInformation.dwProcessId; if AWaitForFinish then WaitForSingleObject(ProcessInformation.hProcess, INFINITE); finally if ProcessInformation.hProcess &lt;&gt; INVALID_HANDLE_VALUE then CloseHandle(ProcessInformation.hProcess); if ProcessInformation.hThread &lt;&gt; INVALID_HANDLE_VALUE then CloseHandle(ProcessInformation.hThread); end; end; finally CloseHandle(StdOutFileHandle); end; end; procedure TfAdmin.DoDBBackup(ADBBackupFile: String); var b, p, q: String; begin b := ExtractFilePath(ParamStr(0)) + 'PPDB.bak'; p := ExtractFilePath(ParamStr(0)) + 'sqlite3.exe'; q := ExtractFilePath(ParamStr(0)) + 'PPDB.db .dump'; fMain.UniConnection1.Close; try StartProcessWithRedirectedOutput(p + ' ' + q, b, True, True); finally fMain.UniConnection1.Open; end; ZipMaster1.FSpecArgs.Add(b); ZipMaster1.ZipFileName := ADBBackupFile; ZipMaster1.Add; DeleteFile(b); ShowMessage('Backup complete!'); end; </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload