// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright © 1993, 1994  Microsoft Corporation.  All Rights Reserved.
//
//  PROGRAM:  print.c
//
//  PURPOSE:  Routines used for printing.
//
//  PLATFORMS:  Chicago
//

#include <windows.h>
#include <string.h>
#define PRINTSS_LOCAL
#include "print.h"
#include "icmtest.h"

//***************************************************************************
//                                                                          * 
//   Functions private to this module                                       *
//                                                                          *
//***************************************************************************

BOOL FAR PASCAL AbortProc (HDC, short);
BOOL FAR PASCAL PrintDlgProc (HWND, unsigned, WORD, DWORD);

//***************************************************************************
//                                                                          *
//  Global vars external to this module                                     *
//                                                                          *
//***************************************************************************
extern WORD                     gwBMPIndex;
extern BMPINFO                  gBMPInfo[MAX_BMP];
extern RECT                     grcClip;
extern HCURSOR                  ghcurSave;
extern HINSTANCE                ghInst;
extern HCOLORSPACE              ghlcsCurrent;
extern COLORSPACECONTROLENTRY   galcsControl[MAX_COLORSPACES];
extern UINT                     guiColorSpacesUsed;
extern HCOLORSPACE              ghlcsDefault;
extern BOOL                     gfICMEnabled;

//***************************************************************************
//                                                                          *
//  Global vars internal to this module                                     *
//                                                                          *
//***************************************************************************
FARPROC  glpfnAbortProc    = NULL;
FARPROC  glpfnPrintDlgProc = NULL;
HWND     ghWndParent       = NULL;
HWND     ghDlgPrint        = NULL;
BOOL     gbUserAbort;

//***************************************************************************
//                                                                          *
// FunctionName: PrintICMImage                                              *
//                                                                          *
// Purpose:                                                                 *
//    To print the ICM images on the printer.                               *
//                                                                          *
// Parameters:                                                              *
//    HWND    Handle to window                                              *
//                                                                          *
//                                                                          *
// Return Value:                                                            *
//    BOOL  TRUE  - Success.                                                *
//      FALSE - Failed.                                                     *
//                                                                          *
// Comments:                                                                *
//                                                                          *
//***************************************************************************

BOOL PrintICMImage(HWND hWnd)
{
  BITMAPINFOHEADER  bi;
  char              szDocName[256];
  HDC               hDC; 
  int               xSize, ySize, xRes, yRes, dx, dy;
  HCOLORSPACE       hcsWeird;

  GetWindowText(hWnd, szDocName, sizeof(szDocName));
  bi = *(LPBITMAPINFOHEADER)gBMPInfo[gwBMPIndex].hDib;

  if (!IsRectEmpty(&grcClip))
  {
    bi.biWidth  = grcClip.right  - grcClip.left;
    bi.biHeight = grcClip.bottom - grcClip.top;
  }
 
  // Get DC for DEFAULT printer
  if (!(hDC = GetPrinterDC()))
    return(FALSE);

  // Obtain info about printer resolution
  xSize = GetDeviceCaps(hDC, HORZRES);
  ySize = GetDeviceCaps(hDC, VERTRES);
  xRes  = GetDeviceCaps(hDC, LOGPIXELSX);
  yRes  = GetDeviceCaps(hDC, LOGPIXELSY);

  // Use half inch margins on left, right, and top.
  // Maintain the same aspect ratio.
  dx = xSize - (2 * xRes);
  dy = (int)((long)dx * bi.biHeight/bi.biWidth);

  if (InitPrinting(hDC, hWnd, ghInst, szDocName)) 
  {
    // Override whatever the user has picked in the printer setup dialog box.
    if (gfICMEnabled)
      SetICMMode(hDC, ICM_OFF);

    // First print with no ICM. 
    PrintDIB(hWnd, hDC, xRes/2, yRes/2 + 4*yRes, dx/2, dy/2);

    if (gfICMEnabled)
    {
  // Turn on ICM and see what happens.
  if (!SetICMMode(hDC, ICM_ON))
    OutputDebugString("ICMTEST.C : PrintICMImage : SetICMMode(ICM_ON) FAILED");
  PrintDIB(hWnd, hDC, dx/2 + xRes, yRes/2 + 4*yRes, dx/2, dy/2);

  // Set a different color space.
  SetColorSpace(hDC, ghlcsCurrent);
  PrintDIB(hWnd, hDC, xRes/2, dy/2 + yRes + 4*yRes, dx/2, dy/2);

  // Create and set a color space. Use the last user-entered
  // color space in the array.
  hcsWeird = CreateColorSpace(&galcsControl[(guiColorSpacesUsed-1)].lcs);
  SetColorSpace(hDC, hcsWeird);
  PrintDIB(hWnd, hDC, dx/2 + xRes, dy/2 + yRes + 4*yRes, dx/2, dy/2);
  SetColorSpace(hDC, ghlcsDefault);
  DeleteColorSpace(hcsWeird);
    }

    // Try different intents. 
    // Signal to the driver to begin translating the
    // drawing commands to printer output...
    TermPrinting(hDC);
  }
  DeleteDC(hDC);
}

//***************************************************************************
//                                                                          *
//  FUNCTION:  GetPrinterDC()                                               *
//                                                                          *
//  PURPOSE:  Read Registry.ini for default printer and create DC for it.   *
//                                                                          *
//  PARAMETERS: None                                                        *
//                                                                          *
//  RETURNS:  A handle to the DC if successful or NULL otherwise.           *
//                                                                          *
//***************************************************************************
HDC PASCAL GetPrinterDC()
{
  HDC    hDC;
  LPSTR   lpszPrinter;
  HANDLE  hString;
    
  // Enumerating printers may take time--display wait cursor
  StartWait();

  // Init vars
  hDC = NULL;
  lpszPrinter = NULL;
  hString = NULL;
  
  // Get Name of default printer from registry
  lpszPrinter = GetDefaultPrinter(&hString);

  if(lpszPrinter != NULL)
  {
    // Now get a DC for the printer
    hDC = CreateDC (NULL, lpszPrinter, NULL, NULL);
    GlobalFree(hString);
  }
  
  // Restore cursor and return
  EndWait();
  return(hDC);
}

//***************************************************************************
//                                                                          *
//  FUNCTION:  InitPrinting                                                 *
//                                                                          *
//  PURPOSE:  Makes preliminary driver calls to set up print job.           *
//                                                                          *
//  PARAMETERS:                                                             *
//      HDC     Handle to printer DC                                        *
//      HWND    Handle to the window with the image                         *
//      HANDLE  Instance handle                                             *
//      LPSTR   Title of image                                              *
//                                                                          *
//                                                                          *
//  RETURNS:  TRUE  - if successful.                                        *
//    FALSE - otherwise.                                                    *
//                                                                          *
//***************************************************************************
BOOL PASCAL InitPrinting(HDC hDC, HWND hWnd, HANDLE hInst, LPSTR lpszFriendlyName)
{
  BOOL    bRetVal;
  DOCINFO diDocInfo;  // Document info for StartDoc call

  if (!gBMPInfo[gwBMPIndex].hDib)
    return(FALSE);

  //
  // Init vars
  //
  bRetVal     = TRUE;  // assume success
  gbUserAbort = FALSE;  // user hasn't aborted
  ghWndParent = hWnd;  // save for Enable at Term time

  //
  // Get addresses of dlg procs
  //
  glpfnPrintDlgProc = (FARPROC)&PrintDlgProc;
  glpfnAbortProc    = (FARPROC)&AbortProc;

  //
  // Create the printing dialog
  //
  ghDlgPrint = CreateDialog (hInst, "DLG_PRINT", ghWndParent, (DLGPROC)glpfnPrintDlgProc);

  if (!ghDlgPrint)
  {
    return(FALSE);
  }

  SetWindowText (ghDlgPrint, lpszFriendlyName);
  EnableWindow (ghWndParent, FALSE);        // disable parent   

  //
  // Set the abort procedure
  //
  if (SetAbortProc(hDC, (ABORTPROC)glpfnAbortProc) == SP_ERROR)
  {
    ErrMsg("InitPrinting:  SetAbortProc FAILED");
    bRetVal = FALSE;
    goto exit;
  }
  
  //
  // Fill in the DOCINFO structure
  //
  diDocInfo.cbSize = sizeof(DOCINFO);
  diDocInfo.lpszDocName = lpszFriendlyName;
  diDocInfo.lpszOutput = NULL;
  diDocInfo.lpszDataType = NULL;
  diDocInfo.fwType = 0;

  //
  // Start the document
  //
  if (StartDoc(hDC, &diDocInfo) == SP_ERROR)
  {
    ErrMsg("InitPrinting:  StartDoc FAILED");
    bRetVal = FALSE;
    goto exit;
  }

  //
  // Start the page
  //
  if (StartPage(hDC) == SP_ERROR)
  {
    ErrMsg("InitPrinting:  StartPage FAILED");
    AbortDoc(hDC);
    bRetVal = FALSE;
  }

exit:
  if (bRetVal == FALSE)
  {
    EnableWindow(ghWndParent, TRUE);
    DestroyWindow(ghDlgPrint);
  }
  return(bRetVal);
}

//***************************************************************************
//                                                                          *
//  FUNCTION:  PrintDIB(HWND hWnd, HDC hDC, int x, int y, int dx, int dy)   *
//                                                                          *
//  PURPOSE:  Set the DIB bits to the printer DC.                           *
//                                                                          *
//***************************************************************************
void PrintDIB (HWND hWnd, HDC hDC, int x, int y, int dx, int dy)
{
  LPBITMAPINFOHEADER lpbi;
  HANDLE   hdibCurrent;
  int dibX,  dibY;
  int dibDX, dibDY;

  hdibCurrent = gBMPInfo[gwBMPIndex].hDib;

  lpbi = (LPBITMAPINFOHEADER)hdibCurrent;

  if (IsRectEmpty (&grcClip))
  {
    dibX  = 0;
    dibY  = 0;
    dibDX = (int)lpbi->biWidth;
    dibDY = (int)lpbi->biHeight;
  }
  else
  {
    dibX  = grcClip.left;
    dibY  = (int)lpbi->biHeight - 1 - grcClip.bottom;
    dibDX = grcClip.right  - grcClip.left;
    dibDY = grcClip.bottom - grcClip.top;
  }

  StretchDIBits(hDC,
    x, y,
    dx, dy,
    dibX, dibY,
    dibDX,dibDY,
    (LPSTR)((LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi)),
    (LPBITMAPINFO)lpbi,
    DIB_RGB_COLORS,
    SRCCOPY);
}

//***************************************************************************
//                                                                          *
//  FUNCTION:  TermPrinting(HDC hDC)                                        *
//                                                                          *
//  PURPOSE:  Terminates print job.                                         *
//                                                                          *
//***************************************************************************
void PASCAL TermPrinting(HDC hDC)
{
  if (!gbUserAbort)
  {
    //
    // If the user didn't abort, end the doc
    //
    if (EndPage(hDC) == SP_ERROR)
    {
      ErrMsg("TermPrinting:  EndPage FAILED");
    }
    if (EndDoc(hDC) == SP_ERROR)
    {
      ErrMsg("TermPrinting:  EndDoc FAILED");
    }
    //
    // Destroy the dialog
    //
    EnableWindow(ghWndParent, TRUE);
    DestroyWindow(ghDlgPrint);
  }
  else 
  {
    if (AbortDoc(hDC) == SP_ERROR)
    {
      ErrMsg("TermPrinting:  AbortDoc FAILED");
    }
  }
}

// **************************************************************************
//                                                                          *
//  FUNCTION:  PrintDlgProc (HWND, unsigned , WORD , DWORD )                *
//                                                                          *
//  PURPOSE:  Dialog function for the "Cancel Printing" dialog. It sets     *
//              the abort flag if the user presses <Cancel>.                *
//                                                                          *
// **************************************************************************
BOOL FAR PASCAL PrintDlgProc (HWND hDlg, unsigned iMessage, WORD wParam, DWORD lParam)
{
  switch (iMessage) 
  {
    case WM_INITDIALOG:
      EnableMenuItem (GetSystemMenu (hDlg, FALSE), SC_CLOSE, MF_GRAYED);
      break;

    case WM_COMMAND:
      gbUserAbort = TRUE;
      EnableWindow (ghWndParent, TRUE);
      DestroyWindow (hDlg);
      ghDlgPrint = 0;
      break;

    default:
      return(FALSE);
  }
  return(TRUE);
}

// **************************************************************************
//                                                                          *
//  FUNCTION:  AbortProc (HDC hPrnDC, short nCode)                          *
//                                                                          *
//  PURPOSE:  Checks message queue for messages from the "Cancel Printing"  *
//              dialog. If it sees a message, (this will be from a print    *
//              cancel command), it terminates.                             *
//                                                                          *
//  RETURNS:  Inverse of Abort flag                                         *
//                                                                          *
// **************************************************************************
BOOL FAR PASCAL AbortProc (HDC hPrnDC, short nCode)
{
    MSG   msg;

    while (!gbUserAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) 
    {
      if (!ghDlgPrint || !IsDialogMessage(ghDlgPrint, &msg)) 
      {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
      }
    }
    return(!gbUserAbort);
}

// *****************************************************************************
//
// FunctionName: GetDefaultPrinter()
// 
// Purpose:
//    The purpose of this function is to 
//
// Parameters:
//    None.
//
// Return Value:  
//    LPSTR    NULL - Failed.
//
// Comments:
//
// *****************************************************************************

LPSTR GetDefaultPrinter(LPHANDLE lphString)

{
  LPSTR              lpszDefaultPrinter;
  DWORD              dwPrinters     = 0;
  DWORD              dwIndex        = 0;
  HANDLE             hPrinterInfo   = NULL;
  LPPRINTER_INFO_2   lpPrinterInfo  = NULL;

  //
  // Enumerate Printers.
  //
  dwPrinters = EnumerateAllPrinters(PRINTER_ENUM_LOCAL, NULL, LEVEL2, &hPrinterInfo);
  if ((dwPrinters >= ENUM_ERROR) ||   (dwPrinters == 0))
    return(NULL);

  lpszDefaultPrinter = *lphString = (LPSTR)GlobalAlloc(GPTR, MAX_STRING);
  if (lpszDefaultPrinter == NULL)
    return(NULL);

  lpPrinterInfo = (LPPRINTER_INFO_2)hPrinterInfo;

  if (lpPrinterInfo != NULL)
  {
    //
    // Loop through printers and find default.
    //
    for (dwIndex = 0; dwIndex < dwPrinters; dwIndex++)
    {
      if (lpPrinterInfo[dwIndex].Attributes & PRINTER_ATTRIBUTE_DEFAULT)
      lstrcpy(lpszDefaultPrinter, lpPrinterInfo[dwIndex].pPrinterName);
    }
  }

  //
  // Free Memory.
  //
  GlobalFree(hPrinterInfo);

  return(lpszDefaultPrinter);
}


// *****************************************************************************
//
// FunctionName: EnumerateAllPrinters()
// 
// Purpose:
//    The purpose of this function is to Enumerate and return an array of the 
//    appropriate structure(s) given by dwLevel.
//
// Parameters:
//    DWORD    dwType         - type of printer object to Enumerate.
//    LPSTR    lpszName       - name of printer object.
//    DWORD    dwLevel        - structure level.
//    LPHANDLE lphPrinterInfo - handle which points to array of PRINTER_INFO_X.
//
// Return Value:  
//    DWORD    00000000 - 7FFFFFFF - Success.
//             7FFFFFFF - FFFFFFFF - Fail.
//
// Comments:
//
// *****************************************************************************

DWORD EnumerateAllPrinters(DWORD dwType, LPSTR lpszName, DWORD dwLevel, LPHANDLE lphPrinterInfo)

{
  DWORD        dwSize      = 0;
  DWORD        dwPrinters  = 0;
  DWORD        dwNeeded    = 0;
  DWORD        dwErrorCode = 0;
  BOOL         bReturnCode = 0;
  BOOL         bRC         = FALSE;
  LPBYTE       lpInfo      = NULL;
     
  //
  // Set handle to NULL.
  //
  *lphPrinterInfo = NULL;

  //
  // Enumerate Printers.
  //
  bReturnCode = EnumPrinters(dwType, lpszName, dwLevel, NULL, 0, &dwSize, &dwPrinters);

  //
  // If Return Code is TRUE the first time, we know there is 
  // nothing to enumerate.
  //
  if (bReturnCode)
  {
    dwPrinters = 0L;
    return(dwPrinters);
  }

  //
  // Since Return Code is FALSE, check LastError.
  // If LastError is any thing other than allocate size error, flag and exit.
  //
  dwErrorCode = GetLastError();
  if (dwErrorCode != ERROR_INSUFFICIENT_BUFFER)
    return(ERROR_ENUMPRINTERS);

  //
  // Loop until we have size right.
  //
  while (!bRC)
  {
    if (lpInfo = *lphPrinterInfo = GlobalAlloc(GPTR, dwSize))
    {
      //
      // Enumerate
      //
      bRC = EnumPrinters(dwType, lpszName, dwLevel, lpInfo, dwSize, &dwNeeded, &dwPrinters);
      
      if (!bRC)
      {
        dwErrorCode = GetLastError();

        //
        // If any thing other than allocate size error, flag and exit.
        //
        if (dwErrorCode != ERROR_INSUFFICIENT_BUFFER)
          return(ERROR_ENUMPRINTERS);
        else
        {
    GlobalFree(*lphPrinterInfo);
          dwSize = dwNeeded; 
        }
      }
    }
    else
      return(ERROR_ENUMPRINTERS);
  }
  return(dwPrinters);
}
