Quickreport 6: CGI-bin Applications

These applications are executed by a web server (such as Apache) and produce a document suitable for streaming to the http client making the request to the server.

 

 

A Delphi console application is the basis for a cgi executable. The essentials of a console application are contained in the dpr file which has this structure

 

program Project1;

 

{$APPTYPE CONSOLE}

 

{$R *.res}

 

uses

  System.SysUtils;

 

Procedure ExecuteReport;

begin

   // <stream out html>

end;

 

begin

  try

    ExecuteReport;

  except

    on E: Exception do

      Writeln(E.ClassName, ': ', E.Message);

  end;

end.

 

 

Simplest Report

 

To execute a report design we construct an instance of the server module class TQRRTModule and call its methods to produce the html. The code is amended to

 

uses

  System.SysUtils, QRRTMComp, Windows;

 

Procedure ExecuteReport;

var

   qrMod : TQRRTModule;

   OutputStream : THandleStream;

   strsize : integer;

begin

  OutputStream := THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE));

  qrMod := TQRRTModule.Create(nil);

  try

     qrmod.DesignFile := 'RepUnit2A.dfm';

     qrmod.UseContentHeader := true; // for cgi-bin apps

     qrmod.LoadDesign;

     qrmod.ExecuteDesign;

     strsize := qrmod.QRRTQuickrep.HTMLStream.Size;

     qrmod.QRRTQuickrep.HTMLStream.Position := 0;

     OutputStream.CopyFrom(qrmod.QRRTQuickrep.HTMLStream, strsize);

  finally

     qrmod.Free;

     OutputStream.Free;

  end; 

end;

 

In this version any exceptions are unhandled in ExecuteReport and will be handled in the main body. The report design in this case requires no events to execute nor any data connection nor access to files. It is useful to add exception reporting if the application is to be load tested. The sample application (see below) has conditional error logging included.

 

Using the OnNeedData Event

 

Events may be added by defining an object class whose methods will handle events. The definition is inserted after the new 'uses' clause.

In this example the report has a detail band containing two TQRLabel controls whose captions are set by an OnNeedData event.

 

uses

System.SysUtils, QRRTMComp, classes, fmQuickrpt, fmQRCtrls, windows;

 

type

 

TCallBackObj = class(TOBject)

public

    recnum : integer;

    procedure EvHandler(Sender : TObject; var MoreData : Boolean);

end;

 

procedure  TCallBackObj.EvHandler(Sender : TObject; var MoreData : Boolean);

begin

    TQRLabel(TQuickrep(sender).GetQRControl('QRLabel2')).Caption := inttostr(recnum);

    TQRLabel(TQuickrep(sender).GetQRControl('QRLabel3')).Caption := floattostr(random(1200)/100);

    moreData := recnum < 100;

    inc(recnum);

end;

 

In the body of 'ExecuteReport' we create an instance of this object and assign the event to the component.

 

Procedure ExecuteReport;

var

   qrMod : TQRRTModule;

   OutputStream : THandleStream;

   strsize : integer;

   CBO : TCallBackObj;

begin

  OutputStream := THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE));

  qrMod := TQRRTModule.Create(nil);

  CBO := TCallBackObj.Create;

  CBO.recnum := 1;

  try

     qrmod.DesignFile := 'RepUnit2A.dfm';

     qrmod.OnNeedData := CBO.EvHandler;

     qrmod.UseContentHeader := true; // for cgi-bin apps

     qrmod.LoadDesign;

     qrmod.ExecuteDesign;

     strsize := qrmod.QRRTQuickrep.HTMLStream.Size;

     qrmod.QRRTQuickrep.HTMLStream.Position := 0;

     OutputStream.CopyFrom(qrmod.QRRTQuickrep.HTMLStream, strsize);

  finally

     qrmod.Free;

     OutputStream.Free;

     CBO.Free;

  end; 

end;

 

Adding Event Handlers

 

If a report requires other events to be handled, they can be added in this way. After the report is loaded into memory a procedure of the callback object is assigned

 

     qrmod.LoadDesign;

     qrmod.QRRTQuickrep.GetQRBand('detailband1').BeforePrint := CBO.Detail1OnPrint;

     qrmod.ExecuteDesign;

 

The procedure CBO.Detail1OnPrint is added to the object definition.

 

Using a Client Dataset

 

The basic application is extended thus 

 

Procedure ExecuteReport;

var

   CDS1 : TClientDataset;

   qrMod : TQRRTModule;

   OutputStream : THandleStream;

   strsize : integer;

begin

  CDS1 := TClientDataset.Create(nil);

  CDS1.Name := 'CDS1';// this must match the name in the design file

  OutputStream := THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE));

  qrMod := TQRRTModule.Create(nil);

  try

     LoadDataset(CDS1);

     CDS1.Open;

     qrmod.Dataset := CDS1;

     qrmod.DesignFile := 'RepUnit2A.dfm';

     qrmod.UseContentHeader := true; // for cgi-bin apps

     qrmod.LoadDesign;

     qrmod.ExecuteDesign;

     strsize := qrmod.QRRTQuickrep.HTMLStream.Size;

     qrmod.QRRTQuickrep.HTMLStream.Position := 0;

     OutputStream.CopyFrom(qrmod.QRRTQuickrep.HTMLStream, strsize);

  finally

     qrmod.Free;

     OutputStream.Free;

     CDS1.Free;

  end; 

end;

 

The code required to load the dataset can be found in the sample application QR-RTM-data-cons-app.