/****************************************************************************
 *									   										*
 *  MODULE	: WVPRINT.C						   								*
 *									   										*
 *                  Jim Dumoulin  NASA/KSC                                  *
 *                                                                          *
 *                                                                          *
 *  PURPOSE	: Printing code for WinVN.                                 		*
 *																			*
 *  FUNCTIONS:	FreePrinterMemory () -		Frees all memory associated		*
 *											with a printer device context	*
 *																			*
 *				GetPrinterDC ()		-		Creates a printer DC for the	*
 *											default device.		   			*
 *									  										*
 *				DeletePrinterDC ()	-  		Deletes a printer DC for the 	*
 *											default device.		   			*
 *									   										*
 *				AbortProc ()		-  		Export proc. for GDI to check	*
 *											print abort.					*
 *																			*
 *				PrintDlgProc ()		-		Dialog function for the print	*
 *											cancel dialog.					*
 *																			*
 *				ReportPrintError ()	-		Decodes err codes for calls		*
 *											to Windows print functions		*
 *																			*
 *				PrintHeaderP ()		-		Determines if header string		*
 *											is one that gets printed		*
 *																			*
 *				PrintArticle ()		-  		Prints the contents of the		*
 *											an article window.				*
 ****************************************************************************/

/*
 * $Id: wvprint.c 1.34 1996/08/31 07:02:40 dumoulin Exp $
 */

#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"
#pragma hdrstop

static BOOL near PdlgAbort = FALSE;			/* TRUE if the user has aborted the print job	*/
HWND hwndPDlg = NULL;						/* Handle to the cancel print dialog			*/

          
/****************************************************************************
 *																			*          
 *  FUNCTION   : AbortProc()												*
 *																			*
 *  PURPOSE    : To be called by GDI print code to check for user abort.    *
 *               Returns TRUE to continue Printing, FALSE to cancel.        *
 *																			*
 ****************************************************************************/
#ifndef _WIN32
BOOL CALLBACK __export
#else
BOOL CALLBACK
#endif
AbortProc (HDC hdc, int nCode)
{
 MSG msg;
 char mes[40]; 

  // I give up getting this to work for this release so we won't have
  // print canceling.  This has been intermittent ever since WinVN
  // grew too big.  Major problems with the fact the CALLBACK functions
  // can't access any global variables in the LARGE model.    (JD 11/29/94)
  
  return TRUE;
  
  if ((nCode < 0) && (nCode != SP_OUTOFDISK)) {
 	sprintf (mes, "AbortProc Error %d", (int) nCode);
 	MessageBox (NULL, "Your Windows Print Driver CallBack \n procedure "
 				"returned an error", mes, MB_OK | MB_ICONEXCLAMATION);
 	return FALSE;
  }
  else  
 
	/* Allow other apps to run, or get abort messages */
  while (!PdlgAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)){
 	  if (!hwndPDlg || !IsDialogMessage (hwndPDlg, &msg)) {
 		TranslateMessage (&msg);
 		DispatchMessage (&msg);
 	  }
 	}

  if (PdlgAbort == TRUE)
 	return FALSE;
  else
 	return TRUE;
}

/****************************************************************************
 *																			*
 *  FUNCTION   : PrinterInit ()												*
 *																			*
 *  PURPOSE    : Initializes Global Variables used by the Printing Code.  	*
 *				 This function gets called once when WinVN starts up but	*
 *				 may be called again if a printer error occurs and a device	*
 *				 context is lost.											*
 *																			*
 *  RETURNS    : TRUE if successful, FALSE if not							*
 *																			*
 ****************************************************************************/
BOOL WINAPI 
PrinterInit (void)
{
  memset(&pd, 0, sizeof(pd));
  pd.lStructSize = (DWORD) sizeof (PRINTDLG);
  //(pd.hwndOwner omitted)
  //pd.hDevMode = NULL;
  //pd.hDevNames = NULL;
  //pd.hDC = (HDC) NULL;
  pd.Flags = PD_RETURNDC;
  //pd.nFromPage = 0;
  //pd.nToPage = 0;
  //pd.nMinPage = 0;
  //pd.nMaxPage = 0xFFFE;
  pd.nCopies = 1;
  //pd.hInstance = (HANDLE) NULL;
  //pd.lCustData = 0L;
  //pd.lpfnPrintHook = (UINT) NULL;
  //pd.lpfnSetupHook = (UINT) NULL;
  //pd.lpPrintTemplateName = (LPSTR) NULL;
  //pd.lpSetupTemplateName = (LPSTR) NULL;
  //pd.hPrintTemplate = (HANDLE) NULL;
  //pd.hSetupTemplate = (HANDLE) NULL;

  hFontPrint = NULL;
  hFontPrintB = NULL;
  hFontPrintI = NULL;
  hFontPrintS = NULL;

  return TRUE;
}

/****************************************************************************
 *																			*
 *  FUNCTION:	FreePrinterMemory ()										*
 *																			*
 *  PURPOSE	: 	Frees any memory structures allocated for the Printer		*
 *		 		Device context.	This is typically called once when WinVN	*
 *				exits but will also be called if a printer error occurs.	*
 *																			*
 *  RETURNS	: 	TRUE if successful else FALSE								*
 *																			*
 ****************************************************************************/
BOOL WINAPI 
FreePrinterMemory (void)
{
  BOOL success = TRUE;
  
  if (pd.hDevMode)
	success = (GlobalFree (pd.hDevMode) == NULL) ? TRUE : FALSE;
  if (pd.hDevNames)
	success = (GlobalFree (pd.hDevNames) == NULL) ? success : FALSE;
  if (pd.hDC)
	success = DeletePrinterDC (pd.hDC) ? success : FALSE;
  PrinterInit ();
  return success;
}

/****************************************************************************
 *																			*
 *  FUNCTION   : PrinterSetup ()											*
 *																			*
 *  PURPOSE    : Creates a printer display context for the default device.  *
 *																			*
 *  RETURNS    : Zero if successful, 1 = cancel, else Extended Error Code	*
 *																			*
 ****************************************************************************/
DWORD WINAPI 
PrinterSetup (HWND hwnd, DWORD flags)
{
  char mes[60];
  DWORD cError = 0;

  pd.hwndOwner = hwnd;
  pd.Flags = flags;

  if (pd.hDC != 0)
	DeletePrinterDC (pd.hDC);

  if (PrintDlg (&pd) == 0) {
	cError = CommDlgExtendedError ();
	if (cError != 0) {
	  sprintf (mes, "Comm Dialog Box Extended Error %d", (DWORD) cError);
	  MessageBox (hwnd, "WinVN was unable to either display a \n"
				  "Printer Device Context Dialog Box or \n"
				  "to get a Printer Device Context"
				  ,mes, MB_OK | MB_ICONEXCLAMATION);
	  FreePrinterMemory ();
	  return cError;
	}
	else
	  return 1;
  }
  else
	return 0;
}

/****************************************************************************
 *																			*
 *  FUNCTION:	GetPrinterDC ()												*
 *																			*
 *  PURPOSE:	Finds or creates a printer display context for the			*
 *				selected printer.											*
 *																			*
 *  RETURNS    : HDC - A handle to printer DC or Null if error				*
 *																			*
 ****************************************************************************/
HDC WINAPI 
GetPrinterDC (HWND hwnd)
{
  DWORD pError = 0;

  if (pd.hDC)
	return pd.hDC;
  else {
	if ((pd.hDevMode == NULL) && (pd.hDevNames == NULL))
	  pError = PrinterSetup (hwnd, PD_RETURNDC | PD_RETURNDEFAULT);
	else
	  pError = PrinterSetup (hwnd, PD_RETURNDC);

	if (pError > 0)
	  return NULL;
	else
	  return pd.hDC;
  }
}

/****************************************************************************
 *																			*
 *  FUNCTION   : DeletePrinterDC ()											*
 *																			*
 *  PURPOSE    : Releases a printer display context for the selected        *
 *               printer.                                                   *
 *																			*
 *  RETURNS    : TRUE if Successful, FALSE if Error                    	    *
 *																			*
 ****************************************************************************/

BOOL WINAPI 
DeletePrinterDC (HDC hDC)
{
  BOOL success = TRUE;

  if (pd.hDC != hDC)
	success = DeleteDC (pd.hDC);

  success = DeleteDC (hDC) ? success : FALSE;
  pd.hDC = NULL;
  return success;
}


/****************************************************************************
 *																			*
 *  FUNCTION   : PrintDlgProc ()											*
 *																			*
 *  PURPOSE    : Dialog function for the print cancel dialog box.			*
 *																			*
 *  RETURNS    : TRUE  - OK to abort/ not OK to abort						*
 *				 FALSE - otherwise.											*
 *																			*
 ****************************************************************************/
LRESULT CALLBACK 
PrintDlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg) {
  case WM_INITDIALOG:
	hwndPDlg = hwnd;
	ShowWindow (hwnd, SW_SHOW);
	break;

  case WM_COMMAND:				/* abort printing if the cancel button gets hit */
	switch (LOWORD (wParam)) {
	case ID_OK:
	case ID_CANCEL:

	  PdlgAbort = TRUE;
	  EnableWindow (GetParent (hwnd), TRUE);
	  if (hwndPDlg){
		DestroyWindow (hwndPDlg);	/* Delete Cancel Dialog */
	  	hwndPDlg = NULL;
	  	}
	  return TRUE;
	}
	break;
  }
  return FALSE;
}

/****************************************************************************
 *																			*
 *  FUNCTION   : ReportPrintError ()										*
 *																			*
 *  PURPOSE    : Decodes error codes from calls to Windows Print functions  *
 *																			*
 *  RETURNS    : NULL  - No errors or Error has already been reported       *
 *		 		 short - Error code numbers (from Windows.H)				*
 *																			*
 ****************************************************************************/

void WINAPI 
ReportPrintError (int nError, HWND hWnd)
{
  char mes[60];
  char*msg;

  if (nError >= 0)
    return;

  if ((nError & SP_NOTREPORTED) == 0)
    return;

  switch (nError) {
  case SP_ERROR:
    strcpy(mes, "General Printing Error");
    msg = "The Windows Printer Device driver \n"
          "cannot begin printing your document. \n"
          "Your printer may be off line or out of \n"
          "paper.  It is also possible that the \n"
          "Windows Print Manager isn't loaded and \n"
          "another program is currently printing";
    break;

  case SP_APPABORT:
    strcpy(mes, "Print Canceled by Application");
    msg = "Your Print request has been canceled \n"
          "via an Abort request from your application";
    break;

  case SP_USERABORT:
    strcpy(mes, "Print Canceled by User");
    msg = "Your Print request has been canceled \n"
          "via a User cancel request from the \n"
          "Windows Print Manager";
    break;

  case SP_OUTOFDISK:
    strcpy(mes, "Out of Disk Space");
    msg = "Your Print request has been aborted \n"
          "due to insufficient disk space in your \n"
          "Windows TEMP subdirectory";
    break;

  case SP_OUTOFMEMORY:
    strcpy(mes, "Out of Memory Space");
    msg = "Your Print request has been aborted \n"
          "due to insufficient Windows memory.\n"
          "Close some applications and try again";
    break;

  default:
    sprintf (mes, "Unknown Print Error %d", (int) nError);
    msg = "Your Print request has been aborted due to \n"
          "the Windows Print function returning an error \n"
          "code that is undocumented";
    break;

  }
  MessageBox (hWnd, msg, mes, MB_OK | MB_ICONEXCLAMATION);
  return;
}


/****************************************************************************
 *																			*
 *  FUNCTION   : PrintHeaderP ()											*
 *																			*
 *  PURPOSE    : Determines if this is a header we are printing				*
 *																			*
 *        Entry:  str    substring to search                                *
 *                limit  limits the search to no more than num characters   *
 *                                                                          *
 *        Exit:   BOOL   TRUE if we are not excluding print this header     *
 *                       FALSE if we are explicited excluding header        *
 *																			*
 ****************************************************************************/

BOOL WINAPI 
PrintHeaderP (char *str, int limit)
{
  if (_strnicmp (str, "Relay-Version:", limit) == 0 
  	  || _strnicmp (str, "Path:", limit) == 0
	  || _strnicmp (str, "References:", limit) == 0
	  || _strnicmp (str, "NNTP-Posting-Host:", limit) == 0
	  || _strnicmp (str, "Mime-Version:", limit) == 0
	  || _strnicmp (str, "Content-Type:", limit) == 0
	  || _strnicmp (str, "X-Newsreader:", limit) == 0
	  || _strnicmp (str, "X-XXMessage-ID:", limit) == 0
	  || _strnicmp (str, "X-XXDate:", limit) == 0
	  || _strnicmp (str, "Xref:", limit) == 0)
	return (FALSE);
  else
	return (TRUE);
}


/****************************************************************************
 *																			*
 *  FUNCTION   : PrintFile ()												*
 *																			*
 *  PURPOSE    : Prints the contents of the edit control.					*
 *																			*
 ****************************************************************************/

void WINAPI 
PrintFile (HWND hwnd)
{
  MessageBox (hwnd, "Function Removed for Now", "Error", MB_OK);
  return;
}

/****************************************************************************
 *																			*
 *  FUNCTION   : PrintArticle ()											*
 *																			*
 *  PURPOSE    : Prints the current article.								*
 *																			*
 ****************************************************************************/

#define LEFTMARGIN 6			/* Left Margin in characters on printed page */
#define TOPMARGIN 4				/* Top Margin in characters on printed page */
#define BOTTOMMARGIN 6			/* Bottom Margin in characters on printed page */
#define MAXHEADERSIZE 20		/* Largest number of chars allowed in a header name */

void WINAPI 
PrintArticle (HWND hwnd, TypDoc * Doc)
{
  char sz[100];
  char szTitle[MAXHEADERLINE];
  char mybuf[MAXINTERNALLINE];
  DOCINFO di;
  BOOL found;
  BOOL inheader = TRUE;
  BOOL ROT13Mode = GetArticleRot13Mode (Doc->hWndFrame);
  int i, dy, dx, yExtPage, yExtSoFar, nPrintError, x;
  unsigned int LineLen, Offset, nTotalPages, PageNum, iLine, nCharsPerLine,
    nLinesPerPage, nTotalLines;
  char far *textptr;
  char *loc;
  DWORD cError = 0;
  TypBlock far *BlockPtr;
  TypLine far *LinePtr;
  HANDLE hBlock;
  TypLineID MyLineID;
  TEXTMETRIC tm;
  DEVNAMES *dv;
  ABORTPROC lpfnAbortProc = NULL;
  DLGPROC lpfnPrintDlgProc = NULL;
  TextSelect FAR *Start, *End;

  /* Create the job title */
  memset(&di, 0, sizeof(di));
  di.cbSize = sizeof (di);
  di.lpszDocName = "WinVn Article";
  di.lpszOutput = NULL;

  /* Initialize the printer */
  nPrintError = 0;
  hwndPDlg = NULL;
  PdlgAbort = FALSE;
  cError = PrinterSetup (hwnd, PD_RETURNDC | PD_USEDEVMODECOPIES);
  if ((cError != 0) || (pd.hDC == 0))
	goto exitout;

  /* Reinitialize Fonts just in case the user changed printers on us */
  InitPrintFonts ();

  /*  Create the Cancel dialog and Disable the main application window */
  lpfnPrintDlgProc = (DLGPROC) MakeProcInstance ((FARPROC) PrintDlgProc, (HINSTANCE) hInst);
  if (!lpfnPrintDlgProc)
	goto exitout;
  hwndPDlg = CreateDialog ((HINSTANCE) hInst, (LPCSTR) "PRINTDIALOG", hwnd, (DLGPROC) lpfnPrintDlgProc);
  if (!hwndPDlg)
	goto exitout;

  /* Allow the app. to inform GDI of the Abort function to call */
  lpfnAbortProc = (ABORTPROC) MakeProcInstance ((FARPROC) AbortProc, (HINSTANCE) hInst);
  if (!lpfnAbortProc)
	goto exitout;

  EnableWindow (hwnd, FALSE);
  if (SetAbortProc (pd.hDC, (ABORTPROC) lpfnAbortProc) < 0) {
	MessageBox (hwnd, "Unable to Set Abort Procedure",
				"Error", MB_OK | MB_ICONEXCLAMATION);
	nPrintError = 0;			/* don't print double error messages */
	goto exitout;
  }

  /* Get the Subject, printer description and Port number */
  found = GetHeaderLine (Doc, "Subject:", szTitle, sizeof (szTitle));
  if (!found) lstrcpy (szTitle, "Subject: No Subject");
  
  SetDlgItemText ((HWND) hwndPDlg, IDD_PRINTSUBJECT, (LPSTR) szTitle);
  dv = (DEVNAMES *) GlobalLock (pd.hDevNames);
  // sprintf (sz, "To %s on %s", (LPSTR) dv + dv->wDeviceOffset, (LPSTR) dv + dv->wOutputOffset);
  strcpy(mybuf,(LPSTR) dv + dv->wDeviceOffset);   //Heirich 19960829
  if (strncmp(mybuf,"\\\\",2))
      sprintf (sz, "To %s on %s",mybuf, (LPSTR) dv + dv->wOutputOffset);
  else
      sprintf (sz, "To %s (remote)",mybuf);   

  

  SetDlgItemText ((HWND) hwndPDlg, IDD_PRINTDEVICE, (LPSTR) sz);
  GlobalUnlock (pd.hDevNames);
  sprintf (sz, "Initializing Document for Printing");
  SetDlgItemText ((HWND) hwndPDlg, IDD_PRINTSTATUS, (LPSTR) sz);

  /*  Initialize the Printer Device Context */
  nPrintError = StartDoc (pd.hDC, &di);
  if (hwndPDlg) {
	UpdateWindow (hwndPDlg);	/* print to file may overwrite dialog */
	SetFocus (hwndPDlg);
  }
  if (nPrintError < 0)
	goto exitout;

  LockLine (Doc->hFirstBlock, sizeof (TypBlock), (TypLineID) 0L,
			&BlockPtr, &LinePtr);

  /* Get the lines in document and and a handle to the text buffer */
  iLine = 0;
  PageNum = 1;
  nTotalLines = Doc->TotalLines;
  
  // Prepare data structure if we are going to be printing selected text
  // Check to see if selected text was top-to-bottom or bottom-to-top
  if (((pd.Flags & PD_SELECTION) == 1) && (Doc->TextSelected)) {
    if ((Doc->EndSelect.LineNum > Doc->BeginSelect.LineNum) ||
  	    ((Doc->EndSelect.LineNum == Doc->BeginSelect.LineNum) &&
	     (Doc->EndSelect.CharNum >= Doc->BeginSelect.CharNum))) {
	  Start = &Doc->BeginSelect;
	  End = &Doc->EndSelect;
	}
	else {
	  Start = &Doc->EndSelect;
	  End = &Doc->BeginSelect;
	}
  }

  /* Get the height of one line and the height of a page */
  SelectObject (pd.hDC, hFontPrint);	/* Select Printer Font */
  GetTextMetrics (pd.hDC, &tm);
  dy = tm.tmHeight + tm.tmExternalLeading;
  dx = tm.tmAveCharWidth;
  nCharsPerLine = GetDeviceCaps (pd.hDC, HORZRES) / dx;
  nLinesPerPage = GetDeviceCaps (pd.hDC, VERTRES) / dy;
  nTotalPages = (nTotalLines + BOTTOMMARGIN + TOPMARGIN) / nLinesPerPage;
  if (nTotalPages < 1)
	nTotalPages = 1;
  yExtPage = GetDeviceCaps (pd.hDC, VERTRES);
  nPrintError = StartPage (pd.hDC);
  if (nPrintError <= 0)
	goto abortout;

  /* If we are printing the First Page, place the Subject line at the Top */
  if ((((pd.Flags & PD_PAGENUMS) == 0) && ((pd.Flags & PD_SELECTION) == 0)) ||
	  (pd.nFromPage == 0) ||
	  (pd.nFromPage == 1)) {
	sprintf (sz, "Now Printing Page %u of %u", PageNum, nTotalPages);
	SetDlgItemText (hwndPDlg, IDD_PRINTSTATUS, (LPSTR) sz);
	SelectObject (pd.hDC, hFontPrintS);		/* Select Printer Font */
	if ((pd.Flags & PD_SELECTION) == 0){
	  TextOut (pd.hDC, LEFTMARGIN * dx, TOPMARGIN * dy, szTitle, lstrlen (szTitle));
	  }
	else 
	 {
	  sprintf (sz, "Selected Text from ");
	  strncat (sz, szTitle, MAXINTERNALLINE - strlen (sz) - 1);
	  TextOut (pd.hDC, LEFTMARGIN * dx, TOPMARGIN * dy, sz, lstrlen (sz));
	  }
	yExtSoFar = (int) dy *(TOPMARGIN + 4);
  }

  /* Print out text until no more lines or user aborts */
  while ((iLine < nTotalLines) && !PdlgAbort) {
	if ((yExtSoFar + (BOTTOMMARGIN + 1) * dy) >= yExtPage) {
	  /* Reached the end of a page, print Page number */
	  if ((((pd.Flags & PD_PAGENUMS) == 0) &&
		   ((pd.Flags & PD_SELECTION) == 0)) ||	      
	      (((pd.Flags & PD_SELECTION) == 0) && 
	       ((pd.nFromPage == 0) || (PageNum >= pd.nFromPage)) &&
		   ((pd.nToPage == 0) || (PageNum <= pd.nToPage)))  ||
		  (((pd.Flags & PD_SELECTION) == 1) && 
		   (Doc->TextSelected) &&
		   (iLine >= (UINT) Start->LineNum) &&
		   (iLine <= (UINT) End->LineNum))) {
		SelectObject (pd.hDC, hFontPrintB);
		sprintf (sz, "Page %u   ", PageNum);
		if (PageNum > 1) {
		  strncat (sz, szTitle, MAXINTERNALLINE - strlen (sz) - 1);
		  x = dx * LEFTMARGIN;	/* left justified for pages > 1 */
		}
		else {
		  x = (nCharsPerLine / 2) * dx;	/* centered for page 1 */
		}
		TextOut (pd.hDC, x, yExtSoFar + (2 * dy), sz, lstrlen (sz));

		/* Tell device driver to eject page */
		if (PageNum > nTotalPages)
		  nTotalPages = PageNum;
		sprintf (sz, "Now Printing Page %u of %u", PageNum, nTotalPages);
		SetDlgItemText (hwndPDlg, IDD_PRINTSTATUS, (LPSTR) sz);
		nPrintError = EndPage (pd.hDC);
		if ((nPrintError < 0) || PdlgAbort)
		  break;
		nPrintError = StartPage (pd.hDC);
		if ((nPrintError < 0) || PdlgAbort)
		  break;
	  }

	  yExtSoFar = dy * TOPMARGIN;
	  PageNum++;
	}

	/* Print the line and unlock the text handle */
	if (LinePtr->length != END_OF_BLOCK) {
	  textptr = GetTextPtr(LinePtr);
	  LineLen = lstrlen (textptr);
	  if (IsBlankStr (textptr))
		inheader = FALSE;

	  if ((((pd.Flags & PD_PAGENUMS) == 0) &&
		   ((pd.Flags & PD_SELECTION) == 0)) ||		  
		  (((pd.Flags & PD_SELECTION) == 0) && 
		   ((pd.nFromPage == 0) || (PageNum >= pd.nFromPage)) &&
		   ((pd.nToPage == 0) || (PageNum <= pd.nToPage))) ||
		  ((pd.Flags & PD_SELECTION) == 1) && 
		  Doc->TextSelected &&
		  (iLine >= (UINT) Start->LineNum) &&
		  (iLine <= (UINT) End->LineNum)) {
		if (inheader) {
		  loc = memchr (textptr, ':', MAXHEADERSIZE);
		  if (loc) {
			i = loc - textptr + 1;
			if (PrintHeaderP (textptr, i)) {
			  SelectObject (pd.hDC, hFontPrintB);
			  TextOut (pd.hDC, (LEFTMARGIN * dx), yExtSoFar, textptr, i);
			  SelectObject (pd.hDC, hFontPrint);
			  TextOut (pd.hDC, (LEFTMARGIN + MAXHEADERSIZE + 2) * dx,
					   yExtSoFar, textptr + i, LineLen - i);
			}
		  }
		  else {
			SelectObject (pd.hDC, hFontPrint);
			TextOut (pd.hDC, (LEFTMARGIN + MAXHEADERSIZE + 2) * dx,
					 yExtSoFar, textptr, LineLen);
		  }
		}
		else {		
		  if (ROT13Mode) {
			strcpy (mybuf, textptr);
			textptr = mybuf;
			strROT13 (textptr);
		  }
		  if (isLineQuotation (textptr))
			SelectObject (pd.hDC, hFontPrintI);
		  else
			SelectObject (pd.hDC, hFontPrint);

		  TextOut (pd.hDC, (LEFTMARGIN * dx), yExtSoFar, textptr, LineLen);
		}
		yExtSoFar += dy;	
	  }

	NextLine (&BlockPtr, &LinePtr);
  }

	/* Move down the page */
	iLine++;
  }   /* End While */

abortout:

  UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  if (!PdlgAbort && (nPrintError >= 0)) {
	/* Eject the last page. */
	if ((((pd.Flags & PD_PAGENUMS) == 0) &&
		 ((pd.Flags & PD_SELECTION) == 0)) || 
		(((pd.nFromPage == 0) || (PageNum >= pd.nFromPage)) &&
		 ((pd.nToPage == 0) || (PageNum <= pd.nToPage))) ||
		(((pd.Flags & PD_SELECTION) == 1) && 
		 (Doc->TextSelected) &&
		 (iLine >= (UINT) Start->LineNum) &&
		 (iLine <= (UINT) End->LineNum))) {
	  SelectObject (pd.hDC, hFontPrintB);
	  sprintf (sz, "Page %u   ", PageNum);
	  if (PageNum > 1) {
		strncat (sz, szTitle, MAXINTERNALLINE - strlen (sz) - 1);
		x = dx * LEFTMARGIN;	/* left justified for pages > 1 */
	  }
	  else {
		x = (nCharsPerLine / 2) * dx; /* centered for page 1 */
	  }
	  TextOut (pd.hDC, x, yExtPage - (BOTTOMMARGIN * dy), sz, lstrlen (sz));
	  nPrintError = EndPage (pd.hDC);
	}

	/* Complete the document. */
	if (!PdlgAbort && (nPrintError >= 0))
	  nPrintError = EndDoc (pd.hDC);
  }

exitout:

  if (PdlgAbort) {
	if (pd.hDC){
	  AbortDoc (pd.hDC);
	  DeletePrinterDC(pd.hDC);
	  }
	MessageBox (hwnd, "Print Request Canceled",
				"Canceled", MB_OK | MB_ICONEXCLAMATION);
  }
  else if (nPrintError < 0){
	  ReportPrintError (nPrintError, hwnd);
	  }
	  
  EnableWindow (hwnd, TRUE);	/* ReEnable main procedure */
  if (hwndPDlg)
	{
	  DestroyWindow ((HWND) hwndPDlg);	/* Delete Cancel Dialog */
	  PdlgAbort = FALSE;
	  hwndPDlg = NULL;
	}

  if (lpfnPrintDlgProc) FreeProcInstance ((FARPROC) lpfnPrintDlgProc);
  if (lpfnAbortProc) FreeProcInstance ((FARPROC) lpfnAbortProc);

  return;
}

/* 
 * Local Variables:
 * tab-width: 4
 * end:
 */
