_Windows NT Printer Control_
by Paul Trout

Listing One
/*****************************************************************************
* GetLocalPrinters uses EnumPrinters with the PRINTER_ENUM_LOCAL flag to
*   retrieve all of the local printers. It then counts them, allocates an 
*   array of printer structures, initializes name fields, sets numprinters, 
*   and returns a pointer to the array of printer structures.
****************************************************************************/
struct printer *GetLocalPrinters(unsigned int *numprinters) {
  char            *databuff;           /* Buffer for data */
  unsigned int     ctr;                /* FOR loop counter */
  unsigned int     cur_prt=0;          /* Which printer  */
  unsigned int     slen;               /* Scratch variable */
  struct printer  *localprns;          /* Local printers */
  DWORD            bytes_req;          /* Bytes req'd for data */
  DWORD            structs_ret;        /* # of structs returned */
  BOOL             rtc;                /* Win32 return code */

  /************************************************************
  * Allocate the buffer for the returned data, Call EnumPrinters
  * If the call fails because the bufffer is not large enough
  * free the buffer, reallocate it, and reissue the call
  ************************************************************/
  databuff=(char *)calloc(1,sizeof(PRINTER_INFO_1));
  rtc=EnumPrinters(PRINTER_ENUM_LOCAL,NULL,LEVEL1,databuff,\
                   sizeof(PRINTER_INFO_1),&bytes_req,&structs_ret);
  if(rtc==FALSE && bytes_req>0 && structs_ret==0) {
    free(databuff);
    databuff=(char *)calloc(bytes_req,sizeof(char));
    rtc=EnumPrinters(PRINTER_ENUM_LOCAL,NULL,LEVEL1,databuff,\
                     bytes_req,&bytes_req,&structs_ret);
  }
  /************************************************************************
  * Count the number of printers by stepping thru the returned structures,
  * and incrementing the count whenever the Flags field is set to 
  * PRINTER_ENUM_ICON8, ISPRINTER is a more mnemonic name for the flag.
  *************************************************************************/
  *numprinters=0;
  for(ctr=0; ctr<structs_ret; ctr++)
    if( ((PRINTER_INFO_1 *)(databuff)+ctr)->Flags & ISPRINTER)
      (*numprinters)++;
  /***************************************************************************
  * Allocate the array of printer structures to return, and copy printer names
  * from returned data to appropriate fields. The cur_prt variable is req'd
  * because EnumPrinters call will have returned data about print objects other
  * than printers. Also initialize spool field to NULL so that FreePrinterArray
  * can be used before GetLocalSpoolPaths function has been called.
  ************************************************************/
  localprns=(struct printer *)calloc((*numprinters),\ sizeof(struct printer));
  for(ctr=0; ctr<structs_ret; ctr++)
    if( ((PRINTER_INFO_1 *)(databuff)+ctr)->Flags & ISPRINTER) {
      slen=strlen(((PRINTER_INFO_1 *)(databuff)+ctr)->pName);
      localprns[cur_prt].name=(char *)calloc(slen+1,\ sizeof(char));
      strcpy(localprns[cur_prt].name,\ 
                             ((PRINTER_INFO_1 *)(databuff)+ctr)->pName);
      localprns[cur_prt].spool=NULL;
      localprns[cur_prt].driver=NULL;
      cur_prt++;
    }
  free(databuff);                      /* Free working buffer */
  return(localprns);                   /* Return array of printers */
}

Listing Two
/**************************************************************************
* FreePrinterArray frees all of the allocated space for an array of printer 
*   array of printer structures.  It frees the name and spool
*   fields, and then the entire array.
***************************************************************************/
void FreePrinterArray(struct printer *localprns, \
                      unsigned int    numprinters ) {
  unsigned int ctr;                    /* FOR loop counter */
  /************************************************************
  * Do not simply frre the array of structures.  You must also
  * free the name, spool, and driver  fields.
  ************************************************************/
  for(ctr=0; ctr<numprinters; ctr++) {
    free(localprns[ctr].name);
    if(localprns[ctr].spool!=NULL)
      free(localprns[ctr].spool);
    if(localprns[ctr].driver!=NULL)
      free(localprns[ctr].driver);
  }
  free(localprns);
}

Listing Three
/****************************************************************************
* OpenAllLocalPrinters takes the array of printer structures, and the number
*   of printers returned by GetLocalPrinters, and opens a handle for each one 
*   with OpenPrinter.
****************************************************************************/
void OpenAllLocalPrinters(struct printer *localprns, \
                          unsigned int    numprinters) {
  unsigned int     ctr;                /* FOR loop counter */
  PRINTER_DEFAULTS opener;             /* Default behavior */
  BOOL             rtc;                /* Win32 return code */

  /***************************************************************************
  * Initialize the PRINTER_DEFAULTS structure. The only field to worry about 
  * is the DesiredAccess field.  If this is not set to PRINTER_ALL_ACCESS, you
  * will not be able to change the level 2 data on the destination job during 
  * a move, nor will you be able to retrieve the printer driver
  * name with GetPrinter during the GetLocalDriverNames call.
  ****************************************************************************/
  opener.pDatatype=NULL;
  opener.pDevMode=NULL;
  opener.DesiredAccess=PRINTER_ALL_ACCESS;

  for(ctr=0; ctr<numprinters; ctr++) {
    rtc=OpenPrinter(localprns[ctr].name,&localprns[ctr].conn,\
                    &opener);
    if(rtc==TRUE)
      localprns[ctr].conn_used=TRUE;
    else
      localprns[ctr].conn_used=FALSE;
  }
}

Listing Four
/**************************************************************
* CloseAllLocalPrinters takes the array of printer structures,
*   and the number of printers returned by by GetLocalPrinters,
*   and closes the connection for each one with ClosePrinter.
**************************************************************/
void CloseAllLocalPrinters(struct printer *localprns, \
                          unsigned int    numprinters) {
  unsigned int     ctr;                /* FOR loop counter */
  BOOL             rtc;                /* Win32 return code */
  for(ctr=0; ctr<numprinters; ctr++) {
    if(localprns[ctr].conn_used==TRUE) {
      rtc=ClosePrinter(localprns[ctr].conn);
      if(rtc==TRUE)
        localprns[ctr].conn_used=FALSE;
      else
        localprns[ctr].conn_used=TRUE;
    }
    else
      continue;
  }
}

1



