Printing a text buffer

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

A lot of people have been asking questions about printing a simple straight multi-page text buffer to a user-selected printer, without using the docView framework. You could use the classes created by Richard Stringer, but quite often, this is a big overkill for what you want to do. A few suggestions have been made and Chris Maunder provided some samples on how to start with it. But no one gave a real world example. So I puzzled around abit, and finally came up with the code below.

It is far from perfect, and some additional function parameters would be cool. I will make a more advanced version when I find the time.

There is one major drawback to the method below : to find page breaks, it will start at the beginning of the buffer, and calculate the height needed for 1 character, 2 characters, 3 characters, ... and so on. When the height grows beyond the page size, a new page must be started with the previous character that didn't overflow yet. This method will have to call DrawText() for each character. A big calculation peak will be induced ! It would be a lot better to use entire words instead of characters. I intend to make such a version in the next few weeks.

Even better would be to use some statistics scheme and 'guess' where the page break will occur. Then jump back or forward with consecutively smaller blocks until you find the exact pagebreak location. (somewhat like the quicksort sorting algorithm) that's a problem for later. The routine works as it does now, and I hope someone can use it.


// p points to the start of the buffer, pSize holds the number of characters
void PrintString(char *p, DWORD pSize)
{
    CDC             dc;
    CPrintDialog    printDlg(FALSE);
    CRect           r;
    int             nHeight;
    
    // ask the user to select a printer
    if (printDlg.DoModal() == IDCANCEL)
        return;
    
    // Attach a printer DC
    dc.Attach(printDlg.GetPrinterDC());
    dc.m_bPrinting = TRUE;

    // use Textmappingmode, that's easiest to map the fontsize
    dc.SetMapMode(MM_TEXT);
    
    // setup font specifics
    LOGFONT LogFont;
    
    CFont	aFont, *oldFont;
    
    LogFont.lfHeight = -MulDiv(10, GetDeviceCaps(dc, LOGPIXELSY), 72);
    LogFont.lfWidth = 0;
    LogFont.lfEscapement = 0;
    LogFont.lfOrientation = 0;
    LogFont.lfWeight = 0;
    LogFont.lfItalic = false;
    LogFont.lfUnderline = 0;
    LogFont.lfStrikeOut = 0;
    LogFont.lfCharSet = ANSI_CHARSET;
    LogFont.lfOutPrecision = OUT_TT_PRECIS;
    LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    LogFont.lfQuality = DEFAULT_QUALITY;
    LogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
    lstrcpy (LogFont.lfFaceName, "MS Sans Serif");
    dc.SetBkMode(OPAQUE);
    aFont.CreateFontIndirect ( &LogFont );
    // ok, we've build the font, now use it
    oldFont = dc.SelectObject( &aFont );        
        
    // Get the application title
    CString strTitle;
    strTitle.LoadString(AFX_IDS_APP_TITLE);
    
    // Initialise print document details
    
    DOCINFO di;
    ::ZeroMemory (di, sizeof (DOCINFO));
    di.cbSize = sizeof (DOCINFO);
    // application title appears in the spooler view
    di.lpszDocName = strTitle;
    
    // Begin a new print job
    BOOL bPrintingOK = dc.StartDoc( &di );
        
    // Get the printing extents and store in the m_rectDraw field of a 
    // CPrintInfo object
    CPrintInfo Info;
    int w = dc.GetDeviceCaps(HORZRES);
    int h = dc.GetDeviceCaps(VERTRES);
    Info.m_rectDraw.SetRect(0,0, w, h);
    
    char *startAt = p;
    int totalDone = 0;
    int lengthToGo = pSize;
    
    for (UINT page = Info.GetMinPage();
    bPrintingOK & totalDone < lengthToGo; page++)
    {
        // begin new page
        dc.StartPage();
        Info.m_nCurPage = page;
        
        // calc how much text fits on one page
        r = Info.m_rectDraw;
        r.bottom = r.top;
        int i = 0;
        while (r.bottom < Info.m_rectDraw.bottom & totalDone + i < lengthToGo)
        {
            r.right = Info.m_rectDraw.right;
            nHeight = dc.DrawText(startAt, i++, r, 
                DT_CALCRECT|DT_WORDBREAK|DT_NOCLIP|DT_EXPANDTABS);
        }
        // go one back to assure correct height
        if (r.bottom >= Info.m_rectDraw.bottom)
            i--;
        
        
        // print that text
        dc.DrawText(startAt, i, r, DT_WORDBREAK|DT_NOCLIP|DT_EXPANDTABS);
        
        // go to next page
        startAt += i;
        totalDone += i;
        
        // end page
        bPrintingOK = (dc.EndPage() > 0);
    }
    
    // end a print job
    if (bPrintingOK)
        dc.EndDoc();
    else
        // abort job.
        dc.AbortDoc();
    
    
    // restore font
    dc.SelectObject(oldFont);
    // free font memory
    qFont.DeleteObject();
    // detach the printer DC
    dc.Detach();
}



Comments

  • I am the new girl

    Posted by Jimmie Neighbour on 11/22/2016 08:04pm

    Howdy! Do you know if they make any plugins to assist with Search Engine Optimization? I'm trying to get my blog to rank for some targeted keywords but I'm not seeing very good gains. If you know of any please share. Thank you!

    Reply
  • Just want to say Hi!

    Posted by Lori Gabbard on 11/22/2016 07:13pm

    Outstanding post however , I was wanting to know if you could write a litte more on this subject? I'd be very thankful if you could elaborate a little bit more. Appreciate it!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date