PctGL SERIES  
http://pctgl.cnblogs.com
Private Const CCHDEVICENAME = 32
Private Const CCHFORMNAME = 32

Enum PaperClassSize
    DMPAPER_LETTER = GDI.DMPAPER_LETTER
    DMPAPER_LEGAL = GDI.DMPAPER_LEGAL
    DMPAPER_A4 = GDI.DMPAPER_A4
    DMPAPER_CSHEET = GDI.DMPAPER_CSHEET
    DMPAPER_DSHEET = GDI.DMPAPER_DSHEET
    DMPAPER_ESHEET = GDI.DMPAPER_ESHEET
    DMPAPER_LETTERSMALL = GDI.DMPAPER_LETTERSMALL
    DMPAPER_TABLOID = GDI.DMPAPER_TABLOID
    DMPAPER_LEDGER = GDI.DMPAPER_LEDGER
    DMPAPER_STATEMENT = GDI.DMPAPER_STATEMENT
    DMPAPER_EXECUTIVE = GDI.DMPAPER_EXECUTIVE
    DMPAPER_A3 = GDI.DMPAPER_A3
    DMPAPER_A4SMALL = GDI.DMPAPER_A4SMALL
    DMPAPER_A5 = GDI.DMPAPER_A5
    DMPAPER_B4 = GDI.DMPAPER_B4
    DMPAPER_B5 = GDI.DMPAPER_B5
    DMPAPER_FOLIO = GDI.DMPAPER_FOLIO
    DMPAPER_QUARTO = GDI.DMPAPER_QUARTO
    DMPAPER_10X14 = GDI.DMPAPER_10X14
    DMPAPER_11X17 = GDI.DMPAPER_11X17
    DMPAPER_NOTE = GDI.DMPAPER_NOTE
    DMPAPER_ENV_9 = GDI.DMPAPER_ENV_9
    DMPAPER_ENV_10 = GDI.DMPAPER_ENV_10
    DMPAPER_ENV_11 = GDI.DMPAPER_ENV_11
    DMPAPER_ENV_12 = GDI.DMPAPER_ENV_12
    DMPAPER_ENV_14 = GDI.DMPAPER_ENV_14
    DMPAPER_ENV_DL = GDI.DMPAPER_ENV_DL
    DMPAPER_ENV_C5 = GDI.DMPAPER_ENV_C5
    DMPAPER_ENV_C3 = GDI.DMPAPER_ENV_C3
    DMPAPER_ENV_C4 = GDI.DMPAPER_ENV_C4
    DMPAPER_ENV_C6 = GDI.DMPAPER_ENV_C6
    DMPAPER_ENV_C65 = GDI.DMPAPER_ENV_C65
    DMPAPER_ENV_B4 = GDI.DMPAPER_ENV_B4
    DMPAPER_ENV_B5 = GDI.DMPAPER_ENV_B5
    DMPAPER_ENV_B6 = GDI.DMPAPER_ENV_B6
    DMPAPER_ENV_ITALY = GDI.DMPAPER_ENV_ITALY
    DMPAPER_ENV_MONARCH = GDI.DMPAPER_ENV_MONARCH
    DMPAPER_ENV_PERSONAL = GDI.DMPAPER_ENV_PERSONAL
    DMPAPER_FANFOLD_US = GDI.DMPAPER_FANFOLD_US
    DMPAPER_FANFOLD_STD_GERMAN = GDI.DMPAPER_FANFOLD_STD_GERMAN
    DMPAPER_FANFOLD_LGL_GERMAN = GDI.DMPAPER_FANFOLD_LGL_GERMAN
End Enum

Enum PrinterDialogBox
    [DialogBoxDefault] = 0
    [DialogBoxSetup] = PD_PRINTSETUP
    [DialogBoxHide] = PD_RETURNDEFAULT
End Enum

Private Type DevNames
    wDriverOffset As Integer
    wDeviceOffset As Integer
    wOutputOffset As Integer
    wDefault As Integer
    extra(100) As Byte
End Type

Private Type DEVMODE
    dmDeviceName As String * CCHDEVICENAME
    dmSpecVersion As Integer
    dmDriverVersion As Integer
    dmSize As Integer
    dmDriverExtra As Integer
    dmFields As Long
    dmOrientation As Integer
    dmPaperSize As Integer
    dmPaperLength As Integer
    dmPaperWidth As Integer
    dmScale As Integer
    dmCopies As Integer
    dmDefaultSource As Integer
    dmPrintQuality As Integer
    dmColor As Integer
    dmDuplex As Integer
    dmYResolution As Integer
    dmTTOption As Integer
    dmCollate As Integer
    dmFormName As String * CCHFORMNAME
    dmUnusedPadding As Integer
    dmBitsPerPel As Integer
    dmPelsWidth As Long
    dmPelsHeight As Long
    dmDisplayFlags As Long
    dmDisplayFrequency As Long
End Type


Private Type PrinterDlg
    lStructSize As Long
    hwndOwner As Long
    hDevMode As Long
    hDevNames As Long
    hdc As Long
    flags As EPrintDialog
    nFromPage As Integer
    nToPage As Integer
    nMinPage As Integer
    nMaxPage As Integer
    nCopies As Integer
    hInstance As Long
    lCustData As Long
    lpfnPrintHook As Long
    lpfnSetupHook As Long
    lpPrintTemplateName As String
    lpSetupTemplateName As String
    hPrintTemplate As Long
    hSetupTemplate As Long
End Type

Private Type PrinterPageSetupDlg
    lStructSize As Long
    hwndOwner As Long
    hDevMode As Long
    hDevNames As Long
    flags As Long
    ptPaperSize As POINTL
    rtMinMargin As RECT
    rtMargin As RECT
    hInstance As Long
    lCustData As Long
    lpfnPageSetupHook As Long
    lpfnPagePaintHook As Long
    lpPageSetupTemplateName As String
    hPageSetupTemplate As Long
End Type

Private Type DocInfo
    cbSize          As Long
    lpszDocName     As String
    lpszOutput      As String
    lpszDatatype    As String
    fwType          As Long
End Type

Private Declare Function PageSetupDlgX Lib "comdlg32.dll" Alias "PageSetupDlgA" (pPagesetupdlg As PrinterPageSetupDlg) As Long
Private Declare Function PrintDlg Lib "comdlg32.dll" Alias "PrintDlgA" (pPrintdlg As PrinterDlg) As Long
Private Declare Function StartDoc Lib "gdi32" Alias "StartDocA" (ByVal hdc As Long, lpdi As DocInfo) As Long
Private Declare Function StartPage Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function EndPage Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function EndDoc Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function AbortDoc Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateDC Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput As Long, lpInitData As Any) As Long
Private Declare Function ResetDC Lib "gdi32" Alias "ResetDCA" (ByVal hdc As Long, lpInitData As DEVMODE) As Long

Private Declare Function SetViewportOrgEx Lib "gdi32" (ByVal hdc As Long, ByVal nX As Long, ByVal nY As Long, lpPoint As Any) As Long
Private Declare Function SetWindowExtEx Lib "gdi32" (ByVal hdc As Long, ByVal nX As Long, ByVal nY As Long, lpSize As Any) As Long
Private Declare Function SetViewportExtEx Lib "gdi32" (ByVal hdc As Long, ByVal nX As Long, ByVal nY As Long, lpSize As Any) As Long
Private Declare Function SetWindowOrgEx Lib "gdi32" (ByVal hdc As Long, ByVal nX As Long, ByVal nY As Long, lpPoint As Any) As Long

'//  以上是有用无用的相关API声明, 摘用代码 声明就不调着用了


Sub GetSystemDefaultPrinter()
    '// 获取系统默认打印机打印作业
    Dim pd                  As PrinterDlg
    Dim pps                 As PrinterPageSetupDlg
    
    pd.lStructSize = Len(pd)
    pd.flags = PD_RETURNDC Or PD_RETURNDEFAULT
    
    If PrintDlg(pd) Then
        '// 先用 PrintDlg 获取默认打印机DC
        PG.HDC_Printer = pd.hdc
        
        Dim hGlobalData         As Long
    
        '// 锁定临时空间, 获取驱动配置信息
        hGlobalData = GlobalLock(ByVal pd.hDevMode)
        CopyMemory PG.dev_dlgMode, ByVal hGlobalData, Len(PG.dev_dlgMode)
        GlobalUnlock (hGlobalData)
        GlobalFree (pd.hDevMode)
        
        '// 锁定临时空间, 获取驱动,设备信息
        hGlobalData = GlobalLock(ByVal pd.hDevNames)
        CopyMemory PG.dev_dlgName, ByVal hGlobalData, Len(PG.dev_dlgName)
        GlobalUnlock (hGlobalData)
        GlobalFree (pd.hDevNames)
        
        Dim mulbits()       As Byte
        Dim i               As Long
        ReDim mulbits(PG.dev_dlgName.wDriverOffset - 1)
        CopyMemory mulbits(0), PG.dev_dlgName.extra(0), PG.dev_dlgName.wDriverOffset
        PG.dev_DriveName = StrConv(mulbits, vbUnicode)
        '// 获取设备名, 通常为: WINSPOOL , 为固定文本内容; 
'// 也见过 CreateDC 时未使用 winspool 仅指定打印机名字的代码,用以创建HDC,虽未测试,但是公布出来的例子代码应该也能成功
i
= lstrlenByte(PG.dev_dlgName.extra(PG.dev_dlgName.wDriverOffset + 2)) ReDim mulbits(i - 1) CopyMemory mulbits(0), PG.dev_dlgName.extra(PG.dev_dlgName.wDriverOffset + 2), i PG.dev_PrinterName = StrConv(mulbits, vbUnicode) '// 获取打印机名字
'// 获取默认打印机的打印配置 pps.lStructSize = Len(pds) pps.flags = PSD_INHUNDREDTHSOFMILLIMETERS Or PSD_RETURNDEFAULT If PageSetupDlgX(pps) Then '// 获取打印机默认配置参数 '// 锁定临时空间, 获取驱动配置信息 hGlobalData = GlobalLock(ByVal pps.hDevMode) CopyMemory PG.dev_dlgMode, ByVal hGlobalData, Len(PG.dev_dlgMode) ResetDC PG.HDC_Printer, hGlobalData '// ResetDC 用于将获取的默认打印参数应用到已选择的打印机 DC 上 GlobalUnlock (hGlobalData) GlobalFree (pps.hDevMode) '// 获取打印机分辨率, 每英寸内像素量 PG.PrinterResolveX = GetDeviceCaps(PG.HDC_Printer, LOGPIXELSX) PG.PrinterResolveY = GetDeviceCaps(PG.HDC_Printer, LOGPIXELSY) '// 转换打印机默认边距度量单位为屏幕逻辑像素 PG.dev_RectMargin = pds.rtMargin PG.dev_RectMargin.Left = mmeterPerPixelX(PG.dev_RectMargin.Left \ 100) PG.dev_RectMargin.Right = mmeterPerPixelX(PG.dev_RectMargin.Right \ 100) PG.dev_RectMargin.Top = mmeterPerPixelX(PG.dev_RectMargin.Top \ 100) PG.dev_RectMargin.bottom = mmeterPerPixelX(PG.dev_RectMargin.bottom \ 100) '// 设置打印机视图范围度量单位为像素 SetMapMode PG.HDC_Printer, MM_ANISOTROPIC '// 设置打印机设备窗口范围, 窗口设置屏幕分辨率 SetWindowExtEx PG.HDC_Printer, PG.ScreenResolveX, PG.ScreenResolveY, ByVal 0& SetWindowOrgEx PG.HDC_Printer, 0, 0, ByVal 0& '// 设置打印机设备视图范围, 设置为缩放分辨率,系统自动计算为比例 SetViewportExtEx PG.HDC_Printer, PG.PrinterResolveX, PG.PrinterResolveY, ByVal 0& SetViewportOrgEx PG.HDC_Printer, 0, 0, ByVal 0& '// 以上api: SetWindowExtEx ,SetViewportExtEx , 也就是说以 WindowExt 设置的视图范围, 显示以 ViewPort 设置的视图范围 '// 获取设备物理尺寸, 以像素为单位, 打印分辨率不同 DC 的像素尺寸也不同,分辨率越高越大 PG.dev_PaperSize.x = GetDeviceCaps(PG.HDC_Printer, HORZRES) PG.dev_PaperSize.y = GetDeviceCaps(PG.HDC_Printer, VERTRES) '// 物理尺寸解析为逻辑尺寸 DPtoLP PG.HDC_Printer, PG.dev_PaperSize, 1 '// 下面开始打印作业的具体内容了 StartDoc PG.HDC_Printer, prtDoc StartPage (PG.HDC_Printer)
TextOut PG.HDC_Printer, ...
'// 此处为向 PG.HDC_Print 用 GDI API 绘图的过程, 绘制的内容就是要打印的内容, 比如 DrawText,TextOut 绘制文本, FillRect,FrameRect 绘制矩形, LineTo,MoveTo 绘制线段等, 与普通 HDC 绘图基本一致, '// 绘图时,PG.HDC_Print 的 Rect 为:0,0,PG.dev_PaperSize.x,PG.dev_PaperSize.Y EndPage PG.HDC_Printer EndDoc PG.HDC_Printer DeleteDC PG.HDC_Printer End If End If End Sub

 

Windows 系统的打印作业目前似乎仅有 GDI API 的方法

将打印实现过程以绘图的形式给coder调用,感觉ms coder 真的很天才

普通程序员编程打印前必须用 SetMapMode ,SetWindowExtEx,SetViewportExtEx 参照上述代码内容设置视图

经过测试,字体是矢量的,无视分辨率及视图大小的变化,但是除此之外的自绘图形则无法匹配分辨率

所以必须设置视图范围,将物理尺寸、不同分辨率格式化为近似的固定范围尺寸,如上面代码将A4纸型格式化为 1000多x700多的矩形

----------------------------------------------------------------------

我没有打印机不方便实际测试,所以用 PDF 打印机测试的打印效果

有个重要问题始终没弄明白,DEVMODE 结构的参数设置到底是自动配置的还是一部分需要手动实现?

比如 DEVMODE.dmCopies 打印份数,到底是打印机自己重复打印指定份数还是需要代码实现? PDF 打印机无论指定多少份都只出一份,由于是虚拟打印机所以不确定结果

 

经过反复测试和搜索例子代码,似乎确定了一个事实,打印预览只能自己手动实现

HDC_Print ,打印机的 HDC 是无法通过 Bitblt 之类api导出的,  普通 HDC  -> Bitblt,StrxxxBlt,xxBlt,  -> 打印机 HDC,是可以的,但这样的话就相当于打印图片了,复制过去后形成了一个图片,这是单向的,打印机HDC 不能通过同样方法输出图形到普通HDC(肯定是不行的,最好也不要测试,我测试时还蓝过), 而且不要尝试直接给 打印机HDC 配置位图,SelectObject HDC_Print,位图 是无效的,但设备无关位图是可以使用的

posted on 2017-12-26 02:59  PctGL  阅读(945)  评论(0编辑  收藏  举报