|  | 
 
| '打印纸相关属性
 Public Type PaperRegion_sq
 Width As Double       '打印纸宽度
 Height As Double      '打印纸高度
 LeftMargin As Double  '左边距
 RightMargin As Double '右边距
 TopMargin As Double   '上边距
 BottomMargin As Double    '下边距
 Left As Double
 Right As Double
 Top As Double
 Bottom As Double
 End Type
 
 '设置夏克纸张到指定大小,单位:mm
 '夏克纸张这个FormName应该存在,这里不作检查
 Public Function UsePaper(pWidth As Double, pHeight As Double, Optional ByRef ErrMsg As String) As Long
 'WinXP下测试
 Dim aFI1() As Byte, sFI1 As sFORM_INFO_1, FormName As String
 Dim PrinterName As String, hPrinter As Long
 Dim nSize As Long, pDevMode As DEVMODE, aDevMode() As Byte
 
 PrinterName = Printer.DeviceName
 FormName = "夏克纸张" '测试时在控制面板-打印机和传真的文件菜单中选服务器属性,添加一个格式,叫夏克纸张,大小随意
 With sFI1
 .Flags = 0
 .PName = FormName
 .Size.cx = pWidth * 1000
 .Size.cy = pHeight * 1000
 .ImageableArea.Left = 0
 .ImageableArea.Top = 0
 .ImageableArea.Right = pWidth * 1000
 .ImageableArea.Bottom = pHeight * 1000
 End With
 
 If OpenPrinter(PrinterName, hPrinter, 0&) = 0 Then GoTo ErrHandle
 
 '修改自定义纸张
 ReDim aFI1(Len(sFI1))
 Call CopyMemory(aFI1(0), sFI1, Len(sFI1))
 If SetForm(hPrinter, FormName, 1, aFI1(0)) = 0 Then GoTo ErrHandle
 
 '更新Printer
 nSize = DocumentProperties(0, hPrinter, PrinterName, 0&, 0&, 0&)
 ReDim aDevMode(1 To nSize)
 nSize = DocumentProperties(0, hPrinter, PrinterName, aDevMode(1), 0&, DM_OUT_BUFFER)
 Call CopyMemory(pDevMode, aDevMode(1), Len(pDevMode))
 pDevMode.dmFormName = FormName & Chr(0)     ' 必须以NULL结尾!!
 pDevMode.dmFields = DM_FORMNAME     '设置dmFields标志位
 Call CopyMemory(aDevMode(1), pDevMode, Len(pDevMode))
 nSize = DocumentProperties(0, hPrinter, PrinterName, aDevMode(1), aDevMode(1), DM_IN_BUFFER Or DM_OUT_BUFFER)
 nSize = ResetDC(Printer.hDC, aDevMode(1))
 ClosePrinter (hPrinter)    '关闭打印机
 Call GetPaperRegion(vbMillimeters) '在这里观察GetPaperRegion的值出现问题,描述在后面
 UsePaper = -1
 Exit Function
 ErrHandle:
 ErrMsg = Err.LastDllError
 Exit Function
 End Function
 
 '返回默认打印机首选打印纸信息
 Public Function GetPaperRegion(Optional pScaleMode As ScaleModeConstants = vbPixels) As PaperRegion_sq
 With GetPaperRegion
 .Width = GetDeviceCaps(Printer.hDC, PHYSICALWIDTH)
 .Height = GetDeviceCaps(Printer.hDC, PHYSICALHEIGHT)
 .LeftMargin = GetDeviceCaps(Printer.hDC, PHYSICALOFFSETX)
 .TopMargin = GetDeviceCaps(Printer.hDC, PHYSICALOFFSETY)
 .RightMargin = GetDeviceCaps(Printer.hDC, PHYSICALWIDTH) - GetDeviceCaps(Printer.hDC, HORZRES) - GetDeviceCaps(Printer.hDC, PHYSICALOFFSETX)
 .BottomMargin = GetDeviceCaps(Printer.hDC, PHYSICALHEIGHT) - GetDeviceCaps(Printer.hDC, VERTRES) - GetDeviceCaps(Printer.hDC, PHYSICALOFFSETY)
 .Left = 0
 .Top = 0
 .Right = .LeftMargin + GetDeviceCaps(Printer.hDC, HORZRES)
 .Bottom = .TopMargin + GetDeviceCaps(Printer.hDC, VERTRES)
 End With
 
 If pScaleMode = vbPixels Then Exit Function
 
 Dim x As Double, y As Double
 '先转换成英寸然后再转换成其它单位
 x = GetDeviceCaps(Printer.hDC, LOGPIXELSX): y = GetDeviceCaps(Printer.hDC, LOGPIXELSY)
 With GetPaperRegion
 .Width = .Width / x
 .Height = .Height / y
 .LeftMargin = .LeftMargin / x
 .TopMargin = .TopMargin / y
 .RightMargin = .RightMargin / x
 .BottomMargin = .BottomMargin / y
 .Right = .Right / x
 .Bottom = .Bottom / y
 End With
 If pScaleMode = vbInches Then Exit Function
 
 With GetPaperRegion
 .Width = Printer.ScaleX(.Width, vbInches, pScaleMode)
 .Height = Printer.ScaleY(.Height, vbInches, pScaleMode)
 .LeftMargin = Printer.ScaleX(.LeftMargin, vbInches, pScaleMode)
 .TopMargin = Printer.ScaleY(.TopMargin, vbInches, pScaleMode)
 .RightMargin = Printer.ScaleX(.RightMargin, vbInches, pScaleMode)
 .BottomMargin = Printer.ScaleY(.BottomMargin, vbInches, pScaleMode)
 .Right = Printer.ScaleX(.Right, vbInches, pScaleMode)
 .Bottom = Printer.ScaleY(.Bottom, vbInches, pScaleMode)
 End With
 End Function
 
 在UsePaper中执行了ResetDC后,通过GetPaperRegion函数来观察宽度和高度,发现对于LQ1600K可以自定义,对联想激光打印机Lj2500就不行,但返回的却是正确的DC值
 
 退出UsePaper时,通过GetPaperRegion函数来观察宽度和高度,发现又变成默认打印纸大小了。不退出进程,观察LQ1600K的打印首选项,发现默认打印纸根本没有改变。
 | 
 |