自定义打印预览设置Windows.pas未定义纸张ID不生效问题求助
问题分析与解决方案
你的问题出在非预定义纸张尺寸仅设置dmPapersize是不够的,部分PDF打印机驱动需要明确指定纸张的实际宽高参数,并且需要主动将修改后的DeviceMode同步回Printer对象,而不是仅依赖GlobalUnlock。
核心原因
Windows预定义的纸张ID(如DMPAPER_A4)对应的宽高已经被驱动默认识别,但像ISO A0(ID=142)这类非通用尺寸,驱动无法仅通过ID直接获取尺寸信息,必须显式设置dmPaperWidth和dmPaperHeight,同时要在dmFields中标记这两个字段已修改。另外,GlobalUnlock只是解锁全局内存块,并不会自动将修改后的DeviceMode同步到TPrinter的上下文里,需要主动调用Printer.SetPrinter完成刷新。
修改后的代码
procedure SetPaperID(APaperID: SmallInt); var Device, Driver, Port: array [0 .. 255] of Char; hDeviceMode: THandle; pDevMode: PDeviceMode; PaperWidth, PaperHeight: Integer; begin // 获取当前打印机的Device、Driver、Port和DeviceMode Printer.GetPrinter(Device, Driver, Port, hDeviceMode); if hDeviceMode <> 0 then begin pDevMode := GlobalLock(hDeviceMode); if pDevMode <> nil then try // 1. 标记要修改的字段:纸张尺寸+宽高 pDevMode^.dmFields := pDevMode^.dmFields or DM_PAPERSIZE or DM_PAPERWIDTH or DM_PAPERHEIGHT; // 2. 设置纸张ID pDevMode^.dmPapersize := APaperID; // 3. 获取对应纸张ID的实际宽高(单位:0.1毫米) case APaperID of 142: // ISO A0的ID begin PaperWidth := 8410; // 841mm × 10 PaperHeight := 11890; // 1189mm ×10 end; // 其他非预定义纸张ID可在此添加对应尺寸 else // 预定义ID直接取当前打印机的默认宽高 PaperWidth := GetDeviceCaps(Printer.Handle, PHYSICALWIDTH); PaperHeight := GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT); end; // 4. 设置纸张宽高 pDevMode^.dmPaperWidth := PaperWidth; pDevMode^.dmPaperHeight := PaperHeight; finally GlobalUnlock(hDeviceMode); // 5. 主动将修改后的DeviceMode同步回Printer对象 Printer.SetPrinter(Device, Driver, Port, hDeviceMode); end; end; end;
额外说明
- 纸张宽高的单位是0.1毫米,比如A0的实际尺寸是841×1189毫米,对应的值就是8410和11890。
- 若要避免硬编码尺寸,可调用
EnumFormsAPI枚举打印机支持的所有表单,动态获取每个纸张ID对应的宽高参数。 Printer.SetPrinter是关键步骤,它会强制TPrinter刷新内部打印上下文,确保后续的预览、打印操作使用最新的纸张设置。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

