home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic 4 Unleashed / Visual_Basic_4_Unleashed_SAMS_Publishing_1995.iso / source / chap08 / 32bitsrc / vbprint.c next >
C/C++ Source or Header  |  1995-06-21  |  49KB  |  1,419 lines

  1. /*************************************************************************
  2.     Print Engine for Visual Basic
  3.     Printing utilities for hardcopy output
  4.  
  5.     Written by Barry Nolte
  6.  
  7.     06-28-92    File Created
  8.     11-12-92    Added Graphics Functions
  9.     01-17-93    General Cleanup of Sources
  10.     02-03-93    Simple Bug Fixes
  11. ************************************************************************
  12.  
  13. ************************************************************************
  14.  Ported to WIN32 by Paul Jason Mahar
  15.  MicroHelp, Inc. 
  16.  June 1994
  17. *************************************************************************/
  18.  
  19. // COPYRIGHT:
  20. //
  21. //   (C) Copyright Microsoft Corp. 1993.  All rights reserved.
  22. //
  23. //   You have a royalty-free right to use, modify, reproduce and
  24. //   distribute the Sample Files (and/or any modified version) in
  25. //   any way you find useful, provided that you agree that
  26. //   Microsoft has no warranty obligations or liability for any
  27. //   Sample Application Files which are modified.
  28. //
  29.  
  30. #include <windows.h>
  31. #include <drivinit.h>
  32. #include <commdlg.h>
  33. #include <memory.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include "vbprint.h"
  37.  
  38. // DLL Version Numbers
  39. #define MAJOR_VERSION     1
  40. #define MINOR_VERSION     0
  41.  
  42. #define BORDER_WIDTH    2        // Default border in points
  43.  
  44. /*************************************************************************
  45.  
  46.     GLOBAL VARIABLES
  47.  
  48. *************************************************************************/
  49.  
  50. static    HANDLE        hInst;        // Handle to calling app
  51. static    HWND        hWndApp;    // Handle ot calling apps main window
  52. static    PRINTDLG    ppPrinter;    // Structure of printer properties
  53.  
  54. // Misc Procs
  55. static    FARPROC        lpfnPrintDlgProc;    // Printing dialog proc
  56. static    FARPROC        lpfnAbortProc;        // Printing about proc
  57. static  BOOL        fAbort;
  58. int result;
  59. static    struct tagPrinterInfo    // Information on printer needed to place objects correctly
  60.     {
  61.         POINT    ptPageSize;            // Size of the page
  62.         RECT    rcUnprintable;        // Unprintable regions of the printer
  63.         RECT    rcMargins;            // Margins that are set in the Page Layout Function
  64.         POINT    ptResolution;        // Printer Resolution in device DPI
  65.  
  66.     } PrinterInfo;
  67.  
  68. static    struct tagPageInfo        // Information on where I'm printing on the page
  69.     {
  70.         POINT    ptCurrentPos;        // Current Print Position
  71.         DWORD    dwCurLineWidth;        // Current Line Width, good for multiple calls to ParagraphText
  72.         int        nTabStop;            // Current Tab Stop value
  73.         BOOL    bPageDirty;            // Is the page dirty?
  74.  
  75.     } PageInfo;
  76.  
  77. static struct tagParagraphInfo    // Information on paragraph attributes
  78.     {
  79.         HFONT        hFont;            // Handle to paragraphs default font
  80.         HFONT        hOldFont;        // Handle to previous font
  81.         TEXTMETRIC    tm;                // Text metric struct that has info on the font
  82.         DWORD        dwWidth;        // Width of column to print into
  83.         int            nStyle;            // Border and Font Attributes
  84.         WORD        wBorderWidth;    // Border Width in device units (HIBYTE = Horizontal, LOBYTE = Vertical)
  85.         int            nWidth[LAST_CHAR - FIRST_CHAR + 1];    // Widths of all the fonts characters
  86.         int            nSpaceBefore;        // Space before Paragraph in Points
  87.         int         nSpaceAfter;        // Space After Paragraph in Points
  88.         int            nLeftIndent;        // Paragraph Left Indent size, good for check box justification
  89.  
  90.     } ParagraphInfo;
  91.  
  92. static struct tagColumnInfo        // Information on printing columns
  93.     {
  94.         HFONT        hFont;                            // Handle to paragraphs default font
  95.         HFONT        hOldFont;                        // Handle to previous font
  96.         TEXTMETRIC    tm;                                // Text Metric struct that has info on the font
  97.         WORD        wBorderWidth;                    // Border Width in device units (HIBYTE = Horizontal, LOBYTE = Vertical)
  98.         int         nNumColumns;                    // Number of vertical Columns
  99.         int         nCellHeight;                    // Height of Cells
  100.         int         rgColumnWidths[MAX_COLUMNS];        // Widths of Columns
  101.         int            nWidth[LAST_CHAR - FIRST_CHAR + 1];    // Widths of all the fonts characters
  102.         int             nStyle;                            // Border and Font attributes
  103.  
  104.     } ColumnInfo;
  105.  
  106. /*************************************************************************
  107.     PROTOTYPES
  108. *************************************************************************/
  109.  
  110. int     FAR PASCAL     PrinterSetup(HWND hWnd);
  111. int     FAR PASCAL     InitializePrinter(HWND hWnd);
  112. int     FAR PASCAL    PageLayoutSetup(int nTop, int nRight, int nBottom, int nLeft);
  113. BOOL                DoCommDlgError(HWND hWnd, DWORD dError);
  114. int     FAR PASCAL     DonePrinting(void);
  115. int     FAR PASCAL     StartParagraph(LPSTR szFontName, int nFontSize, int nStyle);
  116. int     FAR PASCAL    FinishParagraph(void);
  117. int     FAR PASCAL     PrintHeadline(LPSTR szHeadLine, LPSTR szFontName, int nFontSize, int nStyle);
  118. int     FAR PASCAL    ParagraphText(LPSTR szText);
  119. int     FAR PASCAL    EjectPage (void);
  120. int                 TextOutAtCurPos(LPSTR szText);
  121. int                 GetColumnOffset(int nColumn);
  122. int                 CellDrawText(HDC hDC, LPSTR szText, LPRECT rc);
  123. BOOL                GetUnprintableRegion(HDC hDCPrn);
  124. BOOL                GetPrinterResolution(HDC hDCPrn);
  125. BOOL    FAR PASCAL    PrnAbortProc(HDC hDCPrn, short nCode);
  126. BOOL    FAR PASCAL    PrintDlgProc(HWND hDlg, WORD message, WORD wParam, LONG lParam);
  127. int     FAR PASCAL    PrintDLLVersion(VOID);
  128. BOOL    FAR PASCAL    SetParagraphSpacing(int nSpaceBefore, int nSpaceAfter);
  129. BOOL    FAR PASCAL    SetBorderWidth(int nWidth);
  130. int     FAR PASCAL    SetUpColumns(int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle);
  131. int     FAR PASCAL    PrintColumnText(LPSTR szText);
  132. int     FAR PASCAL    EndColumnPrinting(VOID);
  133. int     FAR PASCAL    PrintColumnHeaders(LPSTR szHeader, int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle);
  134. HDC                 GetPrinterDC(void);
  135. BOOL    FAR PASCAL    KillJob(void);
  136. BOOL    FAR PASCAL    PrinterName(LPSTR szPrinterName);
  137. BOOL    FAR PASCAL    PrinterPort(LPSTR szPortName);
  138. BOOL    FAR PASCAL    IsPageDirty(void);
  139. int     FAR PASCAL    PagePosY(void);
  140. int     FAR PASCAL    PagePosX(void);
  141. int     FAR PASCAL    PageSizeY(void);
  142. int     FAR PASCAL    PageSizeX(void);
  143. BOOL    FAR PASCAL    MoveYPos(int nY);
  144. int     FDrawLine(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY);
  145. int     FDrawRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY);
  146. int     FDrawRndRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY, int nElpX, int nElpY);
  147. int     FDrawEllipse(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY);
  148. BOOL    FAR PASCAL    DrawLine(int nX1, int nY1, int nX2, int nY2);
  149. BOOL    FAR PASCAL    DrawRectangle(int nX1, int nY1, int nX2, int nY2);
  150. BOOL    FAR    PASCAL    DrawRndRectangle(int nX1, int nY1, int nX2, int nY2, int nX3, int nY3);
  151. BOOL    FAR PASCAL    DrawEllipse(int nX1, int nY1, int nX2, int nY2);
  152.  
  153. /*************************************************************************
  154.     DLL initialization, called once when loaded
  155. *************************************************************************/
  156. BOOL APIENTRY DllMain( HANDLE hModule, 
  157.                         DWORD ul_reason_for_call, 
  158.                         LPVOID lpReserved )
  159. {
  160.     hInst=hModule;    
  161.   return TRUE;
  162. }
  163.  
  164.  
  165. /*************************************************************************
  166.     Initialize Printer Driver and set defaults
  167. *************************************************************************/
  168.  
  169. int FAR PASCAL InitializePrinter(HWND hWnd)
  170. {
  171.     DOCINFO di;
  172.     
  173.     char szQueueName[80]={""};
  174.     di.fwType=0;    
  175.     hWndApp = hWnd;            // Save the calling apps window handle so we can put up dialogs
  176.  
  177.     fAbort = FALSE;
  178.  
  179.     PageInfo.bPageDirty = FALSE;
  180.     
  181.     ppPrinter.hDC = GetPrinterDC();
  182.  
  183.     if (ppPrinter.hDC)
  184.     {
  185.         // Do stuff for AbortProc and Printing Dialog
  186.         
  187.         lpfnAbortProc = MakeProcInstance(PrnAbortProc, hInst);
  188.         //result=Escape(ppPrinter.hDC, SETABORTPROC,(int) NULL, (LPSTR)(long)lpfnAbortProc, (LPSTR)NULL);
  189.         result=SetAbortProc(ppPrinter.hDC,lpfnAbortProc);
  190.            GetUnprintableRegion(ppPrinter.hDC);
  191.            GetPrinterResolution(ppPrinter.hDC);
  192.            LoadString(hInst, IDS_QUEUE_NAME, (LPSTR)szQueueName, 80);
  193.         //result=Escape(ppPrinter.hDC, STARTDOC,lstrlen((LPSTR)szQueueName) ,(LPSTR)szQueueName, NULL);
  194.         di.cbSize=sizeof(DOCINFO);
  195.         di.lpszDocName=szQueueName;
  196.         di.lpszOutput=NULL;
  197.         result=StartDoc(ppPrinter.hDC,&di);
  198.         result=StartPage(ppPrinter.hDC);
  199.         // Temp Defaults
  200.  
  201.         // Setup defaults
  202.  
  203.         // Set Margins to 1" all around
  204.         PrinterInfo.rcMargins.top =
  205.         PrinterInfo.rcMargins.bottom =
  206.         PrinterInfo.rcMargins.left =
  207.         PrinterInfo.rcMargins.right = (int)(INCH * (PrinterInfo.ptResolution.x * 0.01));
  208.  
  209.         // Start at upper left hand corner
  210.         PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left;
  211.         PageInfo.ptCurrentPos.y = PrinterInfo.rcMargins.top;
  212.  
  213.         // Default Tab Stops = 1/2"
  214.         PageInfo.nTabStop = (int)(HALF_INCH * (PrinterInfo.ptResolution.x * 0.01));
  215.  
  216.         // Default Paragraph Spacing
  217.         ParagraphInfo.nSpaceBefore        = (int)(QUARTER_INCH * (PrinterInfo.ptResolution.y * 0.01));
  218.         // No Indent By Default
  219.         ParagraphInfo.nLeftIndent    = 0;
  220.  
  221.         return TRUE;
  222.     }
  223.     else
  224.     {
  225.         DoCommDlgError(hWnd, CommDlgExtendedError());
  226.         return FALSE;
  227.     }
  228.  
  229. }
  230.  
  231. /*************************************************************************
  232.     Setup for the start of a paragraph, set text attributes
  233. *************************************************************************/
  234.  
  235. int    FAR PASCAL     StartParagraph(LPSTR szFontName, int nFontSize, int nStyle)
  236. {
  237.     int nFontWeight;        // Weight of the font
  238.     BYTE bFontItalic;        // Italic flag
  239.  
  240.     // Check for bogus font size values
  241.     nFontSize = min(nFontSize, MAX_FONT_SIZE);        // No bigger than
  242.     nFontSize = max(nFontSize, MIN_FONT_SIZE);        // No smaller than
  243.  
  244.     // Get weight of font
  245.     if(nStyle & BOLD_FONT)     nFontWeight = FW_BOLD;
  246.     else                     nFontWeight = FW_NORMAL;
  247.  
  248.     // Get font slant
  249.     if(nStyle & ITALIC_FONT)    bFontItalic = 1;
  250.     else                        bFontItalic = 0;
  251.  
  252.     // Remember Border Style and Size
  253.     ParagraphInfo.nStyle = nStyle;
  254.     ParagraphInfo.wBorderWidth =  (WORD)(((PrinterInfo.ptResolution.x * BORDER_WIDTH) / 72) << 8);
  255.     ParagraphInfo.wBorderWidth += (WORD)((PrinterInfo.ptResolution.y * BORDER_WIDTH) / 72);
  256.  
  257.     // Setup Text Attributes
  258.     SetBkMode(ppPrinter.hDC, TRANSPARENT);            // Show whatever was there before through the text
  259.     SetTextColor(ppPrinter.hDC, 0);                    // Black Text
  260.     SetBkColor(ppPrinter.hDC, 0x00FFFFFF);            // White Background
  261.     SetTextAlign(ppPrinter.hDC, TA_TOP|TA_LEFT);    // Text aligned at top, left of bounding box
  262.  
  263.     ParagraphInfo.hFont = CreateFont((int)((PrinterInfo.ptResolution.y * nFontSize) / 72),
  264.                                        0, 0, 0,
  265.                                        nFontWeight,
  266.                                        bFontItalic,
  267.                                        0, 0,
  268.                                        ANSI_CHARSET,
  269.                                        OUT_DEFAULT_PRECIS,
  270.                                        CLIP_DEFAULT_PRECIS,
  271.                                        DEFAULT_QUALITY,
  272.                                        VARIABLE_PITCH | FF_DONTCARE,
  273.                                        szFontName);
  274.     if(ParagraphInfo.hFont)    // If we get the font, selected and get the metrics and width
  275.     {
  276.         ParagraphInfo.hOldFont = SelectObject(ppPrinter.hDC, ParagraphInfo.hFont);
  277.         GetTextMetrics(ppPrinter.hDC, (LPTEXTMETRIC)&ParagraphInfo.tm);
  278.         GetCharWidth(ppPrinter.hDC, FIRST_CHAR, LAST_CHAR, (LPINT)&ParagraphInfo.nWidth);
  279.     }
  280.  
  281.  
  282.     // Set Current Line Width to Zero
  283.     PageInfo.dwCurLineWidth = 0;
  284.  
  285.     // See if first line will fit on page
  286.     if((PageInfo.ptCurrentPos.y += ParagraphInfo.nSpaceBefore) > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading))
  287.     {
  288.         EjectPage(); StartPage(ppPrinter.hDC);        // Sets current positon too
  289.     }
  290.  
  291.     // Get Indent/Check Box Info
  292.     if(nStyle & CHECK_BOX)
  293.     {
  294.         WORD wBorderWidth;
  295.  
  296.         wBorderWidth = ParagraphInfo.wBorderWidth;        // Save the current Border width
  297.         SetBorderWidth(0);
  298.  
  299.         // Set Indent Value
  300.         ParagraphInfo.nLeftIndent    = (int)(QUARTER_INCH * (PrinterInfo.ptResolution.x * 0.01));    // Default Paragraph Indent
  301.         // Draw Check Box
  302.         FDrawRectangle(    ppPrinter.hDC,
  303.                         PrinterInfo.rcMargins.left,
  304.                         PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmExternalLeading,
  305.                         PrinterInfo.rcMargins.left  + (int)(EIGHTH_INCH * (PrinterInfo.ptResolution.x * 0.01)),
  306.                         PageInfo.ptCurrentPos.y + (int)(EIGHTH_INCH * (PrinterInfo.ptResolution.y * 0.01)) + ParagraphInfo.tm.tmExternalLeading);
  307.  
  308.         ParagraphInfo.wBorderWidth = wBorderWidth;        // Restore Border width
  309.  
  310.     }
  311.     else
  312.     {
  313.         ParagraphInfo.nLeftIndent    = 0;
  314.     }
  315.  
  316.     if(ParagraphInfo.nStyle & TOP_BORDER)            // Top Border Line
  317.         FDrawLine(    ppPrinter.hDC,
  318.                     PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  319.                     PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  320.                     PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  321.                     PageInfo.ptCurrentPos.y - (int)(LOBYTE(ParagraphInfo.wBorderWidth)/2));
  322.  
  323.     // Width of column to print into
  324.     ParagraphInfo.dwWidth =     PrinterInfo.ptPageSize.x -
  325.                                 PrinterInfo.rcMargins.left -
  326.                                 PrinterInfo.rcMargins.right -
  327.                                 ParagraphInfo.nLeftIndent;
  328.  
  329.     // Start at left margin
  330.     PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent;
  331.  
  332.  
  333.     if(ParagraphInfo.hFont)    // If the font was generated, then we're cool
  334.         return TRUE;
  335.     else                    // Otherwise we're not
  336.         return FALSE;
  337. }
  338.  
  339.  
  340. /*************************************************************************
  341.     Print the actual paragraph taking in to consideration tab's
  342.     returns, etc...
  343. *************************************************************************/
  344.  
  345. int    FAR PASCAL    ParagraphText(LPSTR szText)
  346. {
  347.     char far *cpStart;                      // Pointer in string to print
  348.     char far *cpCurrent;
  349.     char far *cpEnd;
  350.     HGLOBAL    hText;
  351.     LPSTR    lpText;
  352.     
  353.     SIZE size;
  354.  
  355.     PageInfo.bPageDirty = TRUE;
  356.  
  357.     // Get our own private copy of the text
  358.     hText = GlobalAlloc(GHND, lstrlen((LPSTR)szText)+1);
  359.  
  360.     if(!hText) return FALSE;
  361.  
  362.     lpText = GlobalLock(hText);
  363.  
  364.     if(!lpText) return FALSE;
  365.  
  366.     lstrcpy((LPSTR)lpText, (LPSTR) szText);
  367.  
  368.     cpStart = cpCurrent = cpEnd = (LPSTR)lpText;    // All pointers to the start of the text string
  369.  
  370.     if(cpStart == NULL) return TRUE;        // If the string is NULL, thats alright, just don't do anything
  371.     
  372.     while(*cpCurrent != (int)NULL)
  373.     {        
  374.         switch(*cpCurrent)
  375.         {
  376.             GetTextExtentPoint32(ppPrinter.hDC, (LPSTR)cpStart, lstrlen((LPSTR)cpStart),&size);
  377. /* TAB */    case '\t'    :    cpEnd = cpCurrent;
  378.                             *cpEnd = 0;                            // Set end of string to null
  379.                             TextOutAtCurPos((LPSTR)cpStart);    // Print text up to tab
  380.                             PageInfo.ptCurrentPos.x += size.cx;
  381.                             PageInfo.ptCurrentPos.x = (PageInfo.nTabStop * ((PageInfo.ptCurrentPos.x / PageInfo.nTabStop)+1));
  382.                             PageInfo.dwCurLineWidth = PageInfo.ptCurrentPos.x - PrinterInfo.rcMargins.left;
  383.                             cpStart = cpCurrent = cpEnd+1;
  384.                             break;
  385.  
  386. /* CR */    case '\r'    :    cpEnd = cpCurrent;
  387.                             *cpEnd = 0;                            // Set end of string to null
  388.                             TextOutAtCurPos((LPSTR)cpStart);    // Print the text
  389.                             // Next Line Down
  390.                             PageInfo.ptCurrentPos.y += ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading;
  391.                             if(PageInfo.ptCurrentPos.y > PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading)
  392.                             {
  393.                                 EjectPage(); StartPage(ppPrinter.hDC);
  394.                             }
  395.                             // Start at left margin
  396.                             PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent;
  397.                             cpStart = cpCurrent = cpEnd+1;        // Set everything to start of next line
  398.                             if(*cpStart == '\n')                // Get rid of those dang line feeds
  399.                                 cpStart = cpEnd = ++cpCurrent;
  400.  
  401.                             // Clear Width
  402.                             PageInfo.dwCurLineWidth = 0;
  403.                             break;
  404.  
  405. /* NULL */    case 0    :    cpEnd = cpCurrent; goto showline;
  406.                             break;
  407.  
  408.             default        :    if(*cpCurrent < FIRST_CHAR) *cpCurrent = ' ';    // Set any control chars to space
  409.                             PageInfo.dwCurLineWidth += ParagraphInfo.nWidth[(int)(*cpCurrent) - FIRST_CHAR];        // Width of character
  410.                             if(*cpCurrent == ' ') cpEnd = cpCurrent;        // Space is always an excuse to break a line
  411.                             cpCurrent++;    // Goto next character
  412.                             break;
  413.         }
  414.         if( PageInfo.dwCurLineWidth > ParagraphInfo.dwWidth && (cpStart != cpEnd)) // Wrap Line
  415.         {
  416.             *cpEnd = 0;        // Set end of string to null
  417.  
  418.             TextOutAtCurPos((LPSTR)cpStart);
  419.  
  420.             // Next Line Down
  421.             PageInfo.ptCurrentPos.y += ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading;
  422.             if(PageInfo.ptCurrentPos.y > PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading)
  423.             {
  424.                 EjectPage(); StartPage(ppPrinter.hDC);
  425.             }
  426.             // Start at left margin
  427.             PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent;
  428.  
  429.             cpStart = cpCurrent = cpEnd+1;        // Set everything to start of next line
  430.             PageInfo.dwCurLineWidth = 0;        // Clear Width
  431.         }
  432.     }
  433. showline:
  434.     if(*cpStart)            // No Text, so don't print it
  435.     {
  436.  
  437.         TextOutAtCurPos((LPSTR) cpStart);
  438.  
  439.         PageInfo.ptCurrentPos.x += (int)PageInfo.dwCurLineWidth;    // Set current X position
  440.  
  441.     }
  442.     else                    // We still have to put the border around the current line
  443.     {
  444.         if(ParagraphInfo.nStyle & LEFT_BORDER)        // Left border
  445.             FDrawLine(    ppPrinter.hDC,
  446.                         PrinterInfo.rcMargins.left - (int)((HIBYTE(ParagraphInfo.wBorderWidth))),
  447.                         PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  448.                         PrinterInfo.rcMargins.left - (int)((HIBYTE(ParagraphInfo.wBorderWidth))),
  449.                         PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2));
  450.  
  451.         if(ParagraphInfo.nStyle & RIGHT_BORDER)        // Right border
  452.             FDrawLine(    ppPrinter.hDC,
  453.                         PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)((HIBYTE(ParagraphInfo.wBorderWidth))),
  454.                         PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  455.                         PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)((HIBYTE(ParagraphInfo.wBorderWidth))),
  456.                         PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2));
  457.  
  458.     }
  459.  
  460.     GlobalUnlock(hText);
  461.     GlobalFree(hText);
  462.  
  463.     return TRUE;
  464. }
  465.  
  466. /*************************************************************************
  467.     Clean up after printing a paragraph of text
  468. *************************************************************************/
  469.  
  470. int    FAR PASCAL    FinishParagraph(void)
  471. {
  472.  
  473.     SelectObject(ppPrinter.hDC, ParagraphInfo.hOldFont);
  474.     DeleteObject(ParagraphInfo.hFont);
  475.  
  476.     // Next Line Down
  477.     PageInfo.ptCurrentPos.y += ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading;
  478.  
  479.     // Bottom Border Line
  480.     if(ParagraphInfo.nStyle & BOTTOM_BORDER)
  481.         FDrawLine(    ppPrinter.hDC,
  482.                     PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  483.                     PageInfo.ptCurrentPos.y + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  484.                     PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  485.                     PageInfo.ptCurrentPos.y + (int)(LOBYTE(ParagraphInfo.wBorderWidth)/2));
  486.  
  487.     if((PageInfo.ptCurrentPos.y += ParagraphInfo.nSpaceAfter) > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom))
  488.     {
  489.         EjectPage(); StartPage(ppPrinter.hDC);        // Sets current positon too
  490.     }
  491.  
  492.     if(PageInfo.ptCurrentPos.y > PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading)
  493.     {
  494.         EjectPage(); StartPage(ppPrinter.hDC);
  495.     }
  496.     // Start at left margin
  497.     PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent;
  498.  
  499.     return TRUE;
  500. }
  501.  
  502. /*************************************************************************
  503.     Internal function to print a line of text at a specific position.
  504. *************************************************************************/
  505.  
  506. int TextOutAtCurPos(LPSTR szText)
  507. {
  508.     RECT    rc;
  509.     int        nRetVal;
  510.  
  511.     if(ParagraphInfo.nStyle & LEFT_BORDER)        // Left border
  512.         FDrawLine(    ppPrinter.hDC,
  513.                     PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  514.                     PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  515.                     PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  516.                     PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2));
  517.  
  518.     if(ParagraphInfo.nStyle & RIGHT_BORDER)        // Right border
  519.         FDrawLine(    ppPrinter.hDC,
  520.                     PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  521.                     PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2),
  522.                     PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)),
  523.                     PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2));
  524.  
  525.     SetRect((LPRECT)&rc,
  526.             (int)PageInfo.ptCurrentPos.x     -     PrinterInfo.rcUnprintable.left,
  527.             (int)PageInfo.ptCurrentPos.y     -     PrinterInfo.rcUnprintable.top,
  528.             (int)PrinterInfo.ptPageSize.x     -     PrinterInfo.rcMargins.right     -     PrinterInfo.rcUnprintable.left,
  529.             (int)PageInfo.ptCurrentPos.y     -     PrinterInfo.rcUnprintable.top     +    ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading);
  530.  
  531.     nRetVal = ExtTextOut(    ppPrinter.hDC,
  532.                             PageInfo.ptCurrentPos.x - PrinterInfo.rcUnprintable.left,
  533.                             PageInfo.ptCurrentPos.y - PrinterInfo.rcUnprintable.top,
  534.                             ETO_OPAQUE,
  535.                             (LPRECT)&rc,
  536.                             szText,
  537.                             lstrlen(szText),
  538.                             NULL);
  539.     return nRetVal;
  540. }
  541.  
  542. /*************************************************************************
  543.     Draw an Ellipse
  544. *************************************************************************/
  545. int FDrawEllipse(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY)
  546. {
  547.     int nRet=FALSE;
  548.     HPEN hPen, hOldPen;
  549.  
  550.     // Black Pen
  551.     hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0);
  552.  
  553.     if(hPen)
  554.     {
  555.         hOldPen = SelectObject(hDC, hPen);
  556.  
  557.         nRet = Ellipse(    hDC,
  558.                         nStartX - PrinterInfo.rcUnprintable.left,
  559.                         nStartY - PrinterInfo.rcUnprintable.top,
  560.                         nEndX - PrinterInfo.rcUnprintable.left,
  561.                         nEndY - PrinterInfo.rcUnprintable.top);
  562.  
  563.         SelectObject(hDC, hOldPen);
  564.         DeleteObject(hPen);
  565.     }
  566.  
  567.     return nRet;
  568. }
  569.  
  570.  
  571. /*************************************************************************
  572.     Draw a Rectangele with Rounded Corners
  573. *************************************************************************/
  574. int FDrawRndRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY, int nElpX, int nElpY)
  575. {
  576.     int nRet=FALSE;
  577.     HPEN hPen, hOldPen;
  578.  
  579.     // Black Pen
  580.     hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0);
  581.  
  582.     if(hPen)
  583.     {
  584.         hOldPen = SelectObject(hDC, hPen);
  585.  
  586.         nRet = RoundRect(    hDC,
  587.                             nStartX - PrinterInfo.rcUnprintable.left,
  588.                             nStartY - PrinterInfo.rcUnprintable.top,
  589.                             nEndX - PrinterInfo.rcUnprintable.left,
  590.                             nEndY - PrinterInfo.rcUnprintable.top,
  591.                             nElpX,
  592.                             nElpY);
  593.         SelectObject(hDC, hOldPen);
  594.         DeleteObject(hPen);
  595.     }
  596.  
  597.     return nRet;
  598. }
  599.  
  600. /*************************************************************************
  601.     Draw a Rectangle with Square Corners
  602. *************************************************************************/
  603. int FDrawRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY)
  604. {
  605.     int nRet=FALSE;
  606.     HPEN hPen, hOldPen;
  607.  
  608.     // Black Pen
  609.     hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0);
  610.  
  611.     if(hPen)
  612.     {
  613.         hOldPen = SelectObject(hDC, hPen);
  614.  
  615.         nRet = Rectangle(    hDC,
  616.                             nStartX - PrinterInfo.rcUnprintable.left,
  617.                             nStartY - PrinterInfo.rcUnprintable.top,
  618.                             nEndX - PrinterInfo.rcUnprintable.left,
  619.                             nEndY - PrinterInfo.rcUnprintable.top);
  620.         SelectObject(hDC, hOldPen);
  621.         DeleteObject(hPen);
  622.     }
  623.  
  624.     return nRet;
  625. }
  626.  
  627. /*************************************************************************
  628.     Draw a line
  629. *************************************************************************/
  630. int    FDrawLine(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY)
  631. {
  632.     int nRet=FALSE;
  633.     HPEN    hPen, hOldPen;
  634.     POINT pt;
  635.  
  636.     hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0);
  637.  
  638.     if(hPen)
  639.     {
  640.         hOldPen = SelectObject(hDC, hPen);
  641.  
  642.         MoveToEx(    hDC,
  643.                 nStartX - PrinterInfo.rcUnprintable.left,
  644.                 nStartY - PrinterInfo.rcUnprintable.top,&pt);
  645.         nRet = LineTo(    hDC,
  646.                         (int)nEndX - PrinterInfo.rcUnprintable.left,
  647.                         (int)nEndY - PrinterInfo.rcUnprintable.top);
  648.  
  649.         SelectObject(hDC, hOldPen);
  650.         DeleteObject(hPen);
  651.     }
  652.  
  653.     return nRet;
  654. }
  655.  
  656. /*************************************************************************
  657.     Print a Headline which is just a special case of a paragraph,
  658.     makes all setup and clean up calls for you.
  659. *************************************************************************/
  660. int    FAR PASCAL     PrintHeadline(LPSTR szHeadLine, LPSTR szFontName, int nFontSize, int nStyle)
  661. {
  662.  
  663.     StartParagraph(szFontName, nFontSize, nStyle);
  664.     ParagraphText(szHeadLine);
  665.     FinishParagraph();
  666.  
  667.     return TRUE;
  668. }
  669.  
  670. /*************************************************************************
  671.     End of printing function, cleans up memory and ejects the last page
  672. *************************************************************************/
  673.  
  674. int FAR PASCAL DonePrinting(void)
  675. {
  676.     int nRet=FALSE;
  677.  
  678.     //result=Escape(ppPrinter.hDC,NEWFRAME, 0, 0L, 0L);            // Kick out last page
  679.     //result=Escape(ppPrinter.hDC,ENDDOC, 0, 0L, 0L);
  680.     result=EndPage(ppPrinter.hDC);
  681.     result=EndDoc(ppPrinter.hDC);
  682.     FreeProcInstance(lpfnAbortProc);
  683.  
  684.     nRet = DeleteDC(ppPrinter.hDC);
  685.        if (ppPrinter.hDevMode != NULL)
  686.        {
  687.         GlobalFree(ppPrinter.hDevMode);
  688.         ppPrinter.hDevMode = NULL;
  689.        }
  690.        if (ppPrinter.hDevNames != NULL)
  691.        {
  692.         GlobalFree(ppPrinter.hDevNames);
  693.         ppPrinter.hDevNames = NULL;
  694.        }
  695.  
  696.     return nRet;
  697.  
  698. }
  699.  
  700. /*************************************************************************
  701.     Unconditionally ejects page from printer, then sets the current page
  702.     position to upper left corner, this also restores the currently
  703.     selected font.
  704. *************************************************************************/
  705.  
  706. int    FAR PASCAL    EjectPage(void)
  707. {
  708.     int nRet;
  709.     HFONT hFont;
  710.  
  711.     // Save Currently selected Font
  712.     hFont = SelectObject(ppPrinter.hDC, GetStockObject(DEVICE_DEFAULT_FONT));
  713.  
  714.     //nRet = Escape(ppPrinter.hDC,NEWFRAME, 0, 0L, 0L);            // Kick out page
  715.     nRet=EndPage(ppPrinter.hDC);
  716.     // Restore Currently select Font
  717.     SelectObject(ppPrinter.hDC, hFont);
  718.  
  719.     PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left;        // Start at upper left hand corner
  720.     PageInfo.ptCurrentPos.y = PrinterInfo.rcMargins.top;
  721.  
  722.     PageInfo.bPageDirty = FALSE;                                // Page is no longer dirty
  723.  
  724.     return nRet;
  725.  
  726. }
  727.  
  728. /*************************************************************************
  729.     Sets margins for pages printed after this function is called.
  730. *************************************************************************/
  731.  
  732. int FAR PASCAL PageLayoutSetup(int nTop, int nRight, int nBottom, int nLeft)
  733. {
  734.  
  735.     nTop = min(nTop, 2 * INCH);            // No bigger than
  736.     nTop = max(nTop, 0);                // No smaller than
  737.  
  738.     nBottom = min(nBottom, 2 * INCH);     // No bigger than
  739.     nBottom = max(nBottom, 0);            // No smaller than
  740.  
  741.     nLeft = min(nLeft, 2 * INCH);        // No bigger than
  742.     nLeft = max(nLeft, 0);                // No smaller than
  743.  
  744.     nRight = min(nRight, 2 * INCH);     // No bigger than
  745.     nRight = max(nRight, 0);            // No smaller than
  746.  
  747.     PrinterInfo.rcMargins.top        = (int)(nTop    * (int)(PrinterInfo.ptResolution.y * 0.01));
  748.     PrinterInfo.rcMargins.bottom    = (int)(nBottom * (int)(PrinterInfo.ptResolution.y * 0.01));
  749.     PrinterInfo.rcMargins.left        = (int)(nLeft    * (int)(PrinterInfo.ptResolution.x * 0.01));
  750.     PrinterInfo.rcMargins.right     = (int)(nRight    * (int)(PrinterInfo.ptResolution.x * 0.01));
  751.  
  752.     PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left;        // Start at upper left hand corner
  753.     PageInfo.ptCurrentPos.y = PrinterInfo.rcMargins.top;
  754.  
  755.     return TRUE;
  756. }
  757.  
  758.  
  759. /*************************************************************************
  760.     This procedure brings up a message box with Common Dialog error text
  761. *************************************************************************/
  762.  
  763. BOOL DoCommDlgError(HWND hWnd, DWORD dwError)
  764. {
  765.     char sz1[80];
  766.     char sz2[32];
  767.  
  768.     if(dwError != 0)
  769.     {
  770.         LoadString(hInst, (WORD)dwError, sz2, 32);
  771.  
  772.         if(!sz2[0])
  773.             lstrcpy(sz2,"Unknown");
  774.  
  775.         wsprintf(sz1," Error: %s ",(LPSTR)sz2);
  776.  
  777.         MessageBox(hWnd,sz1," COMMDLG.DLL ERROR ",MB_ICONSTOP);
  778.         return TRUE;
  779.     }
  780.     else
  781.         return FALSE;
  782.  
  783. }
  784.  
  785. /*************************************************************************
  786.     Fills the PrinterInfo structure with the printers current
  787.     unprintable region
  788. *************************************************************************/
  789.  
  790. BOOL GetUnprintableRegion(HDC hDCPrn)
  791. {
  792.     RECT     rcTemp;
  793.     POINT     ptPhysPageSize;
  794.     POINT     ptOffset;
  795.  
  796.     Escape(hDCPrn, GETPHYSPAGESIZE, (int)NULL, (LPSTR)NULL, (LPSTR) &ptPhysPageSize);
  797.     Escape(hDCPrn, GETPRINTINGOFFSET, (int)NULL, (LPSTR)NULL, (LPSTR) &ptOffset);
  798.     GetClipBox(hDCPrn,&rcTemp);        // Size of Printable region
  799.  
  800.     PrinterInfo.ptPageSize.x            = ptPhysPageSize.x;
  801.     PrinterInfo.ptPageSize.y            = ptPhysPageSize.y;
  802.     PrinterInfo.rcUnprintable.top         = ptOffset.y;
  803.     PrinterInfo.rcUnprintable.left        = ptOffset.x;
  804.     PrinterInfo.rcUnprintable.right        = ptPhysPageSize.x - ptOffset.x;
  805.     PrinterInfo.rcUnprintable.bottom    = ptPhysPageSize.y - ptOffset.y;
  806.  
  807.     return TRUE;
  808.  
  809. }
  810.  
  811. /*************************************************************************
  812.     Sticks the printers current resolution in the PrinterInfo Structure
  813. *************************************************************************/
  814.  
  815. BOOL GetPrinterResolution(HDC hDCPrn)
  816. {
  817.     PrinterInfo.ptResolution.x = GetDeviceCaps(hDCPrn, LOGPIXELSX);
  818.     PrinterInfo.ptResolution.y = GetDeviceCaps(hDCPrn, LOGPIXELSY);
  819.  
  820.     return TRUE;
  821. }
  822.  
  823. /*************************************************************************
  824.     Abort Proc for printing, this is where control is returned to the
  825.     system during printing.  Gets called by the printer driver
  826.     periocically for control release purposes.
  827. *************************************************************************/
  828.  
  829. BOOL FAR PASCAL PrnAbortProc(HDC hDCPrn, short nCode)
  830. {
  831.     MSG msg;
  832.  
  833.     while(!fAbort && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  834.     {
  835.         {
  836.             TranslateMessage(&msg);
  837.             DispatchMessage(&msg);
  838.         }
  839.     }
  840.  
  841.     return !fAbort;
  842. }
  843.  
  844. /*************************************************************************
  845.     Returns version number of the Print DLL
  846. *************************************************************************/
  847.  
  848. int FAR PASCAL PrintDLLVersion(VOID)
  849. {
  850.     return ((MAJOR_VERSION) | (MINOR_VERSION << 8));
  851.  
  852. }
  853.  
  854.  
  855. /*************************************************************************
  856.     Sets the space before and after a paragraph
  857. *************************************************************************/
  858. BOOL    FAR PASCAL SetParagraphSpacing(int nSpaceBefore, int nSpaceAfter)
  859. {
  860.  
  861.     // Check for bogus Spacing size values
  862.     nSpaceBefore = min(nSpaceBefore, MAX_FONT_SIZE);    // No bigger than
  863.     nSpaceBefore = max(nSpaceBefore, MIN_FONT_SIZE);    // No smaller than
  864.  
  865.     ParagraphInfo.nSpaceBefore = (int)((PrinterInfo.ptResolution.y * nSpaceBefore) / 72);
  866.  
  867.     // Check for bogus Spacing size values
  868.     nSpaceAfter = min(nSpaceAfter, MAX_FONT_SIZE);        // No bigger than
  869.     nSpaceAfter = max(nSpaceAfter, MIN_FONT_SIZE);        // No smaller than
  870.  
  871.     ParagraphInfo.nSpaceAfter = (int)((PrinterInfo.ptResolution.y * nSpaceAfter) / 72);
  872.  
  873.     return TRUE;
  874. }
  875.  
  876.  
  877. /*************************************************************************
  878.     Sets Line Weight for borders
  879. *************************************************************************/
  880. BOOL    FAR PASCAL SetBorderWidth(int nWidth)
  881. {
  882.     if(nWidth !=0)
  883.     {
  884.         // Check for bogus Width values
  885.         nWidth = min(nWidth, MAX_WIDTH_SIZE);        // No bigger than
  886.         nWidth = max(nWidth, MIN_WIDTH_SIZE);        // No smaller than
  887.  
  888.         ParagraphInfo.wBorderWidth =  (WORD)(((PrinterInfo.ptResolution.x * nWidth) / 72) << 8);
  889.         ParagraphInfo.wBorderWidth += (WORD)((PrinterInfo.ptResolution.y * nWidth) / 72);
  890.     }
  891.     else    // Gaurentee 1 pixel width
  892.     {
  893.         ParagraphInfo.wBorderWidth =  (WORD)((1) << 8);
  894.         ParagraphInfo.wBorderWidth += (WORD)(1);
  895.  
  896.     }
  897.     return TRUE;
  898. }
  899.  
  900. /*************************************************************************
  901.     Prints headers for a set of columns
  902. *************************************************************************/
  903. int        FAR PASCAL PrintColumnHeaders(LPSTR szHeader, int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle)
  904. {
  905.     SetUpColumns(nNumColumns, nC, szFontName, nFontSize, nStyle);
  906.     PrintColumnText(szHeader);
  907.     EndColumnPrinting();
  908.  
  909.     return TRUE;
  910.  
  911. }
  912. /*************************************************************************
  913.     Sets up the number and widths of columns to be printed
  914. *************************************************************************/
  915. int        FAR PASCAL SetUpColumns(int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle)
  916. {
  917.     int nFontWeight;        // Weight of the font
  918.     BYTE bFontItalic;        // Italic flag
  919.  
  920.     // Remember these
  921.     ColumnInfo.nNumColumns = nNumColumns;
  922.     ColumnInfo.rgColumnWidths[0] = nC[0];
  923.     ColumnInfo.rgColumnWidths[1] = nC[1];
  924.     ColumnInfo.rgColumnWidths[2] = nC[2];
  925.     ColumnInfo.rgColumnWidths[3] = nC[3];
  926.     ColumnInfo.rgColumnWidths[4] = nC[4];
  927.     ColumnInfo.rgColumnWidths[5] = nC[5];
  928.     ColumnInfo.rgColumnWidths[6] = nC[6];
  929.     ColumnInfo.rgColumnWidths[7] = nC[7];
  930.  
  931.     // Check for bogus font size values
  932.     nFontSize = min(nFontSize, MAX_FONT_SIZE);        // No bigger than
  933.     nFontSize = max(nFontSize, MIN_FONT_SIZE);        // No smaller than
  934.  
  935.     // Get weight of font
  936.     if(nStyle & BOLD_FONT)     nFontWeight = FW_BOLD;
  937.     else                     nFontWeight = FW_NORMAL;
  938.  
  939.     // Get font slant
  940.     if(nStyle & ITALIC_FONT)    bFontItalic = 1;
  941.     else                        bFontItalic = 0;
  942.  
  943.     // Remember Border Style and Size
  944.     ColumnInfo.nStyle = nStyle;
  945.     ColumnInfo.wBorderWidth =  (WORD)(((PrinterInfo.ptResolution.x * BORDER_WIDTH) / 72) << 8);
  946.     ColumnInfo.wBorderWidth += (WORD)((PrinterInfo.ptResolution.y * BORDER_WIDTH) / 72);
  947.  
  948.     // Setup Text Attributes
  949.     SetBkMode(ppPrinter.hDC, TRANSPARENT);            // Show whatever was there before through the text
  950.     SetTextColor(ppPrinter.hDC, 0);                    // Black Text
  951.     SetBkColor(ppPrinter.hDC, 0x00FFFFFF);            // White Background
  952.     SetTextAlign(ppPrinter.hDC, TA_TOP|TA_LEFT);    // Text aligned at top, left of bounding box
  953.  
  954.     ColumnInfo.hFont = CreateFont((int)((PrinterInfo.ptResolution.y * nFontSize) / 72),
  955.                                        0, 0, 0,
  956.                                        nFontWeight,
  957.                                        bFontItalic,
  958.                                        0, 0,
  959.                                        ANSI_CHARSET,
  960.                                        OUT_DEFAULT_PRECIS,
  961.                                        CLIP_DEFAULT_PRECIS,
  962.                                        DEFAULT_QUALITY,
  963.                                        VARIABLE_PITCH | FF_DONTCARE,
  964.                                        szFontName);
  965.     if(ColumnInfo.hFont)    // If we get the font, selected and get the metrics and width
  966.     {
  967.         ColumnInfo.hOldFont = SelectObject(ppPrinter.hDC, ColumnInfo.hFont);
  968.         GetTextMetrics(ppPrinter.hDC, (LPTEXTMETRIC)&ColumnInfo.tm);
  969.         GetCharWidth(ppPrinter.hDC, FIRST_CHAR, LAST_CHAR, (LPINT)&ColumnInfo.nWidth);
  970.     }
  971.  
  972.     return TRUE;
  973. }
  974.  
  975. /*************************************************************************
  976.     Printed text in columns, the text is seperated by
  977.     tab (0x09) characters
  978. *************************************************************************/
  979. int        FAR PASCAL PrintColumnText(LPSTR szText)
  980. {
  981.     int     nColumnCount;
  982.     int     nMaxRowHeight;
  983.     int        nLineCount;
  984.     int        nSpaceCount;
  985.     int     nOffset;
  986.     RECT    rc;
  987.     char FAR    *cpColText;
  988.     char FAR    *cpBegin;
  989.     char FAR    *cpCurrent;
  990.     char FAR    *rgcpColText[MAX_COLUMNS];
  991.     int        nColCount;
  992.     DWORD    dwWidth, dwColumnWidth;
  993.     HGLOBAL    hText;
  994.     LPSTR    lpText;
  995.  
  996.     PageInfo.bPageDirty = TRUE;
  997.  
  998.     // Get our own private copy of the text
  999.     hText = GlobalAlloc(GHND, lstrlen((LPSTR)szText)+1);
  1000.  
  1001.     if(!hText) return FALSE;
  1002.  
  1003.     lpText = (LPSTR)GlobalLock(hText);
  1004.  
  1005.     if(!lpText) return FALSE;
  1006.  
  1007.     lstrcpy((LPSTR)lpText, (LPSTR)szText);
  1008.  
  1009.     // Calculate where all the strings are
  1010.     cpColText = (LPSTR)lpText;
  1011.     nColCount = 0;
  1012.     rgcpColText[nColCount++] = (LPSTR)cpColText;        // First Column;
  1013.  
  1014.     // Setup pointers to each column of text
  1015.     while(*cpColText != (int)NULL)
  1016.     {
  1017.         if(*cpColText == '\t')
  1018.         {
  1019.             *cpColText =(char) NULL;                    // NULL Terminate
  1020.             cpColText++;
  1021.             rgcpColText[nColCount++] = (LPSTR)cpColText;
  1022.         }
  1023.         else
  1024.         {
  1025.             cpColText++;
  1026.         }
  1027.  
  1028.     }
  1029.  
  1030.     // Calculate the Max Height of the cells
  1031.     nMaxRowHeight = 1;
  1032.  
  1033.     for(nColumnCount = 0; nColumnCount < ColumnInfo.nNumColumns; nColumnCount++)
  1034.     {
  1035.         cpBegin = cpCurrent = rgcpColText[nColumnCount];
  1036.         dwColumnWidth = (DWORD)(ColumnInfo.rgColumnWidths[nColumnCount] * (PrinterInfo.ptResolution.x * 0.01));
  1037.         dwWidth = 0;
  1038.         nSpaceCount = -1;
  1039.         nLineCount = 1;
  1040.  
  1041.         while(*cpCurrent !=(int) NULL)
  1042.         {
  1043.  
  1044.             dwWidth += ColumnInfo.nWidth[(int)(*cpCurrent) - FIRST_CHAR];        // Width of Character
  1045.             switch(*cpCurrent)
  1046.             {
  1047.                 case ' ' :  if(dwWidth > dwColumnWidth)
  1048.                             {
  1049.                                  nLineCount++;
  1050.                                  if(nSpaceCount >= 0)
  1051.                                  {
  1052.                                      cpCurrent = cpBegin;
  1053.                                      nSpaceCount = -1;
  1054.                                  }
  1055.                                  else
  1056.                                      cpCurrent++;
  1057.                                  dwWidth = 0;
  1058.  
  1059.                             }
  1060.                             else
  1061.                             {
  1062.                                 nSpaceCount++;
  1063.                                 cpBegin = ++cpCurrent;
  1064.                             }
  1065.                             break;
  1066.                 case '\r':    cpBegin = ++cpCurrent;
  1067.                             nLineCount++;
  1068.                             break;
  1069.                 default     :  cpCurrent++;
  1070.                             break;
  1071.  
  1072.             }
  1073.  
  1074.  
  1075.         }
  1076.         if(dwWidth > dwColumnWidth) nLineCount++;        // In case of any left overs
  1077.  
  1078.         nMaxRowHeight = max(nMaxRowHeight, nLineCount);
  1079.     }
  1080.  
  1081.     nMaxRowHeight *= ColumnInfo.tm.tmHeight;
  1082.  
  1083.     // See if first line will fit on page
  1084.     if((PageInfo.ptCurrentPos.y + nMaxRowHeight) > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.top - PrinterInfo.rcMargins.bottom))
  1085.     {
  1086.         EjectPage(); StartPage(ppPrinter.hDC);        // Sets current positon too
  1087.         
  1088.     }
  1089.  
  1090.     SetBorderWidth(0);
  1091.  
  1092.  
  1093.     for(nColumnCount = 0; nColumnCount < ColumnInfo.nNumColumns; nColumnCount++)
  1094.     {
  1095.         nOffset = GetColumnOffset(nColumnCount);
  1096.  
  1097.         SetRect(    &rc,
  1098.                     PrinterInfo.rcMargins.left + nOffset,
  1099.                     PageInfo.ptCurrentPos.y,
  1100.                     PrinterInfo.rcMargins.left + nOffset + (int)(ColumnInfo.rgColumnWidths[nColumnCount] * (PrinterInfo.ptResolution.x * 0.01)),
  1101.                     PageInfo.ptCurrentPos.y + nMaxRowHeight);
  1102.  
  1103.         if(ColumnInfo.nStyle & TOP_BORDER)
  1104.         {
  1105.             // Draw Top Border
  1106.             FDrawLine(ppPrinter.hDC, rc.left, rc.top, rc.right, rc.top);
  1107.         }
  1108.  
  1109.         if(ColumnInfo.nStyle & LEFT_BORDER)
  1110.         {
  1111.             // Draw Left Border
  1112.             FDrawLine(ppPrinter.hDC, rc.left, rc.top, rc.left, rc.bottom);
  1113.         }
  1114.  
  1115.         if(ColumnInfo.nStyle & RIGHT_BORDER)
  1116.         {
  1117.             // Draw Right Border
  1118.             FDrawLine(ppPrinter.hDC, rc.right, rc.top, rc.right, rc.bottom);
  1119.         }
  1120.  
  1121.         if(ColumnInfo.nStyle & BOTTOM_BORDER)
  1122.         {
  1123.             // Draw Bottom Border
  1124.             FDrawLine(ppPrinter.hDC, rc.left, rc.bottom, rc.right, rc.bottom);
  1125.         }
  1126.  
  1127.         rc.left     += 1;        // Get Text Within Borders
  1128.         rc.top      += 1;
  1129.         rc.right     -= 1;
  1130.         rc.bottom     -= 1;
  1131.  
  1132.         CellDrawText(ppPrinter.hDC, (LPSTR)rgcpColText[nColumnCount], (LPRECT)&rc);
  1133.  
  1134.     }
  1135.  
  1136.     PageInfo.ptCurrentPos.y += nMaxRowHeight;
  1137.  
  1138.     GlobalUnlock(hText);
  1139.     GlobalFree(hText);
  1140.  
  1141.     return TRUE;
  1142. }
  1143.  
  1144.  
  1145. /*************************************************************************
  1146.     Ends column printing and does cleanup
  1147. *************************************************************************/
  1148. int        FAR PASCAL EndColumnPrinting(VOID)
  1149. {
  1150.     SelectObject(ppPrinter.hDC, ColumnInfo.hOldFont);
  1151.     DeleteObject(ColumnInfo.hFont);
  1152.  
  1153.     return TRUE;
  1154. }
  1155.  
  1156. /*************************************************************************
  1157.     Calculates the Left Offset of the given column from the left
  1158.     edge of the first column
  1159. *************************************************************************/
  1160. int    GetColumnOffset(int nColumn)
  1161. {
  1162.      int nOffset=0;
  1163.      int nTemp;
  1164.  
  1165.      if(nColumn == 0) return nOffset;
  1166.  
  1167.     for(nTemp=0; nTemp < nColumn; nTemp++)
  1168.     {
  1169.         nOffset += (int)(ColumnInfo.rgColumnWidths[nTemp] * (PrinterInfo.ptResolution.x * 0.01));
  1170.     }
  1171.  
  1172.     return nOffset;
  1173. }
  1174.  
  1175. /*************************************************************************
  1176.     Prints Text on Physical page given logical co-ordinates
  1177. *************************************************************************/
  1178. int CellDrawText(HDC hDC, LPSTR szText, LPRECT rc)
  1179. {
  1180.     RECT rcTemp;
  1181.  
  1182.     rcTemp.top         = rc->top         - PrinterInfo.rcUnprintable.top;
  1183.     rcTemp.bottom     = rc->bottom     - PrinterInfo.rcUnprintable.top;
  1184.     rcTemp.left     = rc->left         - PrinterInfo.rcUnprintable.left;
  1185.     rcTemp.right     = rc->right     - PrinterInfo.rcUnprintable.left;
  1186.  
  1187.     DrawText(hDC, (LPSTR)szText, lstrlen((LPSTR)szText), (LPRECT)&rcTemp, DT_TOP | DT_WORDBREAK);
  1188.  
  1189.     return TRUE;
  1190. }
  1191.  
  1192. /*************************************************************************
  1193.     Internal function to retrieve the Device Context of the current
  1194.     Printer Driver
  1195. *************************************************************************/
  1196.  
  1197. HDC        GetPrinterDC(void)
  1198. {
  1199.     static char szPrinter[80];
  1200.     char *szDevice, *szDriver, *szOutput;
  1201.  
  1202.     GetProfileString("windows", "device",",,,",szPrinter, 80);
  1203.  
  1204.     if(    (szDevice = strtok(szPrinter,"," )) &&
  1205.         (szDriver = strtok(NULL,     ", ")) &&
  1206.         (szOutput = strtok(NULL,     ", ")))
  1207.     {
  1208.         return CreateDC(szDriver, szDevice, szOutput, NULL);
  1209.     }
  1210.  
  1211.     return FALSE;
  1212. }
  1213.  
  1214. /*************************************************************************
  1215.     Unconditionally kills the current print job
  1216. *************************************************************************/
  1217. BOOL FAR PASCAL KillJob(void)
  1218. {
  1219.  
  1220.     fAbort = TRUE;
  1221.  
  1222.     return fAbort;
  1223.  
  1224. }
  1225.  
  1226. /*************************************************************************
  1227.      Returns the name of the current Printer
  1228. *************************************************************************/
  1229. BOOL FAR PASCAL PrinterName(LPSTR szDevName)
  1230. {
  1231.     DEVMODE FAR *lpDevmode;
  1232.  
  1233.     /* Initialize the necessary PRINTDLG structure members. */
  1234.  
  1235.     ppPrinter.lStructSize = sizeof(PRINTDLG);
  1236.     ppPrinter.Flags = PD_RETURNDEFAULT;
  1237.  
  1238.     if(ppPrinter.hDevMode)
  1239.     {
  1240.         lpDevmode = (DEVMODE FAR *)GlobalLock(ppPrinter.hDevMode);
  1241.         lstrcpy(szDevName,(LPSTR)lpDevmode->dmDeviceName);
  1242.         GlobalUnlock(ppPrinter.hDevMode);
  1243.         return TRUE;
  1244.     }
  1245.     if (PrintDlg(&ppPrinter) != 0)
  1246.     {
  1247.         lpDevmode = (DEVMODE FAR *)GlobalLock(ppPrinter.hDevMode);
  1248.         lstrcpy(szDevName,(LPSTR)lpDevmode->dmDeviceName);
  1249.         GlobalUnlock(ppPrinter.hDevMode);
  1250.         return TRUE;
  1251.     }
  1252.     else
  1253.     {
  1254.         DoCommDlgError(hWndApp, CommDlgExtendedError());
  1255.         return FALSE;
  1256.     }
  1257. }
  1258.  
  1259. /*************************************************************************
  1260.     Returns the port to which the current printer is connected
  1261. *************************************************************************/
  1262. BOOL FAR PASCAL PrinterPort(LPSTR szPortName)
  1263. {
  1264.     DEVNAMES FAR *lpDevnames;
  1265.  
  1266.     // Initialize the necessary PRINTDLG structure members.
  1267.  
  1268.     ppPrinter.lStructSize = sizeof(PRINTDLG);
  1269.     ppPrinter.Flags = PD_RETURNDEFAULT;
  1270.  
  1271.     if(ppPrinter.hDevNames)
  1272.     {
  1273.         lpDevnames = (DEVNAMES FAR *)GlobalLock(ppPrinter.hDevNames);
  1274.         lstrcpy(szPortName,(LPSTR)lpDevnames + lpDevnames->wOutputOffset);
  1275.         GlobalUnlock(ppPrinter.hDevNames);
  1276.         return TRUE;
  1277.     }
  1278.     if (PrintDlg(&ppPrinter) != 0)
  1279.     {
  1280.         lpDevnames = (DEVNAMES FAR *)GlobalLock(ppPrinter.hDevNames);
  1281.         lstrcpy(szPortName,(LPSTR)lpDevnames + lpDevnames->wOutputOffset);
  1282.         GlobalUnlock(ppPrinter.hDevNames);
  1283.         return TRUE;
  1284.     }
  1285.     else
  1286.     {
  1287.         DoCommDlgError(hWndApp, CommDlgExtendedError());
  1288.         return FALSE;
  1289.     }
  1290. }
  1291.  
  1292. /*************************************************************************
  1293. Returns TRUE if there are objects on the page, FALSE if the page is
  1294. empty.
  1295. *************************************************************************/
  1296. BOOL FAR PASCAL IsPageDirty(void)
  1297. {
  1298.     return PageInfo.bPageDirty;
  1299.  
  1300. }
  1301.  
  1302. /*************************************************************************
  1303. Returns the current Vertical cursor location in TWIPS
  1304. *************************************************************************/
  1305. int FAR PASCAL PagePosY(void)
  1306. {
  1307.  
  1308.     return ((PageInfo.ptCurrentPos.y/PrinterInfo.ptResolution.y)*72*20);
  1309.  
  1310. }
  1311.  
  1312. /*************************************************************************
  1313. Returns the current Horizontal cursor location in TWIPS
  1314. *************************************************************************/
  1315. int FAR PASCAL PagePosX(void)
  1316. {
  1317.  
  1318.     return ((PageInfo.ptCurrentPos.x/PrinterInfo.ptResolution.x)*72*20);
  1319.  
  1320. }
  1321.  
  1322. /*************************************************************************
  1323. Returns the vertical page size is TWIPS
  1324. *************************************************************************/
  1325. int FAR PASCAL PageSizeY(void)
  1326. {
  1327.     return ((PrinterInfo.ptPageSize.y/PrinterInfo.ptResolution.y)*72*20);
  1328.  
  1329. }
  1330.  
  1331. /*************************************************************************
  1332. Returns the horizontal page size in TWIPS
  1333. *************************************************************************/
  1334. int FAR PASCAL PageSizeX(void)
  1335. {
  1336.     return ((PrinterInfo.ptPageSize.x/PrinterInfo.ptResolution.x)*72*20);
  1337.  
  1338. }
  1339.  
  1340. /*************************************************************************
  1341.     Exported Draw Line Function, takes it parameters in TWIPS
  1342. *************************************************************************/
  1343. BOOL    FAR PASCAL    DrawLine(int nX1, int nY1, int nX2, int nY2)
  1344. {
  1345.     nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20));
  1346.     nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20));
  1347.     nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20));
  1348.     nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20));
  1349.  
  1350.     return FDrawLine(ppPrinter.hDC, nX1, nY1, nX2, nY2);
  1351. }
  1352.  
  1353. /*************************************************************************
  1354.     Exported Draw Rectangle Function, takes it parameters in TWIPS
  1355. *************************************************************************/
  1356. BOOL    FAR PASCAL    DrawRectangle(int nX1, int nY1, int nX2, int nY2)
  1357. {
  1358.  
  1359.     nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20));
  1360.     nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20));
  1361.     nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20));
  1362.     nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20));
  1363.  
  1364.     return FDrawRectangle(ppPrinter.hDC, nX1, nY1, nX2, nY2);
  1365. }
  1366.  
  1367. /*************************************************************************
  1368.     Exported Draw Rounded Rectangle Function, takes it
  1369.     parameters in TWIPS
  1370. *************************************************************************/
  1371. BOOL    FAR    PASCAL    DrawRndRectangle(int nX1, int nY1, int nX2, int nY2, int nX3, int nY3)
  1372. {
  1373.  
  1374.     nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20));
  1375.     nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20));
  1376.     nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20));
  1377.     nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20));
  1378.     nX3 = MulDiv(nX3, PrinterInfo.ptResolution.x, (72 * 20));
  1379.     nY3 = MulDiv(nY3, PrinterInfo.ptResolution.y, (72 * 20));
  1380.  
  1381.     return FDrawRndRectangle(ppPrinter.hDC, nX1, nY1, nX2, nY2, nX3, nY3);
  1382. }
  1383.  
  1384. /*************************************************************************
  1385.     Exported Draw Ellipse Function, takes it parameters in TWIPS
  1386. *************************************************************************/
  1387. BOOL    FAR PASCAL    DrawEllipse(int nX1, int nY1, int nX2, int nY2)
  1388. {
  1389.     nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20));
  1390.     nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20));
  1391.     nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20));
  1392.     nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20));
  1393.  
  1394.     return FDrawEllipse(    ppPrinter.hDC, nX1, nY1, nX2, nY2);
  1395.  
  1396. }
  1397.  
  1398.  
  1399.  
  1400. /*************************************************************************
  1401.     Unconditionally moves the current cursor position
  1402.     in the Y direction, takes its parameters in 100th's
  1403.     of an inch.
  1404. *************************************************************************/
  1405. BOOL FAR PASCAL    MoveYPos(int nY)
  1406. {
  1407.     PageInfo.ptCurrentPos.y += (int)((nY * PrinterInfo.ptResolution.y)/100);
  1408.     if(PageInfo.ptCurrentPos.y > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.top - PrinterInfo.rcMargins.bottom))
  1409.     {
  1410.         EjectPage(); StartPage(ppPrinter.hDC);        // Sets current positon too
  1411.     }
  1412.     return TRUE;
  1413.  
  1414. }
  1415.  
  1416. /*************************************************************************
  1417.     End of VBPRINT.DLL
  1418. *************************************************************************/
  1419.