/***************************************************************************
 *									   *
 *  MODULE	: MpPrint()						   *
 *									   *
 *  PURPOSE	: Printing code for MultiPad.				   *
 *									   *
 *  FUNCTIONS	: GetPrinterDC ()	   -  Creates a printer DC for the *
 *					      default device.		   *
 *									   *
 *		  AbortProc ()		   -  Export proc. for GDI to check*
 *					      print abort.		   *
 *									   *
 *		  PrintDlgProc ()	   -  Dialog function for the print*
 *					      cancel dialog.		   *
 *									   *
 *		  PrintFile ()		   -  Prints the contents of the   *
 *					      edit control.		   *
 *									   *
 *		  GetInitializationData () -  Gets DC initialisation data  *
 *					      from a DC supporting	   *
 *					      ExtDeviceMode().		   *
 *									   *
 ***************************************************************************/
// COPYRIGHT:
//
//   (C) Copyright Microsoft Corp. 1992.  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 "multipad.h"
#include "commdlg.h"

PRINTDLG pd;      /* Common print dialog structure */
BOOL fAbort;		/* TRUE if the user has aborted the print job	 */
HWND hwndPDlg;		/* Handle to the cancel print dialog		 */
PSTR szTitle;		/* Global pointer to job title			 */
HANDLE hInitData=NULL;	/* handle to initialization data		 */


/****************************************************************************
 *									    *
 *  FUNCTION   : GetPrinterDC ()					    *
 *									    *
 *  PURPOSE    : Creates a printer display context for the printer  *
 *									    *
 *  RETURNS    : HDC   - A handle to printer DC.			    *
 *									    *
 ****************************************************************************/
HDC FAR PASCAL GetPrinterDC(void)
{

    HDC         hDC;
    LPDEVMODE   lpDevMode = NULL;
    LPDEVNAMES  lpDevNames;
    LPSTR       lpszDriverName;
    LPSTR       lpszDeviceName;
    LPSTR       lpszPortName;

    if (!PrintDlg((LPPRINTDLG)&pd))
        return(NULL);

    if (pd.hDC)
      {
        hDC = pd.hDC;
      }
    else
      {

        if (!pd.hDevNames)
            return(NULL);

        lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
        lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;
        lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;
        lpszPortName   = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;
        GlobalUnlock(pd.hDevNames);

        if (pd.hDevMode)
            lpDevMode = (LPDEVMODE)GlobalLock(pd.hDevMode);

        hDC = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, (LPSTR)lpDevMode);

        if (pd.hDevMode && lpDevMode)
            GlobalUnlock(pd.hDevMode);
      }

    if (pd.hDevNames)
        GlobalFree(pd.hDevNames);
    if (pd.hDevMode)
        GlobalFree(pd.hDevMode);
    return(hDC);
}


/****************************************************************************
 *									    *
 *  FUNCTION   : AbortProc()						    *
 *									    *
 *  PURPOSE    : To be called by GDI print code to check for user abort.    *
 *									    *
 ****************************************************************************/
int FAR PASCAL AbortProc ( hdc, reserved )
HDC hdc;
WORD reserved;
{
    MSG msg;

    /* Allow other apps to run, or get abort messages */
    while (!fAbort && PeekMessage (&msg, NULL, NULL, NULL, TRUE))
	if (!hwndPDlg || !IsDialogMessage (hwndPDlg, &msg)){
	    TranslateMessage (&msg);
	    DispatchMessage  (&msg);
	}
    return !fAbort;
}

/****************************************************************************
 *									    *
 *  FUNCTION   : PrintDlgProc ()					    *
 *									    *
 *  PURPOSE    : Dialog function for the print cancel dialog box.	    *
 *									    *
 *  RETURNS    : TRUE  - OK to abort/ not OK to abort			    *
 *		 FALSE - otherwise.					    *
 *									    *
 ****************************************************************************/
BOOL FAR PASCAL PrintDlgProc(HWND hwnd, WORD msg, WORD wParam, LONG lParam)
{
   switch (msg){
   	case WM_COMMAND:
	       /* abort printing if the only button gets hit */
	       fAbort = TRUE;
	       break;

	default:
	    return FALSE;
    }
    return TRUE;
}

/****************************************************************************
 *									    *
 *  FUNCTION   : PrintFile ()						    *
 *									    *
 *  PURPOSE    : Prints the contents of the edit control.		    *
 *									    *
 ****************************************************************************/

VOID FAR PASCAL PrintFile(HWND hwnd)
{
    HDC     hdc;
    int     yExtPage;
    char    sz[32];
    WORD    cch;
    WORD    ich;
    PSTR    pch;
    WORD    iLine;
    WORD    nLinesEc;
    HANDLE  hT;
    FARPROC lpfnAbort;
    FARPROC lpfnPDlg;
    HWND    hwndPDlg;
    WORD    dy;
    int     yExtSoFar;
    WORD    fError = TRUE;
    HWND    hwndEdit;

    hwndEdit = (HWND)GetWindowWord(hwnd,GWW_HWNDEDIT);

    /* Create the job title by loading the title string from STRINGTABLE */
    cch = LoadString (hInst, IDS_PRINTJOB, sz, sizeof(sz));
    szTitle = sz + cch;
    cch += GetWindowText (hwnd, sz + cch, 32 - cch);
    sz[31] = 0;

    /* Make instances of the Abort proc. and the Print dialog function */
    lpfnAbort = MakeProcInstance (AbortProc, hInst);
    if (!lpfnAbort)
	goto getout;
    lpfnPDlg = MakeProcInstance (PrintDlgProc, hInst);
    if (!lpfnPDlg)
	goto getout4;

    /* Initialize the printer */
    hdc = GetPrinterDC();
    if (!hdc)
	goto getout5;

    /* Disable the main application window and create the Cancel dialog */
    EnableWindow (hwndFrame, FALSE);
    hwndPDlg = CreateDialog (hInst, IDD_PRINT, hwnd, lpfnPDlg);
    if (!hwndPDlg)
	goto getout3;
    ShowWindow (hwndPDlg, SW_SHOW);
    UpdateWindow (hwndPDlg);

    /* Allow the app. to inform GDI of the escape function to call */
    if (Escape (hdc, SETABORTPROC, 0, (LPSTR)lpfnAbort, NULL) < 0)
	goto getout1;

    /* Initialize the document */
    if (Escape (hdc, STARTDOC, cch, (LPSTR)sz, NULL) < 0)
	goto getout1;

    /* Get the height of one line and the height of a page */
    dy = HIWORD (GetTextExtent (hdc, "CC", 2));
    yExtPage = GetDeviceCaps (hdc, VERTRES);

    /* Get the lines in document and and a handle to the text buffer */
    iLine     = 0;
    yExtSoFar = 0;
    nLinesEc  = (WORD)SendMessage (hwndEdit, EM_GETLINECOUNT, 0, 0L);
    hT	      = (HANDLE)SendMessage (hwndEdit, EM_GETHANDLE, 0, 0L);

    /* While more lines print out the text */
    while (iLine < nLinesEc){
	if (yExtSoFar + (int)dy > yExtPage){
	    /* Reached the end of a page. Tell the device driver to eject a
	     * page
	     */
	    if (Escape (hdc, NEWFRAME, 0, NULL, NULL) < 0 || fAbort)
		goto getout2;
	    yExtSoFar = 0;
	}

	/* Get the length and position of the line in the buffer
	 * and lock from that offset into the buffer */
	ich = (WORD)SendMessage (hwndEdit, EM_LINEINDEX, iLine, 0L);
	cch = (WORD)SendMessage (hwndEdit, EM_LINELENGTH, ich, 0L);
	pch = LocalLock(hT) + ich;

	/* Print the line and unlock the text handle */
	TextOut (hdc, 0, yExtSoFar, (LPSTR)pch, cch);
	LocalUnlock (hT);

	/* Test and see if the Abort flag has been set. If yes, exit. */
	if (fAbort)
	    goto getout2;

	/* Move down the page */
	yExtSoFar += dy;
	iLine++;
    }

    /* 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;

getout3:
    /* Close the cancel dialog and re-enable main app. window */
    EnableWindow (hwndFrame, TRUE);
    DestroyWindow (hwndPDlg);

getout1:
    DeleteDC(hdc);

getout5:
    /* Get rid of dialog procedure instances */
    FreeProcInstance (lpfnPDlg);

getout4:
    FreeProcInstance (lpfnAbort);

getout:

    /* Error? make sure the user knows... */
    if (fError)
	MPError (hwnd, MB_OK | MB_ICONEXCLAMATION, IDS_PRINTERROR, (LPSTR)szTitle);

    return;
}

#if 0

/****************************************************************************
 *									    *
 *  FUNCTION   : GetInitializationData()				    *
 *									    *
 *  PURPOSE    : Gets DC initialization data from a printer driver	    *
 *		 supporting ExtDeviceMode(). Called in response to the	    *
 *		 File/Printer setup menu selection.			    *
 *									    *
 *		 This function allows the user to change the printer	    *
 *		 settings FOR MULTIPAD ONLY.  This allows Multipad to print *
 *		 in a variety of settings without messing up any other	    *
 *		 applications. In a more sophisticated application, this    *
 *		 setup could even be saved on a document-by-document basis. *
 *									    *
 ****************************************************************************/
BOOL FAR PASCAL GetInitializationData( hwnd )
HWND hwnd ;
{
    LPSTR     lpOld;
    LPSTR     lpNew;
    FARPROC   lpfn;
    HANDLE    hT,hDrv;
    char      sz[32];
    WORD      cb;
    int       flag;

    /* Pop up dialog for user and retain data in app buffer */
    flag = DM_PROMPT | DM_COPY;

    /* Load the device driver and find the ExtDeviceMode() function */
    wsprintf (sz, "%s.drv", (LPSTR)szDriver);
    if ((hDrv = LoadLibrary (sz)) < 32)
	return FALSE;
    if (!(lpfn = GetProcAddress (hDrv, szExtDeviceMode)))
	return FALSE;

    if (hInitData){
	/* We have some old data... we want to modify the previously specified
	 * setup rather than starting with the default setup.
	 */
	lpOld = (LPSTR)LocalLock(hInitData);
	flag |= DM_MODIFY;
    }
    else
	lpOld = NULL;

    /* Get the number of bytes needed for the init data */
    cb = (*lpfn) (hwnd,
		  hDrv,
		  NULL,
		  (LPSTR)szDevice,
		  (LPSTR)szPort,
		  (LPDEVMODE)NULL,
		  (LPSTR)NULL,
		  0);

    /* Grab some memory for the new data and lock it. */
    hT	  = LocalAlloc (LHND,cb);
    lpNew = (LPSTR)LocalLock (hT);

    /* Post the device mode dialog. 0 flag iff user hits OK button */
    if ((*lpfn) (hwnd,
		 hDrv,
		 (LPDEVMODE)lpNew,
		 (LPSTR)szDevice,
		 (LPSTR)szPort,
		 (LPDEVMODE)lpOld,
		 (LPSTR)NULL,
		 flag)==IDOK)
	flag = 0;

    /* Unlock the input structures */
    LocalUnlock (hT);
    if (hInitData)
	LocalUnlock (hInitData);

    /* If the user hit OK and everything worked, free the original init.
     * data and retain the new one.  Otherwise, toss the new buffer.
     */
    if (flag)
	LocalFree (hT);
    else{
	if (hInitData)
	    LocalFree (hInitData);
	hInitData = hT;
    }

    FreeLibrary(hDrv);
    return (!flag);
}


#endif

