Board index » delphi » Printer.Abort doesn't abort printing.

Printer.Abort doesn't abort printing.

Hello,

I want to calculate the total number of pages before the actual printing.
So I try to do dummy print job first, and then actually print it using the
calculated number of pages in headers/footers.

For some reasons Printer.Abort, which I use to abort the job after
calculating the total number of pages, and before anything is printed
(before and instead of Printer.EndDoc) doesn't work.

Here's basically the code:

Printer.BeginDoc;
try
   {do the printing, calculating the total number of pages}
   ...
finally
   if ToNotPrint then begin
      Printer.Abort;
   end else begin
      Printer.EndDoc;
   end; {if}
end; {try}

I go through that code twice, first time with ToNotPrint = TRUE (to abort
ptrinting), second time - FALSE.
However, I end up with the two identical printouts actually printed.

There is some information that some print spoolers may actually start
sending pages to the printer even before calling Printer.EndDoc, as
documented, but immediately after Printer.NewPage. If that's true in my
case, what is the workaround?

Any suggestions are greatly appreciated.

Thank you,
Dmitri Papichev

 

Re:Printer.Abort doesn't abort printing.


Hello,

Here is the (already) historic posting from Peter Below:
-----------------------------------------
From: Peter Below (TeamB) (100113.1...@compuXXserve.com)
Subject: Re: Aborting a Print job and Printer settings
Newsgroups: borland.public.delphi.vcl.components.writing
Date: 2000/08/15

Quote
In article <8nbg47$s...@bornews.borland.com>, Jamie Rorrison wrote:
> I'm writing a print preview component at the moment, and I'm having a bit
of
> trouble trying to abort the print job after EndDoc is called.

Don't call EndDoc, call Printer.Abort. But this is really not the way to go.
Depending on the printer setup the spooler may start sending pages to the
printer after a call to NewPage already. Don't call BeginDoc at all if all
you
need is a preview. You can get the information you need to scale a preview
window properly (printer page size, resolution, printable area, nonprintable
margins) from Printer.handle using GetDeviceCaps, without BeginDoc.
--------------------------------------------

That is definitely the fact that my printer receives and prints pages as
soon as NewPage is performed.
Peter, could you please elaborate how to make it without BeginDoc? I tried,
but just to end up with "Printer is not currently printing" error.

Thank you,
Dmitri Papichev

Quote
"Dmitri Papichev" <Dmitri.Papic...@iname.com> wrote in message

news:3b8e9030$1_1@dnews...
Quote
> Hello,

> I want to calculate the total number of pages before the actual printing.
> So I try to do dummy print job first, and then actually print it using the
> calculated number of pages in headers/footers.

> For some reasons Printer.Abort, which I use to abort the job after
> calculating the total number of pages, and before anything is printed
> (before and instead of Printer.EndDoc) doesn't work.

> Here's basically the code:

> Printer.BeginDoc;
> try
>    {do the printing, calculating the total number of pages}
>    ...
> finally
>    if ToNotPrint then begin
>       Printer.Abort;
>    end else begin
>       Printer.EndDoc;
>    end; {if}
> end; {try}

> I go through that code twice, first time with ToNotPrint = TRUE (to abort
> ptrinting), second time - FALSE.
> However, I end up with the two identical printouts actually printed.

> There is some information that some print spoolers may actually start
> sending pages to the printer even before calling Printer.EndDoc, as
> documented, but immediately after Printer.NewPage. If that's true in my
> case, what is the workaround?

> Any suggestions are greatly appreciated.

> Thank you,
> Dmitri Papichev

Re:Printer.Abort doesn't abort printing.


Quote
In article <3b8f8c20$1_1@dnews>, Dmitri Papichev wrote:
> That is definitely the fact that my printer receives and prints pages as
> soon as NewPage is performed.
> Peter, could you please elaborate how to make it without BeginDoc? I tried,
> but just to end up with "Printer is not currently printing" error.

To count pages you do not actually perform any output on the printer canvas,
you simply calculate the positions of the output. The main problem here is
that you need a canvas for measuring text and this canvas needs to have the
same logical resolution than the printer canvas has. I never needed to do
this, so the following is just an idea: create a metafile and use its canvas:

procedure TForm1.Button1Click(Sender: TObject);
var
  mf: TMetafile;
  mfc: TMetafileCanvas;
begin
  mf:= TMetafile.Create;
  try
    mfc:= TMetafilecanvas.create( mf, printer.handle );
    try
      mf.width := printer.pagewidth;
      mf.height := printer.pageheight;
      mfc.font.pixelsperinch := GetDeviceCaps( printer.handle, LOGPIXELSY );
      ...measure using mfc
    finally
      mfc.free
    end;
  finally
    mf.Free;
  end;
end;

The docs are not implicit here but you can use an information context handle
as a reference "DC" for TMetafilecanvas.Create. The result after the code
above is a metafile with the same size as a printed page and the same logical
resolution. It has MM_TEXT mapping mode, the same the printer canvas uses as
default.

OK, how to integrate this with the printing code you already have? Of course
you do not want to write two different versions of the same code. So lets
apply the proxy pattern: instead of directly working with the printer object
your printing routine is handed a class that offers the same methods (and a
canvas) than the printer object. For the actual printing this object will pass
on the requests to the Printer object, for the page counting another object is
used that provides the metafile canvas, has empty BeginDoc, EndDoc and Abort
methods and a NewPage method that counts pages instead of ejecting them.

The following is a sketch on how such objects may look like. I leave the
testing to you <g>.

unit PrinterProxies;

interface

Uses Windows, Classes, graphics;

Type
  TBasePrinterProxy = class
  private
    FhIC: THandle;
    function GetCanvas: Tcanvas; virtual; abstract;
    function Getpageheight: Integer;
    function GetPagenumber: Integer; virtual; abstract;
    function Getpagewidth: Integer;
  protected
    property hIC: THandle read FhIC;
  public
    Constructor Create; virtual;

    Function DeviceCaps( index: Integer ): Integer;
    Procedure BeginDoc; virtual;
    Procedure EndDoc; virtual;
    Procedure NewPage; virtual;
    Procedure Abort; virtual;

    property Canvas: Tcanvas read GetCanvas;
    property Pagewidth: Integer read Getpagewidth;
    property Pageheight: Integer read Getpageheight;
    property Pagenumber: Integer read GetPagenumber;
  end;

  TPagecounter = class( TBasePrinterProxy )
  private
    FPagecount: Integer;
    FMetafile: TMetafile;
    FMetafilecanvas: TMetafilecanvas;
    function GetCanvas: Tcanvas; override;
    function GetPagenumber: Integer; override;
    procedure initCanvas;
  public
    Constructor Create; override;
    Destructor Destroy; override;
    Procedure BeginDoc; override;
    Procedure NewPage; override;
  end;

  TPrinterProxy = class( TBasePrinterProxy )
  private
    function GetCanvas: Tcanvas; override;
    function GetPagenumber: Integer; override;
  public
    Procedure BeginDoc; override;
    Procedure NewPage; override;
    Procedure EndDoc; override;
    Procedure Abort; override;
  end;

implementation

uses sysutils, printers;

{ TBasePrinterProxy }

procedure TBasePrinterProxy.Abort;
begin  { does nothing } end;

procedure TBasePrinterProxy.BeginDoc;
begin  { does nothing } end;

constructor TBasePrinterProxy.Create;
begin
  inherited;
  Assert( not printer.printing );
  FhIC := Printer.Handle;
end;

function TBasePrinterProxy.DeviceCaps(index: Integer): Integer;
begin
  result := GetDeviceCaps( FhIC, index );
end;

procedure TBasePrinterProxy.EndDoc;
begin  { does nothing } end;

function TBasePrinterProxy.Getpageheight: Integer;
begin
  Result := printer.PageHeight;
end;

function TBasePrinterProxy.Getpagewidth: Integer;
begin
  Result := printer.PageWidth;
end;

procedure TBasePrinterProxy.NewPage;
begin  { does nothing } end;

{ TPagecounter }

procedure TPagecounter.BeginDoc;
begin
  FPagecount := 1;
end;

constructor TPagecounter.Create;
begin
  inherited;
  FMetafile := TMetafile.Create;
  InitCanvas;
end;

destructor TPagecounter.Destroy;
begin
  FMetafilecanvas.Free;
  FMetafile.Free;
  inherited;
end;

function TPagecounter.GetCanvas: Tcanvas;
begin
  Result := FMetafilecanvas;
end;

function TPagecounter.GetPagenumber: Integer;
begin
  Result := FPagecount;
end;

procedure TPagecounter.initCanvas;
begin
  FMetafilecanvas := TMetafilecanvas.Create( FMetafile, hIC );
  FMetafile.Width := Pagewidth;
  FMetafile.Height := Pageheight;
  FMetafileCanvas.Font.PixelsPerInch := DeviceCaps( LOGPIXELSY );
end;

procedure TPagecounter.NewPage;
begin
  Inc( FPageCount );
  FreeAndNil( FMetafilecanvas );
  FMetafile.Clear;
  initCanvas;
end;

{ TPrinterProxy }

procedure TPrinterProxy.Abort;
begin
  Printer.Abort;
end;

procedure TPrinterProxy.BeginDoc;
begin
  Printer.BeginDoc;
end;

procedure TPrinterProxy.EndDoc;
begin
  Printer.EndDoc;
end;

function TPrinterProxy.GetCanvas: Tcanvas;
begin
  Result := Printer.Canvas;
end;

function TPrinterProxy.GetPagenumber: Integer;
begin
  Result := Printer.PageNumber;
end;

procedure TPrinterProxy.NewPage;
begin
  Printer.NewPage;
end;

end.

Peter Below (TeamB)  100113.1...@compuserve.com)
No e-mail responses, please, unless explicitly requested!
Note: I'm unable to visit the newsgroups every day at the moment,
so be patient if you don't get a reply immediately.

Re:Printer.Abort doesn't abort printing.


Dmitri,

Before you ask, there is no attachment to Peters message it's just a bug in
Outlook Express.  Hit Ctrl+F3 to get the full message.

--
Regards,
Chris Luck

Other Threads