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