Jump to content

Unable to set a printer font


Recommended Posts

I am trying to print using a small font, but no mater how I try it, the printed font remains unchanged.
I have created a sample script that sets the font to 8.
Here are the functions I use to create, then set the font:

Func _Printer_SetFont($hDC)
    Local $hFont

    If ($a__Printer_Font == 0) Then
        _Printer_MakeFont()
    EndIf

    $hFont = $a__Printer_Font
    _LogMsg("+++: $hDC & " & $hDC & ", $hFont = " & $hFont)

    _WinAPI_SetFont($hDC, $hFont) ; <=====================

EndFunc   ;==>_Printer_SetFont

Func _Printer_MakeFont()
    Local $hFontDC, $err, $errm, $str, $flag, $iHeight

    $flag = $FW_BOLD
    $iHeight = 8

    $hFontDC = _WinAPI_CreateFont( _
            $iHeight, _
            0, _ ; average character width
            0, _ ; angle of escape
            0, _ ; base-line orientation
            $flag, _ ; font weight - $FW_NORMAL, $FW_BOLD, etc.
            False, _ ; italic
            False, _ ; underline
            False, _ ; strikeout
            $DEFAULT_CHARSET, _ ; the character set
            $OUT_DEFAULT_PRECIS, _ ;  the output precision
            $CLIP_DEFAULT_PRECIS, _ ; the clipping precision
            $DEFAULT_QUALITY, _ ; the output quality
            0, _ ; the pitch and family of the font
            "courier new") ;  typeface name

    _LogMsg("+++: $hFontDC = 0x" & Hex($hFontDC))

    If ($hFontDC <= 0) Then
        $str = "_WinAPI_CreateFont() failed." & @CRLF
        $err = _WinAPI_GetLastError()
        $errm = _WinAPI_GetLastErrorMessage()
        _LogMsg("+++: " & $err & ", 0) - '" & $errm & "'" & @CRLF & $str)
        Exit (9)
    EndIf

    $a__Printer_Font = $hFontDC
EndFunc   ;==>_Printer_MakeFont

Here is the complete script:

#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

Opt('MustDeclareVars', 1)

#include <APIDlgConstants.au3>
#include <FontConstants.au3>
#include <WinAPI.au3>

; #VARIABLES# ================================================================
Global $i__LastLineNum = -1, $i__NextLineNum = -1, $i__ThisLineNum = -1
Global $i__LeftMargin_X, $i__TopMargin_Y, $i__PageWidth, $i__PageHeight
Global $i__CurrentPos_X, $i__CurrentPos_Y
Global $i__Printer_Char_H = -1, $i__Printer_Char_W = -1
Global $a__Printer_Font = 0
Global $i__x_start, $i__x_end, $i__y_start, $i__y_end
; ============================================================================

; #CONSTANTS# ================================================================
Global $PHYSICALWIDTH = 110, $PHYSICALHEIGHT = 111
Global $PHYSICALOFFSETX = 112, $PHYSICALOFFSETY = 113
Const $VLINESPACE = 20 ; Number of pixels between lines
Global Const $tagPD = "align 1;DWORD lStructSize;" & "HWND hwndOwner;" & "handle hDevMode;" & "handle hDevNames;" & _
        "handle hDC;" & "DWORD Flags;" & _
        "WORD nFromPage;" & "WORD nToPage;" & "WORD nMinPage;" & "WORD nMaxPage;" & "WORD nCopies;" & _
        "handle hInstance;" & "LPARAM lCustData;" & "ptr lpfnPrintHook;" & "ptr lpfnSetupHook;" & _
        "ptr lpPrintTemplateName;" & "ptr lpSetupTemplateName;" & "handle hPrintTemplate;" & "handle hSetupTemplate"

Global Const $tagDOCINFO = "int   Size;" & "ptr   DocName;" & "ptr   Output;" & "ptr   Datatype;" & "dword Type"
; ============================================================================

_Main()

Func _Main()
    Local $hDC, $str, $str2 = "", $linenum

    $hDC = _Printer_Open(0, Default, "DOCNAME: ++++")
    _LogMsg("+++: $hPrintDc = 0x" & Hex($hDC))
    If (Not $hDC) Then Exit (1)

    _Printer_SetFont($hDC)

    For $y = 1 To 10
        $str2 &= "123456789."
    Next

    $linenum = 30 ; Start in the middle of the page
    For $x = 1 To 15
        $str = "[" & $x & " " & $str2
        _LogMsg("+++: $str ==>" & $str & "<==")
        _Printer_PrintTextLine($hDC, $str, $linenum)
        $linenum += 1
    Next

    _Printer_Close($hDC)

EndFunc   ;==>_Main

Func _Printer_SetFont($hDC)
    Local $hFont

    If ($a__Printer_Font == 0) Then
        _Printer_MakeFont()
    EndIf

    $hFont = $a__Printer_Font
    _LogMsg("+++: $hDC & " & $hDC & ", $hFont = " & $hFont)

    _WinAPI_SetFont($hDC, $hFont) ; <=====================

EndFunc   ;==>_Printer_SetFont

Func _Printer_MakeFont()
    Local $hFontDC, $err, $errm, $str, $flag, $iHeight

    $flag = $FW_BOLD
    $iHeight = 8

    $hFontDC = _WinAPI_CreateFont( _
            $iHeight, _
            0, _ ; average character width
            0, _ ; angle of escape
            0, _ ; base-line orientation
            $flag, _ ; font weight - $FW_NORMAL, $FW_BOLD, etc.
            False, _ ; italic
            False, _ ; underline
            False, _ ; strikeout
            $DEFAULT_CHARSET, _ ; the character set
            $OUT_DEFAULT_PRECIS, _ ;  the output precision
            $CLIP_DEFAULT_PRECIS, _ ; the clipping precision
            $DEFAULT_QUALITY, _ ; the output quality
            0, _ ; the pitch and family of the font
            "courier new") ;  typeface name

    _LogMsg("+++: $hFontDC = 0x" & Hex($hFontDC))

    If ($hFontDC <= 0) Then
        $str = "_WinAPI_CreateFont() failed." & @CRLF
        $err = _WinAPI_GetLastError()
        $errm = _WinAPI_GetLastErrorMessage()
        _LogMsg("+++: " & $err & ", 0) - '" & $errm & "'" & @CRLF & $str)
        Exit (9)
    EndIf

    $a__Printer_Font = $hFontDC
EndFunc   ;==>_Printer_MakeFont

Func _Printer_Open($hGUI = 0, $iFlags = Default, $sDocName = "")
    Local $hDC, $tPD, $err

    If $iFlags = Default Then
        $iFlags = 0
        $iFlags = BitOR($iFlags, $PD_RETURNDC)
        $iFlags = BitOR($iFlags, $PD_USEDEVMODECOPIESANDCOLLATE)
    EndIf

    $tPD = DllStructCreate($tagPD)
    DllStructSetData($tPD, "lStructSize", DllStructGetSize($tPD))
    DllStructSetData($tPD, "hwndOwner", $hGUI) ;

    If $hGUI <> 0 Then
        DllStructGetData($tPD, "hInstance", _WinAPI_GetModuleHandle(""))
    EndIf

    DllStructSetData($tPD, "Flags", $iFlags)
    DllStructSetData($tPD, "nCopies", 2)
    Local $bRet = DllCall("Comdlg32.dll", "int", "PrintDlgW", "ptr", DllStructGetPtr($tPD))
    $err = @error

    If $err Then
        $err = _WinAPI_GetLastError()
        Local $errm = _WinAPI_GetLastErrorMessage()
        _LogMsg("+++: _Printer_Open() returns:  (1, " & $err & ", 0) - '" & $errm & "'")
        $tPD = 0
        Return SetError(1, $err, 0)
    EndIf

    If $bRet[0] = True Then
        $hDC = DllStructGetData($tPD, "hDC")
    Else
        Return SetError(2, $err, 0)
    EndIf

    $tPD = 0

    __Printer_SetupCharWH($hDC)
    _Printer_GetMetrics($hDC)

    _Printer_Startup($hDC, $sDocName)

    Return (SetError(0, 0, $hDC))
EndFunc   ;==>_Printer_Open

Func _Printer_Startup($hDC, $sDocName)
    Local $oDocNameStruct, $DOCINFO, $printJobID, $errstr

    __Printer_SetupCharWH($hDC) ; Get the height and width of a printer character

    $oDocNameStruct = DllStructCreate("char DocName[" & StringLen($sDocName & Chr(0)) & "]")
    DllStructSetData($oDocNameStruct, "DocName", $sDocName & Chr(0)) ; Size of DOCINFO structure
    $DOCINFO = DllStructCreate($tagDOCINFO) ; Structure for Print Document info
    DllStructSetData($DOCINFO, "Size", 20) ; Size of DOCINFO structure
    DllStructSetData($DOCINFO, "DocName", DllStructGetPtr($oDocNameStruct)) ; Set name of print job (Optional)

    _Printer_GetMetrics($hDC)

    $printJobID = _Printer_StartDoc($hDC, $DOCINFO) ; start new print doc

    If ($printJobID <= 0) Then
        $errstr = "_Printer_StartDoc() failed"
        _LogMsg("+++: _Printer_Startup() returns: @error = 1 - " & $errstr)
        Return (SetError(1, 0, $errstr))
    EndIf

    Return (SetError(0, 0, $printJobID)) ; print job ID
EndFunc   ;==>_Printer_Startup

Func _Printer_Close($hDC)
    _Printer_EndPage($hDC) ; End the currend page
    _Printer_EndDoc($hDC) ; End the print job
    _WinAPI_DeleteDC($hDC) ; Delete the printer device context
EndFunc   ;==>_Printer_Close

Func _Printer_EndPage($hDC)
    Local $aResult

    If ($i__ThisLineNum > 1) Then
        $aResult = DllCall("GDI32.dll", "long", "EndPage", "hwnd", $hDC)
    EndIf

    _Printer_SetInitial_XY()

    $i__ThisLineNum = -1

    Return ($aResult[0])
EndFunc   ;==>_Printer_EndPage

Func _Printer_EndDoc($hDC)
    Local $aResult

    $aResult = DllCall("GDI32.dll", "long", "EndDoc", "hwnd", $hDC)

    Return ($aResult[0])
EndFunc   ;==>_Printer_EndDoc

Func _Printer_TextOut($hDC, $iXStart, $iYStart, $sString)
    Local $aResult

    $aResult = DllCall("GDI32.dll", _
            "long", "TextOut", _
            "hwnd", $hDC, _
            "long", $iXStart, _
            "long", $iYStart, _
            "str", $sString, _
            "long", StringLen($sString))

    Return $aResult[0] ; 0 = fail, 1 = OK
EndFunc   ;==>_Printer_TextOut

Func _Printer_PrintTextLine($hDC, $sText, $iLineNumber = -1)
    Local $ret, $lines, $ndx

    If ($iLineNumber <= 0) Then
        $iLineNumber = $i__ThisLineNum
    EndIf

    $sText = StringStripWS($sText, 2) ; Clear trailing whitespace

    ; Break text into an array of lines, based on any of the
    ; usual line endings (@CR, @LF, etc.) found in the string.
    $sText = StringRegExpReplace($sText, "[\\][n]", @CR)

    $sText = StringReplace($sText, @CRLF, @LF)
    $sText = StringReplace($sText, @CR, @LF)
    While (StringRight($sText, 1) == @LF)
        StringTrimRight($sText, 1) ; remove trailing LF's
    WEnd
    $lines = StringSplit($sText, @LF, 2)

    ; Now print each line in the array of lines, advancing the
    ; printer line position each time
    For $ndx = 0 To UBound($lines) - 1
        $i__CurrentPos_X = $i__x_start ;  $i__LeftMargin_X
        $i__CurrentPos_Y = (($i__Printer_Char_H + $VLINESPACE) * $iLineNumber) + $i__y_start

        $ret = _Printer_TextOut($hDC, $i__CurrentPos_X, $i__CurrentPos_Y, $lines[$ndx])

        $iLineNumber += 1
        $i__ThisLineNum += 1

        If ($ret == 0) Then ExitLoop

        If ($iLineNumber > $i__LastLineNum) Then
            _Printer_EndPage($hDC)
            $iLineNumber = 1
            $i__ThisLineNum = 1
        EndIf
    Next

    ; Calculate next x/y position
    $i__CurrentPos_Y = (($i__Printer_Char_H + $VLINESPACE) * $iLineNumber)

    Return (SetError(0, 0, $iLineNumber))

EndFunc   ;==>_Printer_PrintTextLine

Func _Printer_StartDoc($hDC, $tDocInfo)
    Local $aResult

    $aResult = DllCall("GDI32.dll", "long", "StartDoc", "hwnd", $hDC, "ptr", DllStructGetPtr($tDocInfo))

    _Printer_SetInitial_XY()

    Return ($aResult[0]) ; >0 = OK, <=0 = Fail
EndFunc   ;==>_Printer_StartDoc

Func _Printer_GetMetrics($hDC)

    $i__LeftMargin_X = _WinAPI_GetDeviceCaps($hDC, $PHYSICALOFFSETX)
    $i__TopMargin_Y = _WinAPI_GetDeviceCaps($hDC, $PHYSICALOFFSETY)
    $i__PageWidth = _WinAPI_GetDeviceCaps($hDC, $PHYSICALWIDTH)
    $i__PageHeight = _WinAPI_GetDeviceCaps($hDC, $PHYSICALHEIGHT)

#Tidy_Off
    _LogMsg("+++:" & @CRLF _
             & "$PHYSICALOFFSETX [" & $PHYSICALOFFSETX & "] $i__LeftMargin_X = " & $i__LeftMargin_X & @CRLF _
             & "$PHYSICALOFFSETY [" & $PHYSICALOFFSETY & "] $i__TopMargin_Y  = " & $i__TopMargin_Y & @CRLF _
             & "$PHYSICALWIDTH   [" & $PHYSICALWIDTH   & "] $i__PageWidth    = " & $i__PageWidth & @CRLF _
             & "$PHYSICALHEIGHT  [" & $PHYSICALHEIGHT  & "] $i__PageHeight   = " & $i__PageHeight & @CRLF _
            )
#Tidy_On

    $i__x_start = $i__LeftMargin_X - 75
    $i__y_start = $i__TopMargin_Y - 75
    $i__x_end = $i__PageWidth - 250
    $i__y_end = $i__PageHeight - 200

    _Printer_SetInitial_XY()

    $i__LastLineNum = _Printer_GetLastLineNum()
EndFunc   ;==>_Printer_GetMetrics

Func _Printer_SetInitial_XY()

    $i__CurrentPos_X = $i__LeftMargin_X
    $i__CurrentPos_Y = $i__TopMargin_Y * 22
EndFunc   ;==>_Printer_SetInitial_XY

Func _Printer_GetLastLineNum()
    Local $x1, $y, $linenumber

    $linenumber = -1

    If ($i__Printer_Char_H > 0) Then
        For $x1 = 1 To 999
            $y = (($i__Printer_Char_H + $VLINESPACE) * ($x1 + 1))
            If ($y >= $i__y_end) Then
                $linenumber = $x1
                ExitLoop
            EndIf
        Next
    EndIf

    If ($linenumber == -1) Then
        MsgBox(0, "Internal Error", "ERROR: Could not calculate the last line number")
        Exit (1)
    EndIf

    $linenumber -= 1

    Return ($linenumber)
EndFunc   ;==>_Printer_GetLastLineNum

Func __Printer_SetupCharWH($hDC)
    Local $vExtents

    $vExtents = _WinAPI_GetTextExtentPoint32($hDC, "x")
    $i__Printer_Char_W = DllStructGetData($vExtents, "X") ; Get the width of a character
    $i__Printer_Char_H = DllStructGetData($vExtents, "Y") ; Get the height of a character

EndFunc   ;==>__Printer_SetupCharWH

Func _LogMsg($msg, $lnum = @ScriptLineNumber)
    If (StringLeft($msg, 4) = "+++:") Then $msg = StringTrimLeft($msg, 5)
    $msg = StringStripWS($msg, 3)
    ConsoleWrite("+++:" & $lnum & "] " & $msg & @CRLF)
EndFunc   ;==>_LogMsg
Func _Printer_SetFont($hDC)
    Local $hFont

    If ($a__Printer_Font == 0) Then
        _Printer_MakeFont()
    EndIf

    $hFont = $a__Printer_Font
    _LogMsg("+++: $hDC & " & $hDC & ", $hFont = " & $hFont)

    _WinAPI_SetFont($hDC, $hFont) ; <=====================

EndFunc   ;==>_Printer_SetFont

Func _Printer_MakeFont()
    Local $hFontDC, $err, $errm, $str, $flag, $iHeight

    $flag = $FW_BOLD
    $iHeight = 8

    $hFontDC = _WinAPI_CreateFont( _
            $iHeight, _
            0, _ ; average character width
            0, _ ; angle of escape
            0, _ ; base-line orientation
            $flag, _ ; font weight - $FW_NORMAL, $FW_BOLD, etc.
            False, _ ; italic
            False, _ ; underline
            False, _ ; strikeout
            $DEFAULT_CHARSET, _ ; the character set
            $OUT_DEFAULT_PRECIS, _ ;  the output precision
            $CLIP_DEFAULT_PRECIS, _ ; the clipping precision
            $DEFAULT_QUALITY, _ ; the output quality
            0, _ ; the pitch and family of the font
            "courier new") ;  typeface name

    _LogMsg("+++: $hFontDC = 0x" & Hex($hFontDC))

    If ($hFontDC <= 0) Then
        $str = "_WinAPI_CreateFont() failed." & @CRLF
        $err = _WinAPI_GetLastError()
        $errm = _WinAPI_GetLastErrorMessage()
        _LogMsg("+++: " & $err & ", 0) - '" & $errm & "'" & @CRLF & $str)
        Exit (9)
    EndIf

    $a__Printer_Font = $hFontDC
EndFunc   ;==>_Printer_MakeFont

Here is the full script.  Run it to see the problem:

Link to comment
Share on other sites

You need to use _WinAPI_SelectObject($hDC, $hFont) instead of _WinAPI_SetFont($hDC, $hFont)

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

48 minutes ago, AndyS19 said:

I tried this and it printed my text in ''really tiny' font.  Could you try running my script (with your changes)?

Then change font size in _Printer_MakeFont() from 8 to 100 or whatever.

 

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

On 5/23/2018 at 1:34 PM, funkey said:

Then change font size in _Printer_MakeFont() from 8 to 100 or whatever.

 

Setting it to 50 made the print big enough, but not actually a font size of 8.  I used this formula to calculate the font height, based on a font size:
     $iHeight = $iFontSize * $i__LogPixelsY / 72

And in the actual code:
 

$i__LogPixelsY = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY) ; $LOGPIXELSY = 90

    $ar = DllCall("kernel32.dll", "long", "MulDiv", "long", $iFontSize, "long", $i__LogPixelsY, "long", 72)

    $iHeight = Abs($ar[0])

 

Edited by AndyS19
Link to comment
Share on other sites

Why use Abs()?  Value should be negative...

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...