home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / stock / print.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-09  |  43.6 KB  |  1,584 lines

  1. /***    print.c - printing support
  2.  *
  3.  *    This file presents code to make if VERY EASY for an application
  4.  *    to select a printer, manipulate job properties, and open a DC
  5.  *    for printing.
  6.  *
  7.  *    Author:
  8.  *        Benjamin W. Slivka
  9.  *
  10.  *    History:
  11.  *        12-May-1990 bens    Initial version
  12.  *        16-May-1990 bens    Skeletal job property routines
  13.  *        31-May-1990 bens    Final job property routines
  14.  *
  15.  *    APIs Offered:
  16.  *        PrintQueryPrinterList    - Get printer list
  17.  *        PrintQueryNextPrinter    - Enumerate members of printer list
  18.  *        PrintQueryDefaultPrinter - Get default printer
  19.  *        PrintQueryPrinterInfo    - Get information about a printer
  20.  *
  21.  *        PrintOpenDC          - Open a printer DC
  22.  *
  23.  *        PrintQueryJobProperties  - Get JP from a printer
  24.  *        PrintChangeJobProperties - Interact with user to change JP
  25.  *        PrintMatchPrinter         - Find printer which matches JP
  26.  *
  27.  *    Key points:
  28.  *
  29.  *    1)  [PM_SPOOLER,PRINTER] in OS2SYS.INI specifies the default printer.
  30.  *        This entry is of use *only* if [PM_SPOOLER,QUEUE] is empty.
  31.  *
  32.  *    2)  If a [PM_SPOOLER_PRINTER,xxx] entry in OS2SYS.INI entry refers
  33.  *        to *more than one* driver, *and* the printer is *not*
  34.  *        associated with a queue, then we always use the first driver
  35.  *        in the list.  There is no information in the system to help
  36.  *        us choose among the drivers, so we make the easy choice.
  37.  */
  38.  
  39. #define INCL_DEV
  40.  
  41. #define INCL_WINSHELLDATA
  42.  
  43. #include <os2.h>
  44.  
  45. #include <limits.h>
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49.  
  50. #include "ids.h"
  51. #include "file.h"
  52. #include "mem.h"
  53. #include "print.h"
  54.  
  55.  
  56. //************************************************************************
  57. //
  58. //  PRIVATE Types and Definitions
  59. //
  60. //************************************************************************
  61.  
  62.  
  63. // SEARCHP - Search structure for PrinterBegin/Next/EndSearch
  64. //
  65. typedef struct { /* srchp */
  66.     char *  pchName;            // Driver name list
  67.     char *  pchNext;            // Next name in achNames to consume
  68. } SEARCHP;
  69. typedef SEARCHP *PSEARCHP; /* psrchp */
  70.  
  71.  
  72. // PRINTER - Structure for printer destination (used for DevOpenDC)
  73. //
  74. typedef struct _printer {  /* prt */
  75.     LONG    lType;            // Printer type (OD_DIRECT/OD_QUEUED)
  76.     char *  pszName;            // Name (either queue or printer name)
  77.                     //  NOTE: This pointer always points
  78.                     //      to either pszLogAddr or
  79.                     //      pszPrinter.  This pointer
  80.                     //      should never be freed!
  81.     char *  pszLogAddr;         // Logical address for DevOpenDC
  82.     char *  pszPrinter;         // Printer Name
  83.     char *  pszDriver;            // Driver name
  84.     char *  pszModel;            // Driver model name
  85.     char *  pszDescription;        // Description
  86.     BOOL    fMultipleDrivers;        // TRUE => pszDriver/pszModel contain
  87.                     //    the first driver in the printer
  88.                     //    definition.  If this is a queue
  89.                     //    (lType == OD_QUEUED), the
  90.                     //    driver/model must be gotten
  91.                     //    from PM_SPOOLER_QUEUE_DD.
  92.     USHORT  cbDriverData;        // Length of driver data
  93.     BYTE *  pbDriverData;        // Driver data
  94.     struct _printer *pprtNext;        // Link to next printer
  95.     struct _printer *pprtPrev;        // Link to previous printer
  96.     struct _printerlist *pprtlist;    // Owning list
  97. } PRINTER;
  98. typedef PRINTER *PPRINTER;  /* pprt */
  99.  
  100.  
  101. //  PRINTERLIST - Structure for list of printers
  102. //
  103. typedef struct _printerlist { /* prtlist */
  104.     HAB     hab;            // Anchor block for list
  105.     PPRINTER    pprtHead;        // Head of printer list
  106.     PPRINTER    pprtTail;        // Tail of printer list
  107.     PPRINTER    pprtDefault;        // System default printer
  108. } PRINTERLIST;
  109. typedef PRINTERLIST *PPRINTERLIST; /* pprtlist */
  110.  
  111.  
  112. //  JOBPROP - Structure for exporting/importing job properties
  113. //
  114. typedef struct {    /* jp */
  115.     USHORT  cb;             // Total buffer size
  116.     USHORT  cbName;            // Size of printer name (counting NUL)
  117.     USHORT  cbDriver;            // Size of driver name (counting NUL)
  118.     USHORT  cbModel;            // Size of model name (counting NUL)
  119.     USHORT  cbData;            // Size of driver data
  120.  //
  121.  // The "fields" below show the order in which the strings/data follow the
  122.  // structure "header":
  123.  //
  124.  // CHAR    achName[];            // Printer name (asciiz)
  125.  // CHAR    achDriver[];        // Driver name (asciiz)
  126.  // CHAR    achModel[];         // Model name (asciiz)
  127.  // BYTE    abData[];            // Driver data (binary)
  128.  //
  129. } JOBPROP;
  130. typedef JOBPROP *PJOBPROP;  /* pjp */
  131.  
  132.  
  133. //************************************************************************
  134. //
  135. //  PRIVATE Global Variables
  136. //
  137. //************************************************************************
  138.  
  139.  
  140. static    char    achPath[CCHMAXPATH];
  141.  
  142.  
  143. //************************************************************************
  144. //
  145. //  PRIVATE Function Prototypes
  146. //
  147. //************************************************************************
  148.  
  149.  
  150. BOOL      AddPrinter(PPRINTERLIST pprtlist,PPRINTER pprtNew);
  151. PPRINTER  ClonePrinter(PPRINTER pprtOriginal,char *pszLogAddr);
  152. PPRINTER  CreatePrinter(LONG  lType,
  153.             char *pszLogAddr,
  154.             char *Printer,
  155.             char *pszDriver,
  156.             char *pszModel,
  157.             BOOL  fMultipleDrivers);
  158. VOID      DestroyPrinter(PPRINTER pprt);
  159. VOID      GetDriverData(PPRINTER pprt);
  160. VOID      GetDriverModel(PPRINTER pprt);
  161. VOID      GetDescription(PPRINTER pprt);
  162. PPRINTER  GetPrinterData(char *pszPrinter);
  163. PPRINTER  MatchPrinter(PPRINTERLIST pprtlist,char *pszQueue,char *pszPrinter);
  164. PSEARCHP  PrinterBeginSearch(PPRINTER *ppprt);
  165. BOOL      PrinterEndSearch(PSEARCHP psrchp);
  166. PPRINTER  PrinterNextSearch(PSEARCHP psrchp);
  167. VOID      QueryDefaultPrinterQueue(char **ppszQueue,char **ppszPrinter);
  168. PPRINTER  SplitPrinter(PPRINTERLIST pprtlist,PPRINTER pprtOld);
  169. void      TrimTrailingSemicolon(char *psz);
  170.  
  171.  
  172. //************************************************************************
  173. //
  174. //  PUBLIC Functions
  175. //
  176. //************************************************************************
  177.  
  178.  
  179. /***    PrintCreatePrinterList - Get list of printers
  180.  *
  181.  *    Use PrintQueryNextPrinter to enumerate printers.
  182.  *    Use PrintQueryPrinterInfo to get information on a printer.
  183.  *
  184.  *    Entry
  185.  *        hab - anchor block handle
  186.  *
  187.  *    Exit-Success
  188.  *        Returns HPRINTERLIST
  189.  *
  190.  *    Exit-Failure
  191.  *        Returns NULL
  192.  */
  193. HPRINTERLIST PrintCreatePrinterList(HAB hab)
  194. {
  195.     PSEARCHP        psrchp=NULL;
  196.     static PPRINTER pprt;
  197.     PPRINTER        pprtQueue=NULL;
  198.     PPRINTER        pprtPrinter=NULL;
  199.     PPRINTERLIST    pprtlist;
  200.     static char *   pszPrinter;
  201.     static char *   pszQueue;
  202.  
  203.     // Build initial printer list
  204.  
  205.     psrchp = PrinterBeginSearch(&pprt); // Get first printer
  206.     if (psrchp == NULL)         // No printers installed
  207.     return NULL;            //  Fail
  208.  
  209.     pprtlist = MemAlloc(sizeof(PRINTERLIST)); // Create list
  210.     if (pprtlist == NULL) {        // No memory
  211.     PrinterEndSearch(psrchp);    // Done searching
  212.     return NULL;            // Fail
  213.     }
  214.     pprtlist->pprtHead = NULL;
  215.     pprtlist->pprtTail = NULL;
  216.  
  217.     // Add all printers
  218.  
  219.     while (pprt != NULL) {        // Get all printers
  220.     AddPrinter(pprtlist,pprt);    // Add to list
  221.     pprt = PrinterNextSearch(psrchp); // Get another printer
  222.     }
  223.     PrinterEndSearch(psrchp);        // Done searching
  224.  
  225.     // Now we have a list of printers that may have multiple queues
  226.     // associated with them, and may have multiple drivers.
  227.     //
  228.     // Here, we split entries to get one per queue
  229.     // It may still be the case that the driver.model are incorrect
  230.     // for the Queue.  However, we do a "lazy evaluation" of this,
  231.     // using the fMultipleDrivers flag.  See PrintQueryPrinterInfo
  232.     // and GetDriverModel for more details.
  233.  
  234.     // Split any multi-queue entries
  235.  
  236.     for (pprt=pprtlist->pprtHead; pprt!=NULL; ) {
  237.     pprt = SplitPrinter(pprtlist,pprt);     // Split, if necessary
  238.     }
  239.  
  240.     // Find default printer
  241.  
  242.     QueryDefaultPrinterQueue(&pszQueue,&pszPrinter);
  243.     pprt = MatchPrinter(pprtlist,pszQueue,pszPrinter);
  244.     if (pprt == NULL)            // No default printer
  245.     pprt = pprtlist->pprtHead;    //  Choose first printer
  246.     pprtlist->pprtDefault = pprt;    // Remember default printer
  247.  
  248.     if (pszQueue != NULL)        // Free default printer/queue names
  249.     MemFree(pszQueue);
  250.     if (pszPrinter != NULL)
  251.     MemFree(pszPrinter);
  252.  
  253.     pprtlist->hab = hab;        // Remember hab
  254.     return pprtlist;            // Return list to caller
  255. }
  256.  
  257.  
  258. /***    PrintDestroyPrinterList - Destroy printer list
  259.  *
  260.  *    Entry
  261.  *        hprtlist - printer list
  262.  *
  263.  *    Exit-Success
  264.  *        Returns TRUE, list destroyed
  265.  *
  266.  *    Exit-Failure
  267.  *        Returns FALSE
  268.  */
  269. BOOL      PrintDestroyPrinterList(HPRINTERLIST hprtlist)
  270. {
  271.     PPRINTER        pprt;
  272.     PPRINTERLIST    pprtlist = hprtlist;
  273.     PPRINTER        pprtNext;
  274.  
  275.     if (pprtlist == NULL)
  276.     return FALSE;
  277.  
  278.     MemAssert(pprtlist);
  279.  
  280.     pprt = pprtlist->pprtHead;        // Start with first printer
  281.     while (pprt != NULL) {        // Loop through list
  282.     pprtNext = pprt->pprtNext;    // Next printer
  283.     DestroyPrinter(pprt);        // Destroy this one
  284.     pprt = pprtNext;        // Advance
  285.     }
  286.     return TRUE;
  287. }
  288.  
  289.  
  290. /***    PrintQueryNextPrinter - Get a printer from a list of printers
  291.  *
  292.  *    Use PrintQueryPrinterInfo to get information on a printer.
  293.  *
  294.  *    Entry
  295.  *        hprtlist - printer list
  296.  *        hprt     - starting printer
  297.  *              NULL => return first printer in list
  298.  *             !NULL => return printer after hprt
  299.  *
  300.  *    Exit-Success
  301.  *        Returns HPRT
  302.  *
  303.  *    Exit-Failure
  304.  *        Returns NULL
  305.  */
  306. HPRINTER PrintQueryNextPrinter(HPRINTERLIST hprtlist,HPRINTER hprt)
  307. {
  308.     PPRINTERLIST    pprtlist = hprtlist;
  309.     PPRINTER        pprt = hprt;
  310.  
  311.     MemAssert(pprtlist);
  312.     if (pprt == NULL)            // Get first printer
  313.     return pprtlist->pprtHead;
  314.     else {                // Get next printer
  315.     MemAssert(pprt);
  316.     if (pprt->pprtlist != pprtlist) // Verify hprt is on specified list
  317.         MemAssert(NULL);
  318.     return pprt->pprtNext;
  319.     }
  320. }
  321.  
  322.  
  323. /***    PrintQueryDefaultPrinter - Return default printer
  324.  *
  325.  *    Entry
  326.  *        hprtlist - printer list
  327.  *
  328.  *    Exit
  329.  *        Returns HPRINTER of default printer.
  330.  */
  331. HPRINTER PrintQueryDefaultPrinter(HPRINTERLIST hprtlist)
  332. {
  333.     PPRINTERLIST    pprtlist = hprtlist;
  334.  
  335.     MemAssert(pprtlist);
  336.     return pprtlist->pprtDefault;
  337. }
  338.  
  339.  
  340. /***    PrintQueryPrinterInfo - Get info on a printer
  341.  *
  342.  *    Entry
  343.  *        hprt  - printer handle
  344.  *        index - index of printer info
  345.  *
  346.  *    Exit-Success
  347.  *        Returns requested information
  348.  *        PQPI_NAME      - char * - Nice name
  349.  *        PQPI_LOG_ADDRESS  - char * - Logical address
  350.  *        PQPI_DRIVER      - char * - Driver name
  351.  *        PQPI_MODEL      - char * - Model name
  352.  *        PQPI_TYPE      - ULONG  - OD_QUEUED or OD_DIRECT
  353.  *        PQPI_PRINTER      - char * - Printer name
  354.  *        PQPI_DESCRIPTION  - char * - Description
  355.  *
  356.  *    Exit-Failure
  357.  *        Returns -1L
  358.  */
  359. ULONG PrintQueryPrinterInfo(HPRINTER hprt,USHORT index)
  360. {
  361.     PPRINTER    pprt = hprt;
  362.  
  363.     MemAssert(pprt);
  364.     switch (index) {
  365.     case PQPI_NAME:
  366.         return (ULONG)(VOID FAR *)pprt->pszName;
  367.  
  368.     case PQPI_LOG_ADDRESS:
  369.         return (ULONG)(VOID FAR *)pprt->pszLogAddr;
  370.  
  371.     case PQPI_DRIVER:
  372.         GetDriverModel(pprt);    // Make sure we get correct data
  373.         return (ULONG)(VOID FAR *)pprt->pszDriver;
  374.  
  375.     case PQPI_MODEL:
  376.         GetDriverModel(pprt);    // Make sure we get correct data
  377.         return (ULONG)(VOID FAR *)pprt->pszModel;
  378.  
  379.     case PQPI_TYPE:
  380.         return pprt->lType;
  381.  
  382.     case PQPI_PRINTER:
  383.         return (ULONG)(VOID FAR *)pprt->pszPrinter;
  384.  
  385.     case PQPI_DESCRIPTION:
  386.         GetDescription(pprt);    // Get appropriate description
  387.         return (ULONG)(VOID FAR *)pprt->pszDescription;
  388.  
  389.     default:
  390.         return -1L;
  391.     }
  392. }
  393.  
  394.  
  395. /***    PrintOpenDC - Open DC on specified printer
  396.  *
  397.  *    Entry
  398.  *        hab     - Anchor block
  399.  *        hprt    - Printer handle
  400.  *        pszDataType - "PM_Q_STD" or "PM_Q_RAW"
  401.  *
  402.  *    Exit-Success
  403.  *        Returns hdc
  404.  *
  405.  *    Exit-Failure
  406.  *        Returns NULL
  407.  */
  408. HDC PrintOpenDC(HAB hab,HPRINTER hprt,char *pszDataType)
  409. {
  410.     DEVOPENSTRUC    dop;
  411.     HDC         hdc;
  412.     PPRINTER        pprt = hprt;
  413.  
  414.     MemAssert(pprt);
  415.     GetDriverData(pprt);        // Make sure we have driver data
  416.  
  417.     dop.pszLogAddress = pprt->pszLogAddr; // Logical address
  418.     dop.pszDriverName = pprt->pszDriver; // Driver name (PSCRIPT)
  419.     dop.pdriv          = (VOID *)pprt->pbDriverData; // Driver data
  420.     dop.pszDataType   = pszDataType;    // PM_Q_STD or PM_Q_RAW
  421.  
  422.  // dop.pszComment    = "stock chart";    // Comment for OD_Q
  423.  // dop.pszQueueProcName   = NULL;    // queue processor; NULL => use default
  424.  // dop.pszQueueProcParams = NULL;    // parms for queue processor
  425.  // dop.pszSpoolerParams   = NULL;    // spooler parms (use NULL!)
  426.  // dop.pszNetworkParams   = NULL;    // network parms (use NULL!)
  427.  
  428.     hdc = DevOpenDC(
  429.         hab,            // anchor block
  430.         pprt->lType,        // DC type: OD_DIRECT or OD_QUEUED
  431.         "*",            // device info(?) "*"
  432.         4L,             // count of info in DEVOPENSTRUC
  433.         (PDEVOPENDATA)&dop,     // DEVOPENSTRUC
  434.         NULL            // Compatible DC (use NULL?)
  435.     );
  436.     return hdc;
  437. }
  438.  
  439.  
  440. /***    PrintQueryJobProperties - Get printer job properties
  441.  *
  442.  *    Entry
  443.  *        hprt    - printer handle
  444.  *        pcbData - pointer to size of pb buffer in bytes
  445.  *            Pass 0 to determine required buffer size.
  446.  *        pbData  - pointer to buffer to receive job properties
  447.  *
  448.  *    Exit-Success
  449.  *        Returns TRUE, job properties retrieved
  450.  *        pb filled in with job property data
  451.  *        pcb filled in with size of pb data
  452.  *
  453.  *    Exit-Failure
  454.  *        Returns FALSE, pb too small for job properties
  455.  *        pcb filled in with required size
  456.  *
  457.  *    Note
  458.  *        (1) It is valid for a printer to require no job properties.
  459.  *        In this case, *pcb == 0.
  460.  */
  461. BOOL PrintQueryJobProperties(HPRINTER hprt,USHORT *pcbData,BYTE *pbData)
  462. {
  463.     USHORT    cb;            // Total buffer size
  464.     USHORT    cbData;         // Size of driver data
  465.     USHORT    cbDriver;        // Size of driver name (counting NUL)
  466.     USHORT    cbModel;        // Size of model name (counting NUL)
  467.     USHORT    cbName;         // Size of printer name (counting NUL)
  468.     BYTE *    pb;
  469.     PJOBPROP    pjp;
  470.     PPRINTER    pprt = hprt;
  471.  
  472.     MemAssert(pprt);
  473.     GetDriverData(pprt);        // Make sure we have driver data
  474.  
  475.     cbName   = strlen(pprt->pszName)+1; // Count NUL
  476.     cbDriver = strlen(pprt->pszDriver)+1; // Count NUL
  477.     cbModel  = strlen(pprt->pszModel)+1; // Count NUL
  478.     cbData   = pprt->cbDriverData;    // Driver data length
  479.  
  480.     // Check size of return buffer
  481.  
  482.     cb = sizeof(JOBPROP)+cbName+cbDriver+cbModel+cbData;
  483.     if (*pcbData < cb) {        // Check buffer size
  484.     *pcbData = cb;            //  Too small, return required size
  485.     return FALSE;            // Indicate failure
  486.     }
  487.  
  488.     // Fill in return buffer
  489.  
  490.     pjp = (PJOBPROP)pbData;
  491.     pjp->cb      = cb;
  492.     pjp->cbName   = cbName;
  493.     pjp->cbDriver = cbDriver;
  494.     pjp->cbModel  = cbModel;
  495.     pjp->cbData   = cbData;
  496.  
  497.     pb = (BYTE *)pjp+sizeof(JOBPROP);    // Start of data space
  498.  
  499.     pb = memcpy(pb,pprt->pszName,cbName);
  500.     pb += cbName;
  501.  
  502.     pb = memcpy(pb,pprt->pszDriver,cbDriver);
  503.     pb += cbDriver;
  504.  
  505.     pb = memcpy(pb,pprt->pszModel,cbModel);
  506.     pb += cbModel;
  507.  
  508.     memcpy(pb,pprt->pbDriverData,cbData);
  509.  
  510.     *pcbData = cb;            // Return actual size
  511.     return TRUE;
  512. }
  513.  
  514.  
  515. /***    PrintChangeJobProperties - Let user change printer job properties
  516.  *
  517.  *    Entry
  518.  *        hprt    - printer handle
  519.  *
  520.  *    Exit-Success
  521.  *        Returns TRUE, job properties changed
  522.  *
  523.  *    Exit-Failure
  524.  *        Returns FALSE, job properties not changed
  525.  */
  526. BOOL PrintChangeJobProperties(HPRINTER hprt)
  527. {
  528.     HAB     hab;
  529.     BYTE *    pb;
  530.     PPRINTER    pprt = hprt;
  531.     char *    pszName;
  532.     LONG    rc;
  533.  
  534.     MemAssert(pprt);
  535.     MemAssert(pprt->pprtlist);
  536.     hab = pprt->pprtlist->hab;
  537.  
  538.     GetDriverData(pprt);        // Try to get driver data
  539.  
  540.     if (pprt->pbDriverData != NULL) {    // We do have it
  541.     pb = pprt->pbDriverData;    //  Use our data as starting point
  542.     pszName = NULL;         // Do not use printer name
  543.     }
  544.     else {
  545.     pb = NULL;            // We have no data
  546.     pszName = pprt->pszName;    // Tell driver to get it from printer
  547.     }
  548.  
  549.     rc = DevPostDeviceModes(
  550.         hab,            // Anchor block
  551.         (VOID *)pb,         // Buffer for data
  552.         pprt->pszDriver,        // Driver name
  553.         pprt->pszModel,        // Device name
  554.         pszName,            // Printer name
  555.         DPDM_POSTJOBPROP        // Option
  556.     );
  557.     return (rc == DEV_OK);
  558. }
  559.  
  560.  
  561. /***    PrintResetJobProperties - Reset printer to default job properties
  562.  *
  563.  *    Entry
  564.  *        hprt - printer handle
  565.  *
  566.  *    Exit
  567.  *        Job properties set to default for printer
  568.  */
  569. VOID PrintResetJobProperties(HPRINTER hprt)
  570. {
  571.     HAB     hab;
  572.     PPRINTER    pprt = hprt;
  573.  
  574.     MemAssert(pprt);
  575.     MemAssert(pprt->pprtlist);
  576.     hab = pprt->pprtlist->hab;
  577.  
  578.     // Free properties, if present
  579.  
  580.     if (pprt->pbDriverData != NULL) {
  581.     MemFree(pprt->pbDriverData);
  582.     pprt->pbDriverData = NULL;
  583.     pprt->cbDriverData = 0;
  584.     }
  585.  
  586.     // Get job properties
  587.  
  588.     GetDriverData(pprt);
  589. }
  590.  
  591.  
  592. /***    PrintMatchPrinter - Select printer that matches job properties
  593.  *
  594.  *    Entry
  595.  *        hprtlist - printer list
  596.  *        cbData   - size of pb buffer in bytes
  597.  *        pbData   - buffer with job properties
  598.  *
  599.  *    Exit-Success
  600.  *        Returns valid HPRINTER that matches Job Properties
  601.  *        Supplied job properties are set for printer.
  602.  *
  603.  *    Exit-Failure
  604.  *        Returns NULL, no matching printer
  605.  *        Caller should use default printer (PrintQueryDefaultPrinter)
  606.  */
  607. HPRINTER PrintMatchPrinter(HPRINTERLIST hprtlist,USHORT cbData,BYTE *pbData)
  608. {
  609.     ULONG        cb;
  610.     HAB         hab;
  611.     BYTE *        pb;         // Driver data
  612.     PJOBPROP        pjp;
  613.     PPRINTER        pprt;
  614.     PPRINTER        pprtMatch;
  615.     PPRINTERLIST    pprtlist = hprtlist;
  616.     char *        pszDriver;        // Driver name
  617.     char *        pszModel;        // Model name
  618.     char *        pszName;        // Printer name
  619.  
  620.     MemAssert(pprtlist);
  621.     hab = pprtlist->hab;
  622.  
  623.     // Buffer must be at least as large as header
  624.  
  625.     if (cbData < sizeof(JOBPROP))    // Too small
  626.     return NULL;            //  Fail
  627.  
  628.     // Check internal length
  629.  
  630.     pjp = (PJOBPROP)pbData;        // Point at header
  631.     if (pjp->cb != cbData)        // Internal length does not match
  632.     return NULL;            //  Fail
  633.  
  634.     // Check internal counts
  635.  
  636.     cb = pjp->cbName+pjp->cbDriver+pjp->cbModel+pjp->cbData+sizeof(JOBPROP);
  637.     if (cb > (ULONG)USHRT_MAX)        // Numbers too large
  638.     return NULL;
  639.     if ((USHORT)cb != cbData)        // Lengths do not match
  640.     return NULL;
  641.  
  642.     // Set string/data pointers
  643.  
  644.     pszName = (BYTE *)pjp+sizeof(JOBPROP); // Name
  645.     pszDriver = pszName + pjp->cbName;       // Driver
  646.     pszModel = pszDriver + pjp->cbDriver;  // Model
  647.     pb = pszModel + pjp->cbModel;       // Data
  648.  
  649.     // Try to find close match
  650.     //
  651.     // If we find a printer that matches Name, Driver, Model, and driver
  652.     // data size, we have an exact match, and return that.
  653.     //
  654.     // If we find a printer that matches all but the Name, we return the
  655.     // first such printer (after examining all printers to make sure there
  656.     // is no exact match.
  657.     //
  658.     // Otherwise, we return NULL.
  659.  
  660.     pprtMatch = NULL;            // No match, yet
  661.     for (pprt=pprtlist->pprtHead; pprt!=NULL; pprt=pprt->pprtNext) {
  662.     if ( (stricmp(pprt->pszDriver,pszDriver) == 0) &&
  663.          (stricmp(pprt->pszModel,pszModel) == 0) ) { // Match Driver.Model
  664.  
  665.         cb = DevPostDeviceModes(    // Get driver data size
  666.             hab,        // Anchor block
  667.             NULL,        // Buffer for data (NULL returns size)
  668.             pprt->pszDriver,    // Driver name
  669.             pprt->pszModel,    // Device name
  670.             NULL,        // Printer name
  671.             DPDM_QUERYJOBPROP    // Option
  672.         );
  673.  
  674.         if (cb == pjp->cbData) {    // Match driver data size
  675.         if (stricmp(pprt->pszName,pszName) == 0) { // Exact match?
  676.             pprtMatch = pprt;    // Exact match
  677.             break;        // Exit loop
  678.         }
  679.         else if (pprtMatch == NULL) // First close match
  680.             pprtMatch = pprt;    // Remember close match
  681.         }
  682.     }
  683.     }
  684.  
  685.     // Update job properties in printer
  686.  
  687.     if (pprtMatch != NULL) {        // Found a match
  688.     if (pprt->pbDriverData == NULL) // No buffer, yet
  689.         pprt->pbDriverData = MemAlloc(pjp->cbData); // Alloc buffer
  690.  
  691.     if (pprt->pbDriverData != NULL) { // Have buffer
  692.         memcpy(pprt->pbDriverData,pb,pjp->cbData); // Save job properties
  693.         pprt->cbDriverData = pjp->cbData; // Save JP size
  694.     }
  695.     }
  696.     return pprtMatch;            // Return best match
  697. }
  698.  
  699.  
  700. //************************************************************************
  701. //
  702. //  PRIVATE Functions
  703. //
  704. //************************************************************************
  705.  
  706.  
  707. /***    MatchPrinter - Look for printer in list
  708.  *
  709.  *    Entry
  710.  *        pprtlist   - Printer list
  711.  *        pszQueue   - Queue name to match (may be NULL)
  712.  *        pszPrinter - Printer name to match (may be NULL)
  713.  *
  714.  *    Exit-Success
  715.  *        Returns TRUE
  716.  *
  717.  *    Exit-Failure
  718.  *        Returns FALSE
  719.  */
  720. PPRINTER MatchPrinter(PPRINTERLIST pprtlist,char *pszQueue,char *pszPrinter)
  721. {
  722.     PPRINTER    pprt;
  723.  
  724.     for (pprt=pprtlist->pprtHead; pprt!=NULL; pprt=pprt->pprtNext) {
  725.     if ((pprt->lType == OD_QUEUED) && (pszQueue != NULL)) { // A queue
  726.         if (strcmp(pprt->pszLogAddr,pszQueue) == 0)
  727.         return pprt;
  728.     }
  729.     else if (pszPrinter != NULL) {    // A direct printer
  730.         if (strcmp(pprt->pszPrinter,pszPrinter) == 0)
  731.         return pprt;
  732.     }
  733.     }
  734.     return NULL;
  735. }
  736.  
  737.  
  738. /***    AddPrinter - Add printer to printer list (if unique)
  739.  *
  740.  *    NOTE: If the printer is not added, it is freed!
  741.  *
  742.  *    Entry
  743.  *        pprtlist - printer list
  744.  *        pprt     - printer to be added
  745.  *
  746.  *    Exit-Success
  747.  *        Returns TRUE
  748.  *
  749.  *    Exit-Failure
  750.  *        Returns FALSE
  751.  */
  752. BOOL AddPrinter(PPRINTERLIST pprtlist,PPRINTER pprtNew)
  753. {
  754.     PPRINTER    pprt;
  755.  
  756.     // Avoid duplicate entry
  757.  
  758.     if (pprtNew->lType == OD_QUEUED) {    // Queue, check for duplicate
  759.     pprt = MatchPrinter(pprtlist,pprtNew->pszLogAddr,NULL);
  760.     if (pprt != NULL) {        // Found a match
  761.         pprt->fMultipleDrivers = TRUE; // Force query of driver/model
  762.         DestroyPrinter(pprtNew);    // No need for new printer
  763.         return TRUE;        // Do not add printer
  764.     }
  765.     }
  766.     else {                // Direct printer
  767.     // Do nothing, since Print Manager/Spooler never produce
  768.     // duplicate printers.
  769.     ;                // Do nothing
  770.     }
  771.  
  772.     // Link onto list
  773.  
  774.     pprtNew->pprtPrev = pprtlist->pprtTail; // Set previous printer
  775.     if (pprtlist->pprtHead == NULL)    // List is empty
  776.     pprtlist->pprtHead = pprtNew;    // Put at head of list
  777.     else
  778.     pprtlist->pprtTail->pprtNext = pprtNew; // Add at end of list
  779.     pprtlist->pprtTail = pprtNew;    // New tail of list
  780.     pprtNew->pprtNext = NULL;        // Set next printer
  781.  
  782.     pprtNew->pprtlist = pprtlist;    // Point at owning list
  783.     return TRUE;
  784. }
  785.  
  786.  
  787. /***    SplitPrinter - Split printer if it contains multiple queue names
  788.  *
  789.  *    Entry
  790.  *        pprtlist - printer list
  791.  *        pprt     - printer to be split
  792.  *
  793.  *    Exit
  794.  *        Returns next PPRINTER
  795.  */
  796. PPRINTER SplitPrinter(PPRINTERLIST pprtlist,PPRINTER pprtOld)
  797. {
  798.     PPRINTER    pprt;
  799.     PPRINTER    pprtNext;
  800.     PPRINTER    pprtPrev;
  801.     char *    psz;
  802.     char *    psz1;
  803.     USHORT    cprtAdded=0;
  804.  
  805.     if (pprtOld->lType != OD_QUEUED)    // If not a queue
  806.     return pprtOld->pprtNext;    //  Next printer
  807.  
  808.     psz = strpbrk(pprtOld->pszLogAddr,","); // Find queue name separator
  809.     if (psz == NULL)            // If no separator
  810.     return pprtOld->pprtNext;    //  Next printer
  811.  
  812.     // Split up the printer
  813.  
  814.     strcpy(achPath,pprtOld->pszLogAddr); // Get working copy of queue name
  815.     psz = achPath;
  816.     while (psz != NULL) {
  817.     psz1 = strpbrk(psz,",");    // Find separator
  818.     if (psz1 != NULL) {        // Found one
  819.         *psz1 = '\0';        // Terminate this queue name
  820.         psz1++;            // Advance to next queue name
  821.     }
  822.     pprt = ClonePrinter(pprtOld,psz); // Clone with different pszLogAddr
  823.     if (pprt == NULL)        // Clone failed
  824.         psz = NULL;         // Exit loop
  825.     else {                // Clone successful
  826.         AddPrinter(pprtlist,pprt);    // Add new printer
  827.         cprtAdded++;        // Printer (may have been) added
  828.         psz = psz1;         // Advance to next queue (if any)
  829.         // Note: AddPrinter may not have actually added the printer,
  830.         //         because it the split printer may have been a duplicate.
  831.         //         That is okay, though, because we use cprtAdded only
  832.         //         to know if we can delete pprtOld.
  833.     }
  834.     }
  835.  
  836.     // Delete old printer, if we were able to split it
  837.     //
  838.     // If we were not able to clone the printer at all, then we leave
  839.     // it in the list, since the queue list was truncated to the first
  840.     // queue name!
  841.     //
  842.     // The normal case, however, is that we did split it successfully,
  843.     // so we want to delete the old printer.
  844.     //
  845.     // NOTE: If we were guaranteed that one of the AddPrinter calls actually
  846.     //         added a printer, we would *know* that pprtNext would never be
  847.     //         NULL.  However, it is possible that a split could result in
  848.     //         printers that are *all* already in the list.  Besides, the
  849.     //         code is more robust this way.
  850.  
  851.     pprtNext = pprtOld->pprtNext;    // Next printer
  852.     if (cprtAdded != 0) {        // Have to delete old printer
  853.     pprtPrev = pprtOld->pprtPrev;    // Previous printer
  854.     if (pprtNext != NULL)        // There is a following printer
  855.         pprtNext->pprtPrev = pprtPrev; // Set back link
  856.     if (pprtPrev != NULL)        // There is a preceding printer
  857.         pprtPrev->pprtNext = pprtNext; // Set forward link
  858.     DestroyPrinter(pprtOld);    // No need for this anymore
  859.     }
  860.  
  861.     return pprtNext;            // Next printer
  862. }
  863.  
  864.  
  865. /***    ClonePrinter - Create a duplicate PRINTER with a different pszLogAddr
  866.  *
  867.  *    Entry
  868.  *        pprt       - printer to clone
  869.  *        pszLogAddr - logical address to set (QUEUE1)
  870.  *
  871.  *    Exit-Success
  872.  *        Returns PPRINTER
  873.  *
  874.  *    Exit-Failure
  875.  *        Returns NULL
  876.  */
  877. PPRINTER ClonePrinter(PPRINTER pprtOriginal,char *pszLogAddr)
  878. {
  879.     PPRINTER    pprt;
  880.  
  881.     pprt = CreatePrinter(
  882.         pprtOriginal->lType,        // Copy type
  883.         pszLogAddr,            // New logical address
  884.         pprtOriginal->pszPrinter,    // Copy printer
  885.         pprtOriginal->pszDriver,    // Copy driver
  886.         pprtOriginal->pszModel,     // Copy model
  887.         pprtOriginal->fMultipleDrivers    // Copy flag
  888.        );
  889.     return pprt;
  890. }
  891.  
  892.  
  893. /***    GetDriverModel - Get Driver and Model for a printer
  894.  *
  895.  *    Entry
  896.  *        pprt - printer
  897.  *
  898.  *    Exit
  899.  *        If printer was a queue, and the existing printer/model may
  900.  *        not be the one the user setup, get it from the HINI_SYSTEM.
  901.  *
  902.  *    Uses
  903.  *        achPath
  904.  *
  905.  *    NOTE 1:
  906.  *        We *need* to query the PM_SPOOLER_QUEUE_DD section *only* if the
  907.  *        queue might have more than one driver associated with it.  This
  908.  *        could happen in several cases:
  909.  *
  910.  *        1)  If the queue is associated with a single printer, but
  911.  *            that printer has more than one driver/model pair.
  912.  *
  913.  *        2)  If the queue is associated with more than one printer,
  914.  *            and the set of driver/model pairs supported by
  915.  *            these printers has more than one member.
  916.  *
  917.  *        (1) Is easy to compute (we keep a flag when we build the PRINTER
  918.  *        object).
  919.  *
  920.  *        (2) Is more complicated, so we compute a cheaper version:
  921.  *
  922.  *        2a) If the queue is associated with more than one printer.
  923.  *
  924.  *        We compute this in AddPrinter.    If AddPrinter tries to add
  925.  *        a PRINTER that has a pszLogAddr that matches one already
  926.  *        added, then it knows we have a queue pointing to more than
  927.  *        one printer.  So, it sets the fMultipleDrivers flag, and then
  928.  *        the code below can use that single flag to determine if it
  929.  *        has to get the driver/model from HINI_SYSTEM).
  930.  *
  931.  *    NOTE 2:
  932.  *         For an OD_DIRECT printer (no queue) there is no way to figure
  933.  *         out which driver/model pair to use, so we take the first one
  934.  *         in the list!  Since that is what we did when we built the
  935.  *         printer object initialy, we have nothing to do.
  936.  */
  937. VOID GetDriverModel(PPRINTER pprt)
  938. {
  939.     LONG    cb;
  940.     char *  psz;
  941.     char *  pszDriver;
  942.     char *  pszModel;
  943.  
  944.  
  945.     if (pprt->lType != OD_QUEUED)    // Not a queue
  946.     return;             //  Driver.model are correct
  947.  
  948.     if (!pprt->fMultipleDrivers)    // Only one driver
  949.     return;             //  No change needed
  950.  
  951.     // We have a queue with multiple driver.model choices
  952.  
  953.     pprt->fMultipleDrivers = FALSE;    // Only do this computation once
  954.  
  955.     // Get driver.model for this queue
  956.  
  957.     cb = PrfQueryProfileString(
  958.         HINI_SYSTEM,        // system ini
  959.         "PM_SPOOLER_QUEUE_DD",    // app section
  960.         pprt->pszName,        // printer name
  961.         "",             // Default value
  962.         achPath,            // Buffer to receive value
  963.         (ULONG)sizeof(achPath)    // Buffer size
  964.     );
  965.     if (cb <= 1)            // No driver.model
  966.     return;             // Use existing one
  967.  
  968.     // Parse driver.model string
  969.  
  970.     psz = achPath;
  971.     // A: "IBM4201;"
  972.     //       ^
  973.     // B: "LASERJET.HP LaserJet IID;"
  974.     //       ^
  975.  
  976.     // Parse the driver and model names
  977.  
  978.     pszDriver = psz;            // Set driver name
  979.     psz = strpbrk(psz,".;");        // Find separator
  980.     if (psz == NULL)            // Bad format
  981.     return;             //  Exit without changing
  982.     if (*psz == '.') {            // Found model name separator
  983.     *psz = '\0';            // Null terminate driver name
  984.     pszModel = psz + 1;        // Set model name
  985.     psz = strpbrk(pszModel,";");    // Find end of model name
  986.     if (psz == NULL)        // Bad format
  987.         return;            //  Exit without changing
  988.     }
  989.     else                // No model name
  990.     pszModel = pszDriver;        // Make model same as driver name
  991.     *psz = '\0';            // Null terminate driver name
  992.  
  993.     // Create string copies
  994.  
  995.     pszDriver = MemStrDup(pszDriver);
  996.     if (pszDriver == NULL)
  997.     return;
  998.  
  999.     pszModel = MemStrDup(pszModel);
  1000.     if (pszModel == NULL) {
  1001.     MemFree(pszDriver);
  1002.     return;
  1003.     }
  1004.  
  1005.     // Update printer structure
  1006.  
  1007.     if (pprt->pszDriver != NULL)
  1008.     MemFree(pprt->pszDriver);
  1009.     if (pprt->pszModel != NULL)
  1010.     MemFree(pprt->pszModel);
  1011.  
  1012.     pprt->pszDriver = pszDriver;
  1013.     pprt->pszModel = pszModel;
  1014. }
  1015.  
  1016.  
  1017. /***    GetDescription - Get description from HINI_SYSTEM
  1018.  *
  1019.  *    Get printer description or queue description, as appropriate.
  1020.  *
  1021.  *    Entry
  1022.  *        pprt - printer
  1023.  *
  1024.  *    Exit
  1025.  *        Set description from HINI_SYSTEM.
  1026.  *
  1027.  *    Uses
  1028.  *        achPath
  1029.  */
  1030. VOID GetDescription(PPRINTER pprt)
  1031. {
  1032.     LONG    cb;
  1033.     char *  psz;
  1034.     char *  pszApp;
  1035.  
  1036.     if (pprt->lType == OD_QUEUED)    // Queue
  1037.     pszApp = "PM_SPOOLER_QUEUE_DESCR";
  1038.     else
  1039.     pszApp = "PM_SPOOLER_PRINTER_DESCR";
  1040.  
  1041.     cb = PrfQueryProfileString(
  1042.         HINI_SYSTEM,        // System ini
  1043.         pszApp,            // App
  1044.         pprt->pszName,        // Queue/printer name
  1045.         "",             // Default value
  1046.         achPath,            // Buffer to receive value
  1047.         (ULONG)sizeof(achPath)    // Buffer size
  1048.     );
  1049.     if (cb <= 1)            // No description
  1050.     return;             // Use existing one
  1051.  
  1052.     // Parse description
  1053.  
  1054.     psz = achPath;
  1055.     psz = strpbrk(psz,";");        // Find end of description
  1056.     if (psz == NULL)            // Bad format
  1057.     return;             //  Exit without changing
  1058.     *psz = '\0';            // Null terminate desription
  1059.  
  1060.     // Duplicate description
  1061.  
  1062.     psz = MemStrDup(achPath);
  1063.     if (psz == NULL)
  1064.     return;
  1065.  
  1066.     if (pprt->pszDescription != NULL)
  1067.     MemFree(pprt->pszDescription);
  1068.     pprt->pszDescription = psz;
  1069. }
  1070.  
  1071.  
  1072. /***    QueryDefaultPrinterQueue - Get the default printer and queue
  1073.  *
  1074.  *    Entry
  1075.  *        ppszQueue    - pointer to receive pointer to queue name
  1076.  *        ppszPrinter - pointer to receive pointer to printer name
  1077.  *
  1078.  *    Exit
  1079.  *        One or both of ppszQueue/ppszPrinter may be set to NULL!
  1080.  *        Caller must call MemFree on ppszQueue/Printer!
  1081.  *
  1082.  *    Uses
  1083.  *        achPath
  1084.  */
  1085. VOID QueryDefaultPrinterQueue(char **ppszQueue,char **ppszPrinter)
  1086. {
  1087.     ULONG   cb;
  1088.  
  1089.     // Get default printer and queue
  1090.  
  1091.     cb = PrfQueryProfileString(
  1092.         HINI_USER,            // OS2.INI
  1093.         "PM_SPOOLER",        // Application
  1094.         "PRINTER",            // Variable
  1095.         "",             // Default value
  1096.         achPath,            // Buffer to receive value
  1097.         (ULONG)sizeof(achPath)    // Buffer size
  1098.      );
  1099.     if (cb == 0)            // Couldn't get value
  1100.     *ppszPrinter = NULL;
  1101.     else {
  1102.     TrimTrailingSemicolon(achPath); // Get rid of trailing ";"
  1103.     *ppszPrinter = MemStrDup(achPath);
  1104.     }
  1105.  
  1106.     cb = PrfQueryProfileString(
  1107.         HINI_USER,            // OS2.INI
  1108.         "PM_SPOOLER",        // Application
  1109.         "QUEUE",            // Variable
  1110.         "",             // Default value
  1111.         achPath,            // Buffer to receive value
  1112.         (ULONG)sizeof(achPath)    // Buffer size
  1113.      );
  1114.     if (cb == 0)
  1115.     *ppszQueue = NULL;        // Couldn't get value
  1116.     else {
  1117.     TrimTrailingSemicolon(achPath); // Get rid of trailing ";"
  1118.     *ppszQueue = MemStrDup(achPath);
  1119.     }
  1120. }
  1121.  
  1122.  
  1123. /***    TrimTrailingSemicolon - truncate string at first semicolon
  1124.  *
  1125.  *    Entry
  1126.  *        psz - string to truncate
  1127.  *    Exit
  1128.  *        String truncated at first semicolon (if any)
  1129.  */
  1130. void TrimTrailingSemicolon(char *psz)
  1131. {
  1132.     while ((*psz != '\0') && (*psz != ';'))
  1133.     psz++;
  1134.     *psz = '\0';
  1135. }
  1136.  
  1137.  
  1138. /***    PrinterBeginSearch - Start enumeration of installed printers
  1139.  *
  1140.  *    Entry
  1141.  *        ppprt - pointer to receive pointer to printer
  1142.  *
  1143.  *    Exit-Success
  1144.  *        Returns search handle, ppprt filled in
  1145.  *
  1146.  *    Exit-Failure
  1147.  *        Returns NULL
  1148.  */
  1149. PSEARCHP PrinterBeginSearch(PPRINTER *ppprt)
  1150. {
  1151.     ULONG    cb;
  1152.     ULONG    cb1;
  1153.     BOOL    f;
  1154.     PSEARCHP    psrchp;
  1155.  
  1156.     // Get size of buffer for printer names
  1157.  
  1158.     f = PrfQueryProfileSize(
  1159.         HINI_SYSTEM,        // Only look in system profile
  1160.         "PM_SPOOLER_PRINTER",    // Pointer to application name
  1161.         NULL,            // Pointer to keyname
  1162.         &cb             // Pointer to return buffer size
  1163.         );
  1164.     if (!f)
  1165.     return NULL;            // Failed
  1166.  
  1167.     // Create search structure
  1168.  
  1169.     psrchp = MemAlloc(sizeof(SEARCHP));
  1170.     if (psrchp == NULL)
  1171.     return NULL;
  1172.     psrchp->pchNext = NULL;
  1173.  
  1174.     // Allocate buffer for names
  1175.  
  1176.     psrchp->pchName = MemAlloc((USHORT)cb);
  1177.     if (psrchp->pchName == NULL) {
  1178.     PrinterEndSearch(psrchp);    // Frees search structure
  1179.     return NULL;            // Failed
  1180.     }
  1181.  
  1182.     // Get all printer names
  1183.  
  1184.     cb1 = PrfQueryProfileString(
  1185.         HINI_SYSTEM,        // Only look in system profile
  1186.         "PM_SPOOLER_PRINTER",    // Application name
  1187.         NULL,            // Keyname
  1188.         "",             // Default value
  1189.         psrchp->pchName,        // Name list to be returned
  1190.         cb                // Buffer size
  1191.         );
  1192.  
  1193.     if (cb1 == 0) {            // No printers installed
  1194.     PrinterEndSearch(psrchp);
  1195.     return NULL;
  1196.     }
  1197.  
  1198.     // Get first printer
  1199.  
  1200.     psrchp->pchNext = psrchp->pchName;    // Start at first printer
  1201.     *ppprt = PrinterNextSearch(psrchp); // Get a printer
  1202.     if (*ppprt != NULL)         // Found one
  1203.     return psrchp;            //  Return success
  1204.     else {
  1205.     PrinterEndSearch(psrchp);    // No printer found
  1206.     return NULL;            //  Return failure
  1207.     }
  1208. }
  1209.  
  1210.  
  1211. /***    PrinterNextSearch - Continue enumeration of installed printers
  1212.  *
  1213.  *    Entry
  1214.  *        psrchp - search handle from PrinterBeginSearch
  1215.  *
  1216.  *    Exit-Success
  1217.  *        Returns PPRINTER
  1218.  *
  1219.  *    Exit-Failure
  1220.  *        Returns NULL
  1221.  */
  1222. PPRINTER PrinterNextSearch(PSEARCHP psrchp)
  1223. {
  1224.     PPRINTER    pprt=NULL;
  1225.  
  1226.     // Scan printers until we find a valid one, or the list is exhausted
  1227.     while ((*psrchp->pchNext != '\0') && (pprt == NULL)) {
  1228.     pprt = GetPrinterData(psrchp->pchNext); // Get printer
  1229.     psrchp->pchNext += strlen(psrchp->pchNext)+1; // Next printer
  1230.     }
  1231.     return pprt;
  1232. }
  1233.  
  1234.  
  1235. /***    PrinterEndSearch - End enumeration of installed printer drivers
  1236.  *
  1237.  *    Entry
  1238.  *        psearchp - search handle from PrinterBeginSearch
  1239.  *
  1240.  *    Exit-Success
  1241.  *        Returns TRUE
  1242.  *
  1243.  *    Exit-Failure
  1244.  *        Returns FALSE
  1245.  */
  1246. BOOL PrinterEndSearch(PSEARCHP psrchp)
  1247. {
  1248.     if (psrchp == NULL)
  1249.     return TRUE;
  1250.  
  1251.     if (psrchp->pchName != NULL)
  1252.     MemFree(psrchp->pchName);
  1253.     MemFree(psrchp);
  1254.     return TRUE;
  1255. }
  1256.  
  1257.  
  1258. /***    GetPrinterData - Get printer data
  1259.  *
  1260.  *    Entry
  1261.  *        achPrinter - printer name
  1262.  *
  1263.  *    Exit-Success
  1264.  *        returns PPRINTER
  1265.  *
  1266.  *        NOTE 1: if lType == OD_QUEUED, then pprt->pszLogAddr is one or
  1267.  *            more queue names (separated by ",").
  1268.  *
  1269.  *            The caller should clone the PRINTER structure as many
  1270.  *            times as necessary so that there is one for each queue.
  1271.  *
  1272.  *        NOTE 2: pprt->pszDescription is not filled in.
  1273.  *
  1274.  *            After the caller solves Note 1, the description should
  1275.  *            be retrieved from OS2.INI.    Use PM_SPOOLER_QUEUE_DESCR
  1276.  *            for a queue, and PM_SPOOLER_PRINTER_DESCR for a port
  1277.  *            (both in HINI_SYSTEM)
  1278.  *
  1279.  *        NOTE 3: pprt->pszDriver/pszModel may not be correct
  1280.  *
  1281.  *            After the caller solves Note 1, for each queue the
  1282.  *            driver/model should be retrieved from PM_SPOOLER_QUEUE_DD
  1283.  *            (in HINI_SYSTEM).
  1284.  *
  1285.  *    Exit-Failure
  1286.  *        Returns NULL
  1287.  *
  1288.  *    Uses
  1289.  *        achPath
  1290.  */
  1291. PPRINTER GetPrinterData(char *pszPrinter)
  1292. {
  1293.     USHORT    cb;
  1294.     BOOL    fComma;         // True if multiple drivers
  1295.     ULONG    lType;
  1296.     PPRINTER    pprt;
  1297.     char *    psz;
  1298.     char *    pszDriver;
  1299.     char *    pszLogAddr;
  1300.     char *    pszModel;
  1301.     char *    pszQueue;
  1302.  
  1303.     // Get the printer details
  1304.     cb = (USHORT)PrfQueryProfileString(
  1305.         HINI_SYSTEM,        // Only look in system profile
  1306.         "PM_SPOOLER_PRINTER",    // Application name
  1307.         pszPrinter,         // Keyname
  1308.         "",             // Default value
  1309.         achPath,            // Buffer to receive value
  1310.         (ULONG)sizeof(achPath)    // Buffer size
  1311.      );
  1312.  
  1313.     if (cb == 0)
  1314.     return NULL;
  1315.  
  1316.     // Get the logical address name, driver name, model name, and queue name
  1317.  
  1318.     psz = achPath;
  1319.  
  1320.     // Parse off logical address (usually a port name)
  1321.     //
  1322.     // A: "LPT1;LASERJET.HP LaserJet IID;QUEUE1;;"
  1323.     //       ^
  1324.     // B: "LPT1;LASERJET.HP LaserJet IID,PSCRIPT;QUEUE1,QUEUE2;;"
  1325.     //       ^
  1326.  
  1327.     pszLogAddr = achPath;        // Set logical address
  1328.     psz = strchr(psz,';');        // Find end of log addr
  1329.     if (psz == NULL)            // Bad format
  1330.     return NULL;            //  FAIL
  1331.  
  1332.     *psz = '\0';            // Null terminate log addr
  1333.     psz++;                // Skip separator
  1334.  
  1335.     // Parse off driver name and model
  1336.     //
  1337.     // NOTE:  These are provisional.  For a print queue, the driver/model
  1338.     //          have to be retrieved (by the caller) from PM_SPOOLER_QUEUE_DD
  1339.     //          in HINI_SYSTEM.
  1340.     //
  1341.     // A: "LPT1_LASERJET.HP LaserJet IID;QUEUE1;;"
  1342.     //        ^
  1343.     // B: "LPT1_LASERJET.HP LaserJet IID,POSTSCRIPT;QUEUE1,QUEUE2;;"
  1344.     //        ^
  1345.  
  1346.     pszDriver = psz;            // Set driver name
  1347.     psz = strpbrk(psz,".,;");        // Find separator
  1348.     if (psz == NULL)            // Bad format
  1349.     return NULL;            //  FAIL
  1350.     fComma = FALSE;            // Assume no comma
  1351.     if (*psz == '.') {            // Found model name separator
  1352.     *psz = '\0';            // Null terminate driver name
  1353.     pszModel = psz + 1;        // Set model name
  1354.     psz = strpbrk(pszModel,",;");    // Find end of model name
  1355.     if (psz == NULL)        // Bad format
  1356.         return NULL;        //  FAIL
  1357.     }
  1358.     else if (*psz == ',' || *psz == ';') // No model name
  1359.     pszModel = pszDriver;        // Make model same as driver name
  1360.  
  1361.     // A: "LPT1_LASERJET_HP LaserJet IID;QUEUE1;;"
  1362.     //                    ^
  1363.     // B: "LPT1_LASERJET_HP LaserJet IID,POSTSCRIPT;QUEUE1,QUEUE2;;"
  1364.     //                    ^
  1365.     if (*psz == ',')            // More drivers, remember to skip them
  1366.     fComma = TRUE;
  1367.     *psz = '\0';            // Null terminate driver name
  1368.     psz++;                // Skip separator
  1369.  
  1370.     // A: "LPT1_LASERJET_HP LaserJet IID_QUEUE1;;"
  1371.     //                     ^
  1372.     // B: "LPT1_LASERJET_HP LaserJet IID_POSTSCRIPT;QUEUE1,QUEUE2;;"
  1373.     //                     ^
  1374.     if (fComma) {            // Need to skip rest of field
  1375.     psz = strpbrk(psz,";");     // Skip to end of driver field
  1376.     if (psz == NULL)        // Bad format
  1377.         return NULL;        //  FAIL
  1378.     psz++;                // Skip separator
  1379.     }
  1380.  
  1381.     // A: "LPT1_LASERJET_HP LaserJet IID_QUEUE1;;"
  1382.     //                        ^
  1383.     // B: "LPT1_LASERJET_HP LaserJet IID_POSTSCRIPT;QUEUE1,QUEUE2;;"
  1384.     //                            ^
  1385.     // NOTE: We leave the list of queues, so that caller can enumerate
  1386.     //         all queues!
  1387.     //
  1388.     if (*psz == ';')            // No queue
  1389.     pszQueue = NULL;
  1390.     else {                // Queue present
  1391.     pszQueue = psz;         // Set queue name
  1392.     psz = strpbrk(psz,";");     // Find end of queue name(s)!
  1393.     if (psz == NULL)        // Bad format
  1394.         return NULL;        //  FAIL
  1395.     *psz = '\0';            // Null terminate queue name
  1396.     }
  1397.  
  1398.     // Figure out whether this printer is queued or not
  1399.  
  1400.     if (pszQueue != NULL) {        // Printer is queued
  1401.     lType = OD_QUEUED;
  1402.     psz = pszQueue;
  1403.     }
  1404.     else {                // Printer is direct
  1405.     lType = OD_DIRECT;
  1406.     psz = pszLogAddr;
  1407.     }
  1408.  
  1409.     // Create printer structure
  1410.  
  1411.     pprt = CreatePrinter(
  1412.         lType,            // Set type
  1413.         psz,            // Set logical address
  1414.         pszPrinter,         // Set printer
  1415.         pszDriver,            // Set driver
  1416.         pszModel,            // Set model
  1417.         fComma            // Set flag
  1418.        );
  1419.     return pprt;
  1420. }
  1421.  
  1422.  
  1423. /***    CreatePrinter - Create a PRINTER
  1424.  *
  1425.  *    Entry
  1426.  *        lType      - printer type (OD_DIRECT or OD_QUEUED)
  1427.  *        pszLogAddr - logical address (LPT1 or QUEUE1)
  1428.  *        pszPrinter - printer name
  1429.  *        pszDriver  - driver name
  1430.  *        pszModel   - model name
  1431.  *
  1432.  *    Exit-Success
  1433.  *        Returns PPRINTER
  1434.  *
  1435.  *    Exit-Failure
  1436.  *        Returns NULL
  1437.  */
  1438. PPRINTER CreatePrinter(LONG lType,
  1439.                char *pszLogAddr,
  1440.                char *pszPrinter,
  1441.                char *pszDriver,
  1442.                char *pszModel,
  1443.                BOOL fMultipleDrivers)
  1444. {
  1445.     PPRINTER    pprt;
  1446.  
  1447.     pprt = MemAlloc(sizeof(PRINTER));
  1448.     if (pprt == NULL)
  1449.     return NULL;
  1450.  
  1451.     // Create copies of strings to complete printer structure
  1452.  
  1453.     pprt->pszLogAddr = MemStrDup(pszLogAddr); // Duplicate logical address
  1454.     pprt->pszPrinter = MemStrDup(pszPrinter); // Duplicate printer name
  1455.     pprt->pszDriver  = MemStrDup(pszDriver);  // Duplicate driver
  1456.     pprt->pszModel   = MemStrDup(pszModel);  // Duplicate Model
  1457.  
  1458.     // Set other fields
  1459.  
  1460.     pprt->fMultipleDrivers = fMultipleDrivers; // Set flag
  1461.     pprt->lType = lType;        // Set type
  1462.     pprt->pszDescription = NULL;    // No description, yet
  1463.     pprt->cbDriverData = 0;        // No job properites
  1464.     pprt->pbDriverData = NULL;        // No job properites
  1465.  
  1466.     // Set consistent printer "name"
  1467.     if (lType == OD_QUEUED)
  1468.     pprt->pszName = pprt->pszLogAddr; // Use queue name
  1469.     else
  1470.     pprt->pszName = pprt->pszPrinter; // Use printer name
  1471.  
  1472.     // Make sure copies succeeded
  1473.  
  1474.     if ((pprt->pszLogAddr     == NULL) || // One or more dups failed
  1475.     (pprt->pszDriver      == NULL) ||
  1476.     (pprt->pszModel       == NULL) ||
  1477.     (pprt->pszPrinter     == NULL)) {
  1478.     DestroyPrinter(pprt);        // Destroy printer
  1479.     pprt = NULL;
  1480.     }
  1481.     return pprt;
  1482. }
  1483.  
  1484.  
  1485. /***    DestroyPrinter - Destroy a PRINTER
  1486.  *
  1487.  *    Entry
  1488.  *        pprt - printer to destroy
  1489.  *
  1490.  *    Exit
  1491.  *        NONE
  1492.  */
  1493. VOID DestroyPrinter(PPRINTER pprt)
  1494. {
  1495.     MemAssert(pprt);
  1496.     if (pprt->pszLogAddr != NULL)
  1497.     MemFree(pprt->pszLogAddr);
  1498.     if (pprt->pszDriver != NULL)
  1499.     MemFree(pprt->pszDriver);
  1500.     if (pprt->pszModel != NULL)
  1501.     MemFree(pprt->pszModel);
  1502.     if (pprt->pszPrinter != NULL)
  1503.     MemFree(pprt->pszPrinter);
  1504.     if (pprt->pszDescription != NULL)
  1505.     MemFree(pprt->pszDescription);
  1506.     if (pprt->pbDriverData != NULL)
  1507.     MemFree(pprt->pbDriverData);
  1508.     MemFree(pprt);
  1509. }
  1510.  
  1511.  
  1512. /***    GetDriverData - Get driver data for printer (if not already set)
  1513.  *
  1514.  *    This function attempts to set the Job Properties for a printer
  1515.  *    by querying the driver.  If successful, the Job Properties are
  1516.  *    stored in the printer.    Otherwise, they are left as NULL, and
  1517.  *    the driver will use its own default job properties.
  1518.  *
  1519.  *    Entry
  1520.  *        pprt - printer
  1521.  *
  1522.  *    Exit
  1523.  *        pprt->pbDriverData set to driver data, if at all possible.
  1524.  */
  1525. VOID GetDriverData(PPRINTER pprt)
  1526. {
  1527.     HAB     hab;
  1528.     LONG    cb;
  1529.     BYTE *  pb;
  1530.     LONG    rc;
  1531.  
  1532.     MemAssert(pprt);
  1533.     MemAssert(pprt->pprtlist);
  1534.     hab = pprt->pprtlist->hab;
  1535.  
  1536.     // See if job properties already set
  1537.  
  1538.     if (pprt->pbDriverData != NULL)    // They are
  1539.     return;             //  Nothing to do
  1540.  
  1541.     // Assume no job properties
  1542.  
  1543.     pprt->cbDriverData = 0;
  1544.     pprt->pbDriverData = NULL;
  1545.  
  1546.     // Get size
  1547.  
  1548.     cb =  DevPostDeviceModes(
  1549.         hab,            // Anchor block
  1550.         NULL,            // Buffer for data (NULL returns size)
  1551.         pprt->pszDriver,        // Driver name
  1552.         pprt->pszModel,        // Device name
  1553.         pprt->pszPrinter,        // Printer name
  1554.         DPDM_QUERYJOBPROP        // Option
  1555.     );
  1556.  
  1557.     if (cb == DPDM_NONE)        // No job properties available
  1558.     return;             //  Do nothing
  1559.  
  1560.     if (cb == DPDM_ERROR)        // Could not get job properties
  1561.     return;             //  Do nothing
  1562.  
  1563.     pb = MemAlloc((USHORT)cb);        // Allocate buffer
  1564.     if (pb == NULL)            // Could not allocate it
  1565.     return;             //  Nothing to do
  1566.  
  1567.     // Made it this far, get driver data
  1568.  
  1569.     rc = DevPostDeviceModes(
  1570.         hab,            // Anchor block
  1571.         (VOID *)pb,         // Buffer for data
  1572.         pprt->pszDriver,        // Driver name
  1573.         pprt->pszModel,        // Device name
  1574.         pprt->pszPrinter,        // Printer name
  1575.         DPDM_QUERYJOBPROP        // Option
  1576.     );
  1577.  
  1578.     if (rc == DEV_OK) {
  1579.     pprt->cbDriverData = (USHORT)cb;
  1580.     pprt->pbDriverData = pb;
  1581.     }
  1582.     return;
  1583. }
  1584.