/************************************************************************* Print Engine for Visual Basic Printing utilities for hardcopy output Written by Barry Nolte 06-28-92 File Created 11-12-92 Added Graphics Functions 01-17-93 General Cleanup of Sources 02-03-93 Simple Bug Fixes *************************************************************************/ // COPYRIGHT: // // (C) Copyright Microsoft Corp. 1993. All rights reserved. // // You have a royalty-free right to use, modify, reproduce and // distribute the Sample Files (and/or any modified version) in // any way you find useful, provided that you agree that // Microsoft has no warranty obligations or liability for any // Sample Application Files which are modified. // #include #include #include #include #include #include #include "vbprint.h" // DLL Version Numbers #define MAJOR_VERSION 1 #define MINOR_VERSION 0 #define BORDER_WIDTH 2 // Default border in points /************************************************************************* GLOBAL VARIABLES *************************************************************************/ static HANDLE hInst; // Handle to calling app static HWND hWndApp; // Handle ot calling apps main window static PRINTDLG ppPrinter; // Structure of printer properties // Misc Procs static FARPROC lpfnPrintDlgProc; // Printing dialog proc static FARPROC lpfnAbortProc; // Printing about proc static BOOL fAbort; static struct tagPrinterInfo // Information on printer needed to place objects correctly { POINT ptPageSize; // Size of the page RECT rcUnprintable; // Unprintable regions of the printer RECT rcMargins; // Margins that are set in the Page Layout Function POINT ptResolution; // Printer Resolution in device DPI } PrinterInfo; static struct tagPageInfo // Information on where I'm printing on the page { POINT ptCurrentPos; // Current Print Position DWORD dwCurLineWidth; // Current Line Width, good for multiple calls to ParagraphText int nTabStop; // Current Tab Stop value BOOL bPageDirty; // Is the page dirty? } PageInfo; static struct tagParagraphInfo // Information on paragraph attributes { HFONT hFont; // Handle to paragraphs default font HFONT hOldFont; // Handle to previous font TEXTMETRIC tm; // Text metric struct that has info on the font DWORD dwWidth; // Width of column to print into int nStyle; // Border and Font Attributes WORD wBorderWidth; // Border Width in device units (HIBYTE = Horizontal, LOBYTE = Vertical) int nWidth[LAST_CHAR - FIRST_CHAR + 1]; // Widths of all the fonts characters int nSpaceBefore; // Space before Paragraph in Points int nSpaceAfter; // Space After Paragraph in Points int nLeftIndent; // Paragraph Left Indent size, good for check box justification } ParagraphInfo; static struct tagColumnInfo // Information on printing columns { HFONT hFont; // Handle to paragraphs default font HFONT hOldFont; // Handle to previous font TEXTMETRIC tm; // Text Metric struct that has info on the font WORD wBorderWidth; // Border Width in device units (HIBYTE = Horizontal, LOBYTE = Vertical) int nNumColumns; // Number of vertical Columns int nCellHeight; // Height of Cells int rgColumnWidths[MAX_COLUMNS]; // Widths of Columns int nWidth[LAST_CHAR - FIRST_CHAR + 1]; // Widths of all the fonts characters int nStyle; // Border and Font attributes } ColumnInfo; /************************************************************************* PROTOTYPES *************************************************************************/ int FAR PASCAL PrinterSetup(HWND hWnd); int FAR PASCAL InitializePrinter(HWND hWnd); int FAR PASCAL PageLayoutSetup(int nTop, int nRight, int nBottom, int nLeft); BOOL DoCommDlgError(HWND hWnd, DWORD dError); int FAR PASCAL DonePrinting(void); int FAR PASCAL StartParagraph(LPSTR szFontName, int nFontSize, int nStyle); int FAR PASCAL FinishParagraph(void); int FAR PASCAL PrintHeadline(LPSTR szHeadLine, LPSTR szFontName, int nFontSize, int nStyle); int FAR PASCAL ParagraphText(LPSTR szText); int FAR PASCAL EjectPage (void); int TextOutAtCurPos(LPSTR szText); int GetColumnOffset(int nColumn); int CellDrawText(HDC hDC, LPSTR szText, LPRECT rc); BOOL GetUnprintableRegion(HDC hDCPrn); BOOL GetPrinterResolution(HDC hDCPrn); BOOL FAR PASCAL PrnAbortProc(HDC hDCPrn, short nCode); BOOL FAR PASCAL PrintDlgProc(HWND hDlg, WORD message, WORD wParam, LONG lParam); int FAR PASCAL PrintDLLVersion(VOID); BOOL FAR PASCAL SetParagraphSpacing(int nSpaceBefore, int nSpaceAfter); BOOL FAR PASCAL SetBorderWidth(int nWidth); int FAR PASCAL SetUpColumns(int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle); int FAR PASCAL PrintColumnText(LPSTR szText); int FAR PASCAL EndColumnPrinting(VOID); int FAR PASCAL PrintColumnHeaders(LPSTR szHeader, int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle); HDC GetPrinterDC(void); BOOL FAR PASCAL KillJob(void); BOOL FAR PASCAL PrinterName(LPSTR szPrinterName); BOOL FAR PASCAL PrinterPort(LPSTR szPortName); BOOL FAR PASCAL IsPageDirty(void); int FAR PASCAL PagePosY(void); int FAR PASCAL PagePosX(void); int FAR PASCAL PageSizeY(void); int FAR PASCAL PageSizeX(void); BOOL FAR PASCAL MoveYPos(int nY); int FDrawLine(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY); int FDrawRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY); int FDrawRndRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY, int nElpX, int nElpY); int FDrawEllipse(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY); BOOL FAR PASCAL DrawLine(int nX1, int nY1, int nX2, int nY2); BOOL FAR PASCAL DrawRectangle(int nX1, int nY1, int nX2, int nY2); BOOL FAR PASCAL DrawRndRectangle(int nX1, int nY1, int nX2, int nY2, int nX3, int nY3); BOOL FAR PASCAL DrawEllipse(int nX1, int nY1, int nX2, int nY2); /************************************************************************* DLL initialization, called once when loaded *************************************************************************/ int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine) { hInst = hInstance; // Save this for later, we may need it /* Set all structure members to zero. */ _fmemset(&ppPrinter, 0, sizeof(PRINTDLG)); return TRUE; } /************************************************************************* Initialize Printer Driver and set defaults *************************************************************************/ int FAR PASCAL InitializePrinter(HWND hWnd) { char szQueueName[80]={""}; hWndApp = hWnd; // Save the calling apps window handle so we can put up dialogs fAbort = FALSE; PageInfo.bPageDirty = FALSE; ppPrinter.hDC = GetPrinterDC(); if (ppPrinter.hDC) { // Do stuff for AbortProc and Printing Dialog lpfnAbortProc = MakeProcInstance(PrnAbortProc, hInst); Escape(ppPrinter.hDC, SETABORTPROC, NULL, (LPSTR)(long)lpfnAbortProc, (LPSTR)NULL); GetUnprintableRegion(ppPrinter.hDC); GetPrinterResolution(ppPrinter.hDC); LoadString(hInst, IDS_QUEUE_NAME, (LPSTR)szQueueName, 80); Escape(ppPrinter.hDC, STARTDOC,lstrlen((LPSTR)szQueueName) ,(LPSTR)szQueueName, NULL); // Temp Defaults // Setup defaults // Set Margins to 1" all around PrinterInfo.rcMargins.top = PrinterInfo.rcMargins.bottom = PrinterInfo.rcMargins.left = PrinterInfo.rcMargins.right = (int)(INCH * (PrinterInfo.ptResolution.x * 0.01)); // Start at upper left hand corner PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left; PageInfo.ptCurrentPos.y = PrinterInfo.rcMargins.top; // Default Tab Stops = 1/2" PageInfo.nTabStop = (int)(HALF_INCH * (PrinterInfo.ptResolution.x * 0.01)); // Default Paragraph Spacing ParagraphInfo.nSpaceBefore = (int)(QUARTER_INCH * (PrinterInfo.ptResolution.y * 0.01)); // No Indent By Default ParagraphInfo.nLeftIndent = 0; return TRUE; } else { DoCommDlgError(hWnd, CommDlgExtendedError()); return FALSE; } } /************************************************************************* Setup for the start of a paragraph, set text attributes *************************************************************************/ int FAR PASCAL StartParagraph(LPSTR szFontName, int nFontSize, int nStyle) { int nFontWeight; // Weight of the font BYTE bFontItalic; // Italic flag // Check for bogus font size values nFontSize = min(nFontSize, MAX_FONT_SIZE); // No bigger than nFontSize = max(nFontSize, MIN_FONT_SIZE); // No smaller than // Get weight of font if(nStyle & BOLD_FONT) nFontWeight = FW_BOLD; else nFontWeight = FW_NORMAL; // Get font slant if(nStyle & ITALIC_FONT) bFontItalic = 1; else bFontItalic = 0; // Remember Border Style and Size ParagraphInfo.nStyle = nStyle; ParagraphInfo.wBorderWidth = (WORD)(((PrinterInfo.ptResolution.x * BORDER_WIDTH) / 72) << 8); ParagraphInfo.wBorderWidth += (WORD)((PrinterInfo.ptResolution.y * BORDER_WIDTH) / 72); // Setup Text Attributes SetBkMode(ppPrinter.hDC, TRANSPARENT); // Show whatever was there before through the text SetTextColor(ppPrinter.hDC, 0); // Black Text SetBkColor(ppPrinter.hDC, 0x00FFFFFF); // White Background SetTextAlign(ppPrinter.hDC, TA_TOP|TA_LEFT); // Text aligned at top, left of bounding box ParagraphInfo.hFont = CreateFont((int)((PrinterInfo.ptResolution.y * nFontSize) / 72), 0, 0, 0, nFontWeight, bFontItalic, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH | FF_DONTCARE, szFontName); if(ParagraphInfo.hFont) // If we get the font, selected and get the metrics and width { ParagraphInfo.hOldFont = SelectObject(ppPrinter.hDC, ParagraphInfo.hFont); GetTextMetrics(ppPrinter.hDC, (LPTEXTMETRIC)&ParagraphInfo.tm); GetCharWidth(ppPrinter.hDC, FIRST_CHAR, LAST_CHAR, (LPINT)&ParagraphInfo.nWidth); } // Set Current Line Width to Zero PageInfo.dwCurLineWidth = 0; // See if first line will fit on page if((PageInfo.ptCurrentPos.y += ParagraphInfo.nSpaceBefore) > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading)) { EjectPage(); // Sets current positon too } // Get Indent/Check Box Info if(nStyle & CHECK_BOX) { WORD wBorderWidth; wBorderWidth = ParagraphInfo.wBorderWidth; // Save the current Border width SetBorderWidth(0); // Set Indent Value ParagraphInfo.nLeftIndent = (int)(QUARTER_INCH * (PrinterInfo.ptResolution.x * 0.01)); // Default Paragraph Indent // Draw Check Box FDrawRectangle( ppPrinter.hDC, PrinterInfo.rcMargins.left, PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmExternalLeading, PrinterInfo.rcMargins.left + (int)(EIGHTH_INCH * (PrinterInfo.ptResolution.x * 0.01)), PageInfo.ptCurrentPos.y + (int)(EIGHTH_INCH * (PrinterInfo.ptResolution.y * 0.01)) + ParagraphInfo.tm.tmExternalLeading); ParagraphInfo.wBorderWidth = wBorderWidth; // Restore Border width } else { ParagraphInfo.nLeftIndent = 0; } if(ParagraphInfo.nStyle & TOP_BORDER) // Top Border Line FDrawLine( ppPrinter.hDC, PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)), PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2), PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)), PageInfo.ptCurrentPos.y - (int)(LOBYTE(ParagraphInfo.wBorderWidth)/2)); // Width of column to print into ParagraphInfo.dwWidth = PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.left - PrinterInfo.rcMargins.right - ParagraphInfo.nLeftIndent; // Start at left margin PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent; if(ParagraphInfo.hFont) // If the font was generated, then we're cool return TRUE; else // Otherwise we're not return FALSE; } /************************************************************************* Print the actual paragraph taking in to consideration tab's returns, etc... *************************************************************************/ int FAR PASCAL ParagraphText(LPSTR szText) { char far *cpStart; // Pointer in string to print char far *cpCurrent; char far *cpEnd; HGLOBAL hText; LPSTR lpText; PageInfo.bPageDirty = TRUE; // Get our own private copy of the text hText = GlobalAlloc(GHND, lstrlen((LPSTR)szText)+1); if(!hText) return FALSE; lpText = GlobalLock(hText); if(!lpText) return FALSE; lstrcpy((LPSTR)lpText, (LPSTR) szText); cpStart = cpCurrent = cpEnd = (LPSTR)lpText; // All pointers to the start of the text string if(cpStart == NULL) return TRUE; // If the string is NULL, thats alright, just don't do anything while(*cpCurrent != NULL) { switch(*cpCurrent) { /* TAB */ case '\t' : cpEnd = cpCurrent; *cpEnd = 0; // Set end of string to null TextOutAtCurPos((LPSTR)cpStart); // Print text up to tab PageInfo.ptCurrentPos.x += LOWORD(GetTextExtent(ppPrinter.hDC, (LPSTR)cpStart, lstrlen((LPSTR)cpStart))); PageInfo.ptCurrentPos.x = (PageInfo.nTabStop * ((PageInfo.ptCurrentPos.x / PageInfo.nTabStop)+1)); PageInfo.dwCurLineWidth = PageInfo.ptCurrentPos.x - PrinterInfo.rcMargins.left; cpStart = cpCurrent = cpEnd+1; break; /* CR */ case '\r' : cpEnd = cpCurrent; *cpEnd = 0; // Set end of string to null TextOutAtCurPos((LPSTR)cpStart); // Print the text // Next Line Down PageInfo.ptCurrentPos.y += ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading; if(PageInfo.ptCurrentPos.y > PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading) { EjectPage(); } // Start at left margin PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent; cpStart = cpCurrent = cpEnd+1; // Set everything to start of next line if(*cpStart == '\n') // Get rid of those dang line feeds cpStart = cpEnd = ++cpCurrent; // Clear Width PageInfo.dwCurLineWidth = 0; break; /* NULL */ case NULL : cpEnd = cpCurrent; goto showline; break; default : if(*cpCurrent < FIRST_CHAR) *cpCurrent = ' '; // Set any control chars to space PageInfo.dwCurLineWidth += ParagraphInfo.nWidth[(int)(*cpCurrent) - FIRST_CHAR]; // Width of character if(*cpCurrent == ' ') cpEnd = cpCurrent; // Space is always an excuse to break a line cpCurrent++; // Goto next character break; } if( PageInfo.dwCurLineWidth > ParagraphInfo.dwWidth && (cpStart != cpEnd)) // Wrap Line { *cpEnd = 0; // Set end of string to null TextOutAtCurPos((LPSTR)cpStart); // Next Line Down PageInfo.ptCurrentPos.y += ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading; if(PageInfo.ptCurrentPos.y > PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading) { EjectPage(); } // Start at left margin PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent; cpStart = cpCurrent = cpEnd+1; // Set everything to start of next line PageInfo.dwCurLineWidth = 0; // Clear Width } } showline: if(*cpStart) // No Text, so don't print it { TextOutAtCurPos((LPSTR) cpStart); PageInfo.ptCurrentPos.x += (int)PageInfo.dwCurLineWidth; // Set current X position } else // We still have to put the border around the current line { if(ParagraphInfo.nStyle & LEFT_BORDER) // Left border FDrawLine( ppPrinter.hDC, PrinterInfo.rcMargins.left - (int)((HIBYTE(ParagraphInfo.wBorderWidth))), PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2), PrinterInfo.rcMargins.left - (int)((HIBYTE(ParagraphInfo.wBorderWidth))), PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2)); if(ParagraphInfo.nStyle & RIGHT_BORDER) // Right border FDrawLine( ppPrinter.hDC, PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)((HIBYTE(ParagraphInfo.wBorderWidth))), PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2), PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)((HIBYTE(ParagraphInfo.wBorderWidth))), PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2)); } GlobalUnlock(hText); GlobalFree(hText); return TRUE; } /************************************************************************* Clean up after printing a paragraph of text *************************************************************************/ int FAR PASCAL FinishParagraph(void) { SelectObject(ppPrinter.hDC, ParagraphInfo.hOldFont); DeleteObject(ParagraphInfo.hFont); // Next Line Down PageInfo.ptCurrentPos.y += ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading; // Bottom Border Line if(ParagraphInfo.nStyle & BOTTOM_BORDER) FDrawLine( ppPrinter.hDC, PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)), PageInfo.ptCurrentPos.y + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2), PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)), PageInfo.ptCurrentPos.y + (int)(LOBYTE(ParagraphInfo.wBorderWidth)/2)); if((PageInfo.ptCurrentPos.y += ParagraphInfo.nSpaceAfter) > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom)) { EjectPage(); // Sets current positon too } if(PageInfo.ptCurrentPos.y > PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.bottom - ParagraphInfo.tm.tmHeight - ParagraphInfo.tm.tmExternalLeading) { EjectPage(); } // Start at left margin PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left + ParagraphInfo.nLeftIndent; return TRUE; } /************************************************************************* Internal function to print a line of text at a specific position. *************************************************************************/ int TextOutAtCurPos(LPSTR szText) { RECT rc; int nRetVal; if(ParagraphInfo.nStyle & LEFT_BORDER) // Left border FDrawLine( ppPrinter.hDC, PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)), PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2), PrinterInfo.rcMargins.left - (int)(HIBYTE(ParagraphInfo.wBorderWidth)), PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2)); if(ParagraphInfo.nStyle & RIGHT_BORDER) // Right border FDrawLine( ppPrinter.hDC, PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)), PageInfo.ptCurrentPos.y - (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2), PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right + (int)(HIBYTE(ParagraphInfo.wBorderWidth)), PageInfo.ptCurrentPos.y + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading + (int)((LOBYTE(ParagraphInfo.wBorderWidth))/2)); SetRect((LPRECT)&rc, (int)PageInfo.ptCurrentPos.x - PrinterInfo.rcUnprintable.left, (int)PageInfo.ptCurrentPos.y - PrinterInfo.rcUnprintable.top, (int)PrinterInfo.ptPageSize.x - PrinterInfo.rcMargins.right - PrinterInfo.rcUnprintable.left, (int)PageInfo.ptCurrentPos.y - PrinterInfo.rcUnprintable.top + ParagraphInfo.tm.tmHeight + ParagraphInfo.tm.tmExternalLeading); nRetVal = ExtTextOut( ppPrinter.hDC, PageInfo.ptCurrentPos.x - PrinterInfo.rcUnprintable.left, PageInfo.ptCurrentPos.y - PrinterInfo.rcUnprintable.top, ETO_OPAQUE, (LPRECT)&rc, szText, lstrlen(szText), NULL); return nRetVal; } /************************************************************************* Draw an Ellipse *************************************************************************/ int FDrawEllipse(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY) { int nRet=FALSE; HPEN hPen, hOldPen; // Black Pen hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0); if(hPen) { hOldPen = SelectObject(hDC, hPen); nRet = Ellipse( hDC, nStartX - PrinterInfo.rcUnprintable.left, nStartY - PrinterInfo.rcUnprintable.top, nEndX - PrinterInfo.rcUnprintable.left, nEndY - PrinterInfo.rcUnprintable.top); SelectObject(hDC, hOldPen); DeleteObject(hPen); } return nRet; } /************************************************************************* Draw a Rectangele with Rounded Corners *************************************************************************/ int FDrawRndRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY, int nElpX, int nElpY) { int nRet=FALSE; HPEN hPen, hOldPen; // Black Pen hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0); if(hPen) { hOldPen = SelectObject(hDC, hPen); nRet = RoundRect( hDC, nStartX - PrinterInfo.rcUnprintable.left, nStartY - PrinterInfo.rcUnprintable.top, nEndX - PrinterInfo.rcUnprintable.left, nEndY - PrinterInfo.rcUnprintable.top, nElpX, nElpY); SelectObject(hDC, hOldPen); DeleteObject(hPen); } return nRet; } /************************************************************************* Draw a Rectangle with Square Corners *************************************************************************/ int FDrawRectangle(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY) { int nRet=FALSE; HPEN hPen, hOldPen; // Black Pen hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0); if(hPen) { hOldPen = SelectObject(hDC, hPen); nRet = Rectangle( hDC, nStartX - PrinterInfo.rcUnprintable.left, nStartY - PrinterInfo.rcUnprintable.top, nEndX - PrinterInfo.rcUnprintable.left, nEndY - PrinterInfo.rcUnprintable.top); SelectObject(hDC, hOldPen); DeleteObject(hPen); } return nRet; } /************************************************************************* Draw a line *************************************************************************/ int FDrawLine(HDC hDC, int nStartX, int nStartY, int nEndX, int nEndY) { int nRet=FALSE; HPEN hPen, hOldPen; hPen = CreatePen(0,LOBYTE(ParagraphInfo.wBorderWidth),0); if(hPen) { hOldPen = SelectObject(hDC, hPen); MoveTo( hDC, nStartX - PrinterInfo.rcUnprintable.left, nStartY - PrinterInfo.rcUnprintable.top); nRet = LineTo( hDC, (int)nEndX - PrinterInfo.rcUnprintable.left, (int)nEndY - PrinterInfo.rcUnprintable.top); SelectObject(hDC, hOldPen); DeleteObject(hPen); } return nRet; } /************************************************************************* Print a Headline which is just a special case of a paragraph, makes all setup and clean up calls for you. *************************************************************************/ int FAR PASCAL PrintHeadline(LPSTR szHeadLine, LPSTR szFontName, int nFontSize, int nStyle) { StartParagraph(szFontName, nFontSize, nStyle); ParagraphText(szHeadLine); FinishParagraph(); return TRUE; } /************************************************************************* End of printing function, cleans up memory and ejects the last page *************************************************************************/ int FAR PASCAL DonePrinting(void) { int nRet=FALSE; Escape(ppPrinter.hDC,NEWFRAME, 0, 0L, 0L); // Kick out last page Escape(ppPrinter.hDC,ENDDOC, 0, 0L, 0L); FreeProcInstance(lpfnAbortProc); nRet = DeleteDC(ppPrinter.hDC); if (ppPrinter.hDevMode != NULL) { GlobalFree(ppPrinter.hDevMode); ppPrinter.hDevMode = NULL; } if (ppPrinter.hDevNames != NULL) { GlobalFree(ppPrinter.hDevNames); ppPrinter.hDevNames = NULL; } return nRet; } /************************************************************************* Unconditionally ejects page from printer, then sets the current page position to upper left corner, this also restores the currently selected font. *************************************************************************/ int FAR PASCAL EjectPage(void) { int nRet; HFONT hFont; // Save Currently selected Font hFont = SelectObject(ppPrinter.hDC, GetStockObject(DEVICE_DEFAULT_FONT)); nRet = Escape(ppPrinter.hDC,NEWFRAME, 0, 0L, 0L); // Kick out page // Restore Currently select Font SelectObject(ppPrinter.hDC, hFont); PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left; // Start at upper left hand corner PageInfo.ptCurrentPos.y = PrinterInfo.rcMargins.top; PageInfo.bPageDirty = FALSE; // Page is no longer dirty return nRet; } /************************************************************************* Sets margins for pages printed after this function is called. *************************************************************************/ int FAR PASCAL PageLayoutSetup(int nTop, int nRight, int nBottom, int nLeft) { nTop = min(nTop, 2 * INCH); // No bigger than nTop = max(nTop, 0); // No smaller than nBottom = min(nBottom, 2 * INCH); // No bigger than nBottom = max(nBottom, 0); // No smaller than nLeft = min(nLeft, 2 * INCH); // No bigger than nLeft = max(nLeft, 0); // No smaller than nRight = min(nRight, 2 * INCH); // No bigger than nRight = max(nRight, 0); // No smaller than PrinterInfo.rcMargins.top = (int)(nTop * (int)(PrinterInfo.ptResolution.y * 0.01)); PrinterInfo.rcMargins.bottom = (int)(nBottom * (int)(PrinterInfo.ptResolution.y * 0.01)); PrinterInfo.rcMargins.left = (int)(nLeft * (int)(PrinterInfo.ptResolution.x * 0.01)); PrinterInfo.rcMargins.right = (int)(nRight * (int)(PrinterInfo.ptResolution.x * 0.01)); PageInfo.ptCurrentPos.x = PrinterInfo.rcMargins.left; // Start at upper left hand corner PageInfo.ptCurrentPos.y = PrinterInfo.rcMargins.top; return TRUE; } /************************************************************************* This procedure brings up a message box with Common Dialog error text *************************************************************************/ BOOL DoCommDlgError(HWND hWnd, DWORD dwError) { char sz1[80]; char sz2[32]; if(dwError != 0) { LoadString(hInst, (WORD)dwError, sz2, 32); if(!sz2[0]) lstrcpy(sz2,"Unknown"); wsprintf(sz1," Error: %s ",(LPSTR)sz2); MessageBox(hWnd,sz1," COMMDLG.DLL ERROR ",MB_ICONSTOP); return TRUE; } else return FALSE; } /************************************************************************* Fills the PrinterInfo structure with the printers current unprintable region *************************************************************************/ BOOL GetUnprintableRegion(HDC hDCPrn) { RECT rcTemp; POINT ptPhysPageSize; POINT ptOffset; Escape(hDCPrn, GETPHYSPAGESIZE, NULL, (LPSTR)NULL, (LPSTR) &ptPhysPageSize); Escape(hDCPrn, GETPRINTINGOFFSET, NULL, (LPSTR)NULL, (LPSTR) &ptOffset); GetClipBox(hDCPrn,&rcTemp); // Size of Printable region PrinterInfo.ptPageSize.x = ptPhysPageSize.x; PrinterInfo.ptPageSize.y = ptPhysPageSize.y; PrinterInfo.rcUnprintable.top = ptOffset.y; PrinterInfo.rcUnprintable.left = ptOffset.x; PrinterInfo.rcUnprintable.right = ptPhysPageSize.x - ptOffset.x; PrinterInfo.rcUnprintable.bottom = ptPhysPageSize.y - ptOffset.y; return TRUE; } /************************************************************************* Sticks the printers current resolution in the PrinterInfo Structure *************************************************************************/ BOOL GetPrinterResolution(HDC hDCPrn) { PrinterInfo.ptResolution.x = GetDeviceCaps(hDCPrn, LOGPIXELSX); PrinterInfo.ptResolution.y = GetDeviceCaps(hDCPrn, LOGPIXELSY); return TRUE; } /************************************************************************* Abort Proc for printing, this is where control is returned to the system during printing. Gets called by the printer driver periocically for control release purposes. *************************************************************************/ BOOL FAR PASCAL PrnAbortProc(HDC hDCPrn, short nCode) { MSG msg; while(!fAbort && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { { TranslateMessage(&msg); DispatchMessage(&msg); } } return !fAbort; } /************************************************************************* Returns version number of the Print DLL *************************************************************************/ int FAR PASCAL PrintDLLVersion(VOID) { return ((MAJOR_VERSION) | (MINOR_VERSION << 8)); } /************************************************************************* Sets the space before and after a paragraph *************************************************************************/ BOOL FAR PASCAL SetParagraphSpacing(int nSpaceBefore, int nSpaceAfter) { // Check for bogus Spacing size values nSpaceBefore = min(nSpaceBefore, MAX_FONT_SIZE); // No bigger than nSpaceBefore = max(nSpaceBefore, MIN_FONT_SIZE); // No smaller than ParagraphInfo.nSpaceBefore = (int)((PrinterInfo.ptResolution.y * nSpaceBefore) / 72); // Check for bogus Spacing size values nSpaceAfter = min(nSpaceAfter, MAX_FONT_SIZE); // No bigger than nSpaceAfter = max(nSpaceAfter, MIN_FONT_SIZE); // No smaller than ParagraphInfo.nSpaceAfter = (int)((PrinterInfo.ptResolution.y * nSpaceAfter) / 72); return TRUE; } /************************************************************************* Sets Line Weight for borders *************************************************************************/ BOOL FAR PASCAL SetBorderWidth(int nWidth) { if(nWidth !=0) { // Check for bogus Width values nWidth = min(nWidth, MAX_WIDTH_SIZE); // No bigger than nWidth = max(nWidth, MIN_WIDTH_SIZE); // No smaller than ParagraphInfo.wBorderWidth = (WORD)(((PrinterInfo.ptResolution.x * nWidth) / 72) << 8); ParagraphInfo.wBorderWidth += (WORD)((PrinterInfo.ptResolution.y * nWidth) / 72); } else // Gaurentee 1 pixel width { ParagraphInfo.wBorderWidth = (WORD)((1) << 8); ParagraphInfo.wBorderWidth += (WORD)(1); } return TRUE; } /************************************************************************* Prints headers for a set of columns *************************************************************************/ int FAR PASCAL PrintColumnHeaders(LPSTR szHeader, int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle) { SetUpColumns(nNumColumns, nC, szFontName, nFontSize, nStyle); PrintColumnText(szHeader); EndColumnPrinting(); return TRUE; } /************************************************************************* Sets up the number and widths of columns to be printed *************************************************************************/ int FAR PASCAL SetUpColumns(int nNumColumns, LPINT nC, LPSTR szFontName, int nFontSize, int nStyle) { int nFontWeight; // Weight of the font BYTE bFontItalic; // Italic flag // Remember these ColumnInfo.nNumColumns = nNumColumns; ColumnInfo.rgColumnWidths[0] = nC[0]; ColumnInfo.rgColumnWidths[1] = nC[1]; ColumnInfo.rgColumnWidths[2] = nC[2]; ColumnInfo.rgColumnWidths[3] = nC[3]; ColumnInfo.rgColumnWidths[4] = nC[4]; ColumnInfo.rgColumnWidths[5] = nC[5]; ColumnInfo.rgColumnWidths[6] = nC[6]; ColumnInfo.rgColumnWidths[7] = nC[7]; // Check for bogus font size values nFontSize = min(nFontSize, MAX_FONT_SIZE); // No bigger than nFontSize = max(nFontSize, MIN_FONT_SIZE); // No smaller than // Get weight of font if(nStyle & BOLD_FONT) nFontWeight = FW_BOLD; else nFontWeight = FW_NORMAL; // Get font slant if(nStyle & ITALIC_FONT) bFontItalic = 1; else bFontItalic = 0; // Remember Border Style and Size ColumnInfo.nStyle = nStyle; ColumnInfo.wBorderWidth = (WORD)(((PrinterInfo.ptResolution.x * BORDER_WIDTH) / 72) << 8); ColumnInfo.wBorderWidth += (WORD)((PrinterInfo.ptResolution.y * BORDER_WIDTH) / 72); // Setup Text Attributes SetBkMode(ppPrinter.hDC, TRANSPARENT); // Show whatever was there before through the text SetTextColor(ppPrinter.hDC, 0); // Black Text SetBkColor(ppPrinter.hDC, 0x00FFFFFF); // White Background SetTextAlign(ppPrinter.hDC, TA_TOP|TA_LEFT); // Text aligned at top, left of bounding box ColumnInfo.hFont = CreateFont((int)((PrinterInfo.ptResolution.y * nFontSize) / 72), 0, 0, 0, nFontWeight, bFontItalic, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH | FF_DONTCARE, szFontName); if(ColumnInfo.hFont) // If we get the font, selected and get the metrics and width { ColumnInfo.hOldFont = SelectObject(ppPrinter.hDC, ColumnInfo.hFont); GetTextMetrics(ppPrinter.hDC, (LPTEXTMETRIC)&ColumnInfo.tm); GetCharWidth(ppPrinter.hDC, FIRST_CHAR, LAST_CHAR, (LPINT)&ColumnInfo.nWidth); } return TRUE; } /************************************************************************* Printed text in columns, the text is seperated by tab (0x09) characters *************************************************************************/ int FAR PASCAL PrintColumnText(LPSTR szText) { int nColumnCount; int nMaxRowHeight; int nLineCount; int nSpaceCount; int nOffset; RECT rc; char FAR *cpColText; char FAR *cpBegin; char FAR *cpCurrent; char FAR *rgcpColText[MAX_COLUMNS]; int nColCount; DWORD dwWidth, dwColumnWidth; HGLOBAL hText; LPSTR lpText; PageInfo.bPageDirty = TRUE; // Get our own private copy of the text hText = GlobalAlloc(GHND, lstrlen((LPSTR)szText)+1); if(!hText) return FALSE; lpText = (LPSTR)GlobalLock(hText); if(!lpText) return FALSE; lstrcpy((LPSTR)lpText, (LPSTR)szText); // Calculate where all the strings are cpColText = (LPSTR)lpText; nColCount = 0; rgcpColText[nColCount++] = (LPSTR)cpColText; // First Column; // Setup pointers to each column of text while(*cpColText != NULL) { if(*cpColText == '\t') { *cpColText = NULL; // NULL Terminate cpColText++; rgcpColText[nColCount++] = (LPSTR)cpColText; } else { cpColText++; } } // Calculate the Max Height of the cells nMaxRowHeight = 1; for(nColumnCount = 0; nColumnCount < ColumnInfo.nNumColumns; nColumnCount++) { cpBegin = cpCurrent = rgcpColText[nColumnCount]; dwColumnWidth = (DWORD)(ColumnInfo.rgColumnWidths[nColumnCount] * (PrinterInfo.ptResolution.x * 0.01)); dwWidth = 0; nSpaceCount = -1; nLineCount = 1; while(*cpCurrent != NULL) { dwWidth += ColumnInfo.nWidth[(int)(*cpCurrent) - FIRST_CHAR]; // Width of Character switch(*cpCurrent) { case ' ' : if(dwWidth > dwColumnWidth) { nLineCount++; if(nSpaceCount >= 0) { cpCurrent = cpBegin; nSpaceCount = -1; } else cpCurrent++; dwWidth = 0; } else { nSpaceCount++; cpBegin = ++cpCurrent; } break; case '\r': cpBegin = ++cpCurrent; nLineCount++; break; default : cpCurrent++; break; } } if(dwWidth > dwColumnWidth) nLineCount++; // In case of any left overs nMaxRowHeight = max(nMaxRowHeight, nLineCount); } nMaxRowHeight *= ColumnInfo.tm.tmHeight; // See if first line will fit on page if((PageInfo.ptCurrentPos.y + nMaxRowHeight) > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.top - PrinterInfo.rcMargins.bottom)) { EjectPage(); // Sets current positon too } SetBorderWidth(0); for(nColumnCount = 0; nColumnCount < ColumnInfo.nNumColumns; nColumnCount++) { nOffset = GetColumnOffset(nColumnCount); SetRect( &rc, PrinterInfo.rcMargins.left + nOffset, PageInfo.ptCurrentPos.y, PrinterInfo.rcMargins.left + nOffset + (int)(ColumnInfo.rgColumnWidths[nColumnCount] * (PrinterInfo.ptResolution.x * 0.01)), PageInfo.ptCurrentPos.y + nMaxRowHeight); if(ColumnInfo.nStyle & TOP_BORDER) { // Draw Top Border FDrawLine(ppPrinter.hDC, rc.left, rc.top, rc.right, rc.top); } if(ColumnInfo.nStyle & LEFT_BORDER) { // Draw Left Border FDrawLine(ppPrinter.hDC, rc.left, rc.top, rc.left, rc.bottom); } if(ColumnInfo.nStyle & RIGHT_BORDER) { // Draw Right Border FDrawLine(ppPrinter.hDC, rc.right, rc.top, rc.right, rc.bottom); } if(ColumnInfo.nStyle & BOTTOM_BORDER) { // Draw Bottom Border FDrawLine(ppPrinter.hDC, rc.left, rc.bottom, rc.right, rc.bottom); } rc.left += 1; // Get Text Within Borders rc.top += 1; rc.right -= 1; rc.bottom -= 1; CellDrawText(ppPrinter.hDC, (LPSTR)rgcpColText[nColumnCount], (LPRECT)&rc); } PageInfo.ptCurrentPos.y += nMaxRowHeight; GlobalUnlock(hText); GlobalFree(hText); return TRUE; } /************************************************************************* Ends column printing and does cleanup *************************************************************************/ int FAR PASCAL EndColumnPrinting(VOID) { SelectObject(ppPrinter.hDC, ColumnInfo.hOldFont); DeleteObject(ColumnInfo.hFont); return TRUE; } /************************************************************************* Calculates the Left Offset of the given column from the left edge of the first column *************************************************************************/ int GetColumnOffset(int nColumn) { int nOffset=0; int nTemp; if(nColumn == 0) return nOffset; for(nTemp=0; nTemp < nColumn; nTemp++) { nOffset += (int)(ColumnInfo.rgColumnWidths[nTemp] * (PrinterInfo.ptResolution.x * 0.01)); } return nOffset; } /************************************************************************* Prints Text on Physical page given logical co-ordinates *************************************************************************/ int CellDrawText(HDC hDC, LPSTR szText, LPRECT rc) { RECT rcTemp; rcTemp.top = rc->top - PrinterInfo.rcUnprintable.top; rcTemp.bottom = rc->bottom - PrinterInfo.rcUnprintable.top; rcTemp.left = rc->left - PrinterInfo.rcUnprintable.left; rcTemp.right = rc->right - PrinterInfo.rcUnprintable.left; DrawText(hDC, (LPSTR)szText, lstrlen((LPSTR)szText), (LPRECT)&rcTemp, DT_TOP | DT_WORDBREAK); return TRUE; } /************************************************************************* Internal function to retrieve the Device Context of the current Printer Driver *************************************************************************/ HDC GetPrinterDC(void) { static char szPrinter[80]; char *szDevice, *szDriver, *szOutput; GetProfileString("windows", "device",",,,",szPrinter, 80); if( (szDevice = strtok(szPrinter,"," )) && (szDriver = strtok(NULL, ", ")) && (szOutput = strtok(NULL, ", "))) { return CreateDC(szDriver, szDevice, szOutput, NULL); } return FALSE; } /************************************************************************* Unconditionally kills the current print job *************************************************************************/ BOOL FAR PASCAL KillJob(void) { fAbort = TRUE; return fAbort; } /************************************************************************* Returns the name of the current Printer *************************************************************************/ BOOL FAR PASCAL PrinterName(LPSTR szDevName) { DEVMODE FAR *lpDevmode; /* Initialize the necessary PRINTDLG structure members. */ ppPrinter.lStructSize = sizeof(PRINTDLG); ppPrinter.Flags = PD_RETURNDEFAULT; if(ppPrinter.hDevMode) { lpDevmode = (DEVMODE FAR *)GlobalLock(ppPrinter.hDevMode); lstrcpy(szDevName,(LPSTR)lpDevmode->dmDeviceName); GlobalUnlock(ppPrinter.hDevMode); return TRUE; } if (PrintDlg(&ppPrinter) != 0) { lpDevmode = (DEVMODE FAR *)GlobalLock(ppPrinter.hDevMode); lstrcpy(szDevName,(LPSTR)lpDevmode->dmDeviceName); GlobalUnlock(ppPrinter.hDevMode); return TRUE; } else { DoCommDlgError(hWndApp, CommDlgExtendedError()); return FALSE; } } /************************************************************************* Returns the port to which the current printer is connected *************************************************************************/ BOOL FAR PASCAL PrinterPort(LPSTR szPortName) { DEVNAMES FAR *lpDevnames; // Initialize the necessary PRINTDLG structure members. ppPrinter.lStructSize = sizeof(PRINTDLG); ppPrinter.Flags = PD_RETURNDEFAULT; if(ppPrinter.hDevNames) { lpDevnames = (DEVNAMES FAR *)GlobalLock(ppPrinter.hDevNames); lstrcpy(szPortName,(LPSTR)lpDevnames + lpDevnames->wOutputOffset); GlobalUnlock(ppPrinter.hDevNames); return TRUE; } if (PrintDlg(&ppPrinter) != 0) { lpDevnames = (DEVNAMES FAR *)GlobalLock(ppPrinter.hDevNames); lstrcpy(szPortName,(LPSTR)lpDevnames + lpDevnames->wOutputOffset); GlobalUnlock(ppPrinter.hDevNames); return TRUE; } else { DoCommDlgError(hWndApp, CommDlgExtendedError()); return FALSE; } } /************************************************************************* Returns TRUE if there are objects on the page, FALSE if the page is empty. *************************************************************************/ BOOL FAR PASCAL IsPageDirty(void) { return PageInfo.bPageDirty; } /************************************************************************* Returns the current Vertical cursor location in TWIPS *************************************************************************/ int FAR PASCAL PagePosY(void) { return ((PageInfo.ptCurrentPos.y/PrinterInfo.ptResolution.y)*72*20); } /************************************************************************* Returns the current Horizontal cursor location in TWIPS *************************************************************************/ int FAR PASCAL PagePosX(void) { return ((PageInfo.ptCurrentPos.x/PrinterInfo.ptResolution.x)*72*20); } /************************************************************************* Returns the vertical page size is TWIPS *************************************************************************/ int FAR PASCAL PageSizeY(void) { return ((PrinterInfo.ptPageSize.y/PrinterInfo.ptResolution.y)*72*20); } /************************************************************************* Returns the horizontal page size in TWIPS *************************************************************************/ int FAR PASCAL PageSizeX(void) { return ((PrinterInfo.ptPageSize.x/PrinterInfo.ptResolution.x)*72*20); } /************************************************************************* Exported Draw Line Function, takes it parameters in TWIPS *************************************************************************/ BOOL FAR PASCAL DrawLine(int nX1, int nY1, int nX2, int nY2) { nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20)); nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20)); nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20)); nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20)); return FDrawLine(ppPrinter.hDC, nX1, nY1, nX2, nY2); } /************************************************************************* Exported Draw Rectangle Function, takes it parameters in TWIPS *************************************************************************/ BOOL FAR PASCAL DrawRectangle(int nX1, int nY1, int nX2, int nY2) { nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20)); nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20)); nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20)); nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20)); return FDrawRectangle(ppPrinter.hDC, nX1, nY1, nX2, nY2); } /************************************************************************* Exported Draw Rounded Rectangle Function, takes it parameters in TWIPS *************************************************************************/ BOOL FAR PASCAL DrawRndRectangle(int nX1, int nY1, int nX2, int nY2, int nX3, int nY3) { nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20)); nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20)); nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20)); nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20)); nX3 = MulDiv(nX3, PrinterInfo.ptResolution.x, (72 * 20)); nY3 = MulDiv(nY3, PrinterInfo.ptResolution.y, (72 * 20)); return FDrawRndRectangle(ppPrinter.hDC, nX1, nY1, nX2, nY2, nX3, nY3); } /************************************************************************* Exported Draw Ellipse Function, takes it parameters in TWIPS *************************************************************************/ BOOL FAR PASCAL DrawEllipse(int nX1, int nY1, int nX2, int nY2) { nX1 = MulDiv(nX1, PrinterInfo.ptResolution.x, (72 * 20)); nY1 = MulDiv(nY1, PrinterInfo.ptResolution.y, (72 * 20)); nX2 = MulDiv(nX2, PrinterInfo.ptResolution.x, (72 * 20)); nY2 = MulDiv(nY2, PrinterInfo.ptResolution.y, (72 * 20)); return FDrawEllipse( ppPrinter.hDC, nX1, nY1, nX2, nY2); } /************************************************************************* Unconditionally moves the current cursor position in the Y direction, takes its parameters in 100th's of an inch. *************************************************************************/ BOOL FAR PASCAL MoveYPos(int nY) { PageInfo.ptCurrentPos.y += (int)((nY * PrinterInfo.ptResolution.y)/100); if(PageInfo.ptCurrentPos.y > (PrinterInfo.ptPageSize.y - PrinterInfo.rcMargins.top - PrinterInfo.rcMargins.bottom)) { EjectPage(); // Sets current positon too } return TRUE; } /************************************************************************* End of VBPRINT.DLL *************************************************************************/