Printing a Document

After an application initializes the necessary variables, registers its AbortProc function, and displays its modeless Cancel dialog box, it can start the print job by calling the StartDoc function.

After the application begins a print job, it can define individual pages in the document by calling the StartPage and EndPage functions and embedding the appropriate calls to GDI drawing functions within this bracket. After the application has defined the last page, it can close the document and end the print job by calling the EndDoc function.

The following example shows the code required to print a string of text and a bitmapped image. The string of text, centered at the top of the page, identifies the path and file name of the file that contains the bitmapped image. The bitmapped image, centered vertically and horizontally on the page, is drawn to maintain the same proportions used to draw the image in the application's window. Note that when targeting a printer DC, you should use a DIB instead of a DDB -- that is why StretchDIBits is used in this code.

#include <CommDlg.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
        {

            HDC hDC = NULL;
            HANDLE lhPrinter = NULL;
            DOCINFO di;
            FLOAT fLogPelsX1;
            FLOAT fLogPelsX2;
            FLOAT fLogPelsY1;
            FLOAT fLogPelsY2;
            FLOAT fScaleX;
            FLOAT fScaleY;
            int cWidthPels;
            int cHeightPels;
            int xLeft;
            int yTop;
            BITMAPINFOHEADER bmih = {0};
            OPENFILENAMEA ofn;
            SIZE szMetric;
            int nError;
            BYTE lpBits[1000];
            BITMAPINFO lpBitsInfo;
            WCHAR szDirName[MAX_PATH];
            

    char szFilename[MAX_PATH]="\0";

    // Zero and then initialize the members of a DOCINFO structure.
    
    memset( &di, 0, sizeof(DOCINFO) );
    di.cbSize = sizeof(DOCINFO);
    di.lpszDocName = TEXT("Bitmap Printing Test");
    di.lpszOutput =  NULL;
    di.lpszDatatype =  NULL;
    di.fwType = 0;

    // Initialize a PRINTDLG object's size and set the 
    //    PD_RETURNDC flag.  The PD_RETURNDC flag tells the 
    //  dialog to return a printer device context.
    PRINTDLG pd = {0};
    pd.lStructSize = sizeof( pd );
    pd.Flags = PD_RETURNDC;

    // Retrieves the printer DC
    PrintDlg(&pd);
    
    // Begin a print job by calling the StartDoc function.
    nError = StartDoc(pd.hDC,&di);
    if (nError == SP_ERROR)
    {
        MessageBox(
            hWnd, 
            _T("General Error"), 
            _T("StartDocPrinter"),
            MB_ICONEXCLAMATION);
        goto Error;
    }

    // Inform the driver that the application is about to begin
    //  sending data.

    nError = StartPage(pd.hDC);
    if (nError <= 0)
    {
        MessageBox(
            hWnd, 
            _T("Page could not be sent!"), 
            _T("StartPage"),
            MB_ICONEXCLAMATION);
        goto Error;
    }

    // Retrieve the number of pixels-per-logical-inch in the
    //  horizontal and vertical directions for the display upon which
    //  the bitmap was created. These are likely the same as for
    //  the present display, so we use those values here.

    
    fLogPelsX1 = (float) GetDeviceCaps(hDC, LOGPIXELSX);
    fLogPelsY1 = (float) GetDeviceCaps(hDC, LOGPIXELSY);

    // Retrieve the number of pixels-per-logical-inch in the
    //  horizontal and vertical directions for the printer upon which
    //  the bitmap will be printed.

    fLogPelsX2 = (float) GetDeviceCaps(hDC, LOGPIXELSX);
    fLogPelsY2 = (float) GetDeviceCaps(hDC, LOGPIXELSY);

    // Determine the scaling factors required to print the bitmap and
    //  retain its original proportions.

    if (fLogPelsX1 > fLogPelsX2)
        fScaleX = (fLogPelsX1 / fLogPelsX2);
    else fScaleX = (fLogPelsX2 / fLogPelsX1);

    if (fLogPelsY1 > fLogPelsY2)
        fScaleY = (fLogPelsY1 / fLogPelsY2);
    else fScaleY = (fLogPelsY2 / fLogPelsY1);

    // Compute the coordinates of the upper left corner of the
    //  centered bitmap.

    cWidthPels = GetDeviceCaps(hDC, HORZRES);
    xLeft = ((cWidthPels / 2) - ((int) (((float) bmih.biWidth)
            * fScaleX)) / 2);
    cHeightPels = GetDeviceCaps(hDC, VERTRES);
    yTop = ((cHeightPels / 2) - ((int) (((float) bmih.biHeight)
            * fScaleY)) / 2);

    // Use StretchDIBits to scale the bitmap and maintain
    //  its original proportions (that is, if the bitmap was square
    //  when it appeared in the application's client area, it should
    //  also appear square on the page).

    if (StretchDIBits(hDC, xLeft, yTop, (int) ((float) bmih.biWidth
        * fScaleX), (int) ((float) bmih.biHeight * fScaleY), 0, 0,
        bmih.biWidth, bmih.biHeight, lpBits, &lpBitsInfo, DIB_RGB_COLORS,
        SRCCOPY)==GDI_ERROR)
    {
        MessageBox(
            hWnd, 
            _T("StretchDIBits Failed"), 
            _T("Failed!"),
            MB_ICONEXCLAMATION); 
    }

    // Retrieve the width of the string that specifies the full path
    //  and filename for the file that contains the bitmap.
    //  Get the current directory name, and store in szDirName 
            GetCurrentDirectory(MAX_PATH, szDirName);
            
            //Set all structure members to zero. 
            ZeroMemory(&ofn, sizeof(OPENFILENAME));
            
            //Initializing the OPENFILENAMEA structure 
            ofn.lStructSize = sizeof(OPENFILENAME);
            ofn.hwndOwner = hWnd;
            ofn.lpstrFilter ="BMP Files (*.BMP)\0 *.BMP\0\0";
            ofn.lpstrFile = szFilename;
            ofn.nMaxFile = sizeof(szFilename);
            ofn.lpstrDefExt = "BMP";
            ofn.lpstrInitialDir = (LPCSTR)szDirName;
            ofn.Flags = OFN_EXPLORER | 
                        OFN_SHOWHELP | 
                        OFN_PATHMUSTEXIST | 
                        OFN_FILEMUSTEXIST;
    
            GetTextExtentPoint32A(hDC, ofn.lpstrFile,
            ofn.nFileExtension + 3, &szMetric);

    // Compute the starting point for the text-output operation. The
    //  string will be centered horizontally and positioned three lines
    //  down from the top of the page.

    xLeft = ((cWidthPels / 2) - (szMetric.cx / 2));
    yTop = (szMetric.cy * 3);

    // Print the path and filename for the bitmap, centered at the top
    //  of the page.

    TextOutA(hDC, xLeft, yTop, ofn.lpstrFile,
        ofn.nFileExtension + 3);


    nError = EndPage(pd.hDC);

    if (nError <= 0)
    {
        MessageBox(
            hWnd, 
            _T("Page has ended"), 
            _T("EndPage"),
            MB_ICONEXCLAMATION);
        goto Error;
    }

    // Inform the driver that document has ended.

    nError = EndDoc(pd.hDC);
    if (nError <= 0)
        MessageBox(
            hWnd, 
            _T("Document has ended"), 
            _T("EndDoc"),
            MB_ICONEXCLAMATION);
    DeleteDC(pd.hDC);
        
Error:
    // Enable the application's window.

    EnableWindow(hWnd, TRUE);

    // Delete the printer DC.

    DeleteDC(pd.hDC);

    }
    
    
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

Because the pixels on a screen typically have different dimensions than the dots on a printer, it is necessary to scale bitmapped images to obtain a WYSIWYG effect. This is done by obtaining horizontal and vertical scaling factors and then applying those factors to the width and height values passed to the StretchDIBits function. In the sample application, the scaling factors are obtained by retrieving the horizontal and vertical logical-pixel count for the two devices. Once the scaling factors are obtained, they are used to adjust the bitmap width and height.

To center the bitmap on the page, the application first computed the width and height of the scaled bitmap—the bitmap was scaled to maintain the original proportions of the image. These values were divided by two and then subtracted from half of the width and height of the page. The result defines the coordinates of the upper-left corner of the bitmap.

To center the text at the top of the page, the application calls the GetTextExtentPoint32 function to retrieve the width and height of the string that specifies the path and file name. After it obtains these values, the application uses the height to position the string three lines down the page and the width to position the string horizontally centered on the page.

The following illustration shows a representation of the page that appears when the application prints the bitmapped image in the Winlogo.bmp file. This illustration also depicts the variables used to position the text and to position and scale the bitmap.

 

A diagram that shows the dimensions used to describe and position a bitmap image

A diagram that shows the dimensions used to describe and position a bitmap image

 

 

 

Send comments about this topic to Microsoft

Build date: 6/4/2010