How to redirect binary gbak output to a Delphi stream? -


i want firebird backup tool gbak write output delphi stream (with no intermediate file). there command line parameter write stdout rather file. use execute method in jedi's jclsysutils launch gbak , process output.

it looks this:

procedure dobackup; var   lbackupabortflag: boolean;   lbackupstream: tstringstream; begin   lbackupabortflag := false;   lbackupstream := tstringstream.create;   try     execute('"c:\path to\gbak.exe" -b -t -v -user sysdba -pas "pw" <db> stdout',       lbackupstream.writestring, // should process stdout (backup)       somememo.lines.append, // should process stderr (log)       true, // backup "raw"       false, // log not       @lbackupabortflag);     lbackupstream.savetofile('c:\path to\output.fbk');       lbackupstream.free;   end; end; 

the problem output file way small contain actual backup. still see elements of file's content. tried different stream types, doesn't seem make difference. going wrong here?

update

to clear: other solutions welcome well. of all, need reliable. that's why went jedi in first place, not reinvent such thing. then, nice, if not complicated.

my first answer effective when wish merge stdout , stderr. however, if need keep these separate, approach no use. , can see, closer reading of question, , comments, wish keep 2 output streams separate.

now, not straightforward extend first answer cover this. problem code there uses blocking i/o. , if need service 2 pipes, there obvious conflict. commonly used solution in windows asynchronous i/o, known in windows world overlapped i/o. however, asynchronous i/o more complex implement blocking i/o.

so, i'm going propose alternative approach still uses blocking i/o. if want service multiple pipes, , want use blocking i/o obvious conclusion need 1 thread each pipe. easy implement – easier asynchronous option. can use identical code move blocking read loops threads. example, re-worked in way, looks this:

{$apptype console}  uses   sysutils, classes, windows;  type   tprocessoutputpipe = class   private     frd: thandle;     fwr: thandle;   public     constructor create;     destructor destroy; override;     property rd: thandle read frd;     property wr: thandle read fwr;     procedure closewritepipe;   end;  constructor tprocessoutputpipe.create; const   pipesecurityattributes: tsecurityattributes = (     nlength: sizeof(tsecurityattributes);     binherithandle: true   ); begin   inherited;   win32check(createpipe(frd, fwr, @pipesecurityattributes, 0));   win32check(sethandleinformation(frd, handle_flag_inherit, 0));//don't inherit read handle of pipe end;  destructor tprocessoutputpipe.destroy; begin   closehandle(frd);   if fwr<>0     closehandle(fwr);   inherited; end;  procedure tprocessoutputpipe.closewritepipe; begin   closehandle(fwr);   fwr := 0; end;  type   treadpipethread = class(tthread)   private     fpipehandle: thandle;     fstream: tstream;   protected     procedure execute; override;   public     constructor create(pipehandle: thandle; stream: tstream);   end;  constructor treadpipethread.create(pipehandle: thandle; stream: tstream); begin   inherited create(false);   fpipehandle := pipehandle;   fstream := stream; end;  procedure treadpipethread.execute; var   buffer: array [0..4096-1] of byte;   bytesread: dword; begin   while readfile(fpipehandle, buffer, sizeof(buffer), bytesread, nil) , (bytesread<>0) begin     fstream.writebuffer(buffer, bytesread);   end; end;  function readoutputfromexternalprocess(const applicationname, commandline: string; stdout, stderr: tstream): dword; var   stdoutpipe, stderrpipe: tprocessoutputpipe;   stdoutthread, stderrthread: treadpipethread;   startupinfo: tstartupinfo;   processinfo: tprocessinformation;   lpapplicationname: pchar;   modfiablecommandline: string; begin   if applicationname=''     lpapplicationname := nil   else     lpapplicationname := pchar(applicationname);   modfiablecommandline := commandline;   uniquestring(modfiablecommandline);    stdoutpipe := nil;   stderrpipe := nil;   stdoutthread := nil;   stderrthread := nil;   try     stdoutpipe := tprocessoutputpipe.create;     stderrpipe := tprocessoutputpipe.create;      zeromemory(@startupinfo, sizeof(startupinfo));     startupinfo.cb := sizeof(startupinfo);     startupinfo.dwflags := startf_useshowwindow or startf_usestdhandles;     startupinfo.wshowwindow := sw_hide;     startupinfo.hstdoutput := stdoutpipe.wr;     startupinfo.hstderror := stderrpipe.wr;     win32check(createprocess(lpapplicationname, pchar(modfiablecommandline), nil, nil, true,       create_no_window or normal_priority_class, nil, nil, startupinfo, processinfo));      stdoutpipe.closewritepipe;//so process able terminate     stderrpipe.closewritepipe;//so process able terminate      stdoutthread := treadpipethread.create(stdoutpipe.rd, stdout);     stderrthread := treadpipethread.create(stderrpipe.rd, stderr);     stdoutthread.waitfor;     stderrthread.waitfor;      win32check(waitforsingleobject(processinfo.hprocess, infinite)=wait_object_0);     win32check(getexitcodeprocess(processinfo.hprocess, result));       stderrthread.free;     stdoutthread.free;     stderrpipe.free;     stdoutpipe.free;   end; end;  procedure test; var   stdout, stderr: tfilestream;   exitcode: dword; begin   stdout := tfilestream.create('c:\desktop\stdout.txt', fmcreate);   try     stderr := tfilestream.create('c:\desktop\stderr.txt', fmcreate);     try       exitcode := readoutputfromexternalprocess('', 'cmd /c dir /s c:\windows\system32', stdout, stderr);           stderr.free;     end;       stdout.free;   end; end;  begin   test; end. 

if wish add support cancelling, add in call terminateprocess when user cancelled. bring halt, , function return exit code supplied terminateprocess. i'm hesitant right suggest cancellation framework you, think code in answer pretty close meeting requirements.


Comments

Popular posts from this blog

c# - How Configure Devart dotConnect for SQLite Code First? -

erlang - Saving a digraph to mnesia is hindered because of its side-effects -

c++ - Clear the memory after returning a vector in a function -