
/******************************************************************************\
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright (C) 1993-1995 Microsoft Corporation.
*       All rights reserved. 
*       This source code is only intended as a supplement to 
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the 
*       Microsoft samples programs.
\******************************************************************************/

/******************************************************************************\
*
*  PROGRAM:     ENUMPRT.C
*
*  PURPOSE:     Handles display of information returned by calls to
*               EnumPrinters, EnumPrinterDrivers. Info formatted and
*               displayed in a dialog box.
*
*
*  FUNTIONS:    EnumPrintersDlgProc      - handles messages for dialog
*               DisplayEnumPrintersInfo  - retrieves printer info
*               SetEnumPrintersDlgFields - formats & displays printer info
*               ComplexEnumPrintersLine  - formats bitfield printer info
*               EnumPrinterDriversDlgProc- handles messages for dialog
*               DisplayPrinterDriversInfo- retrieves, formats, & displays
*                                            printer info
*
\******************************************************************************/

#include <windows.h>
#include <string.h>
#include <drivinit.h>
#include <stdio.h>
#include <winspool.h>
#include "common.h"
#include "enumprt.h"



/******************************************************************************\
*
*  FUNCTION:    EnumPrintersDlgProc (standard dialog procedure INPUTS/RETURNS)
*
*  COMMENTS:    Processes messages for EnumPrinters dialog box
*
\******************************************************************************/

LRESULT CALLBACK EnumPrintersDlgProc (HWND   hwnd, UINT msg, WPARAM wParam,
                                      LPARAM lParam)
{
  switch (msg)
  {
    case WM_INITDIALOG:
    {
      BOOL bReturn;

      //
      // prompt user for EnumPrinters flags...
      //

      if (DialogBox (GetModuleHandle (NULL), (LPCTSTR) "EnumPrtOpt",
                     NULL, (DLGPROC) EnumPrintersOptionsDlgProc))
      {
        //
        // shove all the enum printer info in the list box
        //

        SetCursor (LoadCursor (NULL, IDC_WAIT));
        bReturn = DisplayEnumPrintersInfo (hwnd);
        SetCursor (LoadCursor (NULL, IDC_ARROW));

        if (!bReturn)

          EndDialog (hwnd, TRUE);

        else

          SetWindowText (hwnd, (LPCTSTR)"EnumPrinters");
      }
      else

          EndDialog (hwnd, TRUE);

      break;
    }

    case WM_COMMAND:

      switch (LOWORD (wParam))
      {
        case DID_OK:

          EndDialog (hwnd, TRUE);
          break;
      }
      break;
  }
  return 0;
}



/******************************************************************************\
*
*  FUNCTION:    EnumPrintersOptionsDlgProc (standard dlg proc INPUTS/RETURNS)
*
*  COMMENTS:    Processes messages for EnumPrtOpt dialog box
*
\******************************************************************************/

LRESULT CALLBACK EnumPrintersOptionsDlgProc (HWND   hwnd,   UINT msg,
                                             WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {
    case WM_INITDIALOG:

      gdwEnumFlags = 0;
      gszEnumName[0] = 0;
      break;

    case WM_COMMAND:

      switch (LOWORD (wParam))
      {
        case DID_OK:

          if (gdwEnumFlags)
          {
            if (gdwEnumFlags & PRINTER_ENUM_NAME)
            {
              GetDlgItemText (hwnd, DID_EDITTEXT, (LPTSTR)gszEnumName,
                              BUFSIZE);

#ifdef FORCE_VALID_NAME
              if (!strlen (gszEnumName))
              {
                MessageBox (hwnd,
                            (LPCTSTR) "Please enter a valid domain/server name",
                           (LPCTSTR) "", MB_OK);
                SetFocus (GetDlgItem (hwnd, DID_EDITTEXT));
                break;
              }
#endif

            }

            EndDialog (hwnd, TRUE);
          }

          else

            EndDialog (hwnd, FALSE);

          break;

        case DID_CANCEL:

          EndDialog (hwnd, FALSE);
          break;

        default:

          if (HIWORD(wParam) == BN_CLICKED)
          {
            DWORD dwControlId = (DWORD) LOWORD (wParam);

            if (gdwEnumFlags & dwControlId)
            {
              //
              // remove that flag, if PRINTER_ENUM_NAME disable edittext
              //

              gdwEnumFlags &= ~dwControlId;

              if (dwControlId & PRINTER_ENUM_NAME)
              {
                SetDlgItemText (hwnd, DID_EDITTEXT, (LPCTSTR)"");
                EnableWindow   (GetDlgItem (hwnd, DID_EDITTEXT), FALSE);
              }
            }

            else
            {
              //
              // add that flag, if PRINTER_ENUM_NAME enable edittext
              //

              gdwEnumFlags |= dwControlId;

              if (dwControlId & PRINTER_ENUM_NAME)

                EnableWindow (GetDlgItem (hwnd, DID_EDITTEXT), TRUE);
            }
          }
          break;
      }
  }
  return 0;
}



/******************************************************************************\
*
*  FUNCTION:    DisplayEnumPrintersInfo
*
*  INPUTS:      hwnd - handle of the EnumPrinters dialog box
*
*  RETURNS:     TRUE if successful,
*               FALSE otherwise
*
\******************************************************************************/

BOOL DisplayEnumPrintersInfo (HWND hwnd)
{
  DWORD  dwBytesNeeded;
  DWORD  dwPrtRet1, dwPrtRet2;
  DWORD  dwMaxPrt;
  LPTSTR lpName = gdwEnumFlags & PRINTER_ENUM_NAME ? gszEnumName : NULL;

  LPPRINTER_INFO_1 pPrtInfo1;
  LPPRINTER_INFO_2 pPrtInfo2;

  BOOL   bReturn = TRUE;

  //
  // get byte count needed for buffer, alloc buffer, the enum the printers
  //

  EnumPrinters (gdwEnumFlags, lpName, 1, NULL, 0, &dwBytesNeeded,
                     &dwPrtRet1);

  //
  // (simple error checking, if these work assume rest will too)
  //

  if (!(pPrtInfo1 = (LPPRINTER_INFO_1) LocalAlloc (LPTR, dwBytesNeeded)))
  {
    ErrMsgBox ("EnumPrinters/LocalAlloc failed", ERR_MOD_NAME);
    bReturn = FALSE;
    goto display_prts_info_done1;
  }

  if (!EnumPrinters (gdwEnumFlags, lpName, 1, (LPBYTE) pPrtInfo1,
                dwBytesNeeded, &dwBytesNeeded, &dwPrtRet1))
  {
    TCHAR  tcBuffer[256];
    wsprintf (tcBuffer, "%s, 1, GetLastError: %d", ERR_MOD_NAME, GetLastError());
    ErrMsgBox ("EnumPrinters 1 failed", tcBuffer);
    bReturn = FALSE;
    goto display_prts_info_done2;
  }

  //
  // If we don't get any printers from the Level == 1 call, there is
  //  no point in continuing... report it, free memory, and return.
  //

  if (dwPrtRet1 == 0)
  {
    MessageBox (ghwndMain,
               (LPCTSTR) "EnumPrinters (Level == 1) returned 0 printers",
               ERR_MOD_NAME,
               MB_OK);
    bReturn = FALSE;
    goto display_prts_info_done2;
  }


  //
  // Call EnumPrinters again with Level == 2.
  //
  //  get byte count needed for buffer, alloc buffer, the enum the printers
  //

  EnumPrinters (gdwEnumFlags, lpName, 2, NULL, 0, &dwBytesNeeded,
                &dwPrtRet2);

  pPrtInfo2 = (LPPRINTER_INFO_2) LocalAlloc (LPTR, dwBytesNeeded);

  EnumPrinters (gdwEnumFlags, lpName, 2, (LPBYTE) pPrtInfo2,
                dwBytesNeeded, &dwBytesNeeded, &dwPrtRet2);

  //
  // Calling EnumPrinters with Level == 2 frequently returns 0 printers.
  //  If so display only the PRINTER_INFO_1 structures we got before.
  //

  if (dwPrtRet2 == 0)
  {
    dwMaxPrt = dwPrtRet1;
    pPrtInfo2 = NULL;
  } else {
    dwMaxPrt = dwPrtRet1 > dwPrtRet2 ? dwPrtRet2 : dwPrtRet1;
  }



  SetEnumPrintersDlgFields (hwnd, dwMaxPrt, pPrtInfo1, pPrtInfo2);


  LocalFree (LocalHandle (pPrtInfo2));

display_prts_info_done2:

  LocalFree (LocalHandle (pPrtInfo1));

display_prts_info_done1:

  return bReturn;
}


/******************************************************************************\
*
*  FUNCTION:    SetEnumPrintersDlgFields
*
*  INPUTS:      hwnd      - handle of the EnumPrinters dialog box
*               dwMaxPrt  - number of elements in the following two arrays
*               pdisplay_prts_info1 - ptr to an array of PRINTER_INFO_1 structs
*               pdisplay_prts_info2 - ptr to an array of PRINTER_INFO_2 structs
*
*  COMMENTS:    This function formats the info returned by EnumPrinters()
*               into readable strings and inserts them in the listbox.
*
\******************************************************************************/

void SetEnumPrintersDlgFields (HWND hwnd, DWORD dwMaxPrt,
                               LPPRINTER_INFO_1 pPrtInfo1,
                               LPPRINTER_INFO_2 pPrtInfo2)
{
  char  buf[256];
  WORD  i;
  DWORD j;

  SendDlgItemMessage (hwnd, DID_LISTBOX, LB_RESETCONTENT, 0, 0);

  for (j = 0; j < dwMaxPrt; j++) {
    //
    // Stick PRINTER_INFO_1  data in listbox
    //

    SendDlgItemMessage (hwnd, DID_LISTBOX, LB_INSERTSTRING, (UINT)-1,
                        (LONG) gaEnumPrt[0]);

    outstr (gaEnumPrt[1], (pPrtInfo1 + j)->pDescription);
    outstr (gaEnumPrt[2], (pPrtInfo1 + j)->pName);
    outstr (gaEnumPrt[3], (pPrtInfo1 + j)->pComment);

    //
    // Stick PRINTER_INFO_2  data in listbox
    //

    if (pPrtInfo2 != NULL) {

      SendDlgItemMessage (hwnd, DID_LISTBOX, LB_INSERTSTRING, (UINT)-1,
                          (LONG) gaEnumPrt[4]);

      outstr (gaEnumPrt[5],  (pPrtInfo2 + j)->pServerName);
      outstr (gaEnumPrt[6],  (pPrtInfo2 + j)->pPrinterName);
      outstr (gaEnumPrt[7],  (pPrtInfo2 + j)->pShareName);
      outstr (gaEnumPrt[8],  (pPrtInfo2 + j)->pPortName);
      outstr (gaEnumPrt[9],  (pPrtInfo2 + j)->pDriverName);
      outstr (gaEnumPrt[10], (pPrtInfo2 + j)->pComment);
      outstr (gaEnumPrt[11], (pPrtInfo2 + j)->pLocation);

      if ((pPrtInfo2 + j)->pDevMode)
      {
        DWORD dwFields;

        outstr (gaEnumPrt[12], "");
        outstr (gaEnumPrt[13], (pPrtInfo2 + j)->pDevMode->dmDeviceName);
        outnum (gaEnumPrt[14], (pPrtInfo2 + j)->pDevMode->dmSpecVersion);
        outnum (gaEnumPrt[15], (pPrtInfo2 + j)->pDevMode->dmDriverVersion);
        outnum (gaEnumPrt[16], (pPrtInfo2 + j)->pDevMode->dmSize);
        outnum (gaEnumPrt[17], (pPrtInfo2 + j)->pDevMode->dmDriverExtra);

        dwFields = (pPrtInfo2 + j)->pDevMode->dmFields;
        ComplexEnumPrintersLine (hwnd, gaEnumPrt[18], gaFields, MAX_FIELDS,
                                 dwFields);

        if (dwFields & DM_ORIENTATION)

          ComplexEnumPrintersLine (hwnd, gaEnumPrt[19], gaOrientation,
                                   MAX_ORIENTATION,
                                   (DWORD)
                                   (pPrtInfo2+j)->pDevMode->dmOrientation);

        if (dwFields & DM_PAPERSIZE)

          ComplexEnumPrintersLine (hwnd, gaEnumPrt[20], gaPaperSize,
                                   MAX_PAPERSIZE,
                                   (DWORD)(pPrtInfo2 + j)->pDevMode->dmPaperSize);

        if (dwFields & DM_PAPERLENGTH)

          outnum (gaEnumPrt[21], (pPrtInfo2 + j)->pDevMode->dmPaperLength);


        if (dwFields & DM_PAPERWIDTH)

          outnum (gaEnumPrt[22], (pPrtInfo2 + j)->pDevMode->dmPaperWidth);

        if (dwFields & DM_SCALE)

          outnum (gaEnumPrt[23], (pPrtInfo2 + j)->pDevMode->dmScale);

        if (dwFields & DM_COPIES)

          outnum (gaEnumPrt[24], (pPrtInfo2 + j)->pDevMode->dmCopies);

        if (dwFields & DM_DEFAULTSOURCE)

          ComplexEnumPrintersLine (hwnd, gaEnumPrt[25], gaDefaultSource,
                                   MAX_DEFAULTSOURCE,
                                 (DWORD)(pPrtInfo2+j)->pDevMode->dmDefaultSource);

        if (dwFields & DM_PRINTQUALITY)

          ComplexEnumPrintersLine (hwnd, gaEnumPrt[26], gaPrintQuality,
                                   MAX_PRINTQUALITY,
                                  (DWORD)(pPrtInfo2+j)->pDevMode->dmPrintQuality);

        if (dwFields & DM_COLOR)

          ComplexEnumPrintersLine (hwnd, gaEnumPrt[27], gaColor,
                                   MAX_COLOR,
                                   (DWORD)(pPrtInfo2 + j)->pDevMode->dmColor);

        if (dwFields & DM_DUPLEX)

          ComplexEnumPrintersLine (hwnd, gaEnumPrt[28], gaDuplex,
                                   MAX_DUPLEX,
                                   (DWORD)(pPrtInfo2 + j)->pDevMode->dmDuplex);

        if (dwFields & DM_YRESOLUTION)

          outnum (gaEnumPrt[29], NULL);

        if (dwFields & DM_TTOPTION)

          outnum (gaEnumPrt[29], NULL);

        if (dwFields & DM_COLLATE)

          outnum (gaEnumPrt[30], NULL);

        if (dwFields & DM_FORMNAME)

          outnum (gaEnumPrt[31], NULL);
        }
        else
        {
          outstr (gaEnumPrt[12], NULL);
        }

      outstr (gaEnumPrt[33], (pPrtInfo2 + j)->pSepFile);
      outstr (gaEnumPrt[34], (pPrtInfo2 + j)->pPrintProcessor);
      outstr (gaEnumPrt[35], (pPrtInfo2 + j)->pDatatype);
      outstr (gaEnumPrt[36], (pPrtInfo2 + j)->pParameters);

      ComplexEnumPrintersLine (hwnd, gaEnumPrt[37], gaAttributes,
                               MAX_ATTRIBUTES,
                               (pPrtInfo2 + j)->Attributes);

      for (i = 0; i < MAX_PRIORITIES; i++)

        if ((pPrtInfo2 + j)->Priority & gaPriorities[i].dwValue)
        {
          outstr (gaEnumPrt[38], gaPriorities[i].szValue);
          break;
        }

      if (i == MAX_PRIORITIES)

        outnum (gaEnumPrt[39], (pPrtInfo2 + j)->Priority);

      outnum (gaEnumPrt[40], (pPrtInfo2 + j)->DefaultPriority);
      outnum (gaEnumPrt[41], (pPrtInfo2 + j)->StartTime);
      outnum (gaEnumPrt[42], (pPrtInfo2 + j)->UntilTime);

      ComplexEnumPrintersLine (hwnd, gaEnumPrt[43], gaStatus, MAX_STATUS,
                               (pPrtInfo2 + j)->Status);

      outnum (gaEnumPrt[44], (pPrtInfo2 + j)->cJobs);
      outnum (gaEnumPrt[45], (pPrtInfo2 + j)->AveragePPM);
    }
  }
}



/******************************************************************************\
*
*  FUNCTION:    ComplexEnumPrintersLine
*
*  INPUTS:      hwnd        - handle of the EnumPrinters dialog box
*               pbuf        - pointer to buffer containing a cap-type
*                              string
*               pLkUp       - pointer to a CAPSLOOKUP table
*               iMaxEntries - # of enries in table pointed at by pLkUp
*               iValue      - an integer containing 1+ bit-value flags.
*
*  COMMENTS:    This function is used to expand an int containing
*               multiple bit-values into a set of strings which are
*               inserted into the DevCapsDlg listbox. The iValue
*               parameter is checked against each iIndex entry in the
*               CAPSLOOKUP table pointed at by pLkUp, and when matches
*               are found the corresponding (lpszValue) string is
*               inserted.
*
*               The buffer pointed to by pbuf will be destroyed.
*
\******************************************************************************/

void ComplexEnumPrintersLine (HWND hwnd, char  *pstr, ENUMPRTLOOKUP *pLkUp,
                              int iMaxEntries, DWORD  dwValue)
{
  char buf [BUFSIZE];
  int  i;
  BOOL bNewLine = FALSE;

  strcpy (buf, pstr);

  for (i = 0; i < iMaxEntries; i++)

    if (dwValue & (pLkUp + i)->dwValue)
    {
      if (bNewLine)
      {
        //
        // Keep the first symbolic constant on the same line as the
        //   cap type, eg:  "TECHNOLOGY:     DT_RASDISPLAY".
        //

        strcpy (buf, BLANKS);
        strcat (buf, (pLkUp + i)->szValue);
      }
      else
      {
        //
        // Put symbolic constant on new line, eg:
        //                  "                DT_RASPRINTER".
        //

        strcat (buf, (pLkUp + i)->szValue);
        bNewLine = TRUE;
      }
      SendDlgItemMessage (hwnd, DID_LISTBOX, LB_INSERTSTRING,
                          (UINT)-1, (LONG) buf);
   }
}



/******************************************************************************\
*
*  FUNCTION:    EnumPrinterDriversDlgProc (standard dlg proc INPUTS/RETURNS)
*
*  COMMENTS:    Processes messages for EnumPrinterDrivers dialog box
*
\******************************************************************************/

LRESULT CALLBACK EnumPrinterDriversDlgProc (HWND   hwnd,   UINT   msg,
                                            WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {
    case WM_INITDIALOG:
    {
      BOOL bReturn;

      SetCursor (LoadCursor (NULL, IDC_WAIT));
      bReturn = DisplayPrinterDriversInfo (hwnd);
      SetCursor (LoadCursor (NULL, IDC_ARROW));

      if (!bReturn)

        EndDialog (hwnd, TRUE);

      else

        SetWindowText (hwnd, (LPCTSTR) "EnumPrinterDrivers");

      break;
    }

    case WM_COMMAND:

      switch (LOWORD (wParam))
      {
        case DID_OK:

          EndDialog (hwnd, TRUE);

          return 1;
      }
      break;
  }
  return 0;
}



/******************************************************************************\
*
*  FUNCTION:    DisplayPrinterDriversInfo
*
*  INPUTS:      hwnd - handle of the EnumPrinterDrivers dialog box
*
*  RETURNS:     TRUE if successful,
*               FALSE otherwise
*
*  COMMENTS:    Retrieves EnumPrinterDrivers info, formats, & inserts
*               in listbox.
*
\******************************************************************************/

BOOL DisplayPrinterDriversInfo (HWND hwnd)
{
  DWORD         dwBytesNeeded, dwDrvRet, i;
  DRIVER_INFO_1 *pDriverInfo1;
  DRIVER_INFO_2 *pDriverInfo2;
  char          buf[BUFSIZE];
  BOOL          bReturn = TRUE;

  //
  // get byte count needed for buffer, alloc buffer, the enum the drivers
  //

  EnumPrinterDrivers ((LPTSTR) NULL, (LPTSTR) NULL, 1, NULL,
                      0, &dwBytesNeeded, &dwDrvRet);

  //
  // simple error checking, if these work assume rest will too
  //

  if (!(pDriverInfo1 = (DRIVER_INFO_1 *) LocalAlloc (LPTR, dwBytesNeeded)))
  {
    ErrMsgBox ("LocalAlloc failed", ERR_MOD_NAME);
    bReturn = FALSE;
    goto display_prt_drvs_info_done1;
  }

  if (!EnumPrinterDrivers ((LPTSTR) NULL, (LPTSTR) NULL, 1,
                           (LPBYTE) pDriverInfo1, dwBytesNeeded, &dwBytesNeeded,
                           &dwDrvRet))
  {
    ErrMsgBox ("EnumPrinterDrivers returned 0 drivers", ERR_MOD_NAME);
    bReturn = FALSE;
    goto display_prt_drvs_info_done2;
  }

  EnumPrinterDrivers ((LPTSTR) NULL,(LPTSTR) NULL, 2, NULL,
                      0, &dwBytesNeeded, &dwDrvRet);

  pDriverInfo2 = (DRIVER_INFO_2 *) LocalAlloc (LPTR, dwBytesNeeded);

  EnumPrinterDrivers ((LPTSTR) NULL, (LPTSTR) NULL, 2,
                      (LPBYTE) pDriverInfo2, dwBytesNeeded, &dwBytesNeeded,
                      &dwDrvRet);

  if (!dwDrvRet)
  {
    ErrMsgBox ("EnumPrinterDrivers returned 0 drivers", "");
    bReturn = FALSE;
    goto display_prt_drvs_info_done3;
  }

  //
  // insert formatted info into listbox
  //

  for (i = 0; i < dwDrvRet; i++)
  {
    sprintf (buf, gaDriverInfo[0]);
    outstr3();

    sprintf (buf, gaDriverInfo[1], (pDriverInfo1 + i)->pName);
    outstr3();

    sprintf (buf, gaDriverInfo[2]);
    outstr3();

    sprintf (buf, gaDriverInfo[3], (pDriverInfo2 + i)->cVersion);
    outstr3();

    sprintf (buf, gaDriverInfo[4], (pDriverInfo2 + i)->pName);
    outstr3();

    sprintf (buf, gaDriverInfo[5], (pDriverInfo2 + i)->pEnvironment);
    outstr3();

    sprintf (buf, gaDriverInfo[6], (pDriverInfo2 + i)->pDriverPath);
    outstr3();

    sprintf (buf, gaDriverInfo[7], (pDriverInfo2 + i)->pDataFile);
    outstr3();

    sprintf (buf, gaDriverInfo[8], (pDriverInfo2 + i)->pConfigFile);
    outstr3();

  }

display_prt_drvs_info_done3:

  LocalFree (LocalHandle (pDriverInfo2));

display_prt_drvs_info_done2:

  LocalFree (LocalHandle (pDriverInfo1));

display_prt_drvs_info_done1:

  return bReturn;
}
