線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:7931
推到 Plurk!
推到 Facebook!

請問在win2000/winxp下如何改變印表機之預設紙張?

尚未結案
hanigw
一般會員


發表:6
回覆:0
積分:1
註冊:2002-05-29

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-07-23 19:18:35 IP:61.30.xxx.xxx 未訂閱
各位大大您好,小弟之前有搜尋過相關文章,但只有找到98改預設紙張的方式,但小弟的系統需在xp/win2000上run,不知如何去作,謝謝各位大大的回答~
lsu
一般會員


發表:1
回覆:14
積分:3
註冊:2003-03-11

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-07-28 09:07:08 IP:221.3.xxx.xxx 未訂閱
在 WindowsNT/200 環境下要自訂紙張尺寸所使用的方法與 Win9x 不同, 你必須先為目前的印表機定義一個自訂的 "Form"(呼叫 API: AddForm, 此 API 宣告於 WinSpool 單元中),然後把這個 Form 的名稱設定給 DEVMODES 結構中的 dmFormName 欄位。以下的函式可以直接拿來使用: uses Windows, WinSpool, Printers; (*------------------------------------------------------ Define a new Form (WinNT/2000 only). If FormName already exists, do nothing and return. If failed, an exception will be raised. ------------------------------------------------------*) procedure PrnAddForm(const FormName: string; PaperWidth, PaperLength: integer); var PrintDevice, PrintDriver, PrintPort : array[0..255] of Char; hDMode : THandle; hPrinter: THandle; FormInfo: TFormInfo1; PaperSize: TSize; PaperRect: TRect; errcode: integer; s: string; begin Printer.GetPrinter(PrintDevice, PrintDriver, PrintPort, hDMode); OpenPrinter(PrintDevice, hPrinter, nil); if hPrinter = 0 then raise Exception.Create('Failed to open printer!'); FormInfo.Flags := FORM_USER; FormInfo.pName := PChar(FormName); PaperSize.cx := PaperWidth; PaperSize.cy := PaperLength; PaperRect.Left := 0; PaperRect.Top := 0; PaperRect.Right := PaperWidth; PaperRect.Bottom := PaperLength; FormInfo.Size := PaperSize; FormInfo.ImageableArea := PaperRect; if not AddForm(hPrinter, 1, @FormInfo) then begin errcode := GetLastError; if errcode <> ERROR_FILE_EXISTS then // Form name exists? begin case errcode of ERROR_ACCESS_DENIED: s := 'Access is denied'; ERROR_INVALID_HANDLE: s := 'The handle is invalid'; ERROR_NOT_READY: s := 'The device is not ready'; ERROR_CALL_NOT_IMPLEMENTED: s := 'Function "AddForm" is not supported on this system'; else s := 'Failed to add a Form (paper) name!'; end; raise Exception.Create(s); end; end; ClosePrinter(hPrinter); end; (* Set custom paper size for WinNT/2000. Make sure FormName is supported by current printer, You can call PrnAddForm to define a new Form. *) procedure PrnSetPaperSizeNT(FormName: string; PaperWidth, PaperLength: integer); var Device, Driver, Port: array[0..80] of Char; DevMode: THandle; pDevmode: PDeviceMode; begin // Get printer device name etc. Printer.GetPrinter(Device, Driver, Port, DevMode); // force reload of DEVMODE Printer.SetPrinter(Device, Driver, Port, 0) ; // get DEVMODE handle Printer.GetPrinter(Device, Driver, Port, DevMode); if DevMode <> 0 then begin // lock it to get pointer to DEVMODE record pDevMode := GlobalLock( DevMode ); if pDevmode <> nil then try with pDevmode^ do begin // modify form StrLCopy( dmFormName, PChar(FormName), CCHFORMNAME-1 ); // tell printer driver that dmFormname field contains // data it needs to inspect. dmPaperWidth := PaperWidth; dmPaperLength := PaperLength; dmFields := dmFields or DM_FORMNAME or DM_PAPERWIDTH or DM_PAPERLENGTH; end; finally GlobalUnlock( Devmode ); // unlock devmode handle. end; end; { If } end; procedure TForm1.Button1Click(Sender: TObject); begin PrnAddForm( edFormName.Text, StrToInt(edPaperWidth.Text), StrToInt(edPaperLength.Text) ); PrnSetPaperSizeNT( edFormName.Text, StrToInt(edPaperWidth.Text), StrToInt(edPaperLength.Text) ); Printer.BeginDoc; Printer.Canvas.TextOut(10, 10, 'Printer test!'); Printer.EndDoc; end; 在Delphi帮助中,AddForm定义如下: BOOL AddForm( HANDLE hPrinter, // handle to printer object DWORD Level, // data-structure level LPBYTE pForm // pointer to form info. data structure ); 下面是我在Delphi中定义的自定义函数AddPaper(): function AddPaper(PaperName: PChar;fPaperWidth,fPaperHeigth: Double): String; var PrintDevice, PrintDriver, PrintPort : array[0..255] of Char; hDMode : THandle; hPrinter: THandle; FormInfo: TForminfo1; PaperSize: TSize; PaperRect: TRect; PaperWidth,PaperHeigth: Integer; function Zlxs(S: String;nWs: Integer): String; //整理小数位,并转化成厘米 begin Try Result:=FloatToStr(StrToFloat(S)); If pos('.',Result)>0 then Result:=Copy(Result,1,pos('.',Result) 2); Result:=FloatToStr(StrToFloat(Result)*10000); Except Result:='0'; end; end; begin PaperWidth:=StrToInt(Zlxs(FloatToStr(fPaperWidth),3)); Paperheigth:=StrToInt(Zlxs(FloatToStr(fPaperheigth),3)); //判断是否安装打印机,并得到默认打印机的句柄 Printer.GetPrinter(PrintDevice, PrintDriver, PrintPort, hDMode); OpenPrinter(PrintDevice, hPrinter, nil); if hPrinter=0 then begin Result:='没有安装打印机!'; Exit; end; //定义结构 FormInfo.Flags:=FORM_USER; FormInfo.pName:=PChar(PaperName); PaperSize.cx:=PaperWidth; PaperSize.cy:=PaperHeigth; PaperRect.Left:=0; PaperRect.Top:=0; PaperRect.Right:=PaperSize.cx; PaperRect.Bottom:=PaperSize.cy; FormInfo.Size:=PaperSize; FormInfo.ImageableArea:=PaperRect; AddForm(hPrinter,1,@FormInfo); //添加纸张 ClosePrinter(hPrinter); end; 3个参数:PaperName:你给纸张命的名(操作系统中叫描述格式),fPaperWidth:纸张宽度,fPaperHeigth:纸张高度。如果没有安装打印机,返回提示信息。如果已经有同样名称的纸张,函数不起作用,建议大家最好在名称中加入“_”,因为很少有这样命名的纸张,你的程序用你的专用纸张也不为过吧(谁叫Windows不提供,而我们偏偏又要用呢)?里面还有一个函数:Zlxs,这是用来整理小数的,经过试验,加入的纸张采用的单位是厘米时宽度用10000时只有1厘米,大家输入的往往是以厘米为单位的,且带小数,所以得用一个函数来将浮点数转换成整数。当然首先还得在uses段中加入Printers,winspool引用。以上代码在D5,D6 Win 2000中运行通过。将这个函数加入管理系统中,在打印之前调用生成专用纸张,省时又省力。 这种方法应该是处理自定义纸张问题的正解,通用性强,也不会浪费打印机的链式(牵引)走纸功能。大家可以根据各自编程工具的方法进行定义,也可以做成.dll文件,这样不支持结构的编程工具,如VFP等也能使用了。 4、 其他小技巧: 在使用OKI打印机时,我们有时会想把一行比较长的数据打在一张“US Std Fanfold”纸上,但“US Std Fanfold”宽度37.78cm,象OKI5330之类的打印机宽度有限,这么宽的纸放不下啊。我们可以采用自定义的方法实现,首先定义新格式,然后将“US Std Fanfold”的宽和高反过来,命个名:“US Std Fanfold(纵向)”,然后在报表设计中使用这张纸并采用横向打印就行了。 procedure UpdatePrint(Awidth,Aheight:integer); const CustomFormName = 'ZJ Defined'; function Win95SetForm(PDevMode: PDeviceMode): Boolean; begin Printer.PrinterIndex := Printer.PrinterIndex; PDevMode.dmFields := PDevMode.dmFields or DM_PAPERSIZE; PDevMode.dmPaperSize := 256; PDevMode.dmFields := PDevMode.dmFields or DM_PAPERWIDTH; PDevMode.dmPaperWidth := AWidth; PDevMode.dmFields := PDevMode.dmFields or DM_PAPERLENGTH; PDevMode.dmPaperLength := AHeight; Printer.PrinterIndex := Printer.PrinterIndex; Result := True; end; function WinNTSetForm(PDevMode: PDeviceMode; Device: PChar; Port: PChar): Boolean; var hPrinter: THandle; pForm: Pointer; cbNeeded: DWORD; cReturned: DWORD; FormInfo1: TFormInfo1; begin Result := False; if OpenPrinter(Device, hPrinter, nil) then begin pForm := nil; EnumForms(hPrinter, 1, pForm, 0, cbNeeded, cReturned); GetMem(pForm, cbNeeded); //取pForm的大小并分配内存 try if EnumForms(hPrinter, 1, pForm, cbNeeded, cbNeeded, cReturned) then begin if DeleteForm(hPrinter, PChar(CustomFormName)) then Dec(cReturned); //删除旧的Form with FormInfo1 do begin Flags := 0; pName := PChar(CustomFormName); Size.cx := AWidth * 100; Size.cy := AHeight * 100; with ImageAbleArea do begin Left := 0; Top := 0; Right := Size.cx; Bottom := Size.cy; end; end; if AddForm(hPrinter, 1, @FormInfo1) then begin Printer.PrinterIndex := Printer.PrinterIndex; PDevMode.dmFields := PDevMode.dmFields or DM_PAPERSIZE; PDevMode.dmPaperSize := cReturned 1; Printer.PrinterIndex := Printer.PrinterIndex; Result := True; end; end; finally FreeMem(pForm); end; end; end; var Device, Driver, Port: array[0..127] of char; hDevMode: THandle; PDevMode: PDeviceMode; begin Printer.GetPrinter(Device, Driver, Port, hDevMode); if hDevMode <> 0 then begin PDevMode := GlobalLock(hDevMode); try if (Win32Platform = VER_PLATFORM_WIN32s) or (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) then Win95SetForm(PDevMode) else if Win32Platform = VER_PLATFORM_WIN32_NT then WinNTSetForm(PDevMode, Device, Port); finally GlobalUnlock(hDevMode); end; end end; 将《Delphi中票据凭证的精确打印》一文中关于设置打印纸张长、宽的内容贴上来,供你参考 file://设置纸张高度-单位:mm procedure SetPaperHeight(Value:integer); var Device : array[0..255] of char; Driver : array[0..255] of char; Port : array[0..255] of char; hDMode : THandle; PDMode : PDEVMODE; begin file://自定义纸张最小高度127mm if Value < 127 then Value := 127; file://自定义纸张最大高度432mm if Value > 432 then Value := 432; Printer.PrinterIndex := Printer.PrinterIndex; Printer.GetPrinter(Device, Driver, Port, hDMode); if hDMode <> 0 then begin pDMode := GlobalLock(hDMode); if pDMode <> nil then begin pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or DM_PAPERLENGTH; pDMode^.dmPaperSize := DMPAPER_USER; pDMode^.dmPaperLength := Value * 10; pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL; pDMode^.dmDefaultSource := DMBIN_MANUAL; GlobalUnlock(hDMode); end; end; Printer.PrinterIndex := Printer.PrinterIndex; end; file://设置纸张宽度:单位--mm Procedure SetPaperWidth(Value:integer); var Device : array[0..255] of char; Driver : array[0..255] of char; Port : array[0..255] of char; hDMode : THandle; PDMode : PDEVMODE; begin file://自定义纸张最小宽度76mm if Value < 76 then Value := 76; file://自定义纸张最大宽度216mm if Value > 216 then Value := 216; Printer.PrinterIndex := Printer.PrinterIndex; Printer.GetPrinter(Device, Driver, Port, hDMode); if hDMode <> 0 then begin pDMode := GlobalLock(hDMode); if pDMode <> nil then begin pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or DM_PAPERWIDTH; pDMode^.dmPaperSize := DMPAPER_USER; file://将毫米单位转换为0.1mm单位 pDMode^.dmPaperWidth := Value * 10; pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL; pDMode^.dmDefaultSource := DMBIN_MANUAL; GlobalUnlock(hDMode); end; end; Printer.PrinterIndex := Printer.PrinterIndex; end; 设定纸张大小 Procedure PrintPapersize(Width,Length:integer); var Device : array[0..cchDeviceName -1] of Char; Driver : array[0..(MAX_PATH -1)] of Char; Port : array[0..32]of Char; hDMode : THandle; pDMode : PDevMode; begin Printer.GetPrinter(Device,Driver,Port,hDMode); if hDMode <> 0 then begin pDMode := GlobalLock(hDMode); if pDMode <> nil then begin pDMode^.dmPaperSize := 256; pDMode^.dmPaperLength :=Length ; pDMode^.dmPaperWidth := Width; pDMode^.dmFields :=pDMode^.dmFields or DM_PAPERSIZE; pDMode^.dmFields :=pDMode^.dmFields or DM_PAPERLENGTH; pDMode^.dmFields :=pDMode^.dmFields or DM_PAPERWIDTH; ResetDC(Printer.Handle,pDMode^); GlobalUnlock(hDMode); end; end; end; uses WinSpool, Printers, Windows; function CustomAddForm (const Name:String; const Width, Height:Double; const PrinterName:String):Boolean; var FormInfo1: TFormInfo1; pFormInfo: PFormInfo1; hPrinter : THandle; begin Result := False; if OpenPrinter(PChar(PrinterName),hPrinter,NIL) then begin with FormInfo1 do begin Flags := 0; pName := PAnsiChar(Name); Size.cx := Trunc(Width*1000); Size.cy := Trunc(Height*1000); ImageableArea.Left := 0; ImageableArea.Top := 0; ImageableArea.Bottom := Size.cy; ImageableArea.Right := Size.cx; end; pFormInfo := @FormInfo1; Result := AddForm(hPrinter,1,pFormInfo); ClosePrinter(hPrinter); end; end; 有两个方法可以在win2000中设置自定义纸张: 1、手工添加 在“控制面板”、“打印机和传真”中选中一台打印机,在“文件”菜单的“服务器属性”中创建新格式即可。 2、程序动态修改 procedure SetPaperSize(X, Y: Integer); // 单位是0.1mm //改变devicemode结构 var Device: array[0..255] of char; Driver: array[0..255] of char; Port: array[0..255] of char; hDMode: THandle; PDMode: PDEVMODE; begin Printer.PrinterIndex := Printer.PrinterIndex; Printer.GetPrinter(Device, Driver, Port, hDMode); if hDMode <> 0 then begin pDMode := GlobalLock(hDMode); if pDMode <> nil then begin if (x = 0) or (y = 0) then begin {Set to legal} pDMode^.dmFields := pDMode^.dmFields or dm_PaperSize; {pDMode^.dmPaperSize := DMPAPER_LEGAL; changed by wulianmin} pDMode^.dmPaperSize := DMPAPER_FANFOLD_US; end else begin {Set to custom size} pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or DM_PAPERWIDTH or DM_PAPERLENGTH; pDMode^.dmPaperSize := DMPAPER_USER; pDMode^.dmPaperWidth := x {SomeValueInTenthsOfAMillimeter}; pDMode^.dmPaperLength := y {SomeValueInTenthsOfAMillimeter}; end; {Set the bin to use} pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL; pDMode^.dmDefaultSource := DMBIN_MANUAL; GlobalUnlock(hDMode); end; end; end; 我曾经用Delphi 5.0的Printer对象编写打印程序,在许多打印机上使用都没问题 (包括一些其他EPSON打印机),但是在EPSON 460上使用时不能打印,结果发现在这种 环境下,必须给Printer的Title属性赋值后,打印机才会真正去打印,具体方法如下: Printer.BeginDoc; Printer.Title := '在这里给打印文档起个名字'; {打印的内容}; Printer.EndDoc; 不知道我的这个经历能否给你一些启示吗? 你那个程序有没有resetDC,这个函数delphi中不会调用 在使用Printer的Canvas前调用有效呀,偶一直这么用,从票据到激光都有效。 發表人 - lsu 於 2005/07/28 09:37:48
lsu
一般會員


發表:1
回覆:14
積分:3
註冊:2003-03-11

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-07-28 09:07:52 IP:221.3.xxx.xxx 未訂閱
不好意思,当我选中[我使用(GB內碼)發言,請系統幫我自動轉碼.]时, 就不能正常贴上。 發表人 - lsu 於 2005/07/28 09:15:48
lsu
一般會員


發表:1
回覆:14
積分:3
註冊:2003-03-11

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-07-28 09:28:57 IP:221.3.xxx.xxx 未訂閱
win2000/xp下自定义纸张打印,实际上一直是个困扰大家的问题。我想原因很大一部分来自windows本身对打印机驱动程序模式的构造定义。微软不改进打印机方面的不足,不可以很自然地自由打印,迟早会成为OS的一大缺憾。给竞争对手留下把柄。 不过,borland为什么不封装更多的有关打印的API,甚至没有提供自定义纸张的过程,这大概对微软来说,也是个不断变换的东西,不知道longhorn中又将变成什么样式。 發表人 - lsu 於 2005/07/28 09:31:25
lsu
一般會員


發表:1
回覆:14
積分:3
註冊:2003-03-11

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-07-28 09:35:09 IP:221.3.xxx.xxx 未訂閱
以下是borland有关自定义打印的示范程序,在win9x下绝对好用,在2K/xp下只要没有超过系统已经预先定义好的纸张大小(比如最大A3),也是好用的。 procedure TForm1.Button1Click(Sender: TObject); var Device : array[0..255] of char; Driver : array[0..255] of char; Port : array[0..255] of char; hDMode : THandle; PDMode : PDEVMODE; begin Printer.PrinterIndex := Printer.PrinterIndex; Printer.GetPrinter(Device, Driver, Port, hDMode); if hDMode <> 0 then begin pDMode := GlobalLock(hDMode); if pDMode <> nil then begin {Set to legal} pDMode^.dmFields := pDMode^.dmFields or dm_PaperSize; pDMode^.dmPaperSize := DMPAPER_LEGAL; {Set to custom size} pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or DM_PAPERWIDTH or DM_PAPERLENGTH; pDMode^.dmPaperSize := DMPAPER_USER; pDMode^.dmPaperWidth := 100 {SomeValueInTenthsOfAMillimeter}; pDMode^.dmPaperLength := 100 {SomeValueInTenthsOfAMillimeter}; {Set the bin to use} pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL; pDMode^.dmDefaultSource := DMBIN_MANUAL; GlobalUnlock(hDMode); end; end; Printer.PrinterIndex := Printer.PrinterIndex; Printer.BeginDoc; Printer.Canvas.TextOut(100,100, 'Test 1'); Printer.EndDoc; end;
lsu
一般會員


發表:1
回覆:14
積分:3
註冊:2003-03-11

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-07-28 09:53:43 IP:221.3.xxx.xxx 未訂閱
配合这几个函数,基本上就够用了: GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);{页左边距X} GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);{页上边距y} GetDeviceCaps(Printer.Handle, PHYSICALWIDTH); {物理页宽度} GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT); {物理页高度} Printer.PageWidth; {可打印部分的宽度(工作区)} Printer.PageHeight;{可打印部分高度(工作区)} 获取当前打印机的分辨率 GetDeviceCaps(Printer.Handle,LOGPIXELSX);{打印机横向} GetDeviceCaps(Printer.Handle,LOGPIXELSY);{打印机纵向}
lsu
一般會員


發表:1
回覆:14
積分:3
註冊:2003-03-11

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-08-31 07:37:20 IP:221.215.xxx.xxx 未訂閱
这是一个Tprinter的替代程序,转贴一下,有许多自己控制打印机方面的技巧可以参考一下。    {$include options.inc}    unit ZPrinters;    interface    uses   Classes, Graphics, Windows;    { ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::      Unit:      ZPrinters   Version:   2.07   Revision:  19 Nov 2002      Compiler:  Delphi 6.0 Professional   State:     Production, state-of-the-art code                 Copyright (C) 2001 LOGICOMM              http://www.logicomm.it              support@logicomm.it      ..............................................................................         :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: }    var      // Messages; these are actually consts, to allow for localization.      sDpi: string                = '%dx%d dpi';    // 300x300 dpi   sDpiSq: string              = '%d dpi';       // 300 dpi   sDevice: string             = '%s on %s';     // HP LaserJet 4100 on LPT1   sPaper: string              = '%s, %dx%d mm'; // A4, 210x297mm   sPortrait: string           = 'Portrait';   sLandscape: string          = 'Landscape';   sNoSuchDevice: string       = 'No such printer: ''%s''.';   sNoDevices: string          = 'No printers installed.'#13'Please install a '                                +'printer driver from your Windows control '                                +'panel, or ask your system administrator.';   sNoDefaultDevice: string    = 'No default printer.';   sInvalidDevice: string      = 'Selected printer is not valid.';   sNotPrinting: string        = 'Printer is not currently printing.';   sPrinting: string           = 'Printer is already printing.';   sInvalidOperation: string   = 'Operation not supported by current printer.';   sInvalidBin: string         = 'Unknown or unsupported bin: ''%s''.';   sInvalidPaper: string       = 'Unknown or unsupported paper format: ''%s''.';   sInvalidResolution: string  = 'Unknown or unsupported resolution: ''%s''.';   sInvalidOrientation: string = 'Bad orientation: ''%s''.';   sInvalidCopies: string      = 'Bad number of copies.';    var      // Default paper format for any new . The empty string does // nothing. ZPrinter_Force_Paper: string = ''; type // TZPrintCapability and TZPrintCapabilities. TZPrintCapability = (zcUnknown,zcCopies,zcOrientation,zcCollation); TZPrintCapabilities = set of TZPrintCapability; // TZPrintOrientation. TZPrintOrientation = (zoPortrait,zoLandscape,zoNotSupported); // TZPrintDevice. TZPrintDevice = class private FDriver: string; FDevice: string; FPort: string; FBins: TStringList; FPapers: TStringList; FOrientations: TStringList; FResolutions: TStringList; FFonts: TStringList; FCapabilities: TZPrintCapabilities; function GetName: string; protected function GetBins: TStrings; function GetPapers: TStrings; function GetOrientations: TStrings; function GetResolutions: TStrings; function GetFonts: TStrings; function GetCapabilities: TZPrintCapabilities; function IsDevice(ADevice: PChar): boolean; public constructor Create(ADriver,ADevice,APort: PChar); reintroduce; destructor Destroy; override; procedure Refresh; property Name: string read GetName; property Driver: string read FDriver; property Device: string read FDevice; property Port: string read FPort; property Bins: TStrings read GetBins; property Papers: TStrings read GetPapers; property Orientations: TStrings read GetOrientations; property Resolutions: TStrings read GetResolutions; property Fonts: TStrings read GetFonts; property Capabilities: TZPrintCapabilities read GetCapabilities; end; // TZPrintDevices. TZPrintDevices = class private FDevices: TList; procedure ClearDevices; function FetchStr(var Str: PChar): PChar; function GetDevice(Index: integer): TZPrintDevice; function GetCount: integer; function GetDefaultIndex: integer; function GetDefaultDevice: TZPrintDevice; public constructor Create; destructor Destroy; override; procedure Refresh; function DeviceIndex(const Name: string): integer; function FindDevice(const Name: string): TZPrintDevice; function DeviceByName(const Name: string): TZPrintDevice; property Devices[Index: integer]: TZPrintDevice read GetDevice; default; property Count: integer read GetCount; property DefaultIndex: integer read GetDefaultIndex; property DefaultDevice: TZPrintDevice read GetDefaultDevice; end; // TZPrinter. TZPrinter = class private FCanvas: TCanvas; FTitle: string; FDeviceName: string; FPrinterHandle: THandle; FDeviceMode: THandle; FDevMode: PDeviceMode; FHandle: HDC; FAborted: boolean; FPageNumber: integer; function GetHandle: HDC; procedure SetTitle(const Value: string); function GetDeviceIndex: integer; procedure SetDeviceIndex(Value: integer); function GetDevice: TZPrintDevice; function GetBin: string; procedure SetBin(const Value: string); function GetPaper: string; procedure SetPaper(const Value: string); function GetPaperFmt: integer; function GetResolution: TPoint; function GetPaperDesc: string; procedure SetResolution(Value: TPoint); function GetResolutionStr: string; procedure SetResolutionStr(const Value: string); function GetOrientation: TZPrintOrientation; procedure SetOrientation(Value: TZPrintOrientation); function GetOrientationStr: string; procedure SetOrientationStr(const Value: string); function GetPaperSize: TPoint; function GetPaperSizeOriented: TPoint; function GetCopies: SmallInt; procedure SetCopies(Value: SmallInt); function GetPageWidth: integer; function GetPageHeight: integer; function GetPhysicalOffset: TPoint; function GetPhysicalSize: TPoint; function GetPageRect: TRect; function GetClientRect: TRect; function GetPrinting: boolean; protected function GetIC: HDC; procedure ICNeeded; procedure DCNeeded; procedure ReleaseHandle; function IsHandle(Value: HDC): boolean; procedure CheckPrinting(Value: boolean); procedure CheckDevice(Value: string = ''); procedure ClosePrinterHandle; procedure FreeDeviceMode; procedure SetDeviceName(Value: string); virtual; public constructor Create; virtual; destructor Destroy; override; procedure StartDoc(const OutFileName: string = ''); virtual; procedure EndDoc; procedure AbortDoc; procedure StartPage; procedure EndPage; function DocumentProperties(Modal: boolean = true): boolean; function CreateCompatibleCanvas: TCanvas; property Canvas: TCanvas read FCanvas; property PrinterHandle: THandle read FPrinterHandle; property DeviceMode: THandle read FDeviceMode; property DevMode: PDeviceMode read FDevMode; property Handle: HDC read GetHandle; property Title: string read FTitle write SetTitle; property DeviceIndex: integer read GetDeviceIndex write SetDeviceIndex; property DeviceName: string read FDeviceName write SetDeviceName; property Device: TZPrintDevice read GetDevice; property Bin: string read GetBin write SetBin; property Paper: string read GetPaper write SetPaper; property PaperDesc: string read GetPaperDesc; property PaperFmt: integer read GetPaperFmt; property Resolution: TPoint read GetResolution write SetResolution; property ResolutionStr: string read GetResolutionStr write SetResolutionStr; property Orientation: TZPrintOrientation read GetOrientation write SetOrientation; property OrientationStr: string read GetOrientationStr write SetOrientationStr; property PaperSize: TPoint read GetPaperSize; property PaperSizeOriented: TPoint read GetPaperSizeOriented; property Copies: SmallInt read GetCopies write SetCopies; property PageWidth: integer read GetPageWidth; property PageHeight: integer read GetPageHeight; property PhysicalOffset: TPoint read GetPhysicalOffset; property PhysicalSize: TPoint read GetPhysicalSize; property PageRect: TRect read GetPageRect; property ClientRect: TRect read GetClientRect; property Printing: boolean read GetPrinting; property Aborted: boolean read FAborted; property PageNumber: integer read FPageNumber; end; // Print devices handling. function PrintDevices: TZPrintDevices; function PrintDevicesCnt: integer; procedure PrintDevicesCheckAvailable; procedure EnumPrintDevices(List: TStrings); // Paper formats handling. function StdPaperSize(Fmt: integer): TPoint; overload; function StdPaperSize(const Fmt: string): TPoint; overload; function StdPaperFmt(const Fmt: string): integer; overload; function StdPaperFmt(Fmt: integer): string; overload; procedure EnumStdPaperFmts(List: TStrings); implementation uses SysUtils, WinSpool, Forms; // _____________________________________________________________________________ // // Utility functions. // _____________________________________________________________________________ function FmtDpi(Dpi: TPoint): string; overload; begin with Dpi do if (x=0) and (y=0) then result:= '' else if x=y then result:= Format(sDpiSq,[x]) else result:= Format(sDpi,[x,y]); end; function FmtDpi(Dpi: TSmallPoint): string; overload; begin with Dpi do if (x=0) and (y=0) then result:= '' else if x=y then result:= Format(sDpiSq,[x]) else result:= Format(sDpi,[x,y]); end; // _____________________________________________________________________________ // // . // _____________________________________________________________________________ const cchBinName = 24; cchPaperName = 64; constructor TZPrintDevice.Create; begin inherited Create; Assert(ADevice<>''); FDriver:= ADriver; FDevice:= ADevice; FPort:= APort; Refresh; end; destructor TZPrintDevice.Destroy; begin FreeAndNil(FBins); FreeAndNil(FPapers); FreeAndNil(FResolutions); FreeAndNil(FFonts); inherited Destroy; end; procedure TZPrintDevice.Refresh; begin FreeAndNil(FBins); FreeAndNil(FPapers); FreeAndNil(FResolutions); FreeAndNil(FFonts); FCapabilities:= [zcUnknown]; end; function TZPrintDevice.GetName; begin if FPort<>'' then begin result:= Format(sDevice,[FDevice,FPort]); end else begin result:= FDevice; end; end; function TZPrintDevice.IsDevice; begin result:= (ADevice=FDevice); end; function TZPrintDevice.GetBins; var i,z: integer; p: PChar; begin if FBins=nil then begin FBins:= TStringList.Create; with FBins do begin z:= WinSpool.DeviceCapabilities(PChar(FDevice),PChar(FPort),DC_BINNAMES, nil,nil)*cchBinName; GetMem(p,z); try for i:= 0 to WinSpool.DeviceCapabilities(PChar(FDevice),PChar(FPort), DC_BINNAMES,p,nil)-1 do Add(Trim(p cchBinName*i)); for i:= 0 to WinSpool.DeviceCapabilities(PChar(FDevice),PChar(FPort), DC_BINS,p,nil)-1 do Objects[i]:= pointer(integer(PWord(p i*SizeOf (word))^)); i:= Count-1; while i>=0 do begin if i=0 do begin if i'' then AddObject(s,pointer(m)); end; i:= Count-1; while i>=0 do begin if i0 then begin v:= GlobalLock(m); if WinSpool.DocumentProperties(0,r,PChar(FDevice),v^,v^,DM_OUT_BUFFER)<0 then begin GlobalUnlock(m); GlobalFree(m); m:= 0; end; end; if m<>0 then begin h:= CreateIC(PChar(FDriver),PChar(FDevice),PChar(FPort),v); if h<>0 then try EnumFonts(h,nil,@EnumFontsProc,pointer(FFonts)); finally DeleteDC(h); end; end; finally ClosePrinter(r); end; end; result:= FFonts; end; function TZPrintDevice.GetCapabilities; var u: TDeviceMode; r,m: THandle; v: PDeviceMode; f: longword; begin if FCapabilities=[zcUnknown] then begin FCapabilities:= []; if OpenPrinter(PChar(FDevice),r,nil) then try m:= GlobalAlloc(GHND,WinSpool.DocumentProperties(0,r,PChar(FDevice),u,u, 0)); try if m<>0 then begin v:= GlobalLock(m); if WinSpool.DocumentProperties(0,r,PChar(FDevice),v^,v^,DM_OUT_BUFFER) >=0 then begin if m<>0 then f:= v^.dmFields else f:= 0; if f and DM_ORIENTATION<>0 then Include(FCapabilities, zcOrientation); if f and DM_COPIES<>0 then Include(FCapabilities,zcCopies); if f and DM_COLLATE<>0 then Include(FCapabilities,zcCollation); end; end; finally if m<>0 then begin GlobalUnlock(m); GlobalFree(m); end; end; finally ClosePrinter(r); end; end; result:= FCapabilities; end; // _____________________________________________________________________________ // // . // _____________________________________________________________________________ constructor TZPrintDevices.Create; begin inherited Create; FDevices:= TList.Create; Refresh; end; destructor TZPrintDevices.Destroy; begin ClearDevices; FreeAndNil(FDevices); inherited Destroy; end; function TZPrintDevices.FetchStr; var p: PChar; begin result:= Str; if Str=nil then exit; p:= Str; while p^=' ' do inc(p); result:= p; while (p^<>#0) and (p^<>',') do inc(p); if p^=',' then begin p^:= #0; inc(p); end; Str:= p; end; function TZPrintDevices.DeviceIndex; begin for result:= 0 to FDevices.Count-1 do if TZPrintDevice(FDevices[result]).Name=Name then exit; result:= -1; end; function TZPrintDevices.FindDevice; var i: integer; begin i:= DeviceIndex(Name); if i>=0 then result:= FDevices[i] else result:= nil; end; function TZPrintDevices.DeviceByName; begin result:= FindDevice(Name); if result=nil then raise Exception.CreateFmt(sNoSuchDevice,[Name]); end; function TZPrintDevices.GetDevice; begin result:= FDevices[Index]; end; function TZPrintDevices.GetCount; begin result:= FDevices.Count; end; function TZPrintDevices.GetDefaultIndex; var d: TZPrintDevice; begin d:= DefaultDevice; if d=nil then result:= -1 else result:= FDevices.IndexOf(d); end; function TZPrintDevices.GetDefaultDevice; var i: integer; z,c: DWORD; d: array[0..79] of char; u,e: PChar; n: PPrinterInfo5; begin result:= nil; z:= 0; c:= 0; EnumPrinters(PRINTER_ENUM_DEFAULT,nil,5,nil,0,z,c); n:= AllocMem(z); try EnumPrinters(PRINTER_ENUM_DEFAULT,nil,5,n,z,z,c); if c>0 then begin e:= n.pPrinterName; end else begin GetProfileString('windows','device','',d,SizeOf(d)-1); u:= d; e:= FetchStr(u); end; for i:= 0 to FDevices.Count-1 do begin result:= FDevices[i]; if result.IsDevice(e) then break; end; finally FreeMem(n); end; end; procedure TZPrintDevices.ClearDevices; var i: integer; begin if FDevices<>nil then for i:= 0 to FDevices.Count-1 do TZPrintDevice(FDevices[i]).Free; end; procedure TZPrintDevices.Refresh; var p,q,o,n: PChar; f,z,c: DWORD; i: integer; l: byte; begin ClearDevices; if Win32Platform=VER_PLATFORM_WIN32_NT then begin f:= PRINTER_ENUM_CONNECTIONS or PRINTER_ENUM_LOCAL; l:= 4; end else begin f:= PRINTER_ENUM_LOCAL; l:= 5; end; z:= 0; c:= 0; EnumPrinters(f,nil,l,nil,0,z,c); if z>0 then begin GetMem(p,z); try if EnumPrinters(f,nil,l,p,z,z,c) then begin n:= p; for i:= 0 to c-1 do begin if l=4 then with PPrinterInfo4(n)^ do begin FDevices.Add(TZPrintDevice.Create(nil,pPrinterName,nil)); inc(n,SizeOf(TPrinterInfo4)); end else with PPrinterInfo5(n)^ do begin Assert(l=5); q:= pPortName; o:= FetchStr(q); while o^<>#0 do begin FDevices.Add(TZPrintDevice.Create(nil,pPrinterName,o)); o:= FetchStr(q); end; inc(n,SizeOf(TPrinterInfo5)); end; end; end; finally FreeMem(p,z); end; end; end; // _____________________________________________________________________________ // // Print devices handling. // _____________________________________________________________________________ var // holds the list of all available devices. FPrintDevices: TZPrintDevices = nil; function PrintDevices; begin if FPrintDevices=nil then FPrintDevices:= TZPrintDevices.Create; result:= FPrintDevices; end; function PrintDevicesCnt; begin result:= PrintDevices.Count; end; procedure EnumPrintDevices; var i: integer; d: TZPrintDevices; begin List.BeginUpdate; try List.Clear; d:= PrintDevices; for i:= 0 to d.Count-1 do List.Add(d[i].Name); finally List.EndUpdate; end; end; procedure PrintDevicesCheckAvailable; begin // Make sure we have at least one printer installed; if not, raise an // exception. if PrintDevicesCnt<=0 then raise Exception.Create(sNoDevices); end; // _____________________________________________________________________________ // // Helper functions for instances of , and callback for . // _____________________________________________________________________________ var // holds the list of allocated objects; this enables // us to look up the object involved in an call and ultimately // enables the concurrent use of more than one printer at a time. FInstances: TList = nil; procedure AddInstance(Printer: TZPrinter); begin if FInstances=nil then FInstances:= TList.Create; FInstances.Add(Printer); end; procedure RemoveInstance(Printer: TZPrinter); var i: integer; begin if FInstances<>nil then i:= FInstances.IndexOf(Printer) else i:= -1; if i>=0 then FInstances.Delete(i); end; function FindInstance(DC: HDC): TZPrinter; var i: integer; begin if FInstances<>nil then for i:= 0 to FInstances.Count-1 do begin result:= FInstances[i]; if result.IsHandle(DC) then exit; end; result:= nil; end; function AbortProc(DC: HDC; Error: integer): BOOL; stdcall; var p: TZPrinter; begin Application.ProcessMessages; p:= FindInstance(DC); result:= (p<>nil) and (not p.Aborted); end; // _____________________________________________________________________________ // // . // _____________________________________________________________________________ type TZPrinterCanvas = class(TCanvas) private FPrinter: TZPrinter; procedure UpdateFont; protected procedure CreateHandle; override; procedure Changing; override; public constructor Create(APrinter: TZPrinter); property Printer: TZPrinter read FPrinter; end; constructor TZPrinterCanvas.Create; begin inherited Create; FPrinter:= APrinter; end; procedure TZPrinterCanvas.CreateHandle; begin UpdateFont; Handle:= FPrinter.FHandle; end; procedure TZPrinterCanvas.Changing; begin FPrinter.CheckPrinting(true); inherited Changing; UpdateFont; end; procedure TZPrinterCanvas.UpdateFont; var r,z: integer; begin r:= FPrinter.Resolution.y; if r<>Font.PixelsPerInch then begin z:= Font.Size; Font.PixelsPerInch:= r; Font.Size:= z; end; end; // _____________________________________________________________________________ // // . // _____________________________________________________________________________ type TZPrinterCompatibleCanvas = class(TCanvas) private FPixelsPerInch: integer; procedure UpdateFont; protected procedure Changing; override; public constructor Create(APrinter: TZPrinter); reintroduce; destructor Destroy; override; end; constructor TZPrinterCompatibleCanvas.Create; begin inherited Create; if APrinter=nil then raise Exception.Create(sInvalidDevice); FPixelsPerInch:= APrinter.Resolution.y; Handle:= APrinter.GetIC; Assert(Handle<>0); end; destructor TZPrinterCompatibleCanvas.Destroy; begin if Handle<>0 then begin DeleteDC(Handle); Handle:= 0; end; inherited Destroy; end; procedure TZPrinterCompatibleCanvas.Changing; begin inherited Changing; UpdateFont; end; procedure TZPrinterCompatibleCanvas.UpdateFont; var z: integer; begin if FPixelsPerInch<>Font.PixelsPerInch then begin z:= Font.Size; Font.PixelsPerInch:= FPixelsPerInch; Font.Size:= z; end; end; // _____________________________________________________________________________ // // . // _____________________________________________________________________________ constructor TZPrinter.Create; begin inherited Create; FCanvas:= TZPrinterCanvas.Create(Self); try DeviceName:= ''; // Use default printer except DeviceIndex:= 0; // Use the first printer end; AddInstance(Self); // Force initial paper size; forget about errors. if ZPrinter_Force_Paper<>'' then try Paper:= 'A4'; except end; end; destructor TZPrinter.Destroy; begin try if Printing then EndDoc; ReleaseHandle; FreeAndNil(FCanvas); ClosePrinterHandle; FreeDeviceMode; finally RemoveInstance(Self); inherited Destroy; end; end; function TZPrinter.GetIC; var d: TZPrintDevice; begin d:= Device; result:= CreateIC(PChar(d.Driver),PChar(d.Device),PChar(d.Port),FDevMode); if result=0 then raise Exception.Create(sInvalidDevice); end; procedure TZPrinter.ICNeeded; begin if FHandle=0 then FHandle:= GetIC; end; procedure TZPrinter.DCNeeded; var d: TZPrintDevice; begin if FHandle=0 then begin d:= Device; FHandle:= CreateDC(PChar(d.Driver),PChar(d.Device),PChar(d.Port),FDevMode); if FHandle=0 then raise Exception.Create(sInvalidDevice); end; end; procedure TZPrinter.ReleaseHandle; begin if FHandle<>0 then begin DeleteDC(FHandle); FHandle:= 0; end; end; function TZPrinter.IsHandle; begin result:= (FHandle=Value); end; procedure TZPrinter.StartDoc; var DocInfo: TDocInfo; begin // This is similar to . CheckPrinting(false); ReleaseHandle; DCNeeded; if FHandle=0 then raise Exception.Create(sInvalidDevice); try FCanvas.Handle:= FHandle; FPageNumber:= 1; FAborted:= false; FCanvas.Refresh; TZPrinterCanvas(FCanvas).UpdateFont; FillChar(DocInfo,SizeOf(DocInfo),0); with DocInfo do begin cbSize:= SizeOf(DocInfo); lpszDocName:= PChar(FTitle); if OutFileName<>'' then lpszOutput:= PChar(OutFileName); end; SetAbortProc(FHandle,AbortProc); Windows.StartDoc(FHandle,DocInfo); except FCanvas.Handle:= 0; FPageNumber:= 0; raise; end; end; procedure TZPrinter.EndDoc; begin // This is similar to . CheckPrinting(true); try if not FAborted then Windows.EndDoc(FHandle); finally FCanvas.Handle:= 0; FPageNumber:= 0; FAborted:= false; end; end; procedure TZPrinter.AbortDoc; begin // This is similar to . CheckPrinting(true); Windows.AbortDoc(FHandle); FAborted:= true; EndDoc; end; procedure TZPrinter.StartPage; begin // This is taken from ; see also . inc(FPageNumber); Windows.StartPage(FHandle); FCanvas.Refresh; end; procedure TZPrinter.EndPage; begin // This is taken from ; see also . Windows.EndPage(FHandle); end; procedure TZPrinter.CheckPrinting; begin // Check current printing status; raise exception if different from what // expected. if Value then begin if not Printing then raise Exception.Create(sNotPrinting); end else begin if Printing then raise Exception.Create(sPrinting); end; end; procedure TZPrinter.CheckDevice; begin if Value='' then Value:= FDeviceName; if PrintDevices.DeviceIndex(Value)<0 then raise Exception.CreateFmt(sNoSuchDevice,[Value]); end; procedure TZPrinter.ClosePrinterHandle; begin if FPrinterHandle<>0 then begin ClosePrinter(FPrinterHandle); FPrinterHandle:= 0; end; end; procedure TZPrinter.FreeDeviceMode; begin if FDeviceMode<>0 then begin GlobalUnlock(FDeviceMode); GlobalFree(FDeviceMode); FDeviceMode:= 0; FDevMode:= nil; end; end; function TZPrinter.GetHandle; begin ICNeeded; result:= FHandle; end; procedure TZPrinter.SetTitle; begin CheckPrinting(false); FTitle:= Value; end; function TZPrinter.GetDeviceIndex; begin result:= PrintDevices.DeviceIndex(FDeviceName); end; procedure TZPrinter.SetDeviceIndex; begin if Value<0 then DeviceName:= '' else DeviceName:= PrintDevices[Value].Name; end; procedure TZPrinter.SetDeviceName; var e: string; u: TDeviceMode; h,m: THandle; v: PDeviceMode; begin CheckPrinting(false); if Value='' then try Value:= PrintDevices.DefaultDevice.Name; except raise Exception.Create(sNoDefaultDevice); end else begin CheckDevice(Value); end; // is the device name of the current printer. e:= FPrintDevices.DeviceByName(Value).Device; ReleaseHandle; // Open the device and retrieve its handle in . // Set its device mode and devmode . m:= 0; v:= nil; if OpenPrinter(PChar(e),h,nil) then begin m:= GlobalAlloc(GHND,WinSpool.DocumentProperties(0,h,PChar(e),u,u,0)); if m<>0 then begin v:= GlobalLock(m); if WinSpool.DocumentProperties(0,h,PChar(e),v^,v^,DM_OUT_BUFFER)<0 then begin GlobalUnlock(m); GlobalFree(m); m:= 0; end; end; end; if (m=0) or (v=nil) then raise Exception.Create(sInvalidOperation); FDeviceName:= Value; ClosePrinterHandle; FPrinterHandle:= h; FreeDeviceMode; FDeviceMode:= m; FDevMode:= v; end; function TZPrinter.GetDevice; begin result:= FPrintDevices.DeviceByName(FDeviceName); end; function TZPrinter.GetBin; var i: integer; begin if FDevMode=nil then raise Exception.Create(sInvalidOperation); with Device do begin i:= Bins.IndexOfObject(pointer(integer(FDevMode^.dmDefaultSource))); if i>=0 then result:= Bins[i] else result:= ''; end; end; procedure TZPrinter.SetBin; var i: integer; begin CheckPrinting(false); if FDevMode=nil then raise Exception.Create(sInvalidOperation); with Device do begin i:= Bins.IndexOf(Value); if i<0 then raise Exception.CreateFmt(sInvalidBin,[Value]); ReleaseHandle; FDevMode^.dmDefaultSource:= integer(pointer(Bins.Objects[i])); end; end; function TZPrinter.GetPaper; var i: integer; begin with Device do begin i:= Papers.IndexOfObject(pointer(PaperFmt)); if i>=0 then result:= Papers[i] else result:= ''; end; end; procedure TZPrinter.SetPaper; var i: integer; begin CheckPrinting(false); if FDevMode=nil then raise Exception.Create(sInvalidOperation); with Device do begin i:= Papers.IndexOf(Value); if i<0 then raise Exception.CreateFmt(sInvalidPaper,[Value]); ReleaseHandle; FDevMode^.dmPaperSize:= integer(pointer(Papers.Objects[i])); end; end; function TZPrinter.GetPaperDesc; var p: TPoint; begin p:= PaperSize; if (p.x>0) and (p.y>0) then result:= Format(sPaper,[Paper,p.x div 10,p.y div 10]) else result:= Paper; end; function TZPrinter.GetPaperFmt; begin if FDevMode=nil then raise Exception.Create(sInvalidOperation); result:= FDevMode^.dmPaperSize; end; function TZPrinter.GetResolution; begin result.x:= GetDeviceCaps(Handle,LOGPIXELSX); result.y:= GetDeviceCaps(Handle,LOGPIXELSY); end; procedure TZPrinter.SetResolution; begin CheckPrinting(false); if FDevMode=nil then raise Exception.Create(sInvalidOperation); with Device do begin ReleaseHandle; FDevMode^.dmPrintQuality:= Value.x; FDevMode^.dmYResolution:= Value.y; end; end; function TZPrinter.GetResolutionStr; begin result:= FmtDpi(Resolution); end; procedure TZPrinter.SetResolutionStr; var i: integer; m: TSmallPoint; begin with Device do begin i:= Resolutions.IndexOf(Value); if i<0 then raise Exception.CreateFmt(sInvalidResolution,[Value]); m:= TSmallPoint(pointer(Resolutions.Objects[i])); Resolution:= SmallPointToPoint(m); end; end; function TZPrinter.GetOrientation; begin if FDevMode=nil then raise Exception.Create(sInvalidOperation); if zcOrientation in Device.Capabilitie
系統時間:2024-04-25 11:31:20
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!