diff --git a/components/printers/readme.txt b/components/printers/readme.txt index b194c69266..0334fa1021 100644 --- a/components/printers/readme.txt +++ b/components/printers/readme.txt @@ -4,18 +4,23 @@ Printer4Lazarus package This package add some components. TPrinterSetupDialog : for update properties of selected printer TPrintDialog : for select and/or update an printer before printing - TPageSetupDialog : to select margins (currently only under Windows) + TPageSetupDialog : to select margins (currently only under Windows) Win32 : Native implementation + Notes: - 1. TPrinter.CanRenderCopies return information if printer driver is able to print more then one copy at once. - Not all printers drivers support that feature (n that case programmer should print document requested times) + 1. TPrinter.CanRenderCopies return information if printer driver is able to print more then one copy at once. + Not all printers drivers support that feature (n that case programmer should print document requested times) - 2.TPrintDialog.Options indicate which controls should be visible in dialog. - TPrintDialog.PrintToFile indicate that output will be redirected to file. + 2. TPrintDialog.Options indicate which controls should be visible in dialog. + TPrintDialog.PrintToFile indicate that output will be redirected to file. + + 3. Known Issue: After adjusting resolution using Printer.AdvancedProperties. The DevMode structure + shows the change correcly, but getting the value through Printer.XDPI the value is the old one. + However after using the PrintSetup dialog, it returns the correct value. Other changes like + the selected paper are correctly modified after AdvancedProperties, ... (?). - 3.Some (mostly advanced) settings of printer driver are not preserved between two calls to TPrintDialog.Execute function. Linux : diff --git a/components/printers/sample/frmselprinter.lfm b/components/printers/sample/frmselprinter.lfm index 29ca87fe25..397a0763a4 100644 --- a/components/printers/sample/frmselprinter.lfm +++ b/components/printers/sample/frmselprinter.lfm @@ -1,16 +1,16 @@ object Form1: TForm1 ActiveControl = Button2 Caption = 'Form1' - ClientHeight = 487 + ClientHeight = 507 ClientWidth = 339 OnCreate = FormCreate PixelsPerInch = 96 Position = poDesktopCenter HorzScrollBar.Page = 338 - VertScrollBar.Page = 486 - Left = 230 - Height = 487 - Top = 36 + VertScrollBar.Page = 506 + Left = 190 + Height = 507 + Top = 45 Width = 339 object Label1: TLabel Caption = 'This sample show how to use the printer dialogs' @@ -19,10 +19,10 @@ object Form1: TForm1 Left = 16 Height = 14 Top = 8 - Width = 226 + Width = 230 end object Button2: TButton - + BorderSpacing.InnerBorder = 4 Caption = 'Execute TPrinterSetupDialog' OnClick = Button2Click TabOrder = 0 @@ -32,7 +32,7 @@ object Form1: TForm1 Width = 320 end object Button1: TButton - + BorderSpacing.InnerBorder = 4 Caption = 'Execute TPrintDialog' OnClick = Button1Click TabOrder = 1 @@ -60,15 +60,17 @@ object Form1: TForm1 Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goSmoothScroll] RowCount = 15 ScrollBars = ssAutoBoth + TabOrder = 7 + TabStop = True VisibleColCount = 1 VisibleRowCount = 14 Left = 8 - Height = 288 + Height = 304 Top = 192 Width = 320 end object Button3: TButton - + BorderSpacing.InnerBorder = 4 Caption = 'Get default printer info' OnClick = Button3Click TabOrder = 2 @@ -78,7 +80,7 @@ object Form1: TForm1 Width = 320 end object Button4: TButton - + BorderSpacing.InnerBorder = 4 Caption = 'Print test' OnClick = Button4Click TabOrder = 3 @@ -88,7 +90,7 @@ object Form1: TForm1 Width = 69 end object Button5: TButton - + BorderSpacing.InnerBorder = 4 Caption = 'Update printer state info' OnClick = Button5Click TabOrder = 4 @@ -98,7 +100,7 @@ object Form1: TForm1 Width = 224 end object Button6: TButton - + BorderSpacing.InnerBorder = 4 Caption = 'Show printer properties' OnClick = Button6Click TabOrder = 5 @@ -108,7 +110,7 @@ object Form1: TForm1 Width = 224 end object Button7: TButton - + BorderSpacing.InnerBorder = 4 Caption = 'Execute TPageSetupDialog' OnClick = Button7Click TabOrder = 6 diff --git a/components/printers/sample/frmselprinter.lrs b/components/printers/sample/frmselprinter.lrs index 558d425e91..31603d9a02 100644 --- a/components/printers/sample/frmselprinter.lrs +++ b/components/printers/sample/frmselprinter.lrs @@ -1,40 +1,45 @@ +{ This is an automatically generated lazarus resource file } + LazarusResources.Add('TForm1','FORMDATA',[ 'TPF0'#6'TForm1'#5'Form1'#13'ActiveControl'#7#7'Button2'#7'Caption'#6#5'Form1' - +#12'ClientHeight'#3#231#1#11'ClientWidth'#3'S'#1#8'OnCreate'#7#10'FormCreate' + +#12'ClientHeight'#3#251#1#11'ClientWidth'#3'S'#1#8'OnCreate'#7#10'FormCreate' +#13'PixelsPerInch'#2'`'#8'Position'#7#15'poDesktopCenter'#18'HorzScrollBar.P' - +'age'#3'R'#1#18'VertScrollBar.Page'#3#230#1#4'Left'#3#230#0#6'Height'#3#231#1 - +#3'Top'#2'$'#5'Width'#3'S'#1#0#6'TLabel'#6'Label1'#7'Caption'#6'/This sample' + +'age'#3'R'#1#18'VertScrollBar.Page'#3#250#1#4'Left'#3#190#0#6'Height'#3#251#1 + +#3'Top'#2'-'#5'Width'#3'S'#1#0#6'TLabel'#6'Label1'#7'Caption'#6'/This sample' +' show how to use the printer dialogs'#5'Color'#7#6'clNone'#11'ParentColor'#8 - +#4'Left'#2#16#6'Height'#2#14#3'Top'#2#8#5'Width'#3#226#0#0#0#7'TButton'#7'Bu' - +'tton2'#7'Caption'#6#27'Execute TPrinterSetupDialog'#7'OnClick'#7#12'Button2' - +'Click'#8'TabOrder'#2#0#4'Left'#2#8#6'Height'#2#27#3'Top'#2'3'#5'Width'#3'@' - +#1#0#0#7'TButton'#7'Button1'#7'Caption'#6#20'Execute TPrintDialog'#7'OnClick' - +#7#12'Button1Click'#8'TabOrder'#2#1#4'Left'#2#8#6'Height'#2#27#3'Top'#2'N'#5 - +'Width'#3'@'#1#0#0#11'TStringGrid'#5'SGrid'#15'AutoFillColumns'#9#11'BorderS' - +'tyle'#7#6'bsNone'#8'ColCount'#2#2#7'Columns'#14#1#7'MinSize'#2'<'#7'MaxSize' - +#3'^'#1#8'ReadOnly'#9#13'Title.Caption'#6#11'Information'#5'Width'#3#230#0#0 - +#0#15'DefaultColWidth'#2'Z'#10'FixedColor'#7#9'clBtnFace'#4'Flat'#9#13'GridL' - +'ineWidth'#2#0#7'Options'#11#15'goFixedVertLine'#15'goFixedHorzLine'#10'goVe' - +'rtLine'#10'goHorzLine'#13'goRangeSelect'#14'goSmoothScroll'#0#8'RowCount'#2 - +#15#10'ScrollBars'#7#10'ssAutoBoth'#15'VisibleColCount'#2#1#15'VisibleRowCou' - +'nt'#2#14#4'Left'#2#8#6'Height'#3' '#1#3'Top'#3#192#0#5'Width'#3'@'#1#0#0#7 - +'TButton'#7'Button3'#7'Caption'#6#24'Get default printer info'#7'OnClick'#7 - +#12'Button3Click'#8'TabOrder'#2#2#4'Left'#2#8#6'Height'#2#27#3'Top'#2'i'#5'W' - +'idth'#3'@'#1#0#0#7'TButton'#7'Button4'#7'Caption'#6#10'Print test'#7'OnClic' - +'k'#7#12'Button4Click'#8'TabOrder'#2#3#4'Left'#3#0#1#6'Height'#2#27#3'Top'#3 - +#155#0#5'Width'#2'E'#0#0#7'TButton'#7'Button5'#7'Caption'#6#25'Update printe' - +'r state info'#7'OnClick'#7#12'Button5Click'#8'TabOrder'#2#4#4'Left'#2#8#6'H' - +'eight'#2#25#3'Top'#3#132#0#5'Width'#3#224#0#0#0#7'TButton'#7'Button6'#7'Cap' - +'tion'#6#23'Show printer properties'#7'OnClick'#7#12'Button6Click'#8'TabOrde' - +'r'#2#5#4'Left'#2#8#6'Height'#2#25#3'Top'#3#157#0#5'Width'#3#224#0#0#0#7'TBu' - +'tton'#7'Button7'#7'Caption'#6#24'Execute TPageSetupDialog'#7'OnClick'#7#12 - +'Button7Click'#8'TabOrder'#2#6#4'Left'#2#8#6'Height'#2#27#3'Top'#2#24#5'Widt' - +'h'#3'@'#1#0#0#19'TPrinterSetupDialog'#3'PSD'#5'Title'#6#20'Testing dialog t' - +'itle'#4'left'#3#176#0#3'top'#3#240#0#0#0#12'TPrintDialog'#2'PD'#7'Collate'#9 - +#6'Copies'#2#1#8'FromPage'#2#2#7'MinPage'#2#2#7'MaxPage'#2#5#7'Options'#11#13 - +'poPrintToFile'#10'poPageNums'#11'poSelection'#9'poWarning'#6'poHelp'#0#11'P' - +'rintToFile'#9#6'ToPage'#2#3#5'Title'#6#13'Testing title'#4'left'#3#176#0#3 - +'top'#3#16#1#0#0#10'TPopupMenu'#10'PopupMenu1'#4'left'#3#216#0#3'top'#3#240#0 - +#0#0#16'TPageSetupDialog'#5'PAGED'#5'Title'#6#25'Ustawienie strony raportu'#4 - +'left'#3#176#0#3'top'#3'0'#1#0#0#0 + +#4'Left'#2#16#6'Height'#2#14#3'Top'#2#8#5'Width'#3#230#0#0#0#7'TButton'#7'Bu' + +'tton2'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#27'Execute TPrinterSe' + +'tupDialog'#7'OnClick'#7#12'Button2Click'#8'TabOrder'#2#0#4'Left'#2#8#6'Heig' + +'ht'#2#27#3'Top'#2'3'#5'Width'#3'@'#1#0#0#7'TButton'#7'Button1'#25'BorderSpa' + +'cing.InnerBorder'#2#4#7'Caption'#6#20'Execute TPrintDialog'#7'OnClick'#7#12 + +'Button1Click'#8'TabOrder'#2#1#4'Left'#2#8#6'Height'#2#27#3'Top'#2'N'#5'Widt' + +'h'#3'@'#1#0#0#11'TStringGrid'#5'SGrid'#15'AutoFillColumns'#9#11'BorderStyle' + +#7#6'bsNone'#8'ColCount'#2#2#7'Columns'#14#1#7'MinSize'#2'<'#7'MaxSize'#3'^' + +#1#8'ReadOnly'#9#13'Title.Caption'#6#11'Information'#5'Width'#3#230#0#0#0#15 + +'DefaultColWidth'#2'Z'#10'FixedColor'#7#9'clBtnFace'#4'Flat'#9#13'GridLineWi' + +'dth'#2#0#7'Options'#11#15'goFixedVertLine'#15'goFixedHorzLine'#10'goVertLin' + +'e'#10'goHorzLine'#13'goRangeSelect'#14'goSmoothScroll'#0#8'RowCount'#2#15#10 + +'ScrollBars'#7#10'ssAutoBoth'#8'TabOrder'#2#7#7'TabStop'#9#15'VisibleColCoun' + +'t'#2#1#15'VisibleRowCount'#2#14#4'Left'#2#8#6'Height'#3'0'#1#3'Top'#3#192#0 + +#5'Width'#3'@'#1#0#0#7'TButton'#7'Button3'#25'BorderSpacing.InnerBorder'#2#4 + +#7'Caption'#6#24'Get default printer info'#7'OnClick'#7#12'Button3Click'#8'T' + +'abOrder'#2#2#4'Left'#2#8#6'Height'#2#27#3'Top'#2'i'#5'Width'#3'@'#1#0#0#7'T' + +'Button'#7'Button4'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#10'Print ' + +'test'#7'OnClick'#7#12'Button4Click'#8'TabOrder'#2#3#4'Left'#3#0#1#6'Height' + +#2#27#3'Top'#3#155#0#5'Width'#2'E'#0#0#7'TButton'#7'Button5'#25'BorderSpacin' + +'g.InnerBorder'#2#4#7'Caption'#6#25'Update printer state info'#7'OnClick'#7 + +#12'Button5Click'#8'TabOrder'#2#4#4'Left'#2#8#6'Height'#2#25#3'Top'#3#132#0#5 + +'Width'#3#224#0#0#0#7'TButton'#7'Button6'#25'BorderSpacing.InnerBorder'#2#4#7 + +'Caption'#6#23'Show printer properties'#7'OnClick'#7#12'Button6Click'#8'TabO' + +'rder'#2#5#4'Left'#2#8#6'Height'#2#25#3'Top'#3#157#0#5'Width'#3#224#0#0#0#7 + +'TButton'#7'Button7'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#24'Execu' + +'te TPageSetupDialog'#7'OnClick'#7#12'Button7Click'#8'TabOrder'#2#6#4'Left'#2 + +#8#6'Height'#2#27#3'Top'#2#24#5'Width'#3'@'#1#0#0#19'TPrinterSetupDialog'#3 + +'PSD'#5'Title'#6#20'Testing dialog title'#4'left'#3#176#0#3'top'#3#240#0#0#0 + +#12'TPrintDialog'#2'PD'#7'Collate'#9#6'Copies'#2#1#8'FromPage'#2#2#7'MinPage' + +#2#2#7'MaxPage'#2#5#7'Options'#11#13'poPrintToFile'#10'poPageNums'#11'poSele' + +'ction'#9'poWarning'#6'poHelp'#0#11'PrintToFile'#9#6'ToPage'#2#3#5'Title'#6 + +#13'Testing title'#4'left'#3#176#0#3'top'#3#16#1#0#0#10'TPopupMenu'#10'Popup' + +'Menu1'#4'left'#3#216#0#3'top'#3#240#0#0#0#16'TPageSetupDialog'#5'PAGED'#5'T' + +'itle'#6#25'Ustawienie strony raportu'#4'left'#3#176#0#3'top'#3'0'#1#0#0#0 ]); diff --git a/components/printers/sample/frmselprinter.pas b/components/printers/sample/frmselprinter.pas index 0f710d4670..3685acfdd7 100644 --- a/components/printers/sample/frmselprinter.pas +++ b/components/printers/sample/frmselprinter.pas @@ -97,11 +97,11 @@ begin poReverseLandscape : AddInfo('Orientation','ReverseLandscape'); poReversePortrait :AddInfo('Orientation','ReversePortrait'); end; - AddInfo('XDPI',IntToStr(XDPI)); - AddInfo('YDPI',IntToStr(YDPI)); + AddInfo('XDPI',IntToStr(XDPI)+' dpi'); + AddInfo('YDPI',IntToStr(YDPI)+' dpi'); AddInfo('Copies',IntToStr(Copies)); - AddInfo('PageHeight',IntToStr(PageHeight)); - AddInfo('PageWidth',IntToStr(PageWidth)); + AddInfo('PageHeight',IntToStr(PageHeight)+' dots (printable size)'); + AddInfo('PageWidth',IntToStr(PageWidth)+' dots (printable size)'); case PrinterType of ptLocal: AddInfo('PrinterType','Local'); ptNetWork: AddInfo('PrinterType','Network'); @@ -168,6 +168,7 @@ begin {$ELSE} ShowMessage('Printer.AdvancedProperties is not yet implemented for this platform'); {$ENDIF} + UpdatePrinterInfo; end; procedure TForm1.Button7Click(Sender: TObject); diff --git a/components/printers/sample/selectprinter.lpi b/components/printers/sample/selectprinter.lpi index 2f1f35df43..2e5ee605a2 100644 --- a/components/printers/sample/selectprinter.lpi +++ b/components/printers/sample/selectprinter.lpi @@ -1,60 +1,21 @@ - + - + - <ActiveEditorIndexAtStart Value="0"/> </General> - <LazDoc Paths=""/> - <Units Count="4"> - <Unit0> - <CursorPos X="19" Y="15"/> - <Filename Value="selectprinter.lpr"/> - <IsPartOfProject Value="True"/> - <TopLine Value="1"/> - <UnitName Value="selectprinter"/> - <UsageCount Value="154"/> - </Unit0> - <Unit1> - <CursorPos X="34" Y="109"/> - <EditorIndex Value="0"/> - <Filename Value="frmselprinter.pas"/> - <ComponentName Value="Form1"/> - <IsPartOfProject Value="True"/> - <Loaded Value="True"/> - <ResourceFilename Value="frmselprinter.lrs"/> - <TopLine Value="81"/> - <UnitName Value="frmselprinter"/> - <UsageCount Value="154"/> - </Unit1> - <Unit2> - <CursorPos X="10" Y="296"/> - <Filename Value="C:/lazarus/components/PRINTERS/WIN32/winprndialogs.inc"/> - <IsPartOfProject Value="True"/> - <TopLine Value="1"/> - <UnitName Value="text"/> - <UsageCount Value="100"/> - </Unit2> - <Unit3> - <CursorPos X="1" Y="1"/> - <Filename Value="C:/lazarus/components/PRINTERS/LINUX/cupsprndialogs.inc"/> - <IsPartOfProject Value="True"/> - <TopLine Value="1"/> - <UnitName Value="text"/> - <UsageCount Value="100"/> - </Unit3> - </Units> <PublishOptions> <Version Value="2"/> + <DestinationDirectory Value="$(TestDir)\publishedproject\"/> <IgnoreBinaries Value="False"/> <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> @@ -62,7 +23,7 @@ <RunParams> <local> <FormatVersion Value="1"/> - <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> + <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/> </local> </RunParams> <RequiredPackages Count="2"> @@ -74,11 +35,34 @@ <PackageName Value="LCL"/> </Item2> </RequiredPackages> + <Units Count="4"> + <Unit0> + <Filename Value="selectprinter.lpr"/> + <IsPartOfProject Value="True"/> + <UnitName Value="selectprinter"/> + </Unit0> + <Unit1> + <Filename Value="frmselprinter.pas"/> + <ComponentName Value="Form1"/> + <IsPartOfProject Value="True"/> + <ResourceFilename Value="frmselprinter.lrs"/> + <UnitName Value="frmselprinter"/> + </Unit1> + <Unit2> + <Filename Value="..\..\..\..\..\..\..\lazarus\components\PRINTERS\WIN32\winprndialogs.inc"/> + <IsPartOfProject Value="True"/> + </Unit2> + <Unit3> + <Filename Value="..\..\..\..\..\..\..\lazarus\components\PRINTERS\LINUX\cupsprndialogs.inc"/> + <IsPartOfProject Value="True"/> + </Unit3> + </Units> </ProjectOptions> <CompilerOptions> <Version Value="5"/> + <PathDelim Value="\"/> <SearchPaths> - <SrcPath Value="$(LazarusDir)/lcl/;$(LazarusDir)/lcl/interfaces/$(LCLWidgetType)/"/> + <SrcPath Value="$(LazarusDir)\lcl\;$(LazarusDir)\lcl\interfaces\$(LCLWidgetType)\"/> </SearchPaths> <Parsing> <SyntaxOptions> @@ -110,26 +94,4 @@ </Other> <CompileReasons Run="False"/> </CompilerOptions> - <Debugging> - <Watches Count="6"> - <Item1> - <Expression Value="lpp.nCopies"/> - </Item1> - <Item2> - <Expression Value="DevMode^.dmCopies"/> - </Item2> - <Item3> - <Expression Value="PDev.DevMode.dmDriverExtra"/> - </Item3> - <Item4> - <Expression Value="AName"/> - </Item4> - <Item5> - <Expression Value="Pdev.name"/> - </Item5> - <Item6> - <Expression Value="pdev.name"/> - </Item6> - </Watches> - </Debugging> </CONFIG> diff --git a/components/printers/win32/winprinters.inc b/components/printers/win32/winprinters.inc index 621b3ce07d..b7b0ae5f04 100644 --- a/components/printers/win32/winprinters.inc +++ b/components/printers/win32/winprinters.inc @@ -1,8 +1,24 @@ +{%MainUnit ../osprinters.pas} {************************************************************** Implementation for winprinter ***************************************************************} Uses WinUtilPrn, InterfaceBase, Win32Int, LCLIntf,WinVer; +// todo: this ^ is a mess: mixed WinUtilPrn/Windows units clean... + +// todo: this should be a method, cant be atm because mixed units ^ +function GetCurrentDevMode(var DM:PDeviceMode): boolean; +var + PDev: TPrinterDevice; +begin + result := false; + if (Printer.Printers.Count>0) then + begin + PDev:=TPrinterDevice(Printer.Printers.Objects[Printer.PrinterIndex]); + DM := PDev.DevMode; + result := DM<>nil; + end; +end; { TWinPrinter } @@ -69,12 +85,13 @@ begin if (fLastHandleType=0) and (Printers.Count>0) then begin PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); + fDC:=CreateIC(PChar(PDev.Driver),PChar(PDev.Device), - PChar(PDev.Port),@PDev.DevMode); + PChar(PDev.Port),PDev.DevMode); if fDC=0 then fDC:=CreateIC(PChar('WINSPOOL'),PChar(PDev.Device), - PChar(PDev.Port),@PDev.DevMode); + PChar(PDev.Port),PDev.DevMode); if fDC=0 then raise EPrinter.Create(Format('Invalid printer (DC=%d Driver=%s Device=%s Port=%s)',[fDC,Pdev.Driver,PDev.Device,PDev.Port])); @@ -93,16 +110,17 @@ begin PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); try - //Device is only 32 chars long, if the Printername or share is longer than 32 chars, this will return 0 - fDC:=CreateDC(nil,PChar(Printers[PrinterIndex]),nil,@PDev.DevMode); + //Device is only 32 chars long, + //if the Printername or share is longer than 32 chars, this will return 0 + fDC:=CreateDC(nil,PChar(Printers[PrinterIndex]),nil, PDev.DevMode); if fDC=0 then - fDC:=CreateDC(PChar('WINSPOOL'),PChar(Printers[PrinterIndex]),nil,@PDev.DevMode); + fDC:=CreateDC(PChar('WINSPOOL'),PChar(Printers[PrinterIndex]),nil,PDev.DevMode); {Workaround (hack) for Lexmark 1020 JetPrinter (Mono)} if fDC=0 then - fDC:=CreateDC(nil,PChar(PDev.Driver),nil,@PDev.DevMode); + fDC:=CreateDC(nil,PChar(PDev.Driver),nil, PDev.DevMode); if fDC=0 then - fDC:=CreateDC(pChar('WINSPOOL'),PChar(PDev.Driver),nil,@PDev.DevMode); + fDC:=CreateDC(pChar('WINSPOOL'),PChar(PDev.Driver),nil,PDev.DevMode); except on E:Exception do raise EPrinter.Create(Format('CreateDC exception: %s (LastError : %s,DC=%d Driver="%s" Device="%s" Port="%s")',[E.Message,SysErrorMessage(GetLastError),fDC,Pdev.Driver,Printers[PrinterIndex],PDev.Port])); @@ -129,6 +147,41 @@ begin fLastHandleType:=0; end; + +// Based on MS Article Q167345 +procedure TWinPrinter.UpdateDevMode; +var + PDev: TPrinterDevice; + dwRet: Integer; +begin + // now we have a right FPrinterHandle, get current printer settings + PDev := TPrinterDevice(Printers.Objects[PrinterIndex]); + + // allocate a new Devmode + if (Pdev.DevMode=nil) then begin + + // 1. Determine the required size of the buffer from the device, + // and then allocate enough memory for it. + PDev.DevModeSize:=DocumentProperties(0, FPrinterHandle, pchar(PDev.Name), + nil, nil, 0); + if PDev.DevModeSize<=0 then begin + // error + exit; + end; + GetMem(PDev.DevMode, PDev.DevModeSize); + + // 2. Ask the device driver to initialize the DEVMODE buffer with + // the default settings. + dwRet := DocumentProperties(0, FPrinterHandle, pchar(Pdev.Name), + PDev.DevMode, nil, DM_OUT_BUFFER); + if (dwRet<>IDOK) then begin + FreeMem(PDev.DevMode); + PDev.DevMode:=nil; + end; + end; + +end; + procedure TWinPrinter.DoBeginDoc; var Inf: TDocInfo; begin @@ -184,6 +237,7 @@ Var Flags : DWORD; i : Integer; DefaultPrinter : array[0..79] of Char; PDev : TPrinterDevice; + TmpDevMode : PDeviceMode; begin Level:=5; //Compatible with all Win32 versions DefaultPrinter:=''; @@ -221,6 +275,7 @@ begin if Needed<>0 then begin GetMem(Buffer,Needed); + Fillchar(Buffer^, Needed, 0); try //Enumerate Printers if EnumPrinters(Flags,nil,Level,Buffer,Needed,Needed,PrtCount) then @@ -234,10 +289,17 @@ begin PDev.Name :=PPRINTER_INFO_2(InfoPrt)^.pPrinterName; PDev.Driver:=PPRINTER_INFO_2(InfoPrt)^.pDriverName; PDev.Port :=PPRINTER_INFO_2(InfoPrt)^.pPortName; - if PPRINTER_INFO_2(InfoPrt)^.PDevMode <> nil then begin - PDev.DevMode:=PPRINTER_INFO_2(InfoPrt)^.PDevMode^; - PDev.Device:=PDev.DevMode.dmDeviceName; - PDev.DefaultPaper:=PDev.DevMode.dmPaperSize; + TmpDevMode :=PPRINTER_INFO_2(InfoPrt)^.pDevMode; + if TmpDevMode<>nil then begin + // the devmode structure obtained this way have two problems + // 1. It's not the full devmode, because it doesn't have + // the private info + // 2. It's not initialized with the current settings and + // have not extra settings at all. + // + // PDev.DevMode:=PPRINTER_INFO_2(InfoPrt)^.PDevMode^; + PDev.Device:= TmpDevMode^.dmDeviceName; //PDev.DevMode.dmDeviceName; + PDev.DefaultPaper:=TmpDevMode^.dmPaperSize; //PDev.DevMode.dmPaperSize; end else begin PDev.Device:=''; @@ -326,19 +388,17 @@ begin end; function TWinPrinter.DoGetPaperName: string; -var i : Integer; - PDev : TPrinterDevice; +var + i : Integer; + dm : PDeviceMode; begin Result:=inherited DoGetPaperName; - - if (Printers.Count>0) then - begin - PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); - - i:=PaperSize.SupportedPapers.IndexOfObject(TObject(ptrint(PDev.Devmode.dmPaperSize))); - if i<>-1 then - Result:=PaperSize.SupportedPapers.Strings[i]; - end; + if GetCurrentDevMode(dm) then + with PaperSize.SupportedPapers do begin + i := IndexOfObject(TObject(ptrInt(dm^.dmPaperSize))); + if i>=0 then + result := PaperSize.SupportedPapers[i]; + end; end; function TWinPrinter.DoGetDefaultPaperName: string; @@ -359,22 +419,14 @@ end; procedure TWinPrinter.DoSetPaperName(aName: string); var i : Integer; - PDev : TPrinterDevice; - j : SHORT; + dm : PDeviceMode; begin inherited DoSetPaperName(aName); - - if (Printers.Count>0) then - begin - - PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); - + if GetCurrentDevMode(dm) then begin i:=PaperSize.SupportedPapers.IndexOf(aName); - if i<>-1 then - begin + if i<>-1 then begin ClearDC; - j:=SHORT(ptrint(PaperSize.SupportedPapers.Objects[i])); - PDev.DevMode.dmPaperSize:=j; + dm^.dmPaperSize := SHORT(ptrint(PaperSize.SupportedPapers.Objects[i])); end; end; end; @@ -388,20 +440,50 @@ begin if (Printers.Count>0) then begin - PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); + // Information for physical sizes can be obtained for any paper supported + // by the printer, the same is not true for printable paper size, this can + // be obtained only(?) for currently selected paper. + // + if DoGetPaperName=AName then begin + SetDC; + with aPaperRC.PhysicalRect do begin + Left :=0; + Top :=0; + Right :=Windows.GetDeviceCaps(fDC, PHYSICALWIDTH); + Bottom:=Windows.GetDeviceCaps(fDC, PHYSICALHEIGHT); + end; + with aPaperRC.WorkRect do begin + Left :=Windows.GetDeviceCaps(fDC, PHYSICALOFFSETX); + Top :=Windows.GetDeviceCaps(fDC, PHYSICALOFFSETY); + Right :=Left + Windows.GetDeviceCaps(fDC, HORZRES); + Bottom:=Bottom + Windows.GetDeviceCaps(fDC, VERTRES); + end; + end else begin + // for other papers return at least the physical size + // note: old implementation was using DeviceCapabilities function with + // index DC_PAPERSIZE, unfortunately this returns dimensions in + // tenths of millimeter which is wrong, we need points (not font + // points, but printer "pixels" at current resolution). + // + PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); - //Retreive the Width and Height of aName paper - FillChar(ArSizes,SizeOf(ArSizes),0); - NSize:=DeviceCapabilities(PChar(Pdev.Name),PChar(PDev.Port), - DC_PAPERSIZE,@ArSizes,nil); - i:=PaperSize.SupportedPapers.IndexOf(aName); - if (i>=0) and (i<NSize) and (NSize<>0) then - begin - aPaperRc.PhysicalRect:=Classes.Rect(0,0,ArSizes[i].X,ArSizes[i].Y); - aPaperRc.WorkRect:=Classes.Rect(0,0,ArSizes[i].X,ArSizes[i].Y); - - Result:=1; + //Retreive the Width and Height of aName paper + FillChar(ArSizes,SizeOf(ArSizes),0); + NSize:=DeviceCapabilities(PChar(Pdev.Name),PChar(PDev.Port), + DC_PAPERSIZE,@ArSizes,nil); + i:=PaperSize.SupportedPapers.IndexOf(aName); + if (i>=0) and (i<NSize) and (NSize<>0) then + begin + aPaperRc.PhysicalRect:=Classes.Rect(0,0,ArSizes[i].X,ArSizes[i].Y); + with aPaperRC.PhysicalRect do begin + // convert from tenths of millimeter to points + Right := round(Right * XDPI / 254); + Bottom := round(Bottom* YDPI / 254); + end; + aPaperRc.WorkRect := aPaperRC.PhysicalRect; + end; end; + Result:=1; end; end; @@ -418,68 +500,57 @@ begin PDev:=TPrinterDevice(Printers.Objects[i]); if fPrinterHandle<>0 then ClosePrinter(fPrinterHandle); - - if not OpenPrinter(PChar(PDev.Name),fPrinterHandle,nil) then - raise EPrinter.CreateFmt('OpenPrinter exception : %s',[SysErrorMessage(GetlastError)]); + if not OpenPrinter(PChar(PDev.Name),fPrinterHandle, nil) then + raise EPrinter.CreateFmt('OpenPrinter exception : %s',[SysErrorMessage(GetlastError)]) + else + UpdateDevMode; Result:=i; end; end; function TWinPrinter.DoGetCopies: Integer; -var PDev : TPrinterDevice; +var + dm: PDeviceMode; begin Result:=inherited DoGetCopies; - - if (Printers.Count>0) then - begin - PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); - - if PDev.DevMode.dmCopies<>0 then - Result:=PDev.DevMode.dmCopies; + if GetCurrentDevMode(dm) then begin + if dm^.dmCopies<>0 then + result := dm^.dmCopies; end; end; procedure TWinPrinter.DoSetCopies(aValue: Integer); -var PDev : TPrinterDevice; +var + dm: PDeviceMode; begin inherited DoSetCopies(aValue); - - if (Printers.Count>0) and (aValue>0) then - begin - PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); - + if (AValue>0) and GetCurrentDevMode(dm) then begin ClearDC; - PDev.DevMode.dmCopies:=SHORT(aValue); + dm^.dmCopies := SHORT(aValue) end; end; function TWinPrinter.DoGetOrientation: TPrinterOrientation; -var PDev : TPrinterDevice; +var + dm: PDeviceMode; begin Result:=inherited DoGetOrientation; - - if (Printers.Count>0) then - begin - PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); - - Case PDev.DevMode.dmOrientation of - DMORIENT_PORTRAIT : Result:=poPortrait; - DMORIENT_LANDSCAPE : Result:=poLandscape; + if GetCurrentDevMode(dm) then begin + case dm^.dmOrientation of + DMORIENT_PORTRAIT : result:=poPortrait; + DMORIENT_LANDSCAPE: result:=poLandscape; end; end; end; procedure TWinPrinter.DoSetOrientation(aValue: TPrinterOrientation); -var PDev : TPrinterDevice; +var + dm: PDeviceMode; begin inherited DoSetOrientation(aValue); - - if (Printers.Count>0) then - begin - PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); - + if GetCurrentDevMode(dm) then begin ClearDC; - PDev.DevMode.dmOrientation:=Win32Orientations[aValue]; + dm^.dmOrientation := Win32Orientations[aValue]; end; end; @@ -566,14 +637,23 @@ begin if (Printers.Count>0) then begin PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); - Count := DeviceCapabilities(PChar(Pdev.Name),PCHar(PDev.Port),DC_COPIES,nil,@PDev.DevMode); - Result := (Count > 1); - end; + Count := DeviceCapabilities(PChar(Pdev.Name),PCHar(PDev.Port),DC_COPIES,nil,PDev.DevMode); + Result := (Count>1); + end; end; procedure TWinPrinter.AdvancedProperties; +var + PDev: TPrinterDevice; begin - PrinterProperties(TWin32WidgetSet(WidgetSet).AppHandle,fPrinterHandle); + PDev:=TPrinterDevice(Printers.Objects[PrinterIndex]); + DocumentProperties( + TWin32WidgetSet(WidgetSet).AppHandle, + FPrinterHandle, + pchar(PDev.Name), + Pdev.DevMode, Pdev.DevMode, + DM_OUT_BUFFER or DM_IN_BUFFER or DM_IN_PROMPT); + //PrinterProperties(TWin32WidgetSet(WidgetSet).AppHandle,fPrinterHandle) end; initialization diff --git a/components/printers/win32/winprinters_h.inc b/components/printers/win32/winprinters_h.inc index 8e204d1e6a..322b41d4bd 100644 --- a/components/printers/win32/winprinters_h.inc +++ b/components/printers/win32/winprinters_h.inc @@ -1,3 +1,4 @@ +{%MainUnit ../osprinters.pas} { Author: Olivier Guilbaud @@ -41,7 +42,7 @@ Type procedure SetIC; procedure SetDC; procedure ClearDC; - + procedure UpdateDevMode; protected //function GetDefaultPrinter : String; diff --git a/components/printers/win32/winprndialogs.inc b/components/printers/win32/winprndialogs.inc index 2bf31bac79..5331472629 100644 --- a/components/printers/win32/winprndialogs.inc +++ b/components/printers/win32/winprndialogs.inc @@ -1,3 +1,4 @@ +{%MainUnit ../printersdlgs.pp} Uses Windows,WinUtilPrn, InterfaceBase, Win32Int, LCLIntf,LCLType,WinVer; @@ -20,36 +21,26 @@ begin if Printer.Printers.Count>0 then begin FillChar(lpp,SizeOf(lpp),0); - with lpp do - begin + with lpp do begin lStructSize:=SizeOf(lpp); hInstance:=LCLType.HInstance; Flags := PSD_MARGINS; hWndOwner:=TWin32WidgetSet(WidgetSet).AppHandle; rtMargin := fMargins; PDev:=TPrinterDevice(Printer.Printers.Objects[Printer.PrinterIndex]); - Size := DeviceCapabilities(PChar(PDev.Name),PChar(PDev.Port),DC_SIZE,nil,nil); - Extra := DeviceCapabilities(PChar(PDev.Name),PChar(PDev.Port),DC_EXTRA,nil,nil); - Fields := DeviceCapabilities(PChar(PDev.Name),PChar(PDev.Port),DC_FIELDS,nil,nil); - DeviceMode:=GlobalAlloc(GHND,Size + Extra); + // Pdev.DevMode has the required size, just copy to the global memory + DeviceMode:=GLobalAlloc(GHND, PDev.DevModeSize); try - DevMode:=PDeviceMode(GlobalLock(DeviceMode)); - try - CopyMemory(DevMode,@PDev.DevMode,SizeOf(PDev.DevMode)); - DevMode^.dmSize := Word(Size); - DevMode^.dmDriverExtra := Word(Extra); - DevMode^.dmFields := Fields; - finally - GlobalUnLock(DeviceMode); - end; - - hDevMode:= DeviceMode; - if PageSetupDlg(lpp) then - begin - St:=''; - //Change Selected printer - if lpp.hDevNames<>0 then - begin + DevMode:=PDeviceMode(GlobalLock(DeviceMode)); + try + CopyMemory(DevMode, PDev.DevMode, Pdev.DevModeSize); + finally + GlobalUnlock(DeviceMode); + end; + hDevMode:=DeviceMode; + if PageSetupDlg(Lpp) then begin + St :=''; + if Lpp.HdevNames<>0 then begin DevNames:=PDevNames(GlobalLock(lpp.hDevNames)); try St:=PChar(DevNames)+DevNames^.wDeviceOffset; @@ -59,11 +50,12 @@ begin GlobalFree(lpp.hDevNames); end; end; - + Result:=True; - if (Flags and PSD_INHUNDREDTHSOFMILLIMETERS)>0 then fUnits := unMM + if (Flags and PSD_INHUNDREDTHSOFMILLIMETERS)>0 then + fUnits := unMM else - fUnits := unInch; + fUnits := unInch; fMargins := rtMargin; if lpp.hDevMode<>0 then @@ -72,10 +64,7 @@ begin try //Set the properties for the selected printer PDev:=TPrinterDevice(Printer.Printers.Objects[Printer.PrinterIndex]); - CopyMemory(@PDev.DevMode,DevMode,sizeof(Pdev.DevMode)); - PDev.DevMode.dmSize := SizeOf(PDev.DevMode); - PDev.DevMode.dmDriverExtra := 0; - PDev.DevMode.dmPaperSize := DevMode^.dmPaperSize; + CopyMemory(PDev.DevMode,DevMode,PDev.DevModeSize); finally GlobalUnlock(lpp.hDevMode); end; @@ -113,25 +102,18 @@ begin hInstance:=LCLType.HInstance; Flags:= PD_PRINTSETUP or PD_RETURNDC; hWndOwner:=TWin32WidgetSet(WidgetSet).AppHandle; - PDev:=TPrinterDevice(Printer.Printers.Objects[Printer.PrinterIndex]); - Size := DeviceCapabilities(PChar(PDev.Name),PChar(PDev.Port),DC_SIZE,nil,nil); - Extra := DeviceCapabilities(PChar(PDev.Name),PChar(PDev.Port),DC_EXTRA,nil,nil); - Fields := DeviceCapabilities(PChar(PDev.Name),PChar(PDev.Port),DC_FIELDS,nil,nil); - DeviceMode:=GlobalAlloc(GHND,Size + Extra); + // Pdev.DevMode has the required size, just copy to the global memory + DeviceMode:=GlobalAlloc(GHND, PDev.DevModeSize); try - DevMode:=PDeviceMode(GlobalLock(DeviceMode)); - try - CopyMemory(DevMode,@PDev.DevMode,SizeOf(PDev.DevMode)); - DevMode^.dmSize := Word(Size); - DevMode^.dmDriverExtra := Word(Extra); - DevMode^.dmFields := Fields; - finally - GlobalUnLock(DeviceMode); - end; - - hDevMode:= DeviceMode; - if PrintDlg(lpp) then + DevMode:=PDeviceMode(GlobalLock(DeviceMode)); + try + CopyMemory(DevMode, Pdev.DevMode, Pdev.DevModeSize); + finally + GlobalUnlock(DeviceMode); + end; + hDevMode := DeviceMode; + if PrintDlg(lpp) then begin St:=''; //Change Selected printer @@ -155,10 +137,7 @@ begin try //Set the properties for the selected printer PDev:=TPrinterDevice(Printer.Printers.Objects[Printer.PrinterIndex]); - CopyMemory(@PDev.DevMode,DevMode,sizeof(Pdev.DevMode)); - PDev.DevMode.dmSize := SizeOf(PDev.DevMode); - PDev.DevMode.dmDriverExtra := 0; - PDev.DevMode.dmPaperSize := Devmode^.dmPaperSize; + CopyMemory(PDev.DevMode,DevMode,PDev.DevModeSize); TWinPrinter(Printer).Handle := hDC; finally GlobalUnlock(lpp.hDevMode); @@ -210,30 +189,25 @@ begin if not (poWarning in Options) then Flags := Flags or PD_NOWARNING; hWndOwner:=TWin32WidgetSet(WidgetSet).AppHandle; - PDev:=TPrinterDevice(Printer.Printers.Objects[Printer.PrinterIndex]); - Size := DeviceCapabilities(PChar(PDev.Name),PChar(PDev.Port),DC_SIZE,nil,nil); - Extra := DeviceCapabilities(PChar(PDev.Name),PChar(PDev.Port),DC_EXTRA,nil,nil); - Fields := DeviceCapabilities(PChar(PDev.Name),PChar(PDev.Port),DC_FIELDS,nil,nil); - DeviceMode:=GlobalAlloc(GHND,Size + Extra); + // Pdev.DevMode has the required size, just copy to the global memory + DeviceMode:=GlobalAlloc(GHND, PDEV.DevModeSize); try - DevMode:=PDeviceMode(GlobalLock(DeviceMode)); - try - CopyMemory(DevMode,@PDev.DevMode,SizeOf(PDev.DevMode)); - DevMode^.dmSize := Word(Size); - DevMode^.dmDriverExtra := Word(Extra); - DevMode^.dmFields := Fields; - finally - GlobalUnLock(DeviceMode); - end; - - hDevMode:= DeviceMode; - nCopies:= Word(Copies); - nFromPage := Word(FromPage); - nToPage := Word(ToPage); - nMinPage := Word(MinPage); - nMaxPage := Word(MaxPage); - if PrintDlg(lpp) then + DevMode:=PDeviceMode(GlobalLock(DeviceMode)); + try + CopyMemory(DevMode, PDev.DevMode, PDev.DevModeSize); + finally + GlobalUnlock(DeviceMode); + end; + + hDevMode:= DeviceMode; + nCopies:= Word(Copies); + nFromPage := Word(FromPage); + nToPage := Word(ToPage); + nMinPage := Word(MinPage); + nMaxPage := Word(MaxPage); + + if PrintDlg(lpp) then begin St:=''; //Change Selected printer @@ -250,25 +224,24 @@ begin end; Result:=True; - - + if lpp.hDevMode<>0 then begin DevMode:=PDeviceMode(GlobalLock(lpp.hDevMode)); try //Set the properties for the selected printer PDev:=TPrinterDevice(Printer.Printers.Objects[Printer.PrinterIndex]); - CopyMemory(@PDev.DevMode,DevMode,sizeof(Pdev.DevMode)); - PDev.DevMode.dmSize := SizeOf(PDev.DevMode); - PDev.DevMode.dmDriverExtra := 0; + CopyMemory(PDev.DevMode,DevMode,PDev.DevModeSize); + if Printer.PaperSize.SupportedPapers.IndexOfObject(TObject(ptrint(DevMode^.dmPaperSize))) <> -1 then - PDev.DevMode.dmPaperSize := DevMode^.dmPaperSize + PDev.DevMode^.dmPaperSize := DevMode^.dmPaperSize else - PDev.DevMode.dmPaperSize := PDev.DefaultPaper; - if nCopies=1 then Copies := DevMode^.dmCopies + PDev.DevMode^.dmPaperSize := PDev.DefaultPaper; + if nCopies=1 then + Copies := DevMode^.dmCopies else - Copies := nCopies; + Copies := nCopies; Printer.Copies := Copies; TWinPrinter(Printer).Handle := hDC; finally diff --git a/components/printers/win32/winutilprn.pas b/components/printers/win32/winutilprn.pas index 215e57ef7f..b8ca72e5b6 100644 --- a/components/printers/win32/winutilprn.pas +++ b/components/printers/win32/winutilprn.pas @@ -148,15 +148,21 @@ type Type + + { TPrinterDevice } + TPrinterDevice = class + public Name : String; Driver : String; Device : String; Port : String; DefaultPaper : Short; - - DevMode: TDeviceMode; + + DevMode: PDeviceMode; + DevModeSize: Integer; + destructor destroy; override; end; @@ -288,6 +294,16 @@ function AdvancedDocumentProperties( pDevModeInput : PDeviceMode // original device mode data ): Longint; stdcall; external LibWinSpool name 'AdvancedDocumentPropertiesA'; + +function DocumentProperties( + hWnd :HWND; // handle to parent window + hPrinter :THandle; // handle to printer object + pDeviceName :Pchar; // device name + pDevModeOutput:PdeviceMode; // modified device mode + pDevModeInput :PdeviceMode; // original device mode + fMode :DWORD // mode options + ): Longint; stdcall; external LibWinSpool name 'DocumentPropertiesA'; + function DeviceCapabilities(pDevice, pPort: PChar; fwCapability: Word; pOutput: PChar; DevMode: PDeviceMode): Integer; stdcall; external LibWinSpool name 'DeviceCapabilitiesA'; @@ -305,8 +321,20 @@ function EndDoc(DC: HDC): Integer; stdcall; external 'gdi32.dll' name 'EndDoc'; function StartPage(DC: HDC): Integer; stdcall; external 'gdi32.dll' name 'StartPage'; function EndPage(DC: HDC): Integer; stdcall; external 'gdi32.dll' name 'EndPage'; function AbortDoc(DC: HDC): Integer; stdcall; external 'gdi32.dll' name 'AbortDoc'; +function GlobalFree(HMem: HGlobal): HGlobal; stdcall; external 'kernel32.dll' name 'GlobalFree'; implementation +{ TPrinterDevice } + +destructor TPrinterDevice.destroy; +begin + if DevMode<>nil then begin + FreeMem(DevMode); + DevMode:=nil; + end; + inherited destroy; +end; + end. diff --git a/lcl/printers.pas b/lcl/printers.pas index c3e0201e68..8ad6a6b014 100644 --- a/lcl/printers.pas +++ b/lcl/printers.pas @@ -444,18 +444,23 @@ begin Result:=DoGetOrientation; end; +// Returns the height in points (pixels) of printable area function TPrinter.GetPageHeight: Integer; begin Result:=0; if (Printers.Count>0) then - Result:=PaperSize.PaperRect.PhysicalRect.Bottom; + with PaperSize.PaperRect.WorkRect do + Result:=Bottom-Top; end; +// Returns the width in points (pixels) of the printable area function TPrinter.GetPageWidth: Integer; begin Result:=0; if (Printers.Count>0) then - Result:=PaperSize.PaperRect.PhysicalRect.Right; + with PaperSize.PaperRect.WorkRect do + // PageWidth is the size in "pixels" of the printable area + Result:=Right-Left; end; function TPrinter.GetPaperSize: TPaperSize; @@ -500,7 +505,6 @@ begin Result:=1; end; - //Set the copies numbers procedure TPrinter.SetCopies(AValue: Integer); begin