Thread: Need help with Printer code

  1. #1
    Registered User
    Join Date
    Jun 2009
    Posts
    93

    Need help with Printer code

    I'm trying to write a printer code in C for a simple Windows multiline edit control application (like Notepad for example). What the code show below currently does is print multiple lines of text from the edit control within the pre-determined margins. What it does NOT do is wrap lines of text (horizontally) that are longer than space allocated within the margins. For example: if the space between the margins will hold only 50 characters horizontally, and the current string has 60 characters; the printer will not print the additional 10 characters to the next line. So, I would guess that I need some kinda loop that makes sure that all the characters on a line are printed.....And I don't have a clue as to how to accomplish this. Any help is welcome.

    BTW, variables and such not show in the code are declared globally.

    Code:
    int APIENTRY Print (
        HWND    hWnd)
    {
        HDC     hdc;                  // printer DC
        char    sz[32];
        int     cch;
        int     nChars;               // number of chars in line
        WORD    Offset;               // line offset into MLE buffer
        PSTR    pch;                  // current line
        PSTR    pchEOL;               // pointer to end of string from MLE
        PSTR    pNextLine;            // next bit of line to try printing; leftovers
        WORD    LineNum;              // current line number
        WORD    wpNumLines;           // number of lines to print
        HANDLE  hEditData;            // handle to MLE text
        DWORD   dy;
        int     yCurpos;              // current y-position rel. to top margin
        int     xCurpos;              // current x-position rel. to left margin
        int     nPixelsLeft;          // number of pixels left to print in
        int     nLinesPerPage;        // not inc. header and footer
        int     guess;                // number of chars that can print
        int     nPrintedLines;
        static const char letter[] = " ";
        WORD    fError = TRUE;
        HWND    hWndEdit = (HWND)GetWindowLong(hWnd, WL_HWNDEDIT);
        LPSTR   lpEditData;
        LONG    wLength;
        TEXTMETRIC Metrics;
        SIZE    sSize;
        fAbort = FALSE;
    
    
        // Create the job title by loading the title string from STRINGTABLE
        cch = LoadString ((HANDLE)GetModuleHandle (NULL), IDS_PRINTJOB, sz, sizeof(sz));
        szTitle = sz + cch;
        cch += GetWindowText (hWnd, sz + cch, 32 - cch);
        sz[31] = 0;
    
        // Initialize the printer
        hdc = GetPrinterDC();
        if (!hdc)
          AlertBox (hWnd, MB_OK | MB_ICONHAND,
                    IDS_PRINTERROR,
                    lpszYyz);
    
        // Width of the display, in pixels
        xPrintRes = GetDeviceCaps (hdc, HORZRES);
    
        // Height of the display, in raster lines
        yPrintRes = GetDeviceCaps (hdc, VERTRES);
    
        // pixels per inch for 1 inch margins
        xPixInch = 1 * GetDeviceCaps (hdc, LOGPIXELSX);
        yPixInch = 1 * GetDeviceCaps (hdc, LOGPIXELSY);
    
        // Offset of the printable area from top hand corner, in device units
        xPhysOff  = GetDeviceCaps (hdc, PHYSICALOFFSETX);
        yPhysOff  = GetDeviceCaps (hdc, PHYSICALOFFSETY);
    
        // compute margins in pixels
        dxLeft  = (xPixInch - xPhysOff);
        dxRight = (xPixInch - xPhysOff);
        dyTop   = (yPixInch  - yPhysOff);
        dyBottom = (yPixInch - yPhysOff);
    
        SetBkMode( hdc, TRANSPARENT );
    
        // Calculate necessary metrics for file
        GetTextMetrics (hdc, &Metrics);
        yPrintChar = Metrics.tmHeight + Metrics.tmExternalLeading ;
    
        tabSize = Metrics.tmAveCharWidth * 8; /* 8 ave char width pixels for tabs */
    
        // Number of lines on a page with margins
        nLinesPerPage = ((yPrintRes - dyTop - dyBottom) / yPrintChar);
    
        // Disable the main application window and create the Cancel dialog
        EnableWindow (hWnd, FALSE);
        hCancelDlg = CreateDialog ((HANDLE)GetModuleHandle (NULL),
                                  IDD_CANCELDLG,
                                  hWnd,
                                  (DLGPROC) AbortDlgProc);
        if (!hCancelDlg)
    	return IDS_CANCELDLGFAILED;
    
        // job started, so display cancel dialog
        ShowWindow (hCancelDlg, SW_SHOW);
        UpdateWindow (hCancelDlg);
    
        // set AbortProc callback
        SetAbortProc (hdc, AbortProc);
        if (!AbortProc)
    	{
    	// on error, clean up and go away
    	DestroyWindow (hCancelDlg);
    	DeleteDC (hdc);
    	return IDS_SETABORTPROCFAILED;
    	}
    
        // Initialize the document
        if (Escape (hdc, STARTDOC, cch, (LPSTR)sz, NULL) < 0)
    	{
    	// on error, clean up and go away
    	DestroyWindow (hCancelDlg);
    	DeleteDC (hdc);
    	return IDS_STARTDOCFAILED;
    	}
    
        // Get the height of one line and the height of a page
        {
        SIZE sLine;
        GetTextExtentPoint (hdc, letter, 1, &sLine);
        dy = sLine.cy;
        }
    
        // Get the lines in document and a handle to the text buffer
        LineNum	  = 0;
        yCurpos	  = 0;
        xCurpos	  = 0;
        nPrintedLines = 0;
        wpNumLines = (WORD)SendMessage (hWndEdit, EM_GETLINECOUNT, 0, 0L);
        hEditData = (HANDLE)SendMessage (hWndEdit, EM_GETHANDLE, 0, 0L);
    
        // length in bytes of edit control text
        wLength = SendMessage (hWndEdit, WM_GETTEXTLENGTH, 0, 0L);
    
        hEditData = LocalAlloc (LHND, wLength+1);
        lpEditData = (LPSTR)LocalLock (hEditData);
        GetWindowText (hWndEdit, lpEditData, wLength+1);
    
        // Print text line by line from top to bottom
        while (LineNum < wpNumLines) {
    	// If at end of page, start a new page
    	if (yCurpos + (int)dy > yPrintRes) {
    	    // Reached the end of a page. Tell the device driver to eject a
    	    // page
    	    //
    	    if (Escape (hdc, NEWFRAME, 0, NULL, NULL) < 0 || fAbort) {
    		DestroyWindow (hCancelDlg);
    		LocalUnlock (hEditData);
    		LocalFree (hEditData);
    		DeleteDC (hdc);
    		return IDS_PRINTABORTED;
    	    }
    	    yCurpos = 0;
    	}
    
    	// Get the length and position of the line in the buffer
    	// and lock from that offset into the buffer
    	Offset = (WORD)SendMessage (hWndEdit, EM_LINEINDEX, LineNum, 0L);
    	nChars = (WORD)SendMessage (hWndEdit, EM_LINELENGTH, Offset, 0L);
    	pch = (PSTR)LocalLock(hEditData) + Offset;
    	pchEOL = ((PSTR)LocalLock(hEditData) + Offset) + nChars;
    
          // find what to print - up to EOL
          pNextLine = pch;     // find end of line
          while (pNextLine != pchEOL)
          pNextLine++;
    
          // find out how many characters will fit on line
          nPixelsLeft = xPrintRes - dxRight - dxLeft - xCurpos;
          GetTextExtentExPoint( hdc, pch, pNextLine-pch,
                           nPixelsLeft, &guess, NULL, &sSize );
    
          if (guess) {
    	   // Print the current line and unlock the text handle
             TabbedTextOut (hdc, dxLeft+xCurpos, yCurpos+dyTop, (LPSTR)pch, guess, 
                            0, NULL, dxLeft+xCurpos);
             LocalUnlock (hEditData);
          }
    
    	// Test and see if the Abort flag has been set. If yes, exit.
    	if (fAbort)
    	    goto getout2;
    
    	// Move down the page
    	 yCurpos += dy;
    	 LineNum++;
             nPrintedLines++;
             xCurpos = 0;
        }  // end of while (LineNum < wpNumLines) loop
    
        // Eject the last page.
        if (Escape (hdc, NEWFRAME, 0, NULL, NULL) < 0)
    	goto getout2;
    
        // Complete the document.
        if (Escape (hdc, ENDDOC, 0, NULL, NULL) < 0) {
    getout2:
    	// Ran into a problem before NEWFRAME? Abort the document
          Escape (hdc, ABORTDOC, 0, NULL, NULL);
        }
        else
    	fError=FALSE;
    
        // Error? make sure the user knows...
        if (fError)
          AlertBox (hWnd, MB_OK | MB_ICONEXCLAMATION, IDS_PRINTERROR, (LPSTR)szTitle);
    
        // end cancel dialog box, clean up, re-enable main app. window and exit
        DestroyWindow (hCancelDlg);
        DeleteDC(hdc);
        LocalUnlock (hEditData);
        LocalFree (hEditData);
        EnableWindow (hWnd, TRUE);
        return TRUE;
    }

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    So I don't feel like looking things up right this minute: GetTextExtentExPoint tells you where to stop printing, right? Why not check to see if that's in the middle of the line?

  3. #3
    Registered User
    Join Date
    Jun 2009
    Posts
    93
    Since this thread has had a fair amount of reviews I figured I post my somewhat "fix" for the problem I had. Remember, I'm a novice when it comes to programming.
    Code:
    int APIENTRY Print (
        HWND    hWnd)
    {
        HDC     hdc;                  // printer DC
        char    sz[32];
        int     cch;
        int     nChars;               // number of chars in line
        WORD    Offset;               // line offset into MLE buffer
        PSTR    pch;                  // current line
        PSTR    pchEOL;               // pointer to end of string from MLE
        PSTR    pNextLine;            // next bit of line to try printing; leftovers
        WORD    LineNum;              // current line number
        WORD    wpNumLines;           // number of lines to print
        HANDLE  hEditData;            // handle to MLE text HGLOBAL
        DWORD   dy;
        int     yCurpos;              // current y-position rel. to top margin
        int     xCurpos;              // current x-position rel. to left margin
        int     nPixelsLeft;          // number of pixels left to print in
        int     nLinesPerPage;        // not inc. header and footer
        int     guess;                // number of chars that can print
        int     nPrintedLines;
        double  xDl;                  // stuff for calculating margins
        double  xDr;                  //            "
        double  yDt;                  //            "
        double  yDb;                  //            "
        double  xLpix;                //            "
        double  xRpix;                //            "
        double  yTpix;                //            "
        double  yBpix;                //            "
        char    *stopstring;          //            "
        int     count;                // counter for strings larger than margins
        static const char letter[] = " ";
        WORD    fError = TRUE;
        HWND    hWndEdit = (HWND)GetWindowLong(hWnd, WL_HWNDEDIT);
        LPSTR   lpEditData;
        LONG    wLength;   // WPARAM
        TEXTMETRIC Metrics;
        SIZE    sSize;
        fAbort = FALSE;
    
    
        // Create the job title by loading the title string from STRINGTABLE
        cch = LoadString ((HANDLE)GetModuleHandle (NULL), IDS_PRINTJOB, sz, sizeof(sz));
        szTitle = sz + cch;
        cch += GetWindowText (hWnd, sz + cch, 32 - cch);
        sz[31] = 0;
    
        // Initialize the printer
        hdc = GetPrinterDC();
        if (!hdc)
          AlertBox (hWnd, MB_OK | MB_ICONHAND,
                    IDS_PRINTERROR,
                    lpszYyz);
    
        // Retrieve margin strings from pagesetup dialog and convert to double
        xDl = strtod (szLft, &stopstring); // convert char string to double
        xDr = strtod (szRt, &stopstring);
        yDt = strtod (szTop, &stopstring);
        yDb = strtod (szBtm, &stopstring);
    
        // Width of the display, in pixels
        xPrintRes = GetDeviceCaps (hdc, HORZRES);
    
        // Height of the display, in raster lines
        yPrintRes = GetDeviceCaps (hdc, VERTRES);
    
        // Pixels per inch for margins
        xLpix = xDl * GetDeviceCaps (hdc, LOGPIXELSX);
        xRpix = xDr * GetDeviceCaps (hdc, LOGPIXELSX);
        yTpix = yDt * GetDeviceCaps (hdc, LOGPIXELSY);
        yBpix = yDb * GetDeviceCaps (hdc, LOGPIXELSY);
    
        // Round off double so we can store as integer
        lMargin = (int)floor(xLpix + 0.5);
        rMargin = (int)floor(xRpix + 0.5);
        tMargin = (int)floor(yTpix + 0.5);
        bMargin = (int)floor(yBpix + 0.5);
    
        // Offset of the printable area from top hand corner, in device units
        xPhysOff  = GetDeviceCaps (hdc, PHYSICALOFFSETX);
        yPhysOff  = GetDeviceCaps (hdc, PHYSICALOFFSETY);
    
        // Error handling for margins just in
        // case someone inputs an invalid character
        if (lMargin <= xPhysOff)
           lMargin = xPhysOff * 2;
        if (rMargin <= xPhysOff)
           rMargin = xPhysOff * 2;
        if (tMargin <= yPhysOff)
           tMargin = yPhysOff * 2;
        if (bMargin <= yPhysOff)
           bMargin = yPhysOff * 2;
    
        // compute margins in pixels
        dxLeft  = (lMargin - xPhysOff);
        dxRight = (rMargin - xPhysOff);
        dyTop   = (tMargin  - yPhysOff);
        dyBottom = (bMargin - yPhysOff);
    
        SetBkMode (hdc, TRANSPARENT);
    
        // Calculate necessary metrics for file
        GetTextMetrics (hdc, &Metrics);
        yPrintChar = Metrics.tmHeight + Metrics.tmExternalLeading ;  // the height
    
        tabSize = Metrics.tmAveCharWidth * 8;  // 8 ave char width pixels for tabs
    
        // Number of lines on a page with margins
        nLinesPerPage = ((yPrintRes - dyTop - dyBottom) / yPrintChar);
    
        // Disable the main application window and create the Cancel dialog
        EnableWindow (hWnd, FALSE);
        hCancelDlg = CreateDialog ((HANDLE)GetModuleHandle (NULL),
                                  IDD_CANCELDLG,
                                  hWnd,
                                  (DLGPROC) AbortDlgProc);
        if (!hCancelDlg)
    	return IDS_CANCELDLGFAILED;
    
        // job started, so display cancel dialog
        ShowWindow (hCancelDlg, SW_SHOW);
        UpdateWindow (hCancelDlg);
    
        // set AbortProc callback
        SetAbortProc (hdc, AbortProc);
        if (!AbortProc)
    	{
    	// on error, clean up and go away
    	DestroyWindow (hCancelDlg);
    	DeleteDC (hdc);
    	return IDS_SETABORTPROCFAILED;
    	}
    
        // Initialize the document
        if (Escape (hdc, STARTDOC, cch, (LPSTR)sz, NULL) < 0)
    	{
    	// on error, clean up and go away
    	DestroyWindow (hCancelDlg);
    	DeleteDC (hdc);
    	return IDS_STARTDOCFAILED;
    	}
    
        // Get the height of one line and the height of a page
        {
        SIZE sLine;
        GetTextExtentPoint (hdc, letter, 1, &sLine);
        dy = sLine.cy;
        }
    
        // Get the lines in document and a handle to the text buffer
        LineNum   = 0;
        yCurpos	  = 0;
        xCurpos	  = 0;
        nPrintedLines = 0;
        wpNumLines = (WORD)SendMessage (hWndEdit, EM_GETLINECOUNT, 0, 0L);
    
        // length in bytes of edit control text
        wLength = SendMessage (hWndEdit, WM_GETTEXTLENGTH, 0, 0L);
        wLength++;
        hEditData = (HANDLE)LocalAlloc (LHND, (DWORD)wLength);
        lpEditData = (LPSTR)LocalLock (hEditData);
        SendMessage (hWndEdit, WM_GETTEXT, wLength, (LPARAM)lpEditData);
    
        // Print text line by line from top to bottom
        while (LineNum < wpNumLines) {
          count = 0;  // reset counter for textout handling strings larger than margins
          // If at end of page, start a new page
          if (yCurpos + (int)dy > (yPrintRes - dyTop - dyBottom)) {
    	  // Reached the end of a page. Tell the device driver to eject a
    	  // page
    	  //
    	  if (Escape (hdc, NEWFRAME, 0, NULL, NULL) < 0 || fAbort)
                {
                DestroyWindow (hCancelDlg);
                LocalUnlock (hEditData);
                LocalFree (hEditData);
                DeleteDC (hdc);
                return IDS_PRINTABORTED;
                }
              yCurpos = 0;
              nPrintedLines = 0;  // reset lines printed
          }
    
          // Print out header if we are about to print
          // the first line on the page
          if (nPrintedLines == 0) {
             // print header if one exists
             yCurpos = 0;
             if (PrintHeader(hdc))
                yCurpos = 0;
                xCurpos = 0;
          }
    
          // Get the length and position of the line in the buffer
          // and lock from that offset into the buffer
          Offset = (WORD)SendMessage (hWndEdit, EM_LINEINDEX, LineNum, 0L);
          nChars = (WORD)SendMessage (hWndEdit, EM_LINELENGTH, Offset, 0L);  // length in bytes=chars
          pch = (PSTR)LocalLock(hEditData) + Offset;
          pchEOL = ((PSTR)LocalLock(hEditData) + Offset) + nChars;
    
          // find what to print - up to EOL
          pNextLine = pch;     // find end of line
          while (pNextLine != pchEOL)
          pNextLine++;   // increment till EOL
    
          // find out how many characters will fit on line
          nPixelsLeft = xPrintRes - dxRight - dxLeft - xCurpos;  // in logical units
          GetTextExtentExPoint (hdc, pch, pNextLine-pch, 
                           nPixelsLeft, &guess, NULL, &sSize);
    
          do {
             if (nChars > guess) {
    	    // Print the current line and unlock the text handle
                TabbedTextOut (hdc, dxLeft+xCurpos, yCurpos+dyTop, (LPSTR)pch, guess, 
                               0, NULL, dxLeft+xCurpos);
    
                pch += guess;  // add quantity of guess to pch; limit set by nPixelsLeft
                nChars -= guess;  // how many chars left to print in current line
                yCurpos += dy;  // move down the page one line
                xCurpos = 0;  // reset x position to zero
                count++;      // increment by one every time string is larger than margins
    
             if (nChars <= guess) {
                guess = nChars;   // put remaining char count in guess
    
                // print remaining characters on next line
                TabbedTextOut (hdc, dxLeft+xCurpos, yCurpos+dyTop, (LPSTR)pch, guess, 
                               0, NULL, dxLeft+xCurpos);
    
                pch  += guess;
                nChars -= guess;
    
                // since string was larger than the margin
                // calculate the x starting point for the
                // next string on this current line
                xCurpos += (sSize.cx - nPixelsLeft*count);  // account for printing
    
                LineNum++;  // increment line count by one here since
                            // string was larger than horizontal margin
             }
    
             }
             else {
                // If string is smaller or equal to nPixelsLeft
                TabbedTextOut (hdc, dxLeft+xCurpos, yCurpos+dyTop, (LPSTR)pch, guess, 
                               0, NULL, dxLeft+xCurpos);
                xCurpos = 0;    // reset x position to zero
                yCurpos += dy;  // move down the page one line
                LineNum++;      // increment line count by one
             }
    
    	LocalUnlock (hEditData);
    
    	// Test and see if the Abort flag has been set. If yes, exit.
    	if (fAbort)
    	   goto getout2;
    
    	// Increment line count and line printed
    	nPrintedLines++;  // increment lines printed by one
    
    	// If remaining chars is still larger than margins
    	if (nChars > guess)
               guess = guess;
    
          } while (guess < nChars);  // end while/do loop
    
        }  // end of while (LineNum < wpNumLines) loop
    
        // Eject the last page.
        if (Escape (hdc, NEWFRAME, 0, NULL, NULL) < 0)
    	goto getout2;
    
        // Complete the document.
        if (Escape (hdc, ENDDOC, 0, NULL, NULL) < 0) {
    getout2:
    	// Ran into a problem before NEWFRAME? Abort the document
          Escape (hdc, ABORTDOC, 0, NULL, NULL);
        }
        else
    	fError=FALSE;
    
        // Error? make sure the user knows...
        if (fError)
          AlertBox (hWnd, MB_OK | MB_ICONEXCLAMATION, IDS_PRINTERROR, (LPSTR)szTitle);
    
        // end cancel dialog box, clean up, re-enable main app. window and exit
        DestroyWindow (hCancelDlg);
        DeleteDC(hdc);
        LocalUnlock (hEditData);
        LocalFree (hEditData);
        EnableWindow (hWnd, TRUE);
        return TRUE;
    }
    In addition, I posted this code just in case some of the people who viewed this post where looking for answers to there own printer code problems in C.
    BTW, I'm still open to suggestions regarding my original problem even though I created that somewhat terrible looking fix.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Binary Search Trees Part III
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 10-02-2004, 03:00 PM
  2. True ASM vs. Fake ASM ????
    By DavidP in forum A Brief History of Cprogramming.com
    Replies: 7
    Last Post: 04-02-2003, 04:28 AM
  3. Seems like correct code, but results are not right...
    By OmniMirror in forum C Programming
    Replies: 4
    Last Post: 02-13-2003, 01:33 PM
  4. Interface Question
    By smog890 in forum C Programming
    Replies: 11
    Last Post: 06-03-2002, 05:06 PM
  5. Replies: 4
    Last Post: 01-16-2002, 12:04 AM