Sample Code

Windows Driver Samples/ GenPrint Print Processor Sample/ C++/ winprint.cpp/

/*++

Copyright (c) 1990-2003  Microsoft Corporation
All Rights Reserved

Abstract:

    Win32 print processor support functions.


--*/

#include "local.h"

#include <excpt.h>


LPWSTR  Datatypes[]={
    L"RAW",
    L"NT EMF 1.006",
    L"NT EMF 1.007",
    L"NT EMF 1.008",
    L"TEXT",
    0};

/** Misc. constants **/

#define BASE_TAB_SIZE 8

/**
 *  For localization:
**/

PWCHAR pTabsKey     = L"TABS";
PWCHAR pCopiesKey   = L"COPIES";


/**
    Prototypes
**/

/** Functions found in parsparm.c **/

extern USHORT GetKeyValue(
        _In_                         PWCHAR  pParmString,
        _In_                         PWCHAR  pKeyName,
        _In_                         USHORT  ValueType,
        _Inout_                      PUSHORT pDestLength,
        _Out_writes_bytes_(*pDestLength)   PVOID   pDestBuffer
    );

/** Functions found in raw.c **/


extern BOOL PrintRawJob(
    IN PPRINTPROCESSORDATA,
    _In_ IN LPWSTR);


/** Functions found in text.c **/

extern BOOL PrintTextJob(
         IN PPRINTPROCESSORDATA,
    _In_ IN LPWSTR);

/** Functions found in emf.cpp */

extern BOOL PrintEMFJob(
         IN PPRINTPROCESSORDATA,
    _In_ IN LPWSTR);

/** Functions found in support.c **/

extern PUCHAR GetPrinterInfo(
    IN  HANDLE hPrinter,
    IN  ULONG,
    OUT PULONG);


BOOL BReleasePPData(
        _In_ IN  PPRINTPROCESSORDATA * ppData );

DWORD
FillInPPCForLevel1(
    _Out_ PPRINTPROCESSOR_CAPS_1 ppcInfo1,
          DWORD                  dwDatatype,
    _In_  DWORD                  dwAttributes
    );

DWORD
FillInPPCForLevel2(
    _Out_ PPRINTPROCESSOR_CAPS_2 ppcInfo2,
          DWORD                  dwDatatype,
    _In_  DWORD                  dwAttributes
    );

BOOL WINAPI
DllMain(
    HANDLE ,
    DWORD ,
    LPVOID
    )
{
    return TRUE;
}

/*++
*******************************************************************
    E n u m P r i n t P r o c e s s o r D a t a t y p e s W

    Routine Description:
        Enumerates the data types supported by the print processor.

    Arguments:
        pName               => server name
        pPrintProcessorName => print processor name
        Level               => level of data to return (must be 1)
        pDatatypes          => structure array to fill in
        cbBuf               => length of structure array in bytes
        pcbNeeded           => buffer length copied/required
        pcReturned          => number of structures returned

    Return Value:
        TRUE  if successful
        FALSE if failed - caller must use GetLastError for reason
*******************************************************************
--*/
_Use_decl_annotations_
BOOL WINAPI
EnumPrintProcessorDatatypes(
    LPWSTR  pName,
    LPWSTR  pPrintProcessorName,
    DWORD   Level,
    LPBYTE  pDatatypes,
    DWORD   cbBuf,
    LPDWORD pcbNeeded,
    LPDWORD pcReturned
)
{
    DATATYPES_INFO_1    *pInfo1 = (DATATYPES_INFO_1 *)pDatatypes;
    LPWSTR              *pMyDatatypes = Datatypes;
    size_t              cbTotal=0;
    ULONG               cchBuf =0;
    LPBYTE              pEnd;
    BOOL                bRetVal = TRUE;
    HRESULT             hr;
    size_t              tempSizeT;

    UNREFERENCED_PARAMETER(pName);
    UNREFERENCED_PARAMETER(pPrintProcessorName);

    if ( NULL == pcbNeeded  ||
         NULL == pcReturned )
    {
        SetLastError (ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    /** Start assuming failure, no entries returned **/

    *pcbNeeded  = 0;
    *pcReturned = 0;

    if (Level != 1)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    /** Add up the minimum buffer required **/

    while (*pMyDatatypes) {
        if (FAILED(SizeTMult(wcslen(*pMyDatatypes), sizeof(WCHAR), &tempSizeT)) ||
            FAILED(SizeTAdd(tempSizeT, sizeof(WCHAR), &tempSizeT)) ||
            FAILED(SizeTAdd(tempSizeT, sizeof(DATATYPES_INFO_1), &tempSizeT)) ||
            FAILED(SizeTAdd(cbTotal, tempSizeT, &cbTotal)))
        {
            SetLastError (ERROR_ARITHMETIC_OVERFLOW);
            bRetVal = FALSE;
            break;
        }

        pMyDatatypes++;
    }

    /** Set the buffer length returned/required **/

    if (bRetVal && FAILED(SizeTToDWord(cbTotal, pcbNeeded)))
    {
        SetLastError (ERROR_ARITHMETIC_OVERFLOW);
        bRetVal = FALSE;
    }

    /** Fill in the array only if there is sufficient space **/

    if (bRetVal && cbTotal <= cbBuf)
    {

        if ( NULL == pInfo1 ) //pInfo1 is same as pDatatypes
        {
            SetLastError (ERROR_INVALID_PARAMETER);
            bRetVal = FALSE;
        }
        else
        {

            /** Pick up pointer to end of the given buffer **/

            pEnd = (LPBYTE)pInfo1 + cbBuf;


            /** Pick up our list of supported data types **/

            pMyDatatypes = Datatypes;

            /**
                Fill in the given buffer.  We put the data names at the end of
                the buffer, working towards the front.  The structures are put
                at the front, working towards the end.
            **/

            while (*pMyDatatypes) {

                if (FAILED(SizeTAdd(wcslen(*pMyDatatypes), 1, &tempSizeT)) || //+1 is for \0.
                    FAILED(SizeTToDWord(tempSizeT, &cchBuf)))
                {
                    SetLastError (ERROR_ARITHMETIC_OVERFLOW);
                    bRetVal = FALSE;
                    break;
                }
                pEnd -= cchBuf*sizeof(WCHAR);

                hr = StringCchCopy ( (LPWSTR)pEnd, cchBuf, *pMyDatatypes);
                if ( FAILED(hr) )
                {
                    //
                    // For the hr values returned by StringCchCopy, the following macro
                    // is sufficient
                    //
                    SetLastError (HRESULT_CODE(hr));
                    bRetVal = FALSE;
                    break;
                }

                pInfo1->pName = (LPWSTR)pEnd;
                pInfo1++;
                (*pcReturned)++;

                pMyDatatypes++;
            }
        }

    } else {

        /** Caller didn't have large enough buffer, set error and return **/

        SetLastError(ERROR_INSUFFICIENT_BUFFER);
        bRetVal = FALSE;
    }

    return bRetVal;
}


/*++
*******************************************************************
    O p e n P r i n t P r o c e s s o r

    Routine Description:

    Arguments:
        pPrinterName            => name of printer we are
                                    opening for
        pPrintProcessorOpenData => information used for opening
                                    the print processor

    Return Value:
        PPRINTPROCESSORDATA => processor data of opened
                                processor if successful
        NULL if failed - caller uses GetLastError for reason

    NOTE: OpenPrinter will be called iff this returns a valid handle
          (and we're not journal)

*******************************************************************
--*/
HANDLE
OpenPrintProcessor(
    _In_ LPWSTR                  pPrinterName,
    _In_ PPRINTPROCESSOROPENDATA pPrintProcessorOpenData
)
{
    PPRINTPROCESSORDATA pData;
    LPWSTR              *pMyDatatypes    = Datatypes;
    DWORD               uDatatype        = 0;
    HANDLE              hPrinter         = 0;
    HDC                 hDC              = 0;
    PDEVMODEW           pDevmode         = NULL;
    DWORD               dwNewDevmodeSize = 0;


    /** If the caller passed a NULL for the open data, fail the call.
        pPrintProcessorOpenData->pDevMode can be NULL **/

    if (!pPrintProcessorOpenData ||
        !pPrintProcessorOpenData->pDatatype ||
        !*pPrintProcessorOpenData->pDatatype) {

        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }

    /** Search for the data type index we are opening for **/

    while (*pMyDatatypes) {

        if (!_wcsicmp(*pMyDatatypes,pPrintProcessorOpenData->pDatatype)) {
            break;
        }
        pMyDatatypes++;
        uDatatype++;
    }

    /** Allocate a buffer for the print processor data to return **/

    pData = (PPRINTPROCESSORDATA)AllocSplMem(sizeof(PRINTPROCESSORDATA));

    if (!pData) {
        ODS(("Alloc failed in OpenPrintProcessor, while printing on %ws\n", pPrinterName));
        return NULL;
    }

    ZeroMemory ( pData, sizeof (PRINTPROCESSORDATA) );

    /** Open the processor accordingly **/

    switch (uDatatype) {

    case PRINTPROCESSOR_TYPE_RAW:
        if (!OpenPrinter(pPrinterName, &hPrinter, NULL))
            goto Fail;
        break;

    case PRINTPROCESSOR_TYPE_EMF_50_1:
    case PRINTPROCESSOR_TYPE_EMF_50_2:
    case PRINTPROCESSOR_TYPE_EMF_50_3:

        if(pPrintProcessorOpenData->pDevMode)
        {
            if ( ! SUCCEEDED ( DWordAdd(pPrintProcessorOpenData->pDevMode->dmSize,
                                        pPrintProcessorOpenData->pDevMode->dmDriverExtra,
                                        &dwNewDevmodeSize) )
                 ||

                 (NULL == (pDevmode=(PDEVMODE)AllocSplMem( dwNewDevmodeSize ) ) )
               )
            {
                goto Fail;
            }
            memcpy(pDevmode,
                   pPrintProcessorOpenData->pDevMode,
                   pPrintProcessorOpenData->pDevMode->dmSize+
                   pPrintProcessorOpenData->pDevMode->dmDriverExtra);
        }
        break;

    case PRINTPROCESSOR_TYPE_TEXT:
        if ((hDC = CreateDC(
                 L"", pPrinterName, L"",
                 pPrintProcessorOpenData->pDevMode))
            == NULL)
            goto Fail;
        break;

    default:
        SetLastError(ERROR_INVALID_DATATYPE);
        goto Fail;
    }

    /** Fill in the print processors information **/

    pData->cb          = sizeof(PRINTPROCESSORDATA);
    pData->signature   = PRINTPROCESSORDATA_SIGNATURE;
    pData->JobId       = pPrintProcessorOpenData->JobId;
    pData->hPrinter    = hPrinter;
    pData->semPaused   = CreateEvent(NULL, TRUE, TRUE,NULL);
    pData->uDatatype   = uDatatype;
    pData->hDC         = hDC;
    pData->Copies      = 1;
    pData->TabSize     = BASE_TAB_SIZE;

    /** Allocate and fill in the processors strings **/

    pData->pPrinterName = AllocSplStr(pPrinterName);
    pData->pDatatype    = AllocSplStr(pPrintProcessorOpenData->pDatatype);
    pData->pDocument    = AllocSplStr(pPrintProcessorOpenData->pDocumentName);
    pData->pOutputFile  = AllocSplStr(pPrintProcessorOpenData->pOutputFile);
    pData->pParameters  = AllocSplStr(pPrintProcessorOpenData->pParameters);
    pData->pDevmode     = pDevmode;
    pData->pPrinterNameFromOpenData = AllocSplStr(pPrintProcessorOpenData->pPrinterName);

    //
    // Check for validity of pData. In the AllocSplStr above, if RHS is non-null, then LHS
    // should be non-null.
    //
    if ( NULL == pData->semPaused ||
        ( NULL != pPrinterName                           && NULL == pData->pPrinterName )  ||
        ( NULL != pPrintProcessorOpenData->pDatatype     && NULL == pData->pDatatype    )  ||
        ( NULL != pPrintProcessorOpenData->pDocumentName && NULL == pData->pDocument    )  ||
        ( NULL != pPrintProcessorOpenData->pOutputFile   && NULL == pData->pOutputFile  )  ||
        ( NULL != pPrintProcessorOpenData->pParameters   && NULL == pData->pParameters  )  ||
        ( NULL != pPrintProcessorOpenData->pPrinterName  && NULL == pData->pPrinterNameFromOpenData)
      )
    {
        goto Fail;
    }


    /** Parse the parameters string **/
    if (pData->pParameters) {
        ULONG   value;
        USHORT  length = sizeof(ULONG);

        /**
            Look to see if there is a COPIES=n key/value in the
            Parameters field of this job.  This tells us the number
            of times to play the data.
        **/

        if (pData->pParameters) {

            GetKeyValue(pData->pParameters,
                        pCopiesKey,
                        VALUE_ULONG,
                        &length,
                        &value);

            if (length == sizeof(ULONG)) {
                pData->Copies = value;
            }
        }

        /** If this is a text job, see if the tab size is in there **/

        if (uDatatype == PRINTPROCESSOR_TYPE_TEXT) {
            length = sizeof(ULONG);

            GetKeyValue(pData->pParameters,
                        pTabsKey,
                        VALUE_ULONG,
                        &length,
                        &value);

            if ((length == sizeof(ULONG)) && value) {
                pData->TabSize = value;
            }
        }
    } /* If we have a parameter string */

    /**
        If we are doing copies, we need to check to see if
        this is a direct or spooled job.  If it is direct, then
        we can't do copies because we can't rewind the data stream.
    **/

    if (pData->Copies > 1) {
        ULONG           Error;
        PPRINTER_INFO_2 pPrinterInfo2;

        /** If we don't already have the printer open, open it **/

        if (uDatatype != PRINTPROCESSOR_TYPE_RAW
            ) {

            OpenPrinter(pPrinterName, &hPrinter, NULL);
        }
        if (hPrinter && hPrinter != INVALID_HANDLE_VALUE) {

            /** Get the printer info - this returns an allocated buffer **/

            pPrinterInfo2 = (PPRINTER_INFO_2)GetPrinterInfo(hPrinter, 2, &Error);

            /** If we couldn't get the info, be safe and don't do copies **/

            if (!pPrinterInfo2) {
                ODS(("GetPrinter failed - falling back to 1 copy\n"));
                pData->Copies = 1;
            }
            else {
                if (pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_DIRECT) {
                    pData->Copies = 1;
                }
                FreeSplMem((PUCHAR)pPrinterInfo2);
            }

            /** If we just opened the printer, close it **/

            if (uDatatype != PRINTPROCESSOR_TYPE_RAW
                ) {

                ClosePrinter(hPrinter);
            }
        }
        else {
            pData->Copies = 1;
        }
    }

    return (HANDLE)pData;

Fail:
    BReleasePPData(&pData);

    return FALSE;
}


/*++
*******************************************************************
    P r i n t D o c u m e n t O n P r i n t P r o c e s s o r

    Routine Description:

    Arguments:
        hPrintProcessor
        pDocumentName

    Return Value:
        TRUE  if successful
        FALSE if failed - GetLastError() will return reason
*******************************************************************
--*/
BOOL
PrintDocumentOnPrintProcessor(
    _In_ HANDLE  hPrintProcessor,
    _In_ LPWSTR  pDocumentName
)
{
    PPRINTPROCESSORDATA pData;

    /**
        Make sure the handle is valid and pick up
        the Print Processors data area.
    **/

    if ((pData = ValidateHandle(hPrintProcessor)) == NULL) {

        return FALSE;
    }

    /**
        Print the job based on its data type.
    **/

    switch (pData->uDatatype) {

    case PRINTPROCESSOR_TYPE_EMF_50_1:
    case PRINTPROCESSOR_TYPE_EMF_50_2:
    case PRINTPROCESSOR_TYPE_EMF_50_3:

        return PrintEMFJob( pData, pDocumentName );
        break;

    case PRINTPROCESSOR_TYPE_RAW:
        return PrintRawJob(pData, pDocumentName);
        break;

    case PRINTPROCESSOR_TYPE_TEXT:
        return PrintTextJob(pData, pDocumentName);
        break;
    } /* Case on data type */

    /** Return success **/

    return TRUE;
}


/*++
*******************************************************************
    C l o s e P r i n t P r o c e s s o r

    Routine Description:
        Frees the resources used by an open print processor.

    Arguments:
        hPrintProcessor (HANDLE) => print processor to close

    Return Value:
        TRUE  if successful
        FALSE if failed - caller uses GetLastError for reason.
*******************************************************************
--*/

_Use_decl_annotations_
BOOL
ClosePrintProcessor(
    HANDLE  hPrintProcessor
)
{
    PPRINTPROCESSORDATA pData;

    /**
        Make sure the handle is valid and pick up
        the Print Processors data area.
    **/

    if ((pData = ValidateHandle(hPrintProcessor)) == NULL) {
        return FALSE;
    }

    return BReleasePPData(&pData);
}

BOOL BReleasePPData(
        _In_  PPRINTPROCESSORDATA * ppData )
{

    PPRINTPROCESSORDATA pData = NULL;

    if ( NULL == ppData || NULL == *ppData)
    {
        return FALSE;
    }

    pData = *ppData;

    pData->signature = 0;

    /* Release any allocated resources */

    if (pData->hPrinter)
        ClosePrinter(pData->hPrinter);

    if (pData->hDC)
        DeleteDC(pData->hDC);

    if (pData->pDevmode)
        FreeSplMem(pData->pDevmode);

    if (pData->pPrinterNameFromOpenData)
        FreeSplStr(pData->pPrinterNameFromOpenData);

    if (pData->semPaused)
        CloseHandle(pData->semPaused);

    if (pData->pPrinterName)
        FreeSplStr(pData->pPrinterName);

    if (pData->pDatatype)
        FreeSplStr(pData->pDatatype);

    if (pData->pDocument)
        FreeSplStr(pData->pDocument);

    if (pData->pOutputFile)
        FreeSplStr(pData->pOutputFile);

    if (pData->pParameters)
        FreeSplStr(pData->pParameters);

    ZeroMemory ( pData, sizeof (PRINTPROCESSORDATA) );
    FreeSplMem(pData);
    *ppData = pData = NULL;


    return TRUE;
}


/*++
*******************************************************************
    C o n t r o l P r i n t P r o c e s s o r

    Routine Description:
        Handles commands to pause, resume, and cancel print jobs.

    Arguments:
        hPrintProcessor = HANDLE to the PrintProcessor the
        command is issued for.

    Return Value:
        TRUE  if command succeeded
        FALSE if command failed (invalid command)
*******************************************************************
--*/
_Use_decl_annotations_
BOOL
ControlPrintProcessor(
    HANDLE  hPrintProcessor,
    DWORD   Command
)
{
    PPRINTPROCESSORDATA pData;

    /**
        Make sure the handle is valid and pick up
        the Print Processors data area.
    **/

    if ((pData = ValidateHandle(hPrintProcessor)) != NULL) {

        switch (Command) {

        case JOB_CONTROL_PAUSE:

            ResetEvent(pData->semPaused);
            pData->fsStatus |= PRINTPROCESSOR_PAUSED;
            return TRUE;
            break;

        case JOB_CONTROL_CANCEL:

            pData->fsStatus |= PRINTPROCESSOR_ABORTED;

            if ((pData->uDatatype == PRINTPROCESSOR_TYPE_EMF_50_1) ||
                (pData->uDatatype == PRINTPROCESSOR_TYPE_EMF_50_2) ||
                (pData->uDatatype == PRINTPROCESSOR_TYPE_EMF_50_3))

                CancelDC(pData->hDC);

            /* Fall through to release job if paused */

        case JOB_CONTROL_RESUME:

            if (pData->fsStatus & PRINTPROCESSOR_PAUSED) {

                SetEvent(pData->semPaused);
                pData->fsStatus &= ~PRINTPROCESSOR_PAUSED;
            }

            return TRUE;
            break;

        default:

            return FALSE;
            break;
        }
    }

    return FALSE;
}


/*++
*******************************************************************
    V a l i d a t e H a n d l e

    Routine Description:
        Validates the given Print Processor HANDLE (which is
        really a pointer to the Print Processor's data) by
        checking for our signature.

    Arguments:
        hQProc (HANDLE) => Print Processor data structure.  This
        is verified as really being a pointer to the Print
        Processor's data.

    Return Value:
        PPRINTPROCESSORDATA if successful (valid pointer passed)
        NULL if failed - pointer was not valid
*******************************************************************
--*/
PPRINTPROCESSORDATA
ValidateHandle(
    HANDLE  hQProc
)
{
    PPRINTPROCESSORDATA pData = NULL;

    if ((NULL != hQProc) &&
        (INVALID_HANDLE_VALUE != hQProc))
    {
        pData = (PPRINTPROCESSORDATA)hQProc;

        // See if our signature exists in the suspected data region
        if (PRINTPROCESSORDATA_SIGNATURE != pData->signature)
        {
            pData = NULL;
        }
    }

    if (NULL == pData)
    {
        SetLastError(ERROR_INVALID_HANDLE);
    }

    return pData;
}

DWORD
GetPrintProcessorCapabilities(
    _In_                LPTSTR   pValueName,
    _In_                DWORD    dwAttributes,
    _Out_writes_bytes_(nSize) LPBYTE   pData,
    _In_                DWORD    nSize,
    _Out_               LPDWORD  pcbNeeded
)
/*++
Function Description: GetPrintProcessorCapabilities returns information about the
                      options supported by the print processor for the given datatype
                      in a PRINTPROCESSOR_CAPS_1 struct.

Parameters:   pValueName   -- datatype like RAW|NT EMF 1.006|TEXT|...
              dwAttributes -- printer attributes
              pData        -- pointer to the buffer
              nSize        -- size of the buffer
              pcbNeeded    -- pointer to the variable to store the required buffer size


Return Values: Error Codes.
--*/
{
    LPWSTR                  *pDatatypes = Datatypes;
    DWORD                   dwDatatype  = 0;
    DWORD                   dwReturn    = ERROR_SUCCESS;
    DWORD                   dwLevel     = 1;


    // Check for valid parameters.
    if ( !pcbNeeded )
    {
        dwReturn = ERROR_INVALID_PARAMETER;
        goto CleanUp;
    }

    if ( nSize >= sizeof(PRINTPROCESSOR_CAPS_2) )
    {
        *pcbNeeded = sizeof(PRINTPROCESSOR_CAPS_2);
        dwLevel    = 2;
    }
    else if ( nSize >= sizeof(PRINTPROCESSOR_CAPS_1) )
    {

        *pcbNeeded = sizeof(PRINTPROCESSOR_CAPS_1);
        dwLevel    = 1;
    }
    else
    {
        *pcbNeeded = sizeof(PRINTPROCESSOR_CAPS_2);
        dwReturn = ERROR_MORE_DATA;
        goto CleanUp;
    }

    if ( !pData || !pValueName)
    {
        dwReturn = ERROR_INVALID_PARAMETER;
        goto CleanUp;
    }

    // Loop to find the index of the datatype.
    while (*pDatatypes) {
       if (!_wcsicmp(*pDatatypes,pValueName)) {
           break;
       }
       pDatatypes++;
       dwDatatype++;
    }

    switch (dwLevel)
    {
        case 1:
            FillInPPCForLevel1(
                        (PPRINTPROCESSOR_CAPS_1) pData,
                                                 dwDatatype,
                                                 dwAttributes);
            break;
        case 2:
            FillInPPCForLevel2(
                        (PPRINTPROCESSOR_CAPS_2) pData,
                                                 dwDatatype,
                                                 dwAttributes);
            break;
        default:
            dwReturn = ERROR_INVALID_PARAMETER;
    }

CleanUp:

    return dwReturn;

}


DWORD
FillInPPCForLevel1(
    _Out_ PPRINTPROCESSOR_CAPS_1 ppcInfo,
          DWORD                  dwDatatype,
    _In_  DWORD                  dwAttributes
    )
{
    DWORD dwReturn = ERROR_SUCCESS;

    ppcInfo->dwLevel = 1;

    switch (dwDatatype) {

    case PRINTPROCESSOR_TYPE_RAW:
    case PRINTPROCESSOR_TYPE_TEXT:
          ppcInfo->dwNupOptions = 1;
          ppcInfo->dwNumberOfCopies = 0xffffffff; // maximum number of copies.
          ppcInfo->dwPageOrderFlags = NORMAL_PRINT;
          break;

    case PRINTPROCESSOR_TYPE_EMF_50_1:
    case PRINTPROCESSOR_TYPE_EMF_50_2:
    case PRINTPROCESSOR_TYPE_EMF_50_3:
          // For direct printing, masq. printers and print RAW only,
          // EMF is not spooled. Dont expose EMF features in the UI.
          if ((dwAttributes & PRINTER_ATTRIBUTE_DIRECT)   ||
              (dwAttributes & PRINTER_ATTRIBUTE_RAW_ONLY) ||
              ((dwAttributes & PRINTER_ATTRIBUTE_LOCAL)  &&
               (dwAttributes & PRINTER_ATTRIBUTE_NETWORK))) {
              ppcInfo->dwNupOptions = 1;
              ppcInfo->dwNumberOfCopies = 1;
              ppcInfo->dwPageOrderFlags = NORMAL_PRINT;
          } else {
              ppcInfo->dwNupOptions = 0x0000812b;  // for 1,2,4,6,9,16 up options.
              ppcInfo->dwNumberOfCopies = 0xffffffff; // maximum number of copies.
              ppcInfo->dwPageOrderFlags = REVERSE_PRINT | BOOKLET_PRINT;
          }
          break;

    default:
          // Should not happen since the spooler must check if the datatype is
          // supported before calling this print processor.
          dwReturn = ERROR_INVALID_DATATYPE;
    }

    return dwReturn;
}

DWORD
FillInPPCForLevel2(
    _Out_ PPRINTPROCESSOR_CAPS_2 ppcInfo2,
          DWORD                  dwDatatype,
    _In_  DWORD                  dwAttributes
    )
{
    DWORD dwReturn = ERROR_SUCCESS;

    // First Fill in Level 1
    dwReturn = FillInPPCForLevel1(
                        (PPRINTPROCESSOR_CAPS_1) ppcInfo2,
                                                 dwDatatype,
                                                 dwAttributes);

    if ( dwReturn != ERROR_SUCCESS )
    {

          goto CleanUp;
    }


    ppcInfo2->dwLevel = 2;

    switch (dwDatatype) {

    case PRINTPROCESSOR_TYPE_RAW:
    case PRINTPROCESSOR_TYPE_TEXT:
          ppcInfo2->dwNupDirectionCaps = 1;
          ppcInfo2->dwScalingCaps      = 0;  //Scaling not supported.
          break;

    case PRINTPROCESSOR_TYPE_EMF_50_1:
    case PRINTPROCESSOR_TYPE_EMF_50_2:
    case PRINTPROCESSOR_TYPE_EMF_50_3:
        // For direct printing, masq. printers and print RAW only,
        // EMF is not spooled. Dont expose EMF features in the UI.
        if ((dwAttributes & PRINTER_ATTRIBUTE_DIRECT)   ||
            (dwAttributes & PRINTER_ATTRIBUTE_RAW_ONLY) ||
            ((dwAttributes & PRINTER_ATTRIBUTE_LOCAL)  &&
             (dwAttributes & PRINTER_ATTRIBUTE_NETWORK)))
        {
            ppcInfo2->dwNupDirectionCaps        = 0;     //Nup not supported
            ppcInfo2->dwNupBorderCaps           = 0;
            ppcInfo2->dwBookletHandlingCaps     = 0;
            ppcInfo2->dwDuplexHandlingCaps      = 0;
            ppcInfo2->dwScalingCaps             = 0;     //No Scaling
        }
        else
        {
            ppcInfo2->dwNupDirectionCaps        = PPCAPS_RIGHT_THEN_DOWN |
                                                  PPCAPS_DOWN_THEN_RIGHT |
                                                  PPCAPS_LEFT_THEN_DOWN  |
                                                  PPCAPS_DOWN_THEN_LEFT;    //for 4 n-up directions.

            ppcInfo2->dwNupBorderCaps           = PPCAPS_BORDER_PRINT;
            ppcInfo2->dwBookletHandlingCaps     = PPCAPS_BOOKLET_EDGE;
            ppcInfo2->dwDuplexHandlingCaps      = PPCAPS_REVERSE_PAGES_FOR_REVERSE_DUPLEX |
                                                  PPCAPS_DONT_SEND_EXTRA_PAGES_FOR_DUPLEX;
            ppcInfo2->dwScalingCaps             = PPCAPS_SQUARE_SCALING; // Square scaling only

        }
        break;
    default:
          // Should not happen since the spooler must check if the datatype is
          // supported before calling this print processor.
          dwReturn = ERROR_INVALID_DATATYPE;
    }
CleanUp:

    return dwReturn;

}

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS