Contributor: EMINENT DOMAIN SOFTWARE unit EDSPrint; {unit to programmatically set printer options so that user does not} {have to go to the Printer Options Dialog Box} {Revision 2.1} interface uses Classes, Graphics, Forms, Printers, SysUtils, Print, WinProcs, WinTypes, Messages; {see the WinTypes unit for constant declarations such as} {dmPaper_Letter, dmbin_Upper, etc} const CCHBinName = 24; {Size of bin name (should have been in PRINT.PAS} CBinMax = 256; {Maximum number of bin sources} CPaperNames = 256; {Maximum number of paper sizes} type TPrintSet = class (TComponent) private { Private declarations } FDevice: PChar; FDriver: PChar; FPort: PChar; FHandle: THandle; FDeviceMode: PDevMode; FPrinter: integer; {same as Printer.PrinterIndex} procedure CheckPrinter; {-checks to see if the printer has changed and calls SetDeviceMode if it has} protected { Protected declarations } procedure SetOrientation (Orientation: integer); function GetOrientation: integer; {-sets/gets the paper orientation} procedure SetPaperSize (Size: integer); function GetPaperSize: integer; {-sets/gets the paper size} procedure SetPaperLength (Length: integer); function GetPaperLength: integer; {-sets/gets the paper length} procedure SetPaperWidth (Width: integer); function GetPaperWidth: integer; {-sets/gets the paper width} procedure SetScale (Scale: integer); function GetScale: integer; {-sets/gets the printer scale (whatever that is)} procedure SetCopies (Copies: integer); function GetCopies: integer; {-sets/gets the number of copies} procedure SetBin (Bin: integer); function GetBin: integer; {-sets/gets the paper bin} procedure SetPrintQuality (Quality: integer); function GetPrintQuality: integer; {-sets/gets the print quality} procedure SetColor (Color: integer); function GetColor: integer; {-sets/gets the color (monochrome or color)} procedure SetDuplex (Duplex: integer); function GetDuplex: integer; {-sets/gets the duplex setting} procedure SetYResolution (YRes: integer); function GetYResolution: integer; {-sets/gets the y-resolution of the printer} procedure SetTTOption (Option: integer); function GetTTOption: integer; {-sets/gets the TrueType option} public { Public declarations } constructor Create (AOwner: TComponent); override; {-initializes object} destructor Destroy; override; {-destroys class} function GetBinSourceList: TStringList; {-returns the current list of bins} function GetPaperList: TStringList; {-returns the current list of paper sizes} procedure SetDeviceMode; {-sets the internal pointer to the printers TDevMode structure} procedure UpdateDeviceMode; {-updates the printers TDevMode structure} procedure SaveToDefaults; {-updates the default settings for the current printer} procedure SavePrinterAsDefault; {-saves the current printer as the Window's default} function GetPrinterName: string; {-returns the name of the current printer} function GetPrinterPort: string; {-returns the port of the current printer} function GetPrinterDriver: string; {-returns the printer driver name of the current printer} { Property declarations } property Orientation: integer read GetOrientation write SetOrientation; property PaperSize: integer read GetPaperSize write SetPaperSize; property PaperLength: integer read GetPaperLength write SetPaperLength; property PaperWidth: integer read GetPaperWidth write SetPaperWidth; property Scale: integer read GetScale write SetScale; property Copies: integer read GetCopies write SetCopies; property DefaultSource: integer read GetBin write SetBin; property PrintQuality: integer read GetPrintQuality write SetPrintQuality; property Color: integer read GetColor write SetColor; property Duplex: integer read GetDuplex write SetDuplex; property YResolution: integer read GetYResolution write SetYResolution; property TTOption: integer read GetTTOption write SetTTOption; property PrinterName: String read GetPrinterName; property PrinterPort: String read GetPrinterPort; property PrinterDriver: String read GetPrinterDriver; end; { TPrintSet } procedure CanvasTextOutAngle (OutputCanvas: TCanvas; X,Y: integer; Angle: Word; St: string); {-prints text at the desired angle} {-current font must be TrueType!} procedure SetPixelsPerInch; {-insures that PixelsPerInch is set so that text print at the desired size} function GetResolution: TPoint; {-returns the resolution of the printer} procedure Register; {-registers the printset component} implementation constructor TPrintSet.Create (AOwner: TComponent); {-initializes object} begin inherited Create (AOwner); if not (csDesigning in ComponentState) then begin GetMem (FDevice, 255); GetMem (FDriver, 255); GetMem (FPort, 255); {SetDeviceMode;} FPrinter := -99; end {:} else begin FDevice := nil; FDriver := nil; FPort := nil; end; { if... } end; { TPrintSet.Create } procedure TPrintSet.CheckPrinter; {-checks to see if the printer has changed and calls SetDeviceMode if it has} begin if FPrinter <> Printer.PrinterIndex then SetDeviceMode; end; { TPrintSet.CheckPrinter } function TPrintSet.GetBinSourceList: TStringList; {-returns the current list of bins (returns nil for none)} type TcchBinName = array[0..CCHBinName-1] of Char; TBinArray = array[1..cBinMax] of TcchBinName; PBinArray = ^TBinArray; var NumBinsReq: Longint; {number of bins required} NumBinsRec: Longint; {number of bins received} BinArray: PBinArray; BinList: TStringList; BinStr: String; i: Longint; DevCaps: TFarProc; DrvHandle: THandle; DriverName: String; begin CheckPrinter; Result := nil; BinArray := nil; try DrvHandle := LoadLibrary (FDriver); if DrvHandle <> 0 then begin DevCaps := GetProcAddress (DrvHandle, 'DeviceCapabilities'); if DevCaps<>nil then begin NumBinsReq := TDeviceCapabilities (DevCaps)(FDevice, FPort, DC_BinNames, nil, FDeviceMode^); GetMem (BinArray, NumBinsReq * SizeOf (TcchBinName)); NumBinsRec := TDeviceCapabilities (DevCaps)(FDevice, FPort, DC_BinNames, PChar (BinArray), FDeviceMode^); if NumBinsRec <> NumBinsReq then begin {raise an exception} Raise EPrinter.Create ('Error retrieving Bin Source Info'); end; { if... } {now convert to TStringList} BinList := TStringList.Create; for i := 1 to NumBinsRec do begin BinStr := StrPas (BinArray^[i]); BinList.Add (BinStr); end; { next i } end; { if... } FreeLibrary (DrvHandle); Result := BinList; end {:} else begin {raise an exception} DriverName := StrPas (FDriver); Raise EPrinter.Create ('Error loading driver '+DriverName); end; { else } finally if BinArray <> nil then FreeMem (BinArray, NumBinsReq * SizeOf (TcchBinName)); end; { try } end; { TPrintSet.GetBinSourceList } function TPrintSet.GetPaperList: TStringList; {-returns the current list of paper sizes (returns nil for none)} type TcchPaperName = array[0..CCHPaperName-1] of Char; TPaperArray = array[1..cPaperNames] of TcchPaperName; PPaperArray = ^TPaperArray; var NumPaperReq: Longint; {number of paper types required} NumPaperRec: Longint; {number of paper types received} PaperArray: PPaperArray; PaperList: TStringList; PaperStr: String; i: Longint; DevCaps: TFarProc; DrvHandle: THandle; DriverName: String; begin CheckPrinter; Result := nil; PaperArray := nil; try DrvHandle := LoadLibrary (FDriver); if DrvHandle <> 0 then begin DevCaps := GetProcAddress (DrvHandle, 'DeviceCapabilities'); if DevCaps<>nil then begin NumPaperReq := TDeviceCapabilities (DevCaps)(FDevice, FPort, DC_PaperNames, nil, FDeviceMode^); GetMem (PaperArray, NumPaperReq * SizeOf (TcchPaperName)); NumPaperRec := TDeviceCapabilities (DevCaps)(FDevice, FPort, DC_PaperNames, PChar (PaperArray), FDeviceMode^); if NumPaperRec <> NumPaperReq then begin {raise an exception} Raise EPrinter.Create ('Error retrieving Paper Info'); end; { if... } {now convert to TStringList} PaperList := TStringList.Create; for i := 1 to NumPaperRec do begin PaperStr := StrPas (PaperArray^[i]); PaperList.Add (PaperStr); end; { next i } end; { if... } FreeLibrary (DrvHandle); Result := PaperList; end {:} else begin {raise an exception} DriverName := StrPas (FDriver); Raise EPrinter.Create ('Error loading driver '+DriverName); end; { else } finally if PaperArray <> nil then FreeMem (PaperArray, NumPaperReq * SizeOf (TcchPaperName)); end; { try } end; { TPrintSet.GetPaperList } procedure TPrintSet.SetDeviceMode; begin Printer.GetPrinter (FDevice, FDriver, FPort, FHandle); if FHandle = 0 then begin {driver not loaded} Printer.PrinterIndex := Printer.PrinterIndex; {-forces Printer object to load driver} end; { if... } Printer.GetPrinter (FDevice, FDriver, FPort, FHandle); if FHandle<>0 then begin FDeviceMode := Ptr (FHandle, 0); {-PDeviceMode now points to Printer.DeviceMode} FDeviceMode^.dmFields := 0; end {:} else begin FDeviceMode := nil; Raise EPrinter.Create ('Error retrieving DeviceMode'); end; { if... } FPrinter := Printer.PrinterIndex; end; { TPrintSet.SetDeviceMode } procedure TPrintSet.UpdateDeviceMode; {-updates the loaded TDevMode structure} var DrvHandle: THandle; ExtDevCaps: TFarProc; DriverName: String; ExtDevCode: Integer; OutDevMode: PDevMode; begin CheckPrinter; DrvHandle := LoadLibrary (FDriver); if DrvHandle <> 0 then begin ExtDevCaps := GetProcAddress (DrvHandle, 'ExtDeviceMode'); if ExtDevCaps<>nil then begin ExtDevCode := TExtDeviceMode (ExtDevCaps) (0, DrvHandle, FDeviceMode^, FDevice, FPort, FDeviceMode^, nil, DM_IN_BUFFER or DM_OUT_BUFFER); if ExtDevCode <> IDOK then begin {raise an exception} raise EPrinter.Create ('Error updating printer driver.'); end; { if... } end; { if... } FreeLibrary (DrvHandle); end {:} else begin {raise an exception} DriverName := StrPas (FDriver); Raise EPrinter.Create ('Error loading driver '+DriverName); end; { else } end; { TPrintSet.UpdateDeviceMode } procedure TPrintSet.SaveToDefaults; {-updates the default settings for the current printer} var DrvHandle: THandle; ExtDevCaps: TFarProc; DriverName: String; ExtDevCode: Integer; OutDevMode: PDevMode; begin CheckPrinter; DrvHandle := LoadLibrary (FDriver); if DrvHandle <> 0 then begin ExtDevCaps := GetProcAddress (DrvHandle, 'ExtDeviceMode'); if ExtDevCaps<>nil then begin ExtDevCode := TExtDeviceMode (ExtDevCaps) (0, DrvHandle, FDeviceMode^, FDevice, FPort, FDeviceMode^, nil, DM_IN_BUFFER OR DM_UPDATE); if ExtDevCode <> IDOK then begin {raise an exception} raise EPrinter.Create ('Error updating printer driver.'); end {:} else SendMessage ($FFFF, WM_WININICHANGE, 0, 0); end; { if... } FreeLibrary (DrvHandle); end {:} else begin {raise an exception} DriverName := StrPas (FDriver); Raise EPrinter.Create ('Error loading driver '+DriverName); end; { else } end; { TPrintSet.SaveToDefaults } procedure TPrintSet.SavePrinterAsDefault; {-saves the current printer as the Window's default} var DeviceStr: String; begin CheckPrinter; {make sure new printer is loaded} {set the new device setting in the WIN.INI file} DeviceStr := StrPas (FDevice) + ',' + StrPas (FDriver) + ',' + StrPas (FPort) + #0; WriteProfileString ('windows', 'device', @DeviceStr[1]); {force write to WIN.INI} WriteProfileString (nil, nil, nil); {broadcast to everyone that WIN.INI changed} SendMessage ($FFFF, WM_WININICHANGE, 0, 0); end; { TPrintSet.SavePrinterAsDefault } procedure TPrintSet.SetOrientation (Orientation: integer); {-sets the paper orientation} begin CheckPrinter; FDeviceMode^.dmOrientation := Orientation; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_ORIENTATION; end; { TPrintSet.SetOrientation } function TPrintSet.GetOrientation: integer; {-gets the paper orientation} begin CheckPrinter; Result := FDeviceMode^.dmOrientation; end; { TPrintSet.GetOrientation } procedure TPrintSet.SetPaperSize (Size: integer); {-sets the paper size} begin CheckPrinter; FDeviceMode^.dmPaperSize := Size; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_PAPERSIZE; end; { TPrintSet.SetPaperSize } function TPrintSet.GetPaperSize: integer; {-gets the paper size} begin CheckPrinter; Result := FDeviceMode^.dmPaperSize; end; { TPrintSet.GetPaperSize } procedure TPrintSet.SetPaperLength (Length: integer); {-sets the paper length} begin CheckPrinter; FDeviceMode^.dmPaperLength := Length; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_PAPERLENGTH; end; { TPrintSet.SetPaperLength } function TPrintSet.GetPaperLength: integer; {-gets the paper length} begin CheckPrinter; Result := FDeviceMode^.dmPaperLength; end; { TPrintSet.GetPaperLength } procedure TPrintSet.SetPaperWidth (Width: integer); {-sets the paper width} begin CheckPrinter; FDeviceMode^.dmPaperWidth := Width; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_PAPERWIDTH; end; { TPrintSet.SetPaperWidth } function TPrintSet.GetPaperWidth: integer; {-gets the paper width} begin CheckPrinter; Result := FDeviceMode^.dmPaperWidth; end; { TPrintSet.GetPaperWidth } procedure TPrintSet.SetScale (Scale: integer); {-sets the printer scale (whatever that is)} begin CheckPrinter; FDeviceMode^.dmScale := Scale; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_SCALE; end; { TPrintSet.SetScale } function TPrintSet.GetScale: integer; {-gets the printer scale} begin CheckPrinter; Result := FDeviceMode^.dmScale; end; { TPrintSet.GetScale } procedure TPrintSet.SetCopies (Copies: integer); {-sets the number of copies} begin CheckPrinter; FDeviceMode^.dmCopies := Copies; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_COPIES; end; { TPrintSet.SetCopies } function TPrintSet.GetCopies: integer; {-gets the number of copies} begin CheckPrinter; Result := FDeviceMode^.dmCopies; end; { TPrintSet.GetCopies } procedure TPrintSet.SetBin (Bin: integer); {-sets the paper bin} begin CheckPrinter; FDeviceMode^.dmDefaultSource := Bin; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_DEFAULTSOURCE; end; { TPrintSet.SetBin } function TPrintSet.GetBin: integer; {-gets the paper bin} begin CheckPrinter; Result := FDeviceMode^.dmDefaultSource; end; { TPrintSet.GetBin } procedure TPrintSet.SetPrintQuality (Quality: integer); {-sets the print quality} begin CheckPrinter; FDeviceMode^.dmPrintQuality := Quality; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_PRINTQUALITY; end; { TPrintSet.SetPrintQuality } function TPrintSet.GetPrintQuality: integer; {-gets the print quality} begin CheckPrinter; Result := FDeviceMode^.dmPrintQuality; end; { TPrintSet.GetPrintQuality } procedure TPrintSet.SetColor (Color: integer); {-sets the color (monochrome or color)} begin CheckPrinter; FDeviceMode^.dmColor := Color; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_ORIENTATION; end; { TPrintSet.SetColor } function TPrintSet.GetColor: integer; {-gets the color} begin CheckPrinter; Result := FDeviceMode^.dmColor; end; { TPrintSet.GetColor } procedure TPrintSet.SetDuplex (Duplex: integer); {-sets the duplex setting} begin CheckPrinter; FDeviceMode^.dmDuplex := Duplex; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_DUPLEX; end; { TPrintSet.SetDuplex } function TPrintSet.GetDuplex: integer; {-gets the duplex setting} begin CheckPrinter; Result := FDeviceMode^.dmDuplex; end; { TPrintSet.GetDuplex } procedure TPrintSet.SetYResolution (YRes: integer); {-sets the y-resolution of the printer} var PrintDevMode: Print.PDevMode; begin CheckPrinter; PrintDevMode := @FDeviceMode^; PrintDevMode^.dmYResolution := YRes; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_YRESOLUTION; end; { TPrintSet.SetYResolution } function TPrintSet.GetYResolution: integer; {-gets the y-resolution of the printer} var PrintDevMode: Print.PDevMode; begin CheckPrinter; PrintDevMode := @FDeviceMode^; Result := PrintDevMode^.dmYResolution; end; { TPrintSet.GetYResolution } procedure TPrintSet.SetTTOption (Option: integer); {-sets the TrueType option} var PrintDevMode: Print.PDevMode; begin CheckPrinter; PrintDevMode := @FDeviceMode^; PrintDevMode^.dmTTOption := Option; FDeviceMode^.dmFields := FDeviceMode^.dmFields or DM_TTOPTION; end; { TPrintSet.SetTTOption } function TPrintSet.GetTTOption: integer; {-gets the TrueType option} var PrintDevMode: Print.PDevMode; begin CheckPrinter; PrintDevMode := @FDeviceMode^; Result := PrintDevMode^.dmTTOption; end; { TPrintSet.GetTTOption } function TPrintSet.GetPrinterName: string; {-returns the name of the current printer} begin CheckPrinter; Result := StrPas (FDevice); end; { TPrintSet.GetPrinterName } function TPrintSet.GetPrinterPort: string; {-returns the port of the current printer} begin CheckPrinter; Result := StrPas (FPort); end; { TPrintSet.GetPrinterPort } function TPrintSet.GetPrinterDriver: string; {-returns the printer driver name of the current printer} begin CheckPrinter; Result := StrPas (FDriver); end; { TPrintSet.GetPrinterDriver } destructor TPrintSet.Destroy; {-destroys class} begin if FDevice <> nil then FreeMem (FDevice, 255); if FDriver <> nil then FreeMem (FDriver, 255); if FPort <> nil then FreeMem (FPort, 255); inherited Destroy; end; { TPrintSet.Destroy } procedure CanvasTextOutAngle (OutputCanvas: TCanvas; X,Y: integer; Angle: Word; St: string); {-prints text at the desired angle} {-current font must be TrueType!} var LogRec: TLogFont; NewFontHandle: HFont; OldFontHandle: HFont; begin GetObject (OutputCanvas.Font.Handle, SizeOf (LogRec), Addr (LogRec)); LogRec.lfEscapement := Angle; NewFontHandle := CreateFontIndirect (LogRec); OldFontHandle := SelectObject (OutputCanvas.Handle, NewFontHandle); OutputCanvas.TextOut (x, y, St); NewFontHandle := SelectObject (OutputCanvas.Handle, OldFontHandle); DeleteObject (NewFontHandle); end; { CanvasTextOutAngle } procedure SetPixelsPerInch; {-insures that PixelsPerInch is set so that text print at the desired size} var FontSize: integer; begin FontSize := Printer.Canvas.Font.Size; Printer.Canvas.Font.PixelsPerInch := GetDeviceCaps (Printer.Handle, LOGPIXELSY ); Printer.Canvas.Font.Size := FontSize; end; { SetPixelsPerInch } function GetResolution: TPoint; {-returns the resolution of the printer} begin Result.X := GetDeviceCaps(Printer.Handle, LogPixelsX); Result.Y := GetDeviceCaps(Printer.Handle, LogPixelsY); end; { GetResolution } procedure Register; {-registers the printset component} begin RegisterComponents('Domain', [TPrintSet]); end; { Register } end. { EDSPrint }