/* FILE: spool.c */

#include "spool.h"
#include <print.h>
#include <commdlg.h>
#include <string.h>

// Play with this number
#define BUFSIZE 2048

// Convenient structure for use with PASSTHROUGH escape
typedef struct
{
  WORD wSize;
  BYTE bData[2];                  // placeholder
} PASSTHROUGHSTRUCT, FAR *LPPTS;


BOOL bAbort;        // Global printing abort flag


//*************************************************************
//
//  _PrintFile()
//
//  Purpose:
//          Reads a file and copies it to a printer using the
//          PASSTHROUGH escape.
//
//  Parameters:
//      LPSTR   szFile    - Pointer to path/filename to print
//      HDC     hPrnDC    - Handle to printer DC or NULL
//      HGLOBAL hDevNames - Handle to DEVNAMES struct or NULL
//      HGLOBAL hDevMode  - Handle to DEVMODE struct or NULL
//
//  Return:
//      Returns nonzero for success or zero for failure.
//
//  Comments:
//      hDevNames and hDevMode are only used if hPrnDC is NULL.
//      If both hPrnDC and hDevNames are NULL, the default
//      printer is used.
//
//  History:    Date       Author     Comment
//              6/03/93    JMS        Created
//
//*************************************************************

BOOL FAR PASCAL __export _PrintFile ( LPSTR   szFile,
                                      HDC     hPrnDC,
                                      HGLOBAL hDevNames,
                                      HGLOBAL hDevMode )
{
  int iEsc;
  BOOL bLocalDC = TRUE; // Assume we must create a DC (hPrnDC == NULL)

  bAbort = FALSE;       // Haven't aborted yet


  // Make sure we have a printer DC

  if (!hPrnDC)
    hPrnDC = GetPrinterDC(hDevNames, hDevMode);
  else
    bLocalDC = FALSE;   // Use passed in hPrnDC

  if (!hPrnDC)
    return FALSE;


  // PASSTHROUGH is required. If driver doesn't support it, bail out.

  iEsc = PASSTHROUGH;
  if (!Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL))
    {                         
      bAbort = TRUE;
      goto MSFCleanUp;
    }

  // If we created the DC, install an abort procedure. We don't have
  // a Cancel dialog box, but the abort proc enables multitasking.
  // (Use __export and compile with -GA or -GD so we don't need
  // a MakeProcInstance.)

  if (bLocalDC)
    Escape (hPrnDC, SETABORTPROC, 0, (LPSTR) PrintAbortProc, NULL);

  // Call EPSPRINTING if it is supported (that is, if we're on a
  // PostScript printer) to suppress downloading the pscript header.

  iEsc = EPSPRINTING;
  if (Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL))
    {
    iEsc = 1;  // 1 == enable PASSTHROUGH (disable pscript header)
    Escape(hPrnDC, EPSPRINTING, sizeof(int), (LPSTR)&iEsc, NULL);
    }

  SendFile(hPrnDC, szFile); // Send file to printer (could do multiple
                            // files)

MSFCleanUp:                 // Done

  if (bLocalDC)             // Only delete DC if we created it
    DeleteDC(hPrnDC);

  return !bAbort;

} /* _PrintFile() */


BOOL FAR PASCAL __export PrintFile(LPSTR   szFile)
{
  return _PrintFile(szFile, NULL, NULL, NULL);
}

VOID SendFile(HDC hPrnDC, LPSTR szFile)
{        
  HGLOBAL HMem;
  LPPTS lpPTS;          // Pointer to PASSTHROUGHSTRUCT
  OFSTRUCT ofs;
  HFILE hFile;
  
  HMem = GlobalAlloc(GPTR, sizeof(WORD) + BUFSIZE);
  if (HMem == NULL)
  {
    bAbort = TRUE;
    return;
  }
  lpPTS = (LPPTS)GlobalLock(HMem);
  if (lpPTS == NULL)
  {
    bAbort = TRUE;
    GlobalFree(HMem);
    return;
  }

  hFile = OpenFile((LPSTR) szFile, &ofs, OF_READ);
  if (hFile == HFILE_ERROR)
    {
    bAbort = TRUE;  // Can't open file|
    GlobalUnlock(HMem);
    GlobalFree(HMem);
    return;
    }

  Escape (hPrnDC, STARTDOC, 0, "", NULL);

  // Loop through the file, reading a chunk at a time and passing
  // it to the printer. QueryAbort calls the abort procedure, which
  // processes messages so we don't tie up the whole system.
  // We could skip the QueryAbort, in which case we wouldn't need
  // to set an abort proc at all.

  do {
    if ((lpPTS->wSize=_lread(hFile, lpPTS->bData, BUFSIZE)) == HFILE_ERROR)
      {
      bAbort = TRUE;  // error reading file
      break;
      }

    Escape(hPrnDC, PASSTHROUGH, NULL, (LPSTR)lpPTS, NULL);
    }
  while ((lpPTS->wSize == BUFSIZE) && QueryAbort(hPrnDC, 0));

  if (!bAbort)
    Escape(hPrnDC, ENDDOC, NULL, NULL, NULL);

  _lclose(hFile);
  GlobalUnlock(HMem);
  GlobalFree(HMem);
} /* SendFile() */

HDC FAR PASCAL __export GetPrinterDC(HGLOBAL hDevNames, HGLOBAL hDevMode)
{
  HDC hdc;
  int iEsc;
  char szPrinter[64];
  LPSTR szDevice=NULL, szDriver=NULL, szOutput=NULL;
  LPDEVMODE lpdm;

  if (hDevNames)
    {
    LPDEVNAMES lpdn = (LPDEVNAMES) GlobalLock(hDevNames);

    szDriver = (LPSTR) lpdn + lpdn->wDriverOffset;
    szDevice = (LPSTR) lpdn + lpdn->wDeviceOffset;
    szOutput = (LPSTR) lpdn + lpdn->wOutputOffset;

    if (hDevMode)
      lpdm = (LPDEVMODE) GlobalLock(hDevMode);
    }
  else
    {                       // Get default printer info
    GetProfileString ("windows", "device", "", szPrinter, 64);

    if (!((szDevice = strtok (szPrinter, "," )) &&
          (szDriver = strtok (NULL,      ", ")) &&
          (szOutput = strtok (NULL,      ", "))))
            return NULL;    // No default printer

    lpdm = NULL;  // Don't use DEVMODE with default printer
    }

  hdc = CreateDC(szDriver, szDevice, szOutput, lpdm);
  // PASSTHROUGH is required. If driver doesn't support it, try to use raw.drv.

  iEsc = PASSTHROUGH;
  if (!Escape(hdc, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL))
  {
    DeleteDC(hdc);
    // RAW.DRV can be either in current directory, WINDOWS directory or WINDOWS\SYSTEM directory
    hdc = CreateDC( "RAW", NULL, szOutput, lpdm);
  }

//  hdc = CreateDC("RAW", NULL, szOutput, lpdm);

  if (hDevMode && lpdm)
    GlobalUnlock(hDevMode);
  if (hDevNames)
    GlobalUnlock(hDevNames);

  return hdc;

} /* GetPrinterDC() */


BOOL CALLBACK __export PrintAbortProc(HDC hdc, int code)
{
  MSG msg;

  while (!bAbort && PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }

  return (!bAbort);

}  /* PrintAbortProc() */

// The function that prints one line without formfeed
BOOL FAR PASCAL __export _SpoolRow( LPSTR   pData,
                         WORD    cbBytes,
                         HDC     hPrnDC,
                         HGLOBAL hDevNames,
                         HGLOBAL hDevMode )
{
  int       iEsc;
  BOOL      bLocalDC = TRUE; // Assume we must create a DC (hPrnDC == NULL)
  HGLOBAL   HMem;
  char *    pOutput;
         
  HMem = GlobalAlloc(GPTR, sizeof(WORD) + cbBytes);
  if (HMem == NULL)
    return FALSE;
  pOutput = (char *)GlobalLock(HMem);
  if (pOutput == NULL)
  {
    GlobalFree(HMem);
    return FALSE;
  }

  bAbort = FALSE;       // Haven't aborted yet

  // Make sure we have a printer DC

  if (!hPrnDC)
    hPrnDC = GetPrinterDC(hDevNames, hDevMode);
  else
    bLocalDC = FALSE;   // Use passed in hPrnDC

  if (!hPrnDC)
    return FALSE;     
    
  if (bLocalDC)
    Escape (hPrnDC, SETABORTPROC, 0, (LPSTR) PrintAbortProc, NULL);

  // PASSTHROUGH is required. If driver doesn't support it, bail out.
          
  bAbort = FALSE;
  iEsc = PASSTHROUGH;
  if (!Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL))
    {
    bAbort = TRUE;
    goto MPLCleanUp;
    }

  // Call EPSPRINTING if it is supported (that is, if we're on a
  // PostScript printer) to suppress downloading the pscript header.

  iEsc = EPSPRINTING;
  if (Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&iEsc, NULL))
  {
     iEsc = 1;  // 1 == enable PASSTHROUGH (disable pscript header)
     Escape(hPrnDC, EPSPRINTING, sizeof(int), (LPSTR)&iEsc, NULL);
  }


  // Start a Document
  Escape (hPrnDC, STARTDOC, 0, "", NULL);

  // Put data in the buffer and send to the printer
  *(WORD *)pOutput = cbBytes;
  memcpy( &(pOutput[sizeof(WORD)]), pData, cbBytes );
  if( Escape( hPrnDC, PASSTHROUGH, 0, pOutput, NULL ) <= 0 )
    bAbort = TRUE;

  // End the Document
  if (!bAbort)
    Escape(hPrnDC, ENDDOC, NULL, NULL, NULL);

MPLCleanUp:                 // Done
  // Clean up
  if (bLocalDC)
    DeleteDC( hPrnDC );

  GlobalUnlock(HMem);
  GlobalFree(HMem);

  return !bAbort;
}

BOOL FAR PASCAL __export SpoolRow( char *pData, WORD cbBytes )
{
  return _SpoolRow(pData, cbBytes, NULL, NULL, NULL);
}
/*** EOF: spool.c ***/