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;
}