Jump to content

DEVESC_QUERYJOBPROPERTIES

From EDM2
Revision as of 00:07, 12 July 2025 by Martini (talk | contribs) (Created page with "{{DISPLAYTITLE:DEVESC_QUERYJOBPROPERTIES}} '''GreEscape DEVESC_QUERYJOBPROPERTIES''' queries the specified job property types and values inside the job properties structure that is passed in. Refer to Dynamic Job Properties for related information. ;Simulation support: This function is mandatory for all drivers and must be implemented to have a valid OS/2 hardcopy driver. Refer to Dynamic Job Properties for related information. ==Syntax==  GreEscape(hdc, l...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

GreEscape DEVESC_QUERYJOBPROPERTIES queries the specified job property types and values inside the job properties structure that is passed in. Refer to Dynamic Job Properties for related information.

Simulation support

This function is mandatory for all drivers and must be implemented to have a valid OS/2 hardcopy driver. Refer to Dynamic Job Properties for related information.

Syntax

 GreEscape(hdc, lEscape, cInCount, pInData, pcOutCount, pOutData, pInstance, lFunction);

Parameters

hdc (HDC) - input
Device context handle.
lEscape (LONG) - input
DEVESC_QUERYJOBPROPERTIES escape code.
cInCount (LONG) - input
Number of bytes pointed to by pInData.
pInData (PBYTE) - output
Pointer to a list of DJP_ITEM data structures.
The end of the list is indicated by a DJP_ITEM structure that has DJP_NONE as its ulProperty value. On input, the DJP_ITEM structures should be sized as simple (that is, == sizeof (DJP_ITEM)). On output, if lType was DJP_ALL, then the DJP_ITEM size will grow and its new size will be reflected in the cb field.
pcOutCount (PLONG) - input
Pointer to the number of bytes pointed to by pOutData.
pOutData (PLONG) - input
Pointer to the printer driver's job properties structure.

Note: pOutData is used as an input parameter for this call.

pInstance (PVOID) - input
Pointer to instance data.
lFunction (ULONG) - input
High-order WORD=flags; low-order WORD=NGreEscape.

Returns

rc (LONG) - returns
Return Code.
The handling routine returns:
DEV_OK
Successful.
DEV_PROP_BUF_TOO_SMALL
The job properties buffer was too small to contain the proper job properties data or expanded DJP_ITEMs. The buffer will not be updated.
DEV_INV_INP_JOBPROPERTIES
Invalid job properties were passed in. The driver changed them to default values. This is an error and the item buffer will not be updated.
DEV_WARNING
One or more of the DJP_ITEMs has an error in the lType field.
DEVESC_ERROR
Error

Remarks

GreEscape DEVESC_QUERYJOBPROPERTIES queries the information that is within the printer's job properties structure. This structure is known only to the printer presentation driver, and this escape is the only way for an application to look inside the structure.

Since DEVESC_QUERYJOBPROPERTIES is new, applications will call GreEscape DEVESC_QUERYESCSUPPORT to determine if you support this DevEscape.

Note that the DevEscape path has a handle to a device context (HDC) that should already have printer property information associated with the HDC. Job property information may change or may be dependent upon the printer property information in the HDC. In that case, if an application passes job properties for a different device or for a different spooler printer name, then misleading information will be returned.

Remember to test the input job properties to make sure that they are valid. This includes passing tests such as whether they contain your driver's signature string, whether the device name is yours, and whether values are within the proper ranges (only landscape or portrait). If these tests fail, then fail the call.

Sample Source Code

Declaration:

#define INCL_DEV
#define INCL_DEVDJP
#include <os2.h>

HDC       hdc;           /* Device context handle. */
LONG      lEscape;       /* DEVESC_QUERYJOBPROPERTIES escape code. */
LONG      cInCount;      /* Number of bytes pointed to by '''pInData'''. */
PBYTE     pInData;       /* Pointer to a list of [[DJP_ITEM]] data structures. */
PLONG     pcOutCount;    /* Pointer to the number of bytes pointed to by '''pOutData'''. */
PLONG     pOutData;      /* Pointer to the printer driver's job properties structure. */
PVOID     pInstance;     /* Pointer to instance data. */
ULONG     lFunction;     /* High-order WORD=flags; low-order WORD=NGreEscape. */
LONG      rc;            /* Return Code. */

rc = GreEscape(hdc, lEscape, cInCount, pInData,
        pcOutCount, pOutData, pInstance, lFunction);

Implementation Example:

LONG ENGENTRY Escape (HDC       hdc,
                      LONG      lEscape,
                      LONG      cInCount,
                      PBYTE     pInData,
                      PLONG     pcOutCount,
                      PBYTE     pOutData,
                      PDDC      pddc,
                      ULONG     ulFunction)
{
   switch (lEscape)
   {
   case DEVESC_QUERYJOBPROPERTIES:
   {
      INT           cbQueries  = cInCount;
      PBYTE         pbQueries  = pInData;
      PDJP_ITEM     pIQuery    = (PDJP_ITEM)pbQueries;
      BOOL          fError     = FALSE;
      PBYTE         pbNext;
      INT           iNumQueries;
      PQUERYTUPLE   pTuples    = NULL,
                    pTupleCur;

      if (GRE_234 > globals.ulGreVersion)
      {
         assertstring ("Not supported on pre-DAX engine!\n");
         lrc = DEVESC_NOTIMPLEMENTED;
         break;
      }

      pGoodDrivData = ReturnDriverData (pddc->pdb,
                                         pdi,
                                         pddc->pdb->hmcbHeap,
                                         pDrivData,
                                         pddc->pdb->pszPrinterName,
                                         TRUE,
                                         pDevice,
                                         pDriver);
      assertF (pGoodDrivData);

      /* Is the size of the input driver data is not the same as
      ** the size of our good data?
      */
      if (pDrivData->cb != pGoodDrivData->cb)
         lrc = DEV_PROP_BUF_TOO_SMALL;

      /* Or, if the two don't compare, then fail the call.
      */
      if (0 != memcmp (pDrivData, pGoodDrivData, pGoodDrivData->cb))
         lrc = DEV_INV_INP_JOBPROPERTIES;

      // Output buffer must be at least one item in size
      if (sizeof (DJP_ITEM) > cbQueries)
      {
         ulrc = DEV_BAD_PARAMETERS;
         break;
      }

      // Step 1. Count the number of queries
      iNumQueries = 0;
      pIQuery     = (PDJP_ITEM)pbQueries;
      while (pIQuery->ulProperty != DJP_NONE)
      {
         iNumQueries++;
         pIQuery = DJP_NEXT_STRUCTP (pIQuery);
      }
      iNumQueries++;   // Add an EOL marker

      // Step 2. Allocate and copy the query types
      pTuples = (PQUERYTUPLE)GplMemoryAlloc (globals.pvSharedHeap,
                                             iNumQueries * sizeof (QUERYTUPLE));
      assertF (pTuples);
      if (!pTuples)
      {
         ulrc = DEV_ERROR;
         GplErrSetError (PMERR_INSUFFICIENT_MEMORY);
         break;
      }

      /* Since we will be overwriting the input list to the output list, we
      ** need to copy the original input list into an array of tuples
      ** (the only thing that matters)
      */
      pIQuery   = (PDJP_ITEM)pbQueries;
      pTupleCur = pTuples;
      while (pIQuery->ulProperty != DJP_NONE)
      {
         pTupleCur->ulProperty = pIQuery->ulProperty;
         pTupleCur->lType      = pIQuery->lType;

         pIQuery = DJP_NEXT_STRUCTP (pIQuery);
         pTupleCur++;
      }
      // And copy the EOL
      pTupleCur->ulProperty = DJP_NONE;
      pTupleCur->lType      = DJP_NONE;

      // Step 3. Fill in the output list
      pIQuery   = (PDJP_ITEM)pbQueries;
      pTupleCur = pTuples;
      while (0 < iNumQueries)
      {
         BOOL  fCurError = FALSE;

         pIQuery->ulProperty    = pTupleCur->ulProperty;
         pIQuery->lType         = pTupleCur->lType;
         pIQuery->ulNumReturned = 0;

         if (sizeof (DJP_ITEM) > cbQueries)
         {
            fError = DEV_PROP_BUF_TOO_SMALL;
            assertstring ("Not enough space left!\n");
            break;
         }

         DBPRINTF (("Query '%s'/%d. Query type '%s'/%d\n",
                     pszProperty (pTupleCur->ulProperty),
                     pTupleCur->ulProperty,
                     pszType (pTupleCur->lType),
                     pTupleCur->lType));

         if (pTupleCur->lType == DJP_CURRENT)
         {
            pIQuery->ulNumReturned = 1;

            // Assume a simple type... complex types will override it
            pbNext = (PBYTE)(pIQuery + 1);

            switch (pTupleCur->ulProperty)
            {
            case DJP_SJ_ORIENTATION:
               if (ORIENTATION_PORTRAIT == pJobProp->ulOrientation)
                  pIQuery->ulValue = DJP_ORI_PORTRAIT;
               else
                  pIQuery->ulValue = DJP_ORI_LANDSCAPE;
               break;

            case DJP_CJ_RESOLUTION:
            {
               PDJPT_RESOLUTION   pRes   = DJP_ELEMENTP (*pIQuery, DJPT_RESOLUTION);
               PRESINFO           pResInfo;
               DJPT_RESOLUTION    Res;
               LONG               lRet;

               pResInfo = GetpResFromResID (pDriver, pJobProp->ulDefResID);

               if (pResInfo)
               {
                  Res.usXResolution = pResInfo->ulXRes;
                  Res.usYResolution = pResInfo->ulYRes;
                  *pRes++ = Res;

                  pbNext = (PBYTE)pRes;
               }
               else
               {
                  fCurError = TRUE;
               }
               break;
            }

            case DJP_SJ_BITSPERPEL:
            case DJP_SJ_COLOR:
            {
               PPRINTMODE pPrintMode;

               pPrintMode = GetpPrintModeFromID (pDriver,
                                                 pJobProp->ulDefPrintModeID);

               if (pPrintMode)
               {
                  if (DJP_SJ_BITSPERPEL == pTupleCur->ulProperty)
                  {
                     pIQuery->ulValue = pPrintMode->usLogBitCount;
                  }
                  else
                  {
                     if (1 == pPrintMode->usBitsPerPel &&
                         !fFoundMono                       )
                     {
                        fFoundMono = TRUE;
                        *pTmp++ = DJP_CLR_MONOCHROME;
                        iNumReturned++;
                     }
                     else if (!fFoundColor)
                     {
                        fFoundColor = TRUE;
                        *pTmp++ = DJP_CLR_COLOR;
                        iNumReturned++;
                     }
                  }
               }
               else
               {
                  fCurError = TRUE;
               }
               break;
            }

            case DJP_CJ_FORM:
            case DJP_SJ_PAPERSIZE:
            {
               PDJPT_FORM         pDJPForm       = DJP_ELEMENTP (*pIQuery, DJPT_FORM);
               FORMINFO2          FormInfo;
               ULONG              ulDefaultFormID,
                                  ulDefaultTrayID,
                                  ulDefaultMediaID;
               LONG               lRet;

               GetIDsFromConnID (pDriver,
                                 pDevice,
                                 pJobProp->ulDefConnID,
                                 &ulDefaultTrayID,
                                 &ulDefaultFormID,
                                 &ulDefaultMediaID);

               if (DJP_CJ_FORM == pTupleCur->ulProperty)
               {
                  FillFormInfo (pDJPForm,
                                ulDefaultTrayID,
                                ulDefaultFormID,
                                ulDefaultMediaID,
                                pdb,
                                pJobProp->ulDefResID);

                  pDJPForm++;
                  pbNext = (PBYTE)pDJPForm;
               }
               else
               {
                  lRet = GetDefaultFormInfo (pdb,
                                             ulDefaultFormID,
                                             pJobProp->ulDefResID,
                                             &FormInfo);

                  if (lRet)
                     lRet = FormInfo.ulDJPid;
                  else
                     lRet = DJP_PSI_NONE;

                  if (DJP_PSI_NONE == lRet)
                     fCurError = TRUE;
                  else
                     pIQuery->ulValue = lRet;
               }
               break;
            }

            case DJP_SJ_COPIES:
               pIQuery->ulValue = pJobProp->ulCopies;
               break;

            case DJP_NONE:
               // Nothing to do!
               pIQuery->ulValue = DJP_NONE;
               break;

            case DJP_SJ_PRINTQUALITY:
            case DJP_SJ_TRAYTYPE:
            case DJP_SJ_MEDIA:
            case DJP_SJ_MEDIA_COLOR:
            case DJP_CJ_MIXEDFORMS:
            case DJP_SJ_FONTDOWNLOADING:
            case DJP_SJ_DUPLEX:
            case DJP_SJ_COLLATE:
            case DJP_SJ_FEED:
            case DJP_SJ_SCALING:
            case DJP_SJ_FORMFEEDCONTROL:
            case DJP_SJ_N_UP:
            default:
               fCurError = TRUE;
               DBPRINTF (("Unknow query '%s' = %d!\n",
                           pszProperty (pTupleCur->ulProperty),
                           pTupleCur->ulProperty));
               break;
            }
         }
         else if (pTupleCur->lType == DJP_ALL)
         {
            /* No assumptions are made here.  pbNext must be set up by each
            ** case statement
            */

            switch (pTupleCur->ulProperty)
            {
            case DJP_SJ_ORIENTATION:
            {
               PDJPT_ORIENTATION pTmp = DJP_ELEMENTP (*pIQuery, DJPT_ORIENTATION);

               *pTmp++ = DJP_ORI_PORTRAIT;
               *pTmp++ = DJP_ORI_LANDSCAPE;

               pIQuery->ulNumReturned = 2;
               pbNext = (PBYTE)pTmp;
               break;
            }

            case DJP_CJ_RESOLUTION:
            {
               PDJPT_RESOLUTION   pRes          = DJP_ELEMENTP (*pIQuery, DJPT_RESOLUTION);
               PRESINFO           pResInfo      = pDriver->pRES;
               ULONG              ulNumDefined  = pDriver->ulNumRes;
               PULONG             pulResDevice  = pDevice->pulRES;
               ULONG              ulNumDevice   = pDevice->usNumRes;
               DJPT_RESOLUTION    Res;
               INT                iNumReturned  = 0;
               LONG               lRet;
               BOOL               fFound;
               register INT       i, j;

               for (i = 0; i < ulNumDevice; i++)
               {
                  fFound = FALSE;

                  for (j = 0; j < ulNumDefined; j++)
                  {
                     if (pResInfo[j].ulResID == *pulResDevice)
                     {
                        fFound = TRUE;

                        Res.usXResolution = pResInfo[j].ulXRes;
                        Res.usYResolution = pResInfo[j].ulYRes;
                        *pRes++ = Res;

                        pbNext = (PBYTE)pRes;
                     }
                  }

                  if (!fFound)
                  {
                     assertstring ("ResInfo not found!\n");
                  }
                  else
                  {
                     iNumReturned++;
                  }

                  pulResDevice++;
               }

               pIQuery->ulNumReturned = iNumReturned;

               if (0 == iNumReturned)
               {
                  pbNext = (PBYTE)(pIQuery + 1);
                  fCurError = TRUE;
               }
               break;
            }

            case DJP_SJ_BITSPERPEL:
            case DJP_SJ_COLOR:
            {
               PPRINTMODE         pPrintMode    = pDriver->pPrintModes;
               ULONG              ulNumDefined  = pDriver->ulNumPrintModes;
               PULONG             pulPrintModes = pDevice->pulPrintModes;
               ULONG              ulNumDevice   = pDevice->usNumPrintModes;
               PDJPT_BITSPERPEL   pTmp          = DJP_ELEMENTP (*pIQuery, DJPT_BITSPERPEL);
               INT                iNumReturned  = 0;
               BOOL               fFoundMono    = FALSE,
                                  fFoundColor   = FALSE;
               register INT       i, j;

               for (i = 0; i < ulNumDevice; i++)
               {
                  for (j = 0; j < ulNumDefined; j++)
                  {
                     if (pPrintMode[j].ulPrintModeID == pulPrintModes[i])
                     {
                        if (DJP_SJ_BITSPERPEL == pTupleCur->ulProperty)
                        {
                           *pTmp++ = pPrintMode[j].usLogBitCount;
                           iNumReturned++;
                        }
                        else
                        {
                           /* Only return 1 instance for each no matter how
                           ** many print modes there are.
                           */
                           if (1 == pPrintMode[j].usBitsPerPel &&
                               !fFoundMono                        )
                           {
                              fFoundMono = TRUE;
                              *pTmp++ = DJP_CLR_MONOCHROME;
                              iNumReturned++;
                           }
                           else if (!fFoundColor)
                           {
                              fFoundColor = TRUE;
                              *pTmp++ = DJP_CLR_COLOR;
                              iNumReturned++;
                           }
                        }
                     }
                  }

                  pulPrintModes++;
               }

               pIQuery->ulNumReturned = iNumReturned;

               if (0 == iNumReturned)
               {
                  pbNext = (PBYTE)(pIQuery + 1);
                  fCurError = TRUE;
               }
               else
                  pbNext = (PBYTE)pTmp;
               break;
            }

            case DJP_SJ_PAPERSIZE:
            {
               ULONG              ulNumDefined = pDevice->ulNumForms;
               PFORMINFO2         pFormInfo    = pDevice->pFORMS;
               PDJPT_PAPERSIZE    pSize        = DJP_ELEMENTP (*pIQuery, DJPT_PAPERSIZE);
               INT                iNumReturned = 0;
               register INT       i;

               for (i = 0; i < ulNumDefined; i++)
               {
                  LONG lRet;

                  lRet = pFormInfo[i].ulDJPid;

                  if (DJP_PSI_NONE == lRet)
                  {
                     fCurError = TRUE;
                  }
                  else
                  {
                     iNumReturned++;
                     *pSize++ = lRet;

                     pbNext = (PBYTE)pSize;
                  }
               }

               pIQuery->ulNumReturned = iNumReturned;

               if (0 == iNumReturned)
               {
                  pbNext = (PBYTE)(pIQuery + 1);
                  fCurError = TRUE;
               }
               break;
            }

            case DJP_CJ_FORM:
            {
               PDJPT_FORM   pDJPForm    = DJP_ELEMENTP (*pIQuery, DJPT_FORM);
               PUSERCONNECT pUserConn;
               ULONG        ulFormID,
                            ulTrayID,
                            ulMediaID;
               INT          iNumReturned = 0;
               register INT i;

               iNumReturned = 0;

               for (i = 0; i < pDevice->usNumConnects; i++)
               {
                  GetIDsFromConnID (pDriver,
                                    pDevice,
                                    pDevice->pulCONNECTS[i],
                                    &ulTrayID,
                                    &ulFormID,
                                    &ulMediaID);

                  FillFormInfo (pDJPForm,
                                ulTrayID,
                                ulFormID,
                                ulMediaID,
                                pdb,
                                pJobProp->ulDefResID);

                  pDJPForm++;
                  pbNext = (PBYTE)pDJPForm;
                  iNumReturned++;
               }

               // get pointer to first user-defined form connection
               pUserConn = pDevice->pUserDefData->pUserCONNECTS;

               // as long as we have user-defined form connections
               while (pUserConn)
               {
                  FillFormInfo (pDJPForm,
                                pUserConn->fcUser.ulTrayID,
                                pUserConn->fcUser.ulFormID,
                                pUserConn->fcUser.ulMediaID,
                                pdb,
                                pJobProp->ulDefResID);

                  pDJPForm++;
                  pbNext = (PBYTE)pDJPForm;
                  iNumReturned++;

                  // Move to the next connection
                  pUserConn = pUserConn->pNextConnect;
               }

               pIQuery->ulNumReturned = iNumReturned;

               if (0 == iNumReturned)
               {
                  pbNext = (PBYTE)(pIQuery + 1);
                  fCurError = TRUE;
               }
               break;
            }

            case DJP_SJ_COPIES:
            {
               pIQuery->lType         = DJP_ERROR_NOT_ENUM;
               pIQuery->ulNumReturned = 0;
               pIQuery->ulValue       = DJP_NONE;

               pbNext = (PBYTE)(pIQuery + 1);

               fError = TRUE;
               break;
            }

            case DJP_NONE:
            {
               // Nothing to do!
               pIQuery->ulNumReturned = 0;
               pIQuery->ulValue       = DJP_NONE;

               pbNext = (PBYTE)(pIQuery + 1);
               break;
            }

            case DJP_SJ_PRINTQUALITY:
            case DJP_SJ_TRAYTYPE:
            case DJP_SJ_MEDIA:
            case DJP_SJ_MEDIA_COLOR:
            case DJP_CJ_MIXEDFORMS:
            case DJP_SJ_FONTDOWNLOADING:
            case DJP_SJ_DUPLEX:
            case DJP_SJ_COLLATE:
            case DJP_SJ_FEED:
            case DJP_SJ_SCALING:
            case DJP_SJ_FORMFEEDCONTROL:
            case DJP_SJ_N_UP:
            default:
               fCurError = TRUE;

               pbNext = (PBYTE)(pIQuery + 1);

               DBPRINTF (("Unknow query '%s' = %d!\n",
                           pszProperty (pTupleCur->ulProperty),
                           pTupleCur->ulProperty));
               break;
            }
         }
         else if (DJP_NONE != pTupleCur->lType)
         {
            fCurError = TRUE;

            assertstring ("Unknown query type!\n");
         }

         // We now know the final size
         pIQuery->cb = pbNext - (PBYTE)pIQuery;

         /* @TBD We need some way to stop overwriting memory
         */
         assertT (cbQueries < pIQuery->cb);

         cbQueries -= pIQuery->cb;

         if (fCurError)
         {
            pIQuery->ulNumReturned = 0;
            pIQuery->ulValue       = DJP_NONE;
            pIQuery->lType         = DJP_ERROR_NOT_SUPPORTED;
            fError                  = TRUE;
         }

         // Move to the next query item
         pIQuery = DJP_NEXT_STRUCTP (pIQuery);

         iNumQueries--;
         pTupleCur++;
      }

      // Clean up
      if (pTuples)
         GplMemoryFree (pTuples);

      if (fError)
      {
         GplErrSetWarning (PMERR_DATATYPE_ENTRY_INVALID);
         ulrc = DEV_WARNING;
      }
      else
      {
         // good result
         ulrc = DEV_OK;
      }
      break;
   }
   }

   return lrc;
}