Annotation of os232sdk/toolkt20/c/samples/style/sty_prnt.c, revision 1.1.1.1

1.1       root        1: /*==============================================================*\
                      2:  *  Prnt.c - routines for printing of a document
                      3:  *      Created 1990, Microsoft, IBM  Corp.
                      4:  *--------------------------------------------------------------
                      5:  *
                      6:  *  This module contains the routines for the printing of a
                      7:  *  a document.  Included are the routines for calling the
                      8:  *  standard dialogs for obtaining the user's printer and
                      9:  *  page setup preferences.  Also included is the routine to
                     10:  *  determine the number of pages in a document as well as the
                     11:  *  routine to obtain the printer DC and print the document.
                     12:  *
                     13:  *--------------------------------------------------------------
                     14:  *
                     15:  *  This source file contains the following functions:
                     16:  *
                     17:  *           InitPrinting();
                     18:  *           PageSetup(hwndOwner);
                     19:  *           PrintSetup(hwndOwner);
                     20:  *           Print();
                     21:  *           CalcPrintArea(hpsPrinter,
                     22:  *                         hdcPrinter,
                     23:  *                         prclPrintArea,
                     24:  *                         pfm);
                     25:  *           PrintDoc(hdc);
                     26:  *           QueryMaxPages();
                     27:  *
                     28:  *
                     29: \*==============================================================*/
                     30: 
                     31: /*--------------------------------------------------------------*\
                     32:  *  Include files, macros, defined constants, and externs
                     33: \*--------------------------------------------------------------*/
                     34: 
                     35: #define INCL_WINMLE
                     36: #define INCL_GPICONTROL
                     37: #define INCL_GPITRANSFORMS
                     38: #define INCL_GPIPRIMITIVES
                     39: #define INCL_GPILCIDS
                     40: #define INCL_DEV
                     41: 
                     42: #include <os2.h>
                     43: #include "sty_main.h"
                     44: #include "sty_xtrn.h"
                     45: 
                     46: #if 0
                     47: #include "pmkitp.h"
                     48: #define PRINT_DLGS_ENABLED
                     49: #endif
                     50: 
                     51: #define MAXHEADERLEN    100     /* maximum length of header */
                     52: #define MAXFOOTERLEN    100     /* maximum length of footer */
                     53: #define DLGTITLELEN      30     /* length of dialog title string */
                     54: 
                     55: #define DEVDATACOUNT    7L      /* # fields of DEVOPENSTRUCT used */
                     56: 
                     57: #define FONTLCID        1L      /* LCID for printer font */
                     58: 
                     59: #define QMP_ERROR       -1      /* error return from QueryMaxPages() */
                     60: 
                     61: /* constants used in InitPrintingDlgs() for initial and maximum margins */
                     62: #define ONEINCH         (MAKEFIXED(1, 0))
                     63: #define EIGHTINCHES     (MAKEFIXED(8, 0))
                     64: #define ELEVENINCHES    (MAKEFIXED(11, 0))
                     65: 
                     66: /* Macro for converting a FIXED integer value into LO_ENGLISH
                     67:     world coordinates */
                     68: #define FIXEDTOWORLD(x)   ((FIXEDINT(x) * 100L) +  \
                     69:                            ((FIXEDFRAC(x) * 100L) / 65536L))
                     70: 
                     71: 
                     72: /*--------------------------------------------------------------*\
                     73:  *  Global variables
                     74: \*--------------------------------------------------------------*/
                     75: #ifdef PRINT_DLGS_ENABLED
                     76: 
                     77: static PAGESETUPDLG pgsd;
                     78: static PRINTSETUPDLG psd;
                     79: static PRINTDLG prtd;
                     80: static CHAR szHeader[MAXHEADERLEN], szFooter[MAXFOOTERLEN];
                     81: static CHAR szPgsdTitle[DLGTITLELEN];
                     82: static CHAR szPsdtitle[DLGTITLELEN];
                     83: static CHAR szPrtdTitle[DLGTITLELEN];
                     84: 
                     85: #endif
                     86: 
                     87: /*--------------------------------------------------------------*\
                     88:  *  Entry point declarations
                     89: \*--------------------------------------------------------------*/
                     90: SHORT QueryMaxPages(VOID);
                     91: BOOL PrintDoc(HDC hdc);
                     92: BOOL CalcPrintArea(HPS hpsPrinter,
                     93:                    PRECTL prclPrintArea,
                     94:                    PFONTMETRICS pfm);
                     95: 
                     96: 
                     97: /****************************************************************\
                     98:  *  Initalizes the print dialog structures
                     99:  *--------------------------------------------------------------
                    100:  *
                    101:  *  Name:   InitPrintDialogs()
                    102:  *
                    103:  *  Purpose: Places defaults in the global info structures
                    104:  *          used by the standard print dialogs
                    105:  *
                    106:  *  Usage:  called once from the initialization routine
                    107:  *
                    108:  *  Method: places standard defaults into each of the fields
                    109:  *          of the Page Setup, Print Setup, and Print Dialog
                    110:  *          structures.  The values used are standard defaults,
                    111:  *          such as inches for the page units, which can be
                    112:  *          easily changed by changing the default values in
                    113:  *          the routine.  The application developer should
                    114:  *          modify these values if he wishes to have the
                    115:  *          default printer and page setup use different values.
                    116:  *
                    117:  *  Returns:
                    118:  *
                    119: \****************************************************************/
                    120:  VOID InitPrintingDialogs(VOID)
                    121:  {
                    122: 
                    123: #ifdef PRINT_DLGS_ENABLED
                    124: 
                    125:     fPrintEnabled = TRUE;
                    126:                                                           
                    127:     /*--------------------------------------------------------------*\
                    128:      *  Initialize the Page Setup structure
                    129:     \*--------------------------------------------------------------*/
                    130:     pgsd.kgd.cbSize      = sizeof(PAGESETUPDLG);
                    131:     pgsd.kgd.flStyle     = PGSS_CENTER;
                    132: 
                    133:     if(!WinLoadString(hab,
                    134:                       NULL,
                    135:                       IDS_PAGESETUPTITLE,
                    136:                       DLGTITLELEN,
                    137:                       (PSZ)szPgsdTitle))  {
                    138: 
                    139:         MessageBox(hwndMain, IDMSG_CANNOTLOADSTRING, FALSE);
                    140:         fPrintEnabled = FALSE;
                    141:         return;
                    142:     }
                    143: 
                    144:     pgsd.kgd.pszDlgTitle = szPgsdTitle;
                    145:     pgsd.kgd.pfnDlgProc  = NULL;
                    146:     pgsd.kgd.hmod        = NULL;
                    147:     pgsd.kgd.idDlg       = 0;
                    148:     pgsd.kgd.lReturn     = 0L;
                    149:     pgsd.kgd.x           = 0;
                    150:     pgsd.kgd.y           = 0;
                    151: 
                    152:     pgsd.flFlags     = PGSF_INCHES;
                    153: 
                    154:     /* Setup the header and footer fields.  */
                    155:     pgsd.cchHeader = MAXFOOTERLEN;
                    156:     pgsd.cchFooter = MAXHEADERLEN;
                    157:     pgsd.pszHeader = szHeader;
                    158:     pgsd.pszFooter = szFooter;
                    159: 
                    160:     /* Setup the margin fields to one inch top and side margins */
                    161:     pgsd.fxLeftMargin   = ONEINCH;
                    162:     pgsd.fxRightMargin  = ONEINCH;
                    163:     pgsd.fxTopMargin    = ONEINCH;
                    164:     pgsd.fxBottomMargin = ONEINCH;
                    165: 
                    166:     /* maximum margins are 8 inch left and right, 11 inch bottom.  We
                    167:        are assuming the default page size is 8 1/2" x 11 " */
                    168:     pgsd.fxLeftMarginMax   = EIGHTINCHES;
                    169:     pgsd.fxRightMarginMax  = EIGHTINCHES;
                    170:     pgsd.fxTopMarginMax    = ELEVENINCHES;
                    171:     pgsd.fxBottomMarginMax = ELEVENINCHES;
                    172: 
                    173:     pgsd.lUser = 0L;
                    174: 
                    175: 
                    176:     /*--------------------------------------------------------------*\
                    177:      *  Initialize the Print Setup structure
                    178:     \*--------------------------------------------------------------*/
                    179:     psd.kgd.cbSize      = sizeof(PRINTSETUPDLG);
                    180:     psd.kgd.flStyle     = PGSS_CENTER;
                    181: 
                    182:     if(!WinLoadString(hab,
                    183:                       NULL,
                    184:                       IDS_PRINTSETUPTITLE,
                    185:                       DLGTITLELEN,
                    186:                       (PSZ)szPsdTitle))  {
                    187: 
                    188:         MessageBox(hwndMain, IDMSG_CANNOTLOADSTRING, FALSE);
                    189:         fPrintEnabled = FALSE;
                    190:         return;
                    191:     }
                    192: 
                    193:     psd.kgd.pszDlgTitle = szPsdTitle;
                    194:     psd.kgd.pfnDlgProc  = NULL;
                    195:     psd.kgd.hmod        = NULL;
                    196:     psd.kgd.idDlg       = 0;
                    197:     psd.kgd.lReturn     = 0L;
                    198:     psd.kgd.x           = 0;
                    199:     psd.kgd.y           = 0;
                    200: 
                    201:     psd.pszAppName      = szAppName;
                    202:     psd.lUser           = 0L;
                    203: 
                    204:     /*--------------------------------------------------------------*\
                    205:      *  Initialize the Print Dialog structure
                    206:     \*--------------------------------------------------------------*/
                    207:     prtd.kgd.cbSize      = sizeof(PRINTDLG);
                    208:     prtd.kgd.flStyle     = PGSS_CENTER;
                    209: 
                    210:     if(!WinLoadString(hab,
                    211:                       NULL,
                    212:                       IDS_PRINTTITLE,
                    213:                       DLGTITLELEN,
                    214:                       (PSZ)szPrtdTitle))  {
                    215: 
                    216:         MessageBox(hwndMain, IDMSG_CANNOTLOADSTRING, FALSE);
                    217:         fPrintEnabled = FALSE;
                    218:         return;
                    219:     }
                    220: 
                    221: 
                    222:     prtd.kgd.pszDlgTitle = szPrtdTitle;
                    223:     prtd.kgd.pfnDlgProc  = NULL;
                    224:     prtd.kgd.hmod        = NULL;
                    225:     prtd.kgd.idDlg       = 0;
                    226:     prtd.kgd.lReturn     = 0L;
                    227:     prtd.kgd.x           = 0;
                    228:     prtd.kgd.y           = 0;
                    229: 
                    230:     prtd.flFlags    = PRTF_ALLPAGES;
                    231:     prtd.cPages     = 0;
                    232:     prtd.cCopies    = 1;
                    233: 
                    234:     prtd.iFrom      = 0;
                    235:     prtd.iTo        = 0;
                    236: 
                    237:     prtd.cchFileName = 0;
                    238:     prtd.pszFileName = NULL;
                    239: 
                    240:     prtd.lUser       = 0L;
                    241: 
                    242: 
                    243:     /*--------------------------------------------------------------*\
                    244:      *  Associate all of the dialog structures with each other so
                    245:      *  that the dialogs can be called from one another
                    246:     \*--------------------------------------------------------------*/
                    247:     pgsd.ppsd  = &psd;
                    248:     pgsd.pprtd = &prtd;
                    249:     psd.ppgsd  = &pgsd;
                    250:     psd.pprtd  = &prtd;
                    251:     prtd.ppsd  = &psd;
                    252:     prtd.ppgsd = &pgsd;
                    253: 
                    254: 
                    255:     /*--------------------------------------------------------------*\
                    256:      *  Initialize the DEVOPENSTRUC in psd and prtd with the data
                    257:      *  from the default printer in os2.ini
                    258:     \*--------------------------------------------------------------*/
                    259:     psd.kgd.flStyle |= PSS_INITDEVOPENSTRUC;
                    260:     if(!KitPrintSetupDlg(NULL, &psd))
                    261:        fPrintEnabled = FALSE;
                    262: 
                    263:     prtd.kgd.flStyle |= PSS_INITDEVOPENSTRUC;
                    264:     if(!KitPrintDlg(NULL, &prtd))
                    265:        fPrintEnabled = FALSE;
                    266: 
                    267:     if(!fPrintEnabled)
                    268:         MessageBox(HWND_DESKTOP,
                    269:                    IDMSG_PRINTINITFAILED,
                    270:                    MB_OK | MB_ERROR,
                    271:                    FALSE);
                    272: 
                    273: #else
                    274:     fPrintEnabled = FALSE;
                    275: #endif
                    276: 
                    277:  }  /* InitPrintDialogs() */
                    278: 
                    279: #ifdef PRINT_DLGS_ENABLED
                    280: 
                    281: 
                    282: /****************************************************************\
                    283:  *  Calls the page setup dialog
                    284:  *--------------------------------------------------------------
                    285:  *
                    286:  *  Name:   PageSetup(hwndOwner)
                    287:  *
                    288:  *  Purpose: Changes the page setup options by calling the
                    289:  *          standard page setup dialog
                    290:  *
                    291:  *  Usage:  called whenever the user wants to update his
                    292:  *          page setup.
                    293:  *
                    294:  *  Method: Calls the standard Page Setup dialog with the
                    295:  *          global PAGESETUPDLG structure which currently
                    296:  *          holds the user's choices.
                    297:  *
                    298:  *  Returns:
                    299:  *
                    300: \****************************************************************/
                    301: VOID PageSetup(hwndOwner)
                    302: HWND hwndOwner;        /* Owner of the dialog */
                    303: {
                    304:     if(!KitPageSetupDlg(hwndOwner, &pgsd))
                    305:        MessageBox(hwndOwner,
                    306:                   IDMSG_CANNOTRUNPAGESETUP,
                    307:                   MB_OK | MB_ERROR,
                    308:                   TRUE);
                    309: 
                    310: }  /* PageSetup() */
                    311:    
                    312: 
                    313: /****************************************************************\
                    314:  *  Calls the print setup dialog
                    315:  *--------------------------------------------------------------
                    316:  *
                    317:  *  Name:   PrintSetup(hwndOwner)
                    318:  *
                    319:  *  Purpose: Changes the printer setup by calling the standard
                    320:  *          print setup dialog
                    321:  *
                    322:  *  Usage:  called whenever the user wants to update his
                    323:  *          printer set up.
                    324:  *
                    325:  *  Method: Calls the standard Print Setup dialog with the
                    326:  *          global PRINTSETUPDLG structure which currently
                    327:  *          holds the user's choices.
                    328:  *
                    329:  *  Returns:
                    330:  *
                    331: \****************************************************************/
                    332: VOID PrintSetup(hwndOwner)
                    333: HWND hwndOwner;        /* Owner of the dialog */
                    334: {
                    335: 
                    336:     if(!KitPrintSetupDlg(hwndOwner, &psd))
                    337:        MessageBox(hwndOwner,
                    338:                   IDMSG_CANNOTRUNPRINTSETUP,
                    339:                   MB_OK | MB_ERROR,
                    340:                   TRUE);
                    341: 
                    342: }  /* PrintSetup() */
                    343:    
                    344: 
                    345: /****************************************************************\
                    346:  *  Begins the printing of a document
                    347:  *--------------------------------------------------------------
                    348:  *
                    349:  *  Name:   Print()
                    350:  *
                    351:  *  Purpose: Does the groundwork necessary when printing a file
                    352:  *
                    353:  *  Usage:  called whenever the user wants to print his file
                    354:  *
                    355:  *  Method: - determines the number of pages in the document
                    356:  *          - calls the standard print dialog to get the user's
                    357:  *            printing options
                    358:  *          - opens the DC for the selected printer
                    359:  *          - calls the application's printing routine, passing
                    360:  *            it the handle to the DC of the printer
                    361:  *
                    362:  *  Returns:
                    363:  *
                    364: \****************************************************************/
                    365: VOID Print(hwndOwner)
                    366: HWND hwndOwner;        /* Owner of the dialog */
                    367: {
                    368:     HDC hdcPrinter;
                    369: 
                    370:     /* Determine number of pages available to print */
                    371:     prtd.cPages = QueryMaxPages();
                    372:     if(prtd.cPages == QMP_ERROR)  {
                    373:         MessageBox(hwndOwner, IDMSG_CANNOTGETPAGEINFO, MB_OK | MB_ERROR, FALSE);
                    374:         return;
                    375:     }
                    376: 
                    377:     prtd.cCopies = 1;      /* initialize the number of copies to one */
                    378: 
                    379:     /* Bring up the Print Dialog */
                    380:     if(!KitPrintDlg(hwndOwner, &prtd))  {
                    381:        MessageBox(hwndOwner, IDMSG_CANNOTRUNPRINT, MB_OK | MB_ERROR,  TRUE);
                    382:        return;
                    383:     }
                    384: 
                    385:    /* if user cancelled the dialog, cancel the printing */
                    386:    if(prtd.kgd.lReturn == ID_CANCEL)
                    387:        return;
                    388: 
                    389: 
                    390:    /*--------------------------------------------------------------*\
                    391:     *  Open the DC for the default printer.  The default printer
                    392:     *  DEVOPENDATA is stored in the prtd structure
                    393:    \*--------------------------------------------------------------*/
                    394:    hdcPrinter = DevOpenDC(hab,
                    395:                           OD_QUEUED,
                    396:                           "*",
                    397:                           DEVDATACOUNT,
                    398:                           (PDEVOPENDATA)&prtd.ppsd->dop,
                    399:                           (HDC)NULL);
                    400: 
                    401:    if(!hdcPrinter)  {
                    402:        MessageBox(hwndMain, IDMSG_CANNOTOPENPRINTER, MB_OK | MB_ERROR,  FALSE);
                    403:        return;
                    404:    }
                    405: 
                    406:    /*--------------------------------------------------------------*\
                    407:     *  Call the application's printing function
                    408:    \*--------------------------------------------------------------*/
                    409: 
                    410:     if(!PrintDoc(hdcPrinter))
                    411:         MessageBox(hwndOwner, IDMSG_PRINTERROR, MB_OK | MB_ERROR, FALSE);
                    412: 
                    413:     DevCloseDC(hdcPrinter);
                    414: 
                    415: }  /* Print() */
                    416: 
                    417: 
                    418: /****************************************************************\
                    419:  *  Calculates the print area of the printer page
                    420:  *--------------------------------------------------------------
                    421:  *
                    422:  *  Name:   CalcPrintArea(hpsPrinter, prclPrintArea, pfm)
                    423:  *
                    424:  *  Purpose: Sets up the print HPS by installing the font,
                    425:  *              calculating the print rectangle, and returning
                    426:  *              the metrics of the chosen font
                    427:  *
                    428:  *  Usage:  called by PrintDoc() and QueryMaxPages() to set
                    429:  *          up the printer HPS for printing.
                    430:  *
                    431:  *          Note: HPS must be associated with the printer HDC
                    432:  *
                    433:  *  Method:  Routine creates an HPS for the printer DC that
                    434:  *          uses LOENGLISH for page units.  A similar HPS is
                    435:  *          created for the MLE through which the current MLE
                    436:  *          font is translated from device metrics to LOENGLISH
                    437:  *          metrics.  The print rectangle is determined by
                    438:  *          finding the printer page size and then subtracting
                    439:  *          the margins and the headers and footers, if any.
                    440:  *          The new font is selected into the printer PS and
                    441:  *          the metrics are returned for the font.  The HPS
                    442:  *          is returned with the printer font selected.
                    443:  *
                    444:  *  Returns: TRUE if successfull, FALSE if not
                    445:  *
                    446: \****************************************************************/
                    447: BOOL CalcPrintArea(hpsPrinter, prclPrintArea, pfm)
                    448: HPS hpsPrinter;         /* INPUT: HPS associated with the printer DC */
                    449: PRECTL prclPrintArea;   /* OUTPUT: buffer for the print rectangle */
                    450: PFONTMETRICS pfm;       /* OUTPUT: pointer to buffer for fontmetrics of
                    451:                                    printer font */
                    452: {
                    453:     HPS hpsMLE;
                    454:     SIZEL szl;
                    455:     FATTRS fattr;
                    456:     FONTMETRICS fm;
                    457:     HDC hdcPrinter;
                    458: 
                    459:     szl.cx = szl.cy = 0L;
                    460: 
                    461:     /* get the handle to the HDC of the printer */
                    462:     hdcPrinter = GpiQueryDevice(hpsPrinter);
                    463:     if(!hdcPrinter)
                    464:         return FALSE;
                    465: 
                    466:     /* get width and height of paper and convert those points to page units */
                    467:     if(!DevQueryCaps(hdcPrinter, CAPS_WIDTH, 2L, (PLONG)&szl))
                    468:         return FALSE;
                    469: 
                    470:     if(GpiConvert(hpsPrinter, CVTC_DEVICE, CVTC_WORLD, 2L, (PPOINTL)&szl) ==
                    471:                 GPI_ERROR)
                    472:         return FALSE;
                    473: 
                    474: 
                    475: 
                    476:     /*--------------------------------------------------------------*\
                    477:      *  prclPrintArea will be set to the rectangle that encompasses
                    478:      *  the area of the page where the text will be printed.  The
                    479:      *  rectangle is defined to be the rectangle of the page minus
                    480:      *  the margins on each side.  For example, the print area
                    481:      *  on a page using the default margins will be the rectangle
                    482:      *  that is one inch from the left, bottom, right, and top
                    483:      *  edges of the papaer.
                    484:      *
                    485:      *  This routine creates the print area rectangle in world
                    486:      *  coordinates.  Since the printer HPS was created in LOENGLISH
                    487:      *  page units, each point of world coordinate space equals
                    488:      *  .01 inch, or 100 points equals one inch.  The left and
                    489:      *  bottom sides of the print area rectangle are equal to the
                    490:      *  the number of inches of the left and bottom margins times
                    491:      *  100.  The top and right margins can also be calculated by
                    492:      *  multiplying the margin size * 100, but then that distance
                    493:      *  must be subtracted from the width and height of the paper.
                    494:      *
                    495:      *  The FIXEDTOWORLD() macro, as defined above, converts a
                    496:      *  FIXED integer value into LOENGLISH world coordinates.  If
                    497:      *  you change either the page units of the printer HPS or the
                    498:      *  scale of the margins, you must changed FIXEDTOWORLD() to
                    499:      *  translate the margin dimensions to fit the new parameters.
                    500:      *
                    501:     \*--------------------------------------------------------------*/
                    502:     prclPrintArea->xLeft = FIXEDTOWORLD(pgsd.fxLeftMargin);
                    503: 
                    504:     prclPrintArea->yBottom = FIXEDTOWORLD(pgsd.fxBottomMargin);
                    505: 
                    506:     prclPrintArea->xRight = szl.cx - FIXEDTOWORLD(pgsd.fxRightMargin);
                    507: 
                    508:     prclPrintArea->yTop = szl.cy - FIXEDTOWORLD(pgsd.fxTopMargin);
                    509: 
                    510: 
                    511: 
                    512:     /* get a PS for the MLE and set it to be LOENGLISH also.
                    513:      *
                    514:      * Note: only GpiSetPS is checked for an error return.  That is
                    515:      *  because if the WinGetPS() function returns an error, hpsMLE
                    516:      *  will be NULL.  If hpsMLE is NULL, then GpiSetPS() will fail.
                    517:      *  So, GpiSetPS() will fail if WinGetPS() fails, so we only need
                    518:      *  to check the return code from GpiSetPS()
                    519:      */
                    520: 
                    521:     hpsMLE = WinGetPS(hwndMLE);
                    522:     if(GpiSetPS(hpsMLE, &szl, PU_LOENGLISH) == GPI_ERROR)
                    523:         return FALSE;
                    524: 
                    525:     /* get font information from MLE and create similar font on printer */
                    526:     WinSendMsg(hwndMLE, MLM_QUERYFONT, MPFROMP(&fattr), NULL);
                    527: 
                    528:     /* convert font information to LOENGLISH by setting the font into
                    529:      *  the LOENGLISH PS we created for the MLE, getting the
                    530:      *  fontmetrics, and then updating the fattr structure.
                    531:      *
                    532:      *  Note: only GpiSetCharSet's return value is checked, because if
                    533:      *  the GpiCreateLogFont call fails, the LCID passed to GpiSetCharSet
                    534:      *  will be invalid and GpiSetCharSet will fail as well.
                    535:      */
                    536: 
                    537:     GpiCreateLogFont(hpsMLE, (PSTR8)fattr.szFacename, FONTLCID, &fattr);
                    538:     if(GpiSetCharSet(hpsMLE, FONTLCID) == GPI_ERROR)
                    539:         return FALSE;
                    540: 
                    541:     if(GpiQueryFontMetrics(hpsMLE,
                    542:                            (ULONG)sizeof(FONTMETRICS),
                    543:                            (PFONTMETRICS)&fm) == GPI_ERROR)
                    544:         return FALSE;
                    545: 
                    546:     /* delete font and release MLE HPS.  Return values are not checked for
                    547:      *  error because a failure in the clean up of the HPS will not
                    548:      *  adversely affect this routine
                    549:      */
                    550:     GpiSetCharSet(hpsMLE, 0);
                    551:     GpiDeleteSetId(hpsMLE, FONTLCID);
                    552:     WinReleasePS(hpsMLE);
                    553: 
                    554:     /* The FATTRS structure was filled with the information for the font
                    555:      * of the MLE.  The height and width of the font is in device
                    556:      * coordinates, however.  Since we created the same font on a
                    557:      * PU_LOENGLISH HPS, we now can get the height and width in
                    558:      * PU_LOENGLISH page units.  These values are contained in the
                    559:      * fm structure.  We replace the height and width of the font with
                    560:      * the PU_LOENGLISH equavalents and set the lMatch to 0, so that
                    561:      * GPI will look through all printer fonts for the font that most
                    562:      * closely matches the size of the font used on the screen.
                    563:      */
                    564: 
                    565:     fattr.lMaxBaselineExt = fm.lMaxBaselineExt;
                    566:     fattr.lAveCharWidth   = fm.lAveCharWidth;
                    567:     fattr.lMatch = 0L;
                    568: 
                    569:     /* Create the font on the printer HPS.
                    570:      *
                    571:      * Note:  if GpiCreateLogFont() returns 1, then an exact match for
                    572:      *  the font desired was not found.  This application does not care
                    573:      *  if the font matches exactly or not, but your application might.
                    574:      *  If GpiCreateLogFont() returns 0, and error occurred, which will
                    575:      *  be caught when we attempt GpiSetCharSet() with this font's LCID
                    576:      */
                    577:     GpiCreateLogFont(hpsPrinter, (PSTR8)fattr.szFacename, FONTLCID, &fattr);
                    578: 
                    579:     if(GpiSetCharSet(hpsPrinter, FONTLCID) == GPI_ERROR)
                    580:         return FALSE;
                    581: 
                    582:     /* get printer font information for return in pfm */
                    583:     if(GpiQueryFontMetrics(hpsPrinter,
                    584:                           (LONG)sizeof(FONTMETRICS),
                    585:                           pfm) == GPI_ERROR)
                    586:         return FALSE;
                    587: 
                    588: 
                    589:     /*--------------------------------------------------------------*\
                    590:      *  If a header or footer is present, it will take two lines -
                    591:      *  one for the text and one blank line.  Since rclPrintArea
                    592:      *  is the rectangle where the document text is to be printed,
                    593:      *  the two lines of the header or footer are removed from
                    594:      *  the current print area.  The top and bottom side are
                    595:      *  adjusted accordingly.
                    596:      *
                    597:      *  When the header and footer are printed, they are printed
                    598:      *  two lines above and below the print area.
                    599:      *
                    600:     \*--------------------------------------------------------------*/
                    601: 
                    602:     /* if header is present, adjust top for it */
                    603:     if(pgsd.pszHeader[0])
                    604:         prclPrintArea->yTop -= (pfm->lMaxBaselineExt +
                    605:                                    pfm->lExternalLeading) * 2L;
                    606: 
                    607:     /* if footer is present, adjust bottom for it */
                    608:     if(pgsd.pszFooter[0])
                    609:         /*--------------------------------------------------------------*\
                    610:          *  A line of text has a height equal to the MaxBaselineExt
                    611:          *  followed by the ExternalLeading.  Since the footer is
                    612:          *  printed on the bottom of the page, the ExternalLeading
                    613:          *  following the footer is not necessary.  The height of the
                    614:          *  footer, then, is calculated as the sum of the heights
                    615:          *  of the text line, the blank line, and the External Leading  *
                    616:          *  between them.
                    617:          *
                    618:         \*--------------------------------------------------------------*/
                    619:         prclPrintArea->yBottom += (pfm->lMaxBaselineExt * 2L) +
                    620:                                    pfm->lExternalLeading;
                    621: 
                    622:     return TRUE;
                    623: 
                    624: }   /* CalcPrintArea() */
                    625: 
                    626: 
                    627: /****************************************************************\
                    628:  *  Determines the maximum number of pages in the document
                    629:  *--------------------------------------------------------------
                    630:  *
                    631:  *  Name:   QueryMaxPages()
                    632:  *
                    633:  *  Purpose: returns the maximum number of pages in a file
                    634:  *
                    635:  *  Usage:  called by Print() to initialize the prtd.cPages
                    636:  *          field
                    637:  *
                    638:  *  Method:
                    639:  *
                    640:  *  Returns: Number of pages in the document or QMP_ERROR if an error
                    641:  *
                    642: \****************************************************************/
                    643: SHORT QueryMaxPages(VOID)
                    644: {
                    645:     HDC hdcPrinter;
                    646:     FONTMETRICS fm;
                    647:     RECTL rclPrintArea;
                    648:     HPS hpsPrinter;
                    649:     SIZEL szl;
                    650:     LONG lLines, lLinesPerPage;
                    651: 
                    652:     /*--------------------------------------------------------------*\
                    653:      *  Code to determine the number of pages in the document
                    654:      *  to be printed
                    655:     \*--------------------------------------------------------------*/
                    656: 
                    657:     /* create an info dc for the printer */
                    658:     hdcPrinter = DevOpenDC(hab,
                    659:                            OD_INFO,
                    660:                            "*",
                    661:                            DEVDATACOUNT,
                    662:                            (PDEVOPENDATA)&prtd.ppsd->dop,
                    663:                            (HDC)NULL);
                    664:     if(!hdcPrinter)
                    665:         return QMP_ERROR;
                    666: 
                    667:     /* create a ps for the DC.  Use english page units so we can
                    668:        measure the margins easily */
                    669:     szl.cx = szl.cy = 0L;
                    670:     hpsPrinter = GpiCreatePS(hab,
                    671:                         hdcPrinter,
                    672:                         &szl,
                    673:                         PU_LOENGLISH | GPIT_NORMAL | GPIF_DEFAULT | GPIA_ASSOC);
                    674:     if(!hpsPrinter)
                    675:         return QMP_ERROR;
                    676: 
                    677:     if(!CalcPrintArea(hpsPrinter, &rclPrintArea, &fm))
                    678:         return QMP_ERROR;
                    679: 
                    680:     /* get number of lines in the document */
                    681:     lLines = (LONG)WinSendMsg(hwndMLE, MLM_QUERYLINECOUNT, NULL, NULL);
                    682: 
                    683:     /* calculate the number of lines per page */
                    684:     lLinesPerPage = (rclPrintArea.yTop - rclPrintArea.yBottom) /
                    685:                     (fm.lMaxBaselineExt + fm.lExternalLeading);
                    686: 
                    687:     GpiAssociate(hpsPrinter, NULL);
                    688:     GpiDestroyPS(hpsPrinter);
                    689:     DevCloseDC(hdcPrinter);
                    690: 
                    691:     return(SHORT)(lLines / lLinesPerPage) + 1;
                    692: 
                    693: }   /* QueryMaxPages() */
                    694: 
                    695: 
                    696: /****************************************************************\
                    697:  *  Performs the actual printing of a document
                    698:  *--------------------------------------------------------------
                    699:  *
                    700:  *  Name:   PrintDoc(hdc)
                    701:  *
                    702:  *  Purpose: Performs the printing of a file
                    703:  *
                    704:  *  Usage:  called by Print() to actually print the file
                    705:  *
                    706:  *  Method:  This routine prints each line of the MLE.  If a
                    707:  *           line is longer than the page width, then the line
                    708:  *           is clipped to the margin;  it is not wrapped to
                    709:  *           the next line.
                    710:  *
                    711:  *          Note: this routine should NOT close the printer DC
                    712:  *
                    713:  *  Returns:    TRUE if successfull, FALSE if not
                    714:  *
                    715: \****************************************************************/
                    716: BOOL PrintDoc(hdc)
                    717: HDC hdc;               /* hdc of the printer */
                    718: {
                    719:     USHORT usSpoolId, usNumCopies;
                    720:     LONG   lOutData, lOffset = 0L, lFileEnd, lLine, lT, lPageLines;
                    721:     LONG   lLinesPerPage, lLineHeight, lStartOffset, lTotalLines;
                    722:     RECTL  rclPrintArea, rclText;
                    723:     HPS    hpsPrinter;
                    724:     SIZEL  szl;
                    725:     PVOID  pvBuf;
                    726:     FONTMETRICS fm;
                    727:     POINTL ptl;
                    728:     BOOL   fRet = TRUE;
                    729: 
                    730:     /*--------------------------------------------------------------*\
                    731:      *  Creates a PS for the DC.  Note that you can associate an
                    732:      *  existing HPS to the DC here instead if you are using
                    733:      *  retained graphics in the HPS.  The PS must use PU_LOENGLISH
                    734:      *  page units since the CalcPrintArea() routine expects the
                    735:      *  the PS to use them.
                    736:     \*--------------------------------------------------------------*/
                    737:     szl.cx = szl.cy = 0L;
                    738:     hpsPrinter = GpiCreatePS(hab,
                    739:                     hdc,
                    740:                     &szl,
                    741:                     PU_LOENGLISH | GPIT_NORMAL | GPIF_DEFAULT | GPIA_ASSOC);
                    742:     if(!hpsPrinter)
                    743:         return FALSE;
                    744: 
                    745:     if(!CalcPrintArea(hpsPrinter, &rclPrintArea, &fm))  {
                    746:         fRet = FALSE;
                    747:         goto PrintDocExit;
                    748:     }
                    749: 
                    750:     /*--------------------------------------------------------------*\
                    751:      *  Note:  CalcPrintArea() has created the printer font on
                    752:      *  hpsPrinter and selected the font.  It has also returned
                    753:      *  the metrics for the font in fm.  rclPrintArea is the
                    754:      *  rectangle bounding the print area of the page, excluding
                    755:      *  the header and footer.
                    756:     \*--------------------------------------------------------------*/
                    757: 
                    758:     /*--------------------------------------------------------------*\
                    759:      *  rclText is set to the rectangle that will encompass one
                    760:      *  line of output.  Its left and right sides are set to the
                    761:      *  margins of the paper, namely the left and right sides of
                    762:      *  the print area as represented by rclPrintArea.  Its top
                    763:      *  will be repositioned for each line of output and its
                    764:      *  bottom will always be set to one line's height below the
                    765:      *  top.  All text output will be clipped to this rectangle.
                    766:     \*--------------------------------------------------------------*/
                    767: 
                    768:     /* set rectangle for each text line to have its left and right sides
                    769:         equal to the left and right margin of the print area */
                    770:     rclText.xLeft = rclPrintArea.xLeft;
                    771:     rclText.xRight = rclPrintArea.xRight;
                    772: 
                    773:     /* calculate the height of each printed line, including any space
                    774:         (leading) between the lines */
                    775:     lLineHeight = fm.lMaxBaselineExt + fm.lExternalLeading;
                    776: 
                    777:     /* calculate the number of lines that fit on a page */
                    778:     lLinesPerPage =  (rclPrintArea.yTop - rclPrintArea.yBottom) /
                    779:                       lLineHeight;
                    780: 
                    781:     /* If our page size is too small to print even one line, then
                    782:         abort the print job */
                    783:     if(lLinesPerPage < 0L)  {
                    784:         MessageBox(hwndMLE, IDMSG_PRINTAREATOOSMALL, MB_OK | MB_ERROR,  FALSE);
                    785:         goto PrintDocExit;
                    786:     }
                    787: 
                    788: 
                    789:     /* get the length of the output file */
                    790:     lFileEnd = (LONG)WinSendMsg(hwndMLE, MLM_QUERYTEXTLENGTH, NULL, NULL);
                    791: 
                    792:     /* create a buffer to hold the file */
                    793:     DosAllocMem((PPVOID) &pvBuf, lFileEnd, fALLOC);
                    794: 
                    795:     /* set up the buffer for the MLE text */
                    796:     WinSendMsg(hwndMLE,
                    797:                MLM_SETIMPORTEXPORT,
                    798:                MPFROMP(pvBuf),
                    799:                MPFROMLONG(lFileEnd));
                    800: 
                    801: 
                    802:     /* if printing all pages, set file offset to beginning of file  *\
                    803:      *  and set the last line to the end of the file.  If printing
                    804:      *  only certain pages, calculate the beginning and ending line
                    805:     \*  based on the pages                                          */
                    806: 
                    807:     if(prtd.flFlags & PRTF_ALLPAGES) {
                    808:         lStartOffset = 0L;
                    809:         lTotalLines = (LONG)WinSendMsg(hwndMLE,
                    810:                                       MLM_QUERYLINECOUNT,
                    811:                                       NULL,
                    812:                                       NULL);
                    813:     }  else  {
                    814:         /* set lStartOffset to the beginning of the first line of the
                    815:             first page set to print */
                    816:         lT = (LONG)(prtd.iFrom - 1L) * lLinesPerPage;
                    817: 
                    818:         if(lT < 0L);    /* lT should never be less than 0, so this is */
                    819:             lT = 0L;    /* purely defensive programming */
                    820: 
                    821:         /* lT is the number of lines in all pages from the beginning
                    822:             of the document to the first page printed */
                    823: 
                    824:         lStartOffset = (LONG)WinSendMsg(hwndMLE,
                    825:                                         MLM_CHARFROMLINE,
                    826:                                         MPFROMLONG(lT),
                    827:                                         NULL);
                    828: 
                    829:         /* set lTotalLines to the number of lines in the pages between the
                    830:             starting and ending */
                    831:         lTotalLines = (LONG)(prtd.iTo - prtd.iFrom + 1) * lLinesPerPage;
                    832:         lFileEnd = (LONG)WinSendMsg(hwndMLE,
                    833:                                     MLM_QUERYLINECOUNT,
                    834:                                     NULL,
                    835:                                     NULL);
                    836: 
                    837:         /* if last line is beyond end of file, set the last line to
                    838:             be the end of file */
                    839:         if(lTotalLines + lT > lFileEnd)
                    840:             lTotalLines = lFileEnd - lT;
                    841:     }
                    842: 
                    843: 
                    844: 
                    845:     /* print one document for each number of copies */
                    846:     usNumCopies = (USHORT)prtd.cCopies;
                    847:     while(usNumCopies--)  {
                    848: 
                    849:         /* set file offset variable to the beginning of the lines
                    850:            being printed; set line variable to the number of lines
                    851:            to be printed */
                    852:         lLine = lTotalLines;
                    853:         lOffset = lStartOffset;
                    854: 
                    855:         /* send a DEVESC_STARTDOC to start the printing */
                    856:         if(DevEscape(hdc,
                    857:                      DEVESC_STARTDOC,
                    858:                      (LONG)MAXNAMEL,
                    859:                      (PBYTE)szAppName,
                    860:                      (PLONG)NULL,
                    861:                      (PBYTE)NULL) != DEV_OK)  {
                    862: 
                    863:             MessageBox(hwndMain,
                    864:                        IDMSG_CANNOTOPENPRINTER,
                    865:                        MB_OK | MB_ERROR,
                    866:                        FALSE);
                    867: 
                    868:             fRet = FALSE;
                    869:             goto PrintDocExit;
                    870:         }
                    871: 
                    872:         while(lLine)  {
                    873: 
                    874:             /* if we have header text, print the header at the top of the page */
                    875:             if(pgsd.pszHeader[0])  {
                    876: 
                    877:                 /* set text rectangle to two lines above print area since
                    878:                    we reserved two lines for it in CalcPrintArea() */
                    879: 
                    880:                 rclText.yTop = rclPrintArea.yTop + (lLineHeight * 2L);
                    881:                 rclText.yBottom = rclText.yTop - fm.lMaxBaselineExt;
                    882: 
                    883:                 ptl.x = rclText.xLeft;
                    884:                 ptl.y = rclText.yTop - fm.lMaxAscender;
                    885: 
                    886:                 GpiMove(hpsPrinter, &ptl);
                    887: 
                    888:                 GpiCharStringPos(hpsPrinter,
                    889:                                  &rclText,
                    890:                                  CHS_CLIP,
                    891:                                  pgsd.cchHeader,
                    892:                                  pgsd.pszHeader,
                    893:                                  NULL);
                    894: 
                    895:             }
                    896: 
                    897:             /*==============================================================*\
                    898:              * Now print each line of text in the print area
                    899:             \*==============================================================*/
                    900: 
                    901:             /*--------------------------------------------------------------*\
                    902:              *  The top of rclText is set here to the top of the print
                    903:              *  area while the bottom is set to the height of one line
                    904:              *  below the top.  The measurement used to position the
                    905:              *  bottom is not the lLineHeight variable, but rather the
                    906:              *  actual height of the characters in the font as given by
                    907:              *  the lMaxBaselineExt field of the fontmetrics structure.
                    908:              *  Thus, rclText will be the height of the characters in the
                    909:              *  line and will not include any external leading.
                    910:             \*--------------------------------------------------------------*/
                    911:             rclText.yTop = rclPrintArea.yTop;
                    912:             rclText.yBottom = rclText.yTop - fm.lMaxBaselineExt;
                    913: 
                    914:             /*--------------------------------------------------------------*\
                    915:              *  ptl will be the beginning point of the text string.  The
                    916:              *  x coordinate of the point will always be on the left side
                    917:              *  of the print line, as given the rclText.xLeft.  The y
                    918:              *  coordinate is set to the baseline of the font.  The
                    919:              *  baseline is the line at the bottom of all characters,
                    920:              *  excluding any descenders.  The baseline is determined by
                    921:              *  taking the top of the text line and subtracting the height
                    922:              *  of the ascender of the font.  Thus:
                    923:              *
                    924:              *                  ****       ===            ===
                    925:              *                 *    *        |              |
                    926:              *                 *    *        |  ascender    |
                    927:              *                 *    *        |              | MaxBaselineExt
                    928:              *     baseline --- *****------===              |
                    929:              *                      *        |              |
                    930:              *                 *    *        |  descender   |
                    931:              *                  ****       ===            ===
                    932:              *
                    933:              *  ptl.y is set to the baseline coordinate by subracting the
                    934:              *  Ascender of the font (fm.lMaxAscender) from the top of
                    935:              *  the text rectangle (rclText.yTop).
                    936:              *
                    937:             \*--------------------------------------------------------------*/
                    938: 
                    939:             ptl.x = rclText.xLeft;
                    940:             ptl.y = rclText.yTop - fm.lMaxAscender;
                    941: 
                    942:             /* set lPageLines to the number of lines on the page.  If
                    943:                there are fewer lines left in the document, then set
                    944:                it to the number of lines left */
                    945:             lPageLines = min(lLinesPerPage, lLine);
                    946: 
                    947:             while(lPageLines--)  {
                    948:                 ptl.y = rclText.yTop - fm.lMaxAscender;  /* re-set baseline */
                    949: 
                    950:                 /* get current line from MLE */
                    951:                 lT = WinSendMsg(hwndMLE,
                    952:                                 MLM_QUERYFORMATLINELENGTH,
                    953:                                 MPFROMLONG(lOffset),
                    954:                                 NULL);
                    955:                 /* lT is the length of the current line, including the
                    956:                     CR/LF pair at the end */
                    957: 
                    958:                 lOutData = lT - 2L;     /* length of line minus CR/LF pair */
                    959: 
                    960:                 /* get the text from the MLE */
                    961:                 WinSendMsg(hwndMLE,
                    962:                            MLM_EXPORT,
                    963:                            MPFROMP(&lOffset),
                    964:                            MPFROMP(&lT));
                    965: 
                    966:                 /* print the string */
                    967:                 if(GpiMove(hpsPrinter, &ptl) == GPI_ERROR)  {
                    968:                     fRet = FALSE;
                    969:                     goto PrintDocExit;
                    970:                 }
                    971: 
                    972: 
                    973:                 if(GpiCharStringPos(hpsPrinter,
                    974:                                     &rclText,
                    975:                                     CHS_CLIP,
                    976:                                     lOutData,
                    977:                                     pvBuf,
                    978:                                     NULL) == GPI_ERROR)  {
                    979:                     fRet = FALSE;
                    980:                     goto PrintDocExit;
                    981:                 }
                    982: 
                    983:                 /* subtract one from the lines remaining */
                    984:                 lLine--;
                    985: 
                    986:                 /* move offset pointer to the beginning of next line */
                    987:                 lOffset += lT;
                    988: 
                    989:                 /* set the top of the text rectangle to the top of the
                    990:                     next line.  Set the bottom to a character's height
                    991:                     below the top */
                    992:                 rclText.yTop = rclText.yBottom - fm.lExternalLeading;
                    993:                 rclText.yBottom = rclText.yTop - fm.lMaxBaselineExt;
                    994: 
                    995:             }   /* while(lPageLines) */
                    996: 
                    997: 
                    998:             /* add footer if necessary */
                    999:             if(pgsd.pszFooter[0])  {
                   1000: 
                   1001:                 /* set text rectangle to two lines below print area since
                   1002:                    we reserved two lines for it in CalcPrintArea().  Refer
                   1003:                    to the CalcPrintArea() function for an explanation of
                   1004:                    the height of the footer */
                   1005: 
                   1006:                 rclText.yBottom = rclPrintArea.yBottom -
                   1007:                                   ((fm.lMaxBaselineExt * 2L) +
                   1008:                                   fm.lExternalLeading);
                   1009: 
                   1010:                 rclText.yTop = rclText.yBottom + fm.lMaxBaselineExt;
                   1011: 
                   1012:                 /* set ptl to baseline */
                   1013:                 ptl.y = rclText.yTop - fm.lMaxAscender;
                   1014: 
                   1015:                 /* print the footer text */
                   1016:                 if(GpiMove(hpsPrinter, &ptl) == GPI_ERROR)  {
                   1017:                     fRet = FALSE;
                   1018:                     goto PrintDocExit;
                   1019:                 }
                   1020: 
                   1021:                 if(GpiCharStringPos(hpsPrinter,
                   1022:                                     &rclText,
                   1023:                                     CHS_CLIP,
                   1024:                                     pgsd.cchFooter,
                   1025:                                     pgsd.pszFooter,
                   1026:                                     NULL) == GPI_ERROR)  {
                   1027:                     fRet = FALSE;
                   1028:                     goto PrintDocExit;
                   1029:                 }
                   1030: 
                   1031:             }
                   1032: 
                   1033:             /* send a DEVESC_NEWFRAME to end this page */
                   1034:             if(DevEscape(hdc,
                   1035:                          DEVESC_NEWFRAME,
                   1036:                          0L,
                   1037:                          (PBYTE)NULL,
                   1038:                          (PLONG)NULL,
                   1039:                          (PBYTE)NULL) != DEV_OK)  {
                   1040: 
                   1041:                 fRet = FALSE;
                   1042:                 goto PrintDocExit;
                   1043:             }
                   1044: 
                   1045:         }   /* while(lLine) */
                   1046: 
                   1047: 
                   1048: 
                   1049:         /* send a DEVESC_ENDDOC to end the printing */
                   1050:         if(DevEscape(hdc,
                   1051:                      DEVESC_ENDDOC,
                   1052:                      0L,
                   1053:                      (PBYTE)NULL,
                   1054:                      (PLONG)&lOutData,
                   1055:                      (PBYTE)&usSpoolId) != DEV_OK)  {
                   1056: 
                   1057:             fRet = FALSE;
                   1058:             goto PrintDocExit;
                   1059:         }
                   1060: 
                   1061:     }   /* while(usNumCopies) */
                   1062: 
                   1063: PrintDocExit:
                   1064: 
                   1065:     /* free the text buffer and destroy the PS */
                   1066:     GpiFreeMem((PVOID)pvBuf);
                   1067: 
                   1068:     GpiAssociate(hpsPrinter, NULL);
                   1069:     GpiDestroyPS(hpsPrinter);
                   1070: 
                   1071:     return fRet;
                   1072: 
                   1073: }   /* PrintDoc() */
                   1074: 
                   1075: 
                   1076: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.