Code: Select all | Expand
// Modified version of WIN32PRN
/*
* $Id: WINPRN32.prg,v 1.20 2006/01/15 20:29:02 peterrees Exp $
*/
/*
* Harbour Project source code:
* Printing subsystem for Win32 using GUI printing
* Copyright 2004 Peter Rees <peter@rees.co.nz>
* Rees Software & Systems Ltd
*
* See doc/license.txt for licensing terms.
*
* www - http://www.harbour-project.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option )
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/ ).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*/
/*
TPRINT() was designed to make it easy to emulate Clipper Dot Matrix printing.
Dot Matrix printing was in CPI ( Characters per inch & Lines per inch ).
Even though "Mapping Mode" for TPRINT() is MM_TEXT, ::SetFont() accepts the
nWidth parameter in CPI not Pixels. Also the default ::LineHeight is for
6 lines per inch so ::NewLine() works as per "LineFeed" on Dot Matrix printers.
If you do not like this then inherit from the class and override anything you want
Simple example
TO DO: Colour printing
etc....
Peter Rees 21 January 2004 <peter@rees.co.nz>
*/
#ifndef __PLATFORM__Windows
Function WINPRN32()
Return nil
#else
#include "hbclass.ch"
#include "common.ch"
#include "wingdi.ch"
/*
// Cut from wingdi.h
#define MM_TEXT 1
#define MM_LOMETRIC 2
#define MM_HIMETRIC 3
#define MM_LOENGLISH 4
#define MM_HIENGLISH 5
// Device Parameters for GetDeviceCaps()
#define HORZSIZE 4 // Horizontal size in millimeters
#define VERTSIZE 6 // Vertical size in millimeters
#define HORZRES 8 // Horizontal width in pixels
#define VERTRES 10 // Vertical height in pixels
#define NUMBRUSHES 16 // Number of brushes the device has
#define NUMPENS 18 // Number of pens the device has
#define NUMFONTS 22 // Number of fonts the device has
#define NUMCOLORS 24 // Number of colors the device supports
#define RASTERCAPS 38 // Bitblt capabilities
#define LOGPIXELSX 88 // Logical pixels/inch in X
#define LOGPIXELSY 90 // Logical pixels/inch in Y
#define PHYSICALWIDTH 110 // Physical Width in device units
#define PHYSICALHEIGHT 111 // Physical Height in device units
#define PHYSICALOFFSETX 112 // Physical Printable Area x margin
#define PHYSICALOFFSETY 113 // Physical Printable Area y margin
#define SCALINGFACTORX 114 // Scaling factor x
#define SCALINGFACTORY 115 // Scaling factor y
*/
#define MM_TO_INCH 25.4
#define _PORIENT 1
#define _PSIZE 2
#define _PWIDTH 3
#define _PLENGTH 4
#define _PYRES 5
#define _PXRES 6
CLASS WINPRN32
METHOD New(cPrinter,nForTyp)
METHOD Create(nMapMode) // CreatesDC and sets "Courier New" font, set Orientation, Copies, Bin#
// Create() ( & StartDoc() ) must be called before printing can start.
METHOD Destroy() // Calls EndDoc() - restores default font, Deletes DC.
// Destroy() must be called to avoid memory leaks
METHOD StartDoc(cDocame) // Calls StartPage()
METHOD EndDoc(lAbortDoc) // Calls EndPage() if lAbortDoc not .T.
METHOD StartPage()
METHOD EndPage(lFinished) // If lFinished = .F. then StartPage() is called for the next page of output
* METHOD NewLine()
METHOD NewPage()
METHOD SetFont(cFontName, nPointSize, nWidth, nBold, lUnderline, lItalic, lStrike, nCharSet, nAngle)
// NB: nWidth is in "CharactersPerInch"
// _OR_ { nMul, nDiv } which equates to "CharactersPerInch"
// _OR_ ZERO ( 0 ) which uses the default width of the font
// for the nPointSize
// IF nWidth (or nDiv) is < 0 then Fixed font is emulated
METHOD SetDefaultFont()
METHOD GetFonts() // Returns array of { "FontName", lFixed, lTrueType, nCharSetRequired }
METHOD Bold(nBoldWeight)
METHOD UnderLine(lOn)
METHOD Italic(lOn)
METHOD SetDuplexType(nDuplexType) // Get/Set current Duplexmode
METHOD SetPrintQuality(nPrintQuality) // Get/Set Printquality
METHOD CharSet(nCharSet)
METHOD SetPos(nX, nY) // **WARNING** : (Col,Row) _NOT_ (Row,Col)
METHOD SetColor(nClrText, nClrPane, nAlign) INLINE (;
::TextColor:=nClrText, ::BkColor:=nClrPane, ::TextAlign:=nAlign,;
SetColor( ::hPrinterDC, nClrText, nClrPane, nAlign) )
METHOD TextOut(cString, lNewLine, lUpdatePosX, nAlign) // nAlign : 0 = left, 1 = right, 2 = centered
METHOD TextOutAt(nPosX,nPosY, cString, lNewLine, lUpdatePosX, nAlign) // **WARNING** : (Col,Row) _NOT_ (Row,Col)
METHOD TextBox(cString,nLeft, nTop, nRight, nBottom, cAlign) // align same as text out
METHOD SetPen(nStyle, nWidth, nColor)
METHOD SetBrush(lSolid,nStyle,nColor,lNull) // brush for filling in polygons
METHOD Line(nX1, nY1, nX2, nY2) INLINE LineTo(::hPrinterDC, nX1, nY1, nX2, nY2)
METHOD Box(nX1, nY1, nX2, nY2, nWidth, nHeight) INLINE Rectangle(::hPrinterDC, nX1, nY1, nX2, nY2, nWidth, nHeight)
METHOD Arc(nX1, nY1, nX2, nY2) INLINE Arc(::hPrinterDC, nX1, nY1, nX2, nY2)
METHOD Ellipse(nX1, nY1, nX2, nY2) INLINE Ellipse(::hPrinterDC, nX1, nY1, nX2, nY2)
METHOD FillRect(nX1, nY1, nX2, nY2, nColor) INLINE FillRect(::hPrinterDC, nX1, nY1, nX2, nY2, nColor)
METHOD GetCharWidth()
METHOD GetCharHeight()
METHOD GetTextWidth(cString)
METHOD GetTextHeight(cString)
METHOD DrawBitMap(oBmp, nTransparent)
METHOD GetBkColor() // returns the DC background color
METHOD SetBkColor(nColor) // sets the DC background color
METHOD GetBin() // get default printer bin
METHOD SetBin(nBin) // Set the bin number
METHOD GetDefPaperSize() // get default printer page size
METHOD SaveCaps()
// Clipper DOS compatible functions.
* METHOD SetPrc(nRow, nCol) // Based on ::LineHeight and current ::CharWidth
* METHOD PRow()
* METHOD PCol()
* METHOD MaxRow() // Based on ::LineHeight & Form dimensions
* METHOD MaxCol() // Based on ::CharWidth & Form dimensions
* METHOD MM_TO_POSX( nMm ) // Convert position on page from MM to pixel location Column
* METHOD MM_TO_POSY( nMm ) // " " " " " " " " " Row
* METHOD INCH_TO_POSX( nInch ) // Convert position on page from INCH to pixel location Column
* METHOD INCH_TO_POSY( nInch ) // " " " " " " " " " Row
METHOD TextAtFont( nPosX, nPosY, cString, cFont, nPointSize,; // Print text string at location
nWidth, nBold, lUnderLine, lItalic, lStrike, lNewLine,; // in specified font and color.
lUpdatePosX, nColor, nAlign ) // Restore original font and colour
// after printing.
METHOD SetBkMode( nMode ) INLINE (;
::BkMode:=nMode, SetBkMode( ::hPrinterDc, nMode )) // OPAQUE= 2 or TRANSPARENT= 1
METHOD SetPageSize( nPageSize ) // change the nPaperSize - predefined or an array containing
// {paperheight,paperwidth} in units of 0.1 mm
// Set Background mode
VAR PrinterName INIT ""
VAR Printing INIT .F.
VAR HavePrinted INIT .F.
VAR hPrinterDc INIT 0
VAR UsePrintDialog INIT .F.
// These next 4 variables must be set before calling ::Create() if
// you wish to alter the defaults
VAR FormType INIT 0
VAR BinNumber INIT 0
VAR Landscape INIT .F.
VAR Copies INIT 1
VAR CustomHeight INIT 0 // user requested custom height
VAR CustomWidth INIT 0 // user requested custom width
VAR RequestedCopies INIT 1 // copies the program must produce
VAR SetFontOk INIT .F.
VAR FontName INIT "" // Current Point size for font
VAR FontPointSize INIT 12 // Point size for font
VAR FontWidth INIT {0,0} // {Mul, Div} Calc width: nWidth:= MulDiv(nMul, GetDeviceCaps(shDC,LOGPIXELSX), nDiv)
// If font width is specified it is in "characters per inch" to emulate DotMatrix
VAR Pitch INIT 0
VAR fBold INIT 0 HIDDEN // font darkness weight ( Bold). See wingdi.h or WIN SDK CreateFont() for valid values
VAR fUnderLine INIT .F. HIDDEN // UnderLine is on or off
VAR fItalic INIT .F. HIDDEN // Italic is on or off
VAR StrikeThrough INIT .F. HIDDEN
VAR fCharSet INIT 1 HIDDEN // Default character set == DEFAULT_CHARSET ( see wingdi.h )
VAR FontAngle INIT 0 // text angle
VAR PixelsPerInchY
VAR PixelsPerInchX
VAR PageHeightPixels INIT 0
VAR PageWidthPixels INIT 0
VAR TopMarginPixels INIT 0
VAR BottomMarginPixels INIT 0
VAR LeftMarginPixels INIT 0
VAR RightMarginPixels INIT 0
VAR PrintWidthPixels INIT 0
VAR PrintHeightPixels INIT 0
VAR PageWidthMM INIT 0
VAR PageHeightMM INIT 0
VAR LeftMarginMM INIT 0
VAR RightMarginMM INIT 0
VAR TopMarginMM INIT 0
VAR BottomMarginMM INIT 0
VAR PrintWidthMM INIT 0
VAR PrintHeightMM INIT 0
VAR LineHeight INIT 0
VAR CharHeight INIT 0
VAR CharWidth INIT 0
VAR fCharWidth INIT 0 HIDDEN
VAR BitmapsOk INIT .F.
VAR NumColors INIT 1
VAR fDuplexType INIT 1 HIDDEN //DMDUP_SIMPLEX
VAR fPrintQuality INIT -4 HIDDEN //DMRES_HIGH
VAR fNewDuplexType INIT 1 HIDDEN
VAR fNewPrintQuality INIT -4 HIDDEN
VAR fOldLandScape INIT .F. HIDDEN
VAR fOldBinNumber INIT 0 HIDDEN
VAR fOldFormType INIT 0 HIDDEN
VAR PosX INIT 0
VAR PosY INIT 0
VAR TextColor
VAR BkColor
VAR TextAlign
VAR BkMode INIT 2 // opaque is the default
VAR PenStyle INIT PS_SOLID
VAR PenWidth INIT 1
VAR PenColor INIT 0
VAR TextCol
VAR TextRow
VAR FontStyle
VAR PixelsPerMMX
VAR PixelsPerMMY
VAR lSolidBrush INIT .T. HIDDEN // solid brush to start out
VAR BrushStyle INIT -1 HIDDEN // illegal value to force initial setting
VAR BrushColor INIT 0 HIDDEN // brush color
VAR lNullBrush INIT .F. HIDDEN // null - transparent - brush
VAR hWindowHnd INIT 0 // handle to window call print routines
* VAR sDevmodeSmall // DevMode structure without the device specific stuff
// since that returned by the driver is of arbitrary size
VAR SelectedOrientation // User selected orientation
VAR SelectedForm // Form selected by user
VAR PaperWidth // Paper width in inches
VAR PaperLength // Paper length in inches
VAR UsefulItems // useful items from DevMode since I can't seem to get structures
// to work without crashing
ENDCLASS
METHOD New(xPrinter,nForTyp) CLASS WINPRN32
IF VALTYPE(xPrinter)='N'.AND.xPrinter=-1
::UsePrintDialog:=.T.
::PrinterName=' '
ELSE
::UsePrintDialog:=.F.
::PrinterName := IIF(!EMPTY(xPrinter), xPrinter, GetDefaultPrinter())
ENDIF
IF nForTyp <> NIL
::FormType := nForTyp
ENDIF
RETURN(Self)
METHOD Create(nMapMode) CLASS WINPRN32
LOCAL Result:= .F.
LOCAL aPrintData
LOCAL nCopies
LOCAL cCurrentDrv // current disk drive
LOCAL cCurrentDir // current directory
::Destroy() // Finish current print job if any
::hWindowHnd=GetWindowHandle()
nCopies=::Copies
IF ::UsePrintDialog
/* We are going to save the current drive and directory since some print drivers that produce
files - Microsoft Office Document Image Writer being one - uses the standard Windows file
selection dialog. The file selection dialog changes the default directory and these drivers
do not reset it to the original. - Editorial: this is bad form.
*/
cCurrentDrv=CURDRIVE()
cCurrentDir=CURDIR()
aPrintData=PrintDialog(::hWindowHnd,SaveDevMode, SaveDevModeSize, DevNames, ;
DevNamesSize,@nCopies)
* Return to previous default location
DISKCHANGE(cCurrentDrv)
DIRCHANGE("\"+cCurrentDir)
IF aPrintData=NIL
::hPrinterDC=NIL
ELSE
::hPrinterDC=aPrintData[1]
::FormType=aPrintData[3]
::PrinterName=aPrintData[2]
SaveDevMode:=DevMode:=aPrintData[4]
SaveDevModeSize:=DevModeSize:=aPrintData[5]
DevNames=aPrintData[6]
DevNamesSize=aPrintData[7]
::RequestedCopies:=nCopies
DevMode=SetDocumentProperties(::hWindowHnd,::hPrinterDC, ::PrinterName, @DevMode, DevModeSize, ;
::FormType, ::Landscape, , ::BinNumber, ::fDuplexType, ;
::fPrintQuality)
ENDIF
ELSE
IF !EMPTY(::hPrinterDC := CreateDC(::PrinterName, ::Copies, @DevMode, @DevModeSize))
DevMode=SetDocumentProperties(::hWindowHnd,::hPrinterDC, ::PrinterName, DevMode, DevModeSize, ;
::FormType, ::Landscape, ::Copies, ::BinNumber, ::fDuplexType, ;
::fPrintQuality)
ENDIF
ENDIF
IF !EMPTY(::hPrinterDC)
// Set Form Type
// Set Number of Copies
// Set Orientation
// Set Duplex mode
// Set PrintQuality
/* SetDocumentProperties(::hWindowHnd,::hPrinterDC, ::PrinterName, @DevMode, DevModeSize, ;
::FormType, ::Landscape, ::Copies, ::BinNumber, ::fDuplexType, ;
::fPrintQuality)
*/
// Set mapping mode to pixels, topleft down
IF VALTYPE(nMapMode)='N'
SetMapMode(::hPrinterDC,nMapMode)
ELSE
SetMapMode(::hPrinterDC,MM_TEXT)
ENDIF
::UsefulItems=ExtractFromDevmode(DevMode)
::SaveCaps()
// Set the standard font
::SetDefaultFont()
::HavePrinted:= ::Printing:= .F.
::fOldFormType:= ::FormType // Last formtype used
::fOldLandScape:= ::LandScape
::fOldBinNumber:= ::BinNumber
Result:= .T.
// Set the default pen and brush
self:SetPen(::PenStyle,::PenWidth,::PenColor)
self:SetBrush(::lSolidBrush,::BrushStyle,::BrushColor,::lNullBrush)
ENDIF
RETURN(Result)
METHOD SaveCaps() CLASS WINPRN32
* Function to query printer for document and printer properties
// Get Margins etc... here
* ::sDevModeSmall=Move2DevMode()
* Move2DevMode()
::SelectedOrientation := ::UsefulItems[_PORIENT] // sDevModeSmall:dmOrientation
::SelectedForm := ::UsefulItems[_PSIZE] //sDevModeSmall:dmPaperSize
* Get paper size - two ways because all drivers don't behave well
::PaperWidth := ::UsefulItems[_PWIDTH]/254. //sDevModeSmall:dmPaperWidth/254.
IF ::PaperWidth<=0
::PaperWidth := GetDeviceCaps(::hPrinterDC,HORZSIZE)/25.4
ENDIF
::PaperLength := ::UsefulItems[_PLENGTH]/254. //sDevModeSmall:dmPaperLength/254.
IF ::PaperLength<=0
::PaperLength := GetDeviceCaps(::hPrinterDC,VERTSIZE)/25.4
ENDIF
::PixelsPerInchY := ::UsefulItems[_PYRES] // sDevModeSmall:dmYResolution //
IF ::PixelsPerInchY>0
::PixelsPerInchX := ::UsefulItems[_PXRES] // sDevModeSmall:dmPrintQuality // double use variable
ELSE
::PixelsPerInchY := GetDeviceCaps(::hPrinterDC,LOGPIXELSY)
::PixelsPerInchX := GetDeviceCaps(::hPrinterDC,LOGPIXELSX)
ENDIF
::PageWidthPixels := GetDeviceCaps(::hPrinterDC,PHYSICALWIDTH)
::PageHeightPixels := GetDeviceCaps(::hPrinterDC,PHYSICALHEIGHT)
::LeftMarginPixels := GetDeviceCaps(::hPrinterDC,PHYSICALOFFSETX)
::TopMarginPixels := GetDeviceCaps(::hPrinterDC,PHYSICALOFFSETY)
::PrintWidthPixels := GetDeviceCaps(::hPrinterDC,HORZRES)
::PrintHeightPixels := GetDeviceCaps(::hPrinterDC,VERTRES)
* For reliability sake, we will calculate 2 ways since sometimes the call to getdevicecaps doesn't seem to work
IF ::PageWidthPixels<=0 .OR. (::PaperWidth>0.AND.::PageWidthPixels/::PixelsPerInchX > 1.1*::PaperWidth)
::PageWidthPixels := ::Paperwidth*::PixelsPerInchX
ENDIF
IF ::PageHeightPixels<=0 .OR. (::PaperLength>0.AND.::PageHeightPixels/::PixelsPerInchY > 1.1*::PaperLength)
::PageHeightPixels := ::PaperLength*::PixelsPerInchY
ENDIF
IF ::LeftMarginPixels=0
::LeftMarginPixels := ::PixelsPerInchX/4.0 // This is a guess since sometimes we get 0 in the above call
ENDIF
::RightMarginPixels := (::PageWidthPixels - ::LeftMarginPixels)+1
IF ::TopMarginPixels=0
::TopMarginPixels := ::PixelsPerInchY/4.0 // This is a guess - 0.25 inches
ENDIF
::BottomMarginPixels := (::PageHeightPixels - ::TopMarginPixels)+1
::PixelsPerMMX :=::PixelsPerInchX/25.4
::PixelsPerMMY :=::PixelsPerInchY/25.4
::PageWidthMM := ::PageWidthPixels/::PixelsPerMMX
::PageHeightMM := ::PageHeightPixels/::PixelsPerMMY
::LeftMarginMM := ::LeftMarginPixels/::PixelsPerMMX
::RightMarginMM := ::RightMarginPixels/::PixelsPerMMX
::TopMarginMM := ::TopMarginPixels/::PixelsPerMMY
::BottomMarginMM := ::BottomMarginPixels/::PixelsPerMMY
::PrintWidthMM := ::PageWidthMM-(2*::LeftMarginMM)
::PrintHeightMM := ::PageHeightMM-(2*::TopMarginMM)
::LineHeight := INT(::PixelsPerInchY / 6) // Default 6 lines per inch == # of pixels per line
::FontStyle :=0
// Set .T. if can print bitmaps
::BitMapsOk := BitMapsOk(::hPrinterDC)
// supports Colour
::NumColors := GetDeviceCaps(::hPrinterDC,NUMCOLORS)
// bin number
::BinNumber=::GetBin()
RETURN NIL
METHOD Destroy() CLASS WINPRN32
IF !EMPTY(::hPrinterDc)
IF ::Printing
::EndDoc()
ENDIF
::hPrinterDC:= DeleteDC(::hPrinterDC)
ENDIF
RETURN(.T.)
METHOD SetPageSize(nPaperSize) CLASS WINPRN32
// nPapersize for predefined sizes
// nPapersize for height and nWidth for width of custom sizes
DevMode=SetDocumentProperties(::hWindowHnd,::hPrinterDC, ::PrinterName, DevMode, DevModeSize, ;
nPaperSize,::Landscape)
IF ISARRAY(nPaperSize)
::CustomHeight=nPaperSize[1]
::CustomWidth=nPaperSize[2]
ELSE
::CustomHeight=0
::CustomWidth=0
ENDIF
::SaveCaps()
::FormType=nPaperSize
RETURN .T.
METHOD SetPen(nStyle, nWidth, nColor) CLASS WINPRN32
::PenStyle:=nStyle
::PenWidth:=nWidth
::PenColor:=nColor
SetPen(::hPrinterDC, nStyle, nWidth, nColor)
RETURN NIL
METHOD StartDoc(cDocName) CLASS WINPRN32
LOCAL Result:= .F.
IF cDocName == NIL
cDocName:= GetExeFileName()+" ["+DTOC(DATE())+' - '+TIME()+"]"
ENDIF
//ALERTA(::hPrinterDc)
//cDocName := "c:\temp\file.pdf"
IF (Result:= StartDoc(::hPrinterDc, cDocName))
IF !(Result:= ::StartPage(::hPrinterDc))
::EndDoc(.T.)
ELSE
::Printing:= .T.
ENDIF
ENDIF
RETURN(Result)
METHOD EndDoc(lAbortDoc) CLASS WINPRN32
IF lAbortDoc == NIL
lAbortDoc:= .F.
ENDIF
IF !::HavePrinted
lAbortDoc:= .T.
ENDIF
IF !lAbortDoc
::EndPage(.F.)
ENDIF
EndDoc(::hPrinterDC,lAbortDoc)
::Printing:= .F.
::HavePrinted:= .F.
RETURN(.T.)
METHOD StartPage() CLASS WINPRN32
LOCAL lLLandScape, nLBinNumber, nLFormType, nLDuplexType, nLPrintQuality
LOCAL lArray, lChange
IF ::LandScape <> ::fOldLandScape // Direct-modify property
lLLandScape:= ::fOldLandScape := ::LandScape
ENDIF
IF ::BinNumber <> ::fOldBinNumber // Direct-modify property
nLBinNumber:= ::fOldBinNumber := ::BinNumber
ENDIF
/* Form type has changed if 1) Changed from/to custom to/from standard
2) changed the size of custom or 3) changed the standard size */
lChange=(VALTYPE(::FormType)<>VALTYPE(::fOldFormType))
IF !lChange.AND. (VALTYPE(::FormType)='A'.AND.VALTYPE(::fOldFormType)='A')
lChange=((::FormType[1] <> ::fOldFormType[1]).OR.;
(::FormType[2] <> ::fOldFormType[2]))
ELSEIF !lChange
lChange=(::FormType <> ::fOldFormType)
ENDIF
IF lChange
nLFormType:= ::fOldFormType := ::FormType
ENDIF
IF ::fDuplexType <> ::fNewDuplexType // Get/Set property
nLDuplexType:= ::fDuplexType:= ::fNewDuplexType
ENDIF
IF ::fPrintQuality <> ::fNewPrintQuality // Get/Set property
nLPrintQuality:= ::fPrintQuality:= ::fNewPrintQuality
ENDIF
IF lLLandScape <> NIL .or. nLBinNumber <> NIL .or. nLFormType <> NIL .or. nLDuplexType <> NIL .or. nLPrintQuality <> NIL
SetDocumentProperties(::hWindowHnd,::hPrinterDC, ::PrinterName, @DevMode, DevModeSize,;
nLFormType, lLLandscape, , nLBinNumber, nLDuplexType, nLPrintQuality)
::SaveCaps()
::SetFont(::FontName, ::FontPointSize, ::FontWidth, ::fBold, ::fUnderline, ::fItalic, ::StrikeThrough, ::fCharSet, ::FontAngle)
ENDIF
StartPage(::hPrinterDC)
::PosX:=0
::Posy:=0
RETURN(.T.)
METHOD EndPage(lStartNewPage) CLASS WINPRN32
IF lStartNewPage == NIL
lStartNewPage:= .T.
ENDIF
EndPage(::hPrinterDC)
IF lStartNewPage
::StartPage()
IF OS_ISWIN9X() // Reset font on Win9X
::SetFont()
ENDIF
ENDIF
RETURN(.T.)
METHOD NewPage() CLASS WINPRN32
::EndPage(.T.)
RETURN(.T.)
// If font width is specified it is in "characters per inch" to emulate DotMatrix
// An array {nMul,nDiv} is used to get precise size such a the Dot Matric equivalent
// of Compressed print == 16.67 char per inch == { 3,-50 }
// If nDiv is < 0 then Fixed width printing is forced via ExtTextOut()
METHOD SetFont(cFontName, nPointSize, nWidth, nBold, lUnderline, lItalic, lStrike, nCharSet, nAngle) CLASS WINPRN32
LOCAL cType
IF cFontName !=NIL
::FontName:= cFontName
ENDIF
IF nPointSize!=NIL
::FontPointSize:= nPointSize
ENDIF
IF nWidth != NIL
cType:= VALTYPE(nWidth)
IF cType='A'
::FontWidth := nWidth
ELSEIF cType='N' .AND. !EMPTY(nWidth)
::FontWidth := {1,nWidth }
ELSE
::FontWidth := {0, 0 }
ENDIF
ENDIF
IF nBold != NIL
::fBold := nBold
ENDIF
IF lUnderLine != NIL
::fUnderline:= lUnderLine
ENDIF
IF lItalic != NIL
::fItalic := lItalic
ENDIF
IF nCharSet != NIL
::fCharSet := nCharSet
ENDIF
IF nAngle !=NIL
::FontAngle := nAngle
ENDIF
IF lStrike != NIL
::StrikeThrough := lStrike
ENDIF
IF (::SetFontOk:= CreateFont( ::hPrinterDC, ::FontName, ::FontPointSize, ::FontWidth[1], ::FontWidth[2], ::fBold, ::fUnderLine, ::fItalic, ::fCharSet, ::StrikeThrough, ::FontAngle*10))
::fCharWidth := ::GetCharWidth()
::CharWidth := ABS(::fCharWidth)
::CharHeight := ::GetCharHeight()
ENDIF
::FontName:= GetPrinterFontName(::hPrinterDC) // Get the font name that Windows actually used
RETURN(::SetFontOk)
METHOD SetDefaultFont()
RETURN(::SetFont("Courier New",12, 0, 0, .F., .F., 0, 0))
METHOD Bold(nWeight) CLASS WINPRN32
LOCAL Result:= ::fBold
IF nWeight!= NIL
::fBold:= nWeight
IF ::Printing
::SetFont()
ENDIF
ENDIF
RETURN(Result)
METHOD Underline(lUnderLine) CLASS WINPRN32
LOCAL Result:= ::fUnderline
IF lUnderLine!= NIL
::fUnderLine:= lUnderLine
IF ::Printing
::SetFont()
ENDIF
ENDIF
RETURN(Result)
METHOD Italic(lItalic) CLASS WINPRN32
LOCAL Result:= ::fItalic
IF lItalic!= NIL
::fItalic:= lItalic
IF ::Printing
::SetFont()
ENDIF
ENDIF
RETURN(Result)
METHOD CharSet(nCharSet) CLASS WINPRN32
LOCAL Result:= ::fCharSet
IF nCharSet!= NIL
::fCharSet:= nCharSet
IF ::Printing
::SetFont()
ENDIF
ENDIF
RETURN(Result)
METHOD SetDuplexType(nDuplexType) CLASS WINPRN32
LOCAL Result:= ::fDuplexType
IF nDuplexType!= NIL
::fNewDuplexType:= nDuplexType
IF !::Printing
::fDuplexType:= nDuplexType
ENDIF
ENDIF
RETURN(Result)
METHOD SetPrintQuality(nPrintQuality) CLASS WINPRN32
LOCAL Result:= ::fPrintQuality
IF nPrintQuality!= NIL
::fNewPrintQuality:= nPrintQuality
IF !::Printing
::fPrintQuality:= nPrintQuality
ENDIF
ENDIF
RETURN(Result)
METHOD GetFonts() CLASS WINPRN32
RETURN(ENUMFONTS(::hPrinterDC))
METHOD SetPos(nPosX, nPosY) CLASS WINPRN32
LOCAL Result:= {::PosX, ::PosY}
IF nPosX != NIL
::PosX:= INT(nPosX)
ENDIF
IF nPosY != NIL
::PosY:= INT(nPosY)
ENDIF
RETURN(Result)
METHOD TextOut(cString, lNewLine, lUpdatePosX, nAlign) CLASS WINPRN32
LOCAL nPosX
IF nAlign == NIL
nAlign:= 0
ENDIF
IF lUpdatePosX == NIL
lUpdatePosX:=.T.
ENDIF
IF lNewLine == NIL
lNewLine:= .F.
ENDIF
IF cString!=NIL
nPosX:= TextOut(::hPrinterDC,::PosX, ::PosY, cString, LEN(cString), ::fCharWidth, nAlign)
::HavePrinted:= .T.
IF lUpdatePosX
::PosX+= nPosX
ENDIF
IF lNewLine
::NewLine()
ENDIF
ENDIF
RETURN( .T. )
METHOD TextOutAt(nPosX,nPosY, cString, lNewLine, lUpdatePosX, nAlign) CLASS WINPRN32
IF lNewLine == NIL
lNewLine:= .F.
ENDIF
IF lUpdatePosX == NIL
lUpdatePosX:= .T.
ENDIF
::SetPos(nPosX,nPosY)
::TextOut(cString, lNewLine, lUpdatePosX, nAlign)
RETURN(.T.)
METHOD TextBox(cString, nLeft, nTop, nRight, nBottom, nAlign) CLASS WINPRN32
RETURN TextBox(::hPrinterDC,cString,LEN(cString),nLeft,nTop,nRight,nBottom,nAlign)
METHOD GetCharWidth() CLASS WINPRN32
LOCAL nWidth:= 0
IF ::FontWidth[2] < 0 .AND. !EMPTY(::FontWidth[1])
nWidth:= MulDiv(::FontWidth[1], ::PixelsPerInchX,::FontWidth[2])
ELSE
nWidth:= GetCharSize(::hPrinterDC)
ENDIF
RETURN(nWidth)
METHOD GetCharHeight() CLASS WINPRN32
RETURN(GetCharSize(::hPrinterDC, .T.))
METHOD GetTextWidth(cString) CLASS WINPRN32
LOCAL nWidth:= 0
IF ::FontWidth[2] < 0 .AND. !EMPTY(::FontWidth[1])
nWidth:= LEN(cString) * ::CharWidth
ELSE
nWidth:= GetTextSize(::hPrinterDC, cString, LEN(cString)) // Return Width in device units
ENDIF
RETURN(nWidth)
METHOD GetTextHeight(cString) CLASS WINPRN32
RETURN(GetTextSize(::hPrinterDC, cString, LEN(cString), .F.)) // Return Height in device units
METHOD GetBkColor() CLASS WINPRN32
RETURN GetBkColor(::hPrinterDC)
METHOD SetBkColor(nColor) CLASS WINPRN32
::BkColor=nColor
RETURN SetBkColor(::hPrinterDC, nColor)
METHOD GetBin() CLASS WINPRN32
RETURN GetDocumentBin(DevMode)
METHOD SetBin(nBin) CLASS WINPRN32
::BinNumber=SetDocumentBin(::hWindowHnd,::hPrinterDC, ::PrinterName, @DevMode,;
DevModeSize, nBin)
RETURN ::BinNumber
METHOD GetDefPaperSize() CLASS WINPRN32
RETURN GetPrinterSize(::hPrinterDC, ::PrinterName)
METHOD DrawBitMap(oBmp, nTransparent) CLASS WINPRN32
LOCAL Result:= .F.
IF ::BitMapsOk .AND. ::Printing .AND. !EMPTY(oBmp:BitMap)
IF nTransparent!=NIL
Result:= DrawTransBitMap(::hPrinterDc, oBmp:BitMap,oBmp:Rect[1], oBmp:Rect[2], oBmp:rect[3], oBmp:Rect[4], nTransparent)
::HavePrinted:= .T.
ELSE
IF (Result:= DrawBitMap(::hPrinterDc, oBmp:BitMap,oBmp:Rect[1], oBmp:Rect[2], oBmp:rect[3], oBmp:Rect[4]))
::HavePrinted:= .T.
ENDIF
ENDIF
ENDIF
RETURN(Result)
METHOD SetBrush(lSolid,nStyle, nColor, lNull) CLASS WINPRN32
// lSolid is true if the brush is solid
// nStyle is the brush style if the brush is not solid.
// Values from WinGdi.h include HS_VERTICAL, HS_HORIZONTAL, HS_FDIAGONAL,
// HS_BDIAGONAL, HS_CROSS, HS_DIAGCROSS
// nColor is the RGB style color
IF VALTYPE(lSolid)!='L'
lSolid=::lSolidBrush
ENDIF
IF VALTYPE(lNull)!='L'
lNull=::lNullBrush
ENDIF
// If we aren't changing the style then don't do anything
IF lSolid!=::lSolidBrush.OR.nStyle!=::BrushStyle.OR.nColor!=::BrushColor;
.OR.lNull!=::lNullBrush
IF lSolid
// Create a solid brush
CreateSolidBrush(::hPrinterDC,nColor)
ELSEIF !lNull
// hatched brush
CreateHatchBrush(::hPrinterDC,nStyle,nColor)
ELSE
// Null - empty - brush
CreateStockBrush(::hPrinterDC,NULL_BRUSH)
ENDIF
::lSolidBrush=lSolid
::BrushStyle=nStyle
::BrushColor=nColor
::lNullBrush=lNull
ENDIF
RETURN NIL
METHOD TextAtFont( nPosX, nPosY, cString, cFont, nPointSize, nWidth, nBold, lUnderLine, lItalic, lStrike, nCharSet, lNewLine, lUpdatePosX, nColor, nAlign ) CLASS WINPRN32
LOCAL lCreated:= .F., nDiv:= 0, cType
DEFAULT nPointSize TO ::FontPointSize
IF cFont != NIL
cType:= VALTYPE(nWidth)
IF cType='A'
nDiv := nWidth[ 1 ]
nWidth:= nWidth[ 2 ]
ELSEIF cType='N' .AND. !EMPTY(nWidth)
nDiv:= 1
ENDIF
lCreated:= CreateFont( ::hPrinterDC, cFont, nPointSize, nDiv, nWidth, nBold, lUnderLine, lItalic, lStrike, nCharSet )
ENDIF
IF nColor != NIL
nColor:= SetColor( ::hPrinterDC, nColor )
ENDIF
::TextOutAt( nPosX, nPosY, cString, lNewLine, lUpdatePosX, nAlign)
IF lCreated
::SetFont() // Reset font
ENDIF
IF nColor != NIL
SetColor( ::hPrinterDC, nColor ) // Reset Color
ENDIF
RETURN( .T. )
/*STATIC FUNCTION Move2DevMode
*LOCAL sDevmode is cDevMode
sDevmodeSmall:Buffer(GetDevMode(DevMode),.T.)
RETURN NIL /*sDevMode*/
*/
// Bitmap class
CLASS WINBMP32
EXPORTED:
METHOD New()
METHOD LoadFile(cFileName)
METHOD LoadMemory(cBitMap)
METHOD Create()
METHOD Destroy()
METHOD Draw(oPrn,arectangle,nTransparent)
METHOD GetDimensions()
VAR Rect INIT { 0,0,0,0 } // Coordinates to print BitMap
// XDest, // x-coord of destination upper-left corner
// YDest, // y-coord of destination upper-left corner
// nDestWidth, // width of destination rectangle
// nDestHeight, // height of destination rectangle
// See WinApi StretchDIBits()
VAR BitMap INIT ""
VAR FileName INIT ""
VAR BitMapWidth INIT 0 // width (x dimension)
VAR BitMapHeight INIT 0 // heigth (y dimension)
VAR lDown INIT .T. // Top Down bit map
ENDCLASS
METHOD New() CLASS WINBMP32
RETURN(Self)
METHOD LoadMemory(cBitMap) CLASS WINBMP32
::Bitmap := cBitMap
RETURN(Self)
METHOD LoadFile(cFileName) CLASS WINBMP32
::FileName:= cFileName
::Bitmap := LoadBitMapFile(::FileName)
RETURN(!EMPTY(::Bitmap))
METHOD GetDimensions() CLASS WINBMP32
LOCAL aDim // array containing dimensions
aDim=GetBitMapDim(::BitMap)
::BitMapWidth=aDim[1]
::BitMapHeight=aDim[2]
::lDown=(aDim[3]!=aDim[1]) // Top down addressing - Do I need it??
RETURN NIL
METHOD Create() CLASS WINBMP32 // Compatibility function for Alaska Xbase++
Return(Self)
METHOD Destroy() CLASS WINBMP32 // Compatibility function for Alaska Xbase++
RETURN(NIL)
METHOD Draw(oPrn, aRectangle,nTransparent) CLASS WINBMP32 // Pass a TPRINT class reference & Rectangle array
::Rect:= aRectangle
RETURN(oPrn:DrawBitMap(Self,nTransparent))
#pragma BEGINDUMP
#include <windows.h>
#include <winspool.h>
#include "wingdi.h"
#include "hbapiitm.h"
#ifndef INVALID_FILE_SIZE
#define INVALID_FILE_SIZE (DWORD)0xFFFFFFFF
#endif
/*HB_FUNC_STATIC(GETDEVMODE)
{ PDEVMODE pDevMode = (PDEVMODE) hb_parc(1);
hb_retclenAdoptRaw( (char *) pDevMode, sizeof(DEVMODE));
} */
HB_FUNC_STATIC( CREATEDC )
{
LONG Result = 0 ;
LONG lSize ;
HANDLE hPrinter;
LPTSTR pszPrinterName;
PDEVMODE pDevMode;
if (ISCHAR(1))
{
pszPrinterName = (char*) hb_parc(1);
if (OpenPrinter(pszPrinterName, &hPrinter, NULL)) /* Windows Call */
lSize= DocumentProperties(0,hPrinter,pszPrinterName, pDevMode,pDevMode,0);
if (lSize > 0)
{
pDevMode = (PDEVMODE) hb_xgrab(lSize);
DocumentProperties(0,hPrinter,pszPrinterName, pDevMode,pDevMode,DM_OUT_BUFFER);
if (ISNUM(2))
{
pDevMode->dmCopies = hb_parni(2);
pDevMode->dmFields = pDevMode->dmFields | DM_COPIES;
}
Result = (LONG) CreateDC("",pszPrinterName, NULL, pDevMode) ;
hb_storclen((CHAR *) pDevMode, lSize, 3);
hb_stornl(lSize, 4);
hb_xfree(pDevMode);
}
}
hb_retnl(Result) ;
}
HB_FUNC_STATIC( STARTDOC )
{
HDC hDC = (HDC) hb_parnl(1) ;
LPDOCINFO sDoc = NULL;
BOOL Result = FALSE ;
if (hDC )
{
sDoc = (LPDOCINFO) hb_xgrab(sizeof(DOCINFO));
sDoc->cbSize= sizeof(DOCINFO) ;
sDoc->lpszDocName= hb_parc(2) ;
sDoc->lpszOutput = NULL ;
sDoc->lpszDatatype= NULL ;
sDoc->fwType = 0 ;
Result = (BOOL) (StartDoc(hDC, sDoc) >0 ) ;
hb_xfree(sDoc);
}
hb_retl(Result);
}
HB_FUNC_STATIC(ENDDOC)
{
BOOL Result = FALSE;
HDC hDC = (HDC) hb_parnl(1) ;
if (hDC)
{
if (ISLOG(2) && hb_parl(2))
{
Result = (AbortDoc(hDC) > 0) ;
}
else
{
Result = (EndDoc( hDC) > 0) ;
}
}
hb_retnl(Result) ;
}
HB_FUNC_STATIC( DELETEDC )
{
HDC hDC = (HDC) hb_parnl(1) ;
if (hDC)
{
DeleteDC( hDC ) ;
}
hb_retnl(0) ; // Return zero as a new handle even if fails
}
HB_FUNC_STATIC(STARTPAGE)
{
BOOL Result = FALSE ;
HDC hDC = (HDC) hb_parnl(1) ;
if (hDC)
{
Result = ( StartPage( hDC ) > 0) ;
}
hb_retl(Result) ;
}
HB_FUNC_STATIC(ENDPAGE)
{
BOOL Result = FALSE ;
HDC hDC = (HDC) hb_parnl(1) ;
if (hDC)
{
Result = (EndPage( hDC ) > 0) ;
}
hb_retl(Result) ;
}
HB_FUNC_STATIC(TEXTOUT)
{
LONG Result = 0 ;
HDC hDC = (HDC) hb_parnl(1) ;
SIZE sSize ;
if (hDC)
{
int iLen = (int) hb_parnl(5) ;
if ( iLen > 0 )
{
int iRow = (int) hb_parnl(2) ;
int iCol = (int) hb_parnl(3) ;
char *pszData = (char*) hb_parc(4) ;
int iWidth = ISNUM(6) ? (int) hb_parnl(6) : 0 ;
if (ISNUM(7) && (hb_parnl(7) == 1 || hb_parnl(7) == 2))
{
if (hb_parnl(7) == 1)
{
SetTextAlign((HDC) hDC, TA_TOP | TA_RIGHT | TA_NOUPDATECP) ;
}
else
{
SetTextAlign((HDC) hDC, TA_TOP | TA_CENTER | TA_NOUPDATECP) ;
}
}
else
{
SetTextAlign((HDC) hDC, TA_TOP | TA_LEFT | TA_NOUPDATECP) ;
}
if (iWidth < 0 && iLen < 1024 )
{
int n= iLen, aFixed[1024] ;
iWidth = -iWidth ;
while( n )
{
aFixed[ --n ] = iWidth;
}
if (ExtTextOut( hDC, iRow, iCol, 0, NULL, pszData, iLen, aFixed ))
{
Result = (LONG) (iLen * iWidth) ;
}
}
else if (TextOut(hDC, iRow, iCol, pszData, iLen))
{
GetTextExtentPoint32(hDC,pszData, iLen , &sSize) ; // Get the length of the text in device size
Result = (LONG) sSize.cx ; // return the width so we can update the current pen position (::PosY)
}
}
}
hb_retnl(Result) ;
}