Главная страница | назад





Article #16367: Simultaneous printing to multiple printers

 Question and Answer Database

FAQ1367D.txt - Simultaneous printing to multiple printers

Category   :Printing
Platform   :All Windows
Product    :

Question:
Is it possible to print to more than one printer at a given time?

Answer:
Yes! The following example demonstrates how to print to more than
one printer at a given time. The exmple does not use TPrinter, since
TPrinter does not support printing to multiple printers at a given
time.

Example:

unit multiprn;

interface

{$IFDEF WIN32}
  uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls,
    Forms, Dialogs, StdCtrls;
{$ELSE}
  uses
    SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics,
    Controls, Forms, Dialogs, StdCtrls;
{$ENDIF}


type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    ListBox2: TListBox;
    ListBox3: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure ListBox1Click(Sender: TObject);
    procedure ListBox2Click(Sender: TObject);
    procedure ListBox3Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    procedure GetTheListOfPrinters;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

type
  PdcArray = ^TdcArray;
  TdcArray = array[0..0] of hdc;

procedure TForm1.GetTheListOfPrinters;
var
  p : pChar;
  p2 : pChar;
  i : integer;
  sDriver : string;
  sPort : string;
begin
  GetMem(p, 32767);
  p2 := p;
 {Get a list of the printer names from the win.ini file.}
 {The list will be a buffer filled with strings, each seperated}
 {by a null character, with the final string terminated with}
 {a two null characters}
  if GetProfileString('devices', nil, '',p, 32767) <> 0 then begin
   {loop though the null terminated strings. We know we}
   {have reached the end when p2 equals a null character}
    while p2^ <> #0 do begin
     ListBox1.Items.Add(StrPas(p2));
    {increment the pointer past the null to get the next string}
     p2 := @p2[lStrLen(p2) + 1];
    end;
  end;
  GetMem(p2, 32767);
 {Get the driver and port names for each printer found}
  for i := 0 to (ListBox1.Items.Count - 1) do begin
    StrPCopy(p2, ListBox1.Items[i]);
    if GetProfileString('devices', p2, '',p, 32767) <> 0 then begin
     sDriver := StrPas(p);
     sPort := sDriver;
    {The driver is the portion of the string before the comma}
     Delete(sDriver, Pos(',', sDriver), Length(sDriver));
    {The port is the portion of the string after the comma}
     Delete(sPort, 1, Pos(',', sPort));
     ListBox2.Items.Add(sDriver);
     ListBox3.Items.Add(sPort);
    end;
  end;
  FreeMem(p2, 32767);
  FreeMem(p, 32767);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  GetTheListOfPrinters;
 {Allow the user to select multiple printers}
  ListBox1.MultiSelect := true;
  ListBox2.MultiSelect := true;
  ListBox3.MultiSelect := true;
end;

procedure TForm1.ListBox1Click(Sender: TObject);
var
  i : integer;
begin
 {Select same indexes in ListBoxs 2 and 3 as are selected in Listbox1}
  for i := 0 to ListBox1.Items.Count - 1 do begin
    ListBox2.Selected[i] :=  ListBox1.Selected[i];
    ListBox3.Selected[i] :=  ListBox1.Selected[i]
  end;
end;

procedure TForm1.ListBox2Click(Sender: TObject);
var
  i : integer;
begin
 {Select same indexes in ListBoxs 1 and 3 as are selected in Listbox2}
  for i := 0 to ListBox2.Items.Count - 1 do begin
    ListBox1.Selected[i] :=  ListBox2.Selected[i];
    ListBox3.Selected[i] :=  ListBox2.Selected[i]
  end;
end;

procedure TForm1.ListBox3Click(Sender: TObject);
var
  i : integer;
begin
 {Select same indexes in ListBoxs 1 and 2 as are selected in Listbox3}
  for i := 0 to ListBox3.Items.Count - 1 do begin
    ListBox1.Selected[i] :=  ListBox3.Selected[i];
    ListBox2.Selected[i] :=  ListBox3.Selected[i]
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  dcs : PdcArray; {a pointer to an array of hdc's}
  dcsCount : integer; {count of valad hdc's}
  dc : hdc; {test hdc}
  i : integer; {couning variable}
  pPrinter : pChar; {pointer to a printer name}
  pDriver : pChar; {pointer to a printer driver filename}
  pPort : pChar; {pointer to a port}
  DocInfo: TDocInfo; {document information for the spooler}
  {$IFDEF WIN32}
   osv : TOSVERSIONINFO; {to test for Windows NT}
  {$ENDIF}
begin
 {If there are no printers selected then exit}
  if ListBox1.SelCount = 0 then exit;
{If Range Checking is on then rember the setting and turn it off}
{This will allow use to access the dcs[i] array past element zero}
{without a compiler or runtime error}
{$IFOPT R+}
  {$DEFINE CKRANGE}
  {$R-}
{$ENDIF}
 {Allocate the array of dcs}
  GetMem(dcs, sizeof(hdc) * ListBox1.SelCount);
  dcsCount := 0;
 {Loop though the printers that are selected and create dc's for each}
  for i := 0 to (ListBox1.Items.Count - 1) do begin
   {Loop through the list box to find the selected printers}
    if ListBox1.Selected[i] then begin
     {Allocate and get the Printer, Driver and port from the listboxs}
     {in the form of a null terminated string}
      GetMem(pPrinter, Length(ListBox1.Items[i]) + 1);
      GetMem(pDriver, Length(ListBox2.Items[i]) + 1);
      GetMem(pPort, Length(ListBox3.Items[i]) + 1);
      StrPCopy(pPrinter, ListBox1.Items[i]);
      StrPCopy(pDriver, ListBox2.Items[i]);
      StrPCopy(pPort, ListBox3.Items[i]);
     {Attempt to create a dc - notes 1) Not all printers can}
     {support multiple dc's at one time. 2) CreateDc requires}
     {different parameters if Win32 andor Win32 under NT.}
     {Sixteen bit win apps get standard handling}
     {$IFDEF WIN32}
       GetVersionEx(osv);
       if osv.dwPlatformId = VER_PLATFORM_WIN32_NT then
         dc := CreateDc(pDriver, pPrinter, nil, nil) else
         dc := CreateDc(nil, pPrinter, nil, nil);
     {$ELSE}
        dc := CreateDc(pDriver, pPrinter, pPort, nil);
     {$ENDIF}
      FreeMem(pPrinter, Length(ListBox1.Items[i]));
      FreeMem(pDriver, Length(ListBox2.Items[i]));
      FreeMem(pPort, Length(ListBox3.Items[i]));
     {If the dc is valid, then lets save it to our array}
     {and increment our count}
      if dc <> 0 then begin
        dcs^[dcsCount] := dc;
        inc(dcsCOunt);
      end;
    end;
  end;
 {If we ended up with a valid array of dc's then let's print}
  if dcsCount > 0 then begin

   {Fill Out the DocInfo structure for the spooler}
   {and start a document for each printer}
    GetMem(DocInfo.lpszDocName, 32);
    for i := 0 to (dcsCount - 1) do begin
      FillChar(DocInfo, sizeof(DocInfo), #0);
      DocInfo.cbSize := SizeOf(DocInfo);
      StrPCopy(DocInfo.lpszDocName, 'Test Doc' + IntToStr(i));
      StartDoc(dcs^[i], DocInfo);
    end;
    FreeMem(DocInfo.lpszDocName, 32);

   {Start a page for each printer}
    for i := 0 to (dcsCount - 1) do
      StartPage(dcs^[i]);
   {Print something}
    for i := 0 to (dcsCount - 1) do
      TextOut(dcs^[i], 200, 200, 'Test', 4);

   {End a page for each printer}
    for i := 0 to (dcsCount - 1) do
      EndPage(dcs^[i]);

   {End the document for each printer}
    for i := 0 to (dcsCount - 1) do
      EndDoc(dcs^[i]);

   {Delete the dc for each printer}
    for i := 0 to (dcsCount - 1) do
      DeleteDc(dcs^[i]);

  end; {dcsCount}
 {Free our array of printers}
  FreeMem(dcs, sizeof(hdc) * ListBox1.SelCount);

{If range checking was on when we started then turn it back on}
{$IFDEF CKRANGE}
  {$UNDEF CKRANGE}
  {$R+}
{$ENDIF}
end;

end.


4/2/99 11:23:18 AM
 

Last Modified: 01-SEP-99