Subject Re: [firebird-support] Capture the output of GBAK console process and display on your GUI application
Author Salvatore Besso
hello Stefan,

> would you show us (or send me) the code that does it?

it's a pleasure. It consists of only one function and one procedure. The main function was borrowed from some Jedi code
doing some modifications. It is not too long, so I post them into this message:

---------------------------------------------------------------

uses
Classes;

function ExecRedirected(const CommandLine: string; List: TStrings): Integer;
procedure KillExecRedirected;

var
ProcessHandle: Cardinal; // Global variable

implementation

uses
Windows, SysUtils;


function ExecRedirected(const CommandLine: string; List: TStrings): Integer;

const
BlockSize = 2048;

var
Security: TSecurityAttributes;
ReadPipe, WritePipe: THandle;
StartInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
Buffer: array[0..BlockSize + 1] of Char;
Ok: Boolean;
BytesRead: Cardinal;
I: Integer;
Line: string;
ExitCode: DWORD;

begin
Application.ProcessMessages;
Security.nLength := SizeOf(Security);
Security.bInheritHandle := True;
Security.lpSecurityDescriptor := nil;
{ Create pipe to redirect on standard output }
if CreatePipe(ReadPipe, WritePipe, @Security, 0) then
begin
try
{ We use WritePipe as standard output to child process
and we assure that it is not displayed on the screen }
FillChar(StartInfo, SizeOf(StartInfo), 0);
StartInfo.cb := SizeOf(StartInfo);
StartInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
StartInfo.wShowWindow := SW_HIDE;
{ Don't redirect standard input }
StartInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
StartInfo.hStdOutput := WritePipe;
StartInfo.hStdError := WritePipe;
{ Create process }
if CreateProcess(nil, PChar(CommandLine), nil, nil, True,
NORMAL_PRIORITY_CLASS, nil, nil, StartInfo, ProcessInfo) then
begin
try
ProcessHandle := ProcessInfo.hProcess;
{ Now that the handle has been inherited, let's close WritePipe as
a security measure. We don't want to accidentally read or write
on it }
CloseHandle(WritePipe);
{ If process has been created then let's handle its output }
Line := '';
{ Get all output until the console application terminates }
repeat
Application.ProcessMessages;
{ Read a block of characters (it might contain CRLF's) }
Ok := ReadFile(ReadPipe, Buffer, BlockSize, BytesRead, nil);
{ Has anything been read? }
if BytesRead > 0 then
begin
{ Complete PChar buffer }
Buffer[BytesRead] := #0;
{ Convert possible OEM characters into Ansi }
OemToAnsi(Buffer, Buffer);
{ Add what has been read to the local string variable }
Line := Line + Buffer;
{ Normalize CRLF's }
Line := AdjustLineBreaks(Line);
{ Divide what has been read every end of line and add it to the list }
repeat
I := Pos(#13#10, Line);
if I > 0 then
begin
List.Add(Copy(Line, 1, I - 1));
Delete(Line, 1, I + 1)
end
until I = 0
end
until not Ok or (BytesRead = 0);
{ Add any possible remnant to the list }
if Line <> '' then
List.Add(Line);
Line := '';
List.Add(Line);
{ Wait for console application to terminate (it should be already
terminated now) }
WaitForSingleObject(ProcessInfo.hProcess, INFINITE)
finally
{ Get process exit code }
if GetExitCodeProcess(ProcessInfo.hProcess, ExitCode) then
Result := ExitCode
else Result := 996;
{ Close all process' handles }
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
ProcessHandle := 0
end
end
else Result := 997
finally
{ Close all remaining handles }
CloseHandle(ReadPipe)
end
end
else Result := 998
end;

procedure KillExecRedirected;

{ You can kill the above process using its handle }

begin
if ProcessHandle <> 0 then
try
TerminateProcess(ProcessHandle, 999)
finally
ProcessHandle := 0
end
end;

---------------------------------------------------------------------

This is a simple usage example of a backup operation
(ReportMemo is the TMemo component):

CommandLine := 'drive:\path\gbak.exe -B -T -V -USER SYSDBA -PAS masterkey C:\DB\MyDB.fdb Z:\Backups\MyDB.fbk';
ExitCode := ExecRedirected(CommandLine, ReportMemo.Lines);

The TStrings parameter must be NOT NIL!

On exit examine the exit code returned by the function.

I have never tried, but I suppose that you can also use UNC paths.

---------------------------------------------------------------------

Have fun :-)
Salvatore