Sample Code

windows driver samples/ Windows Image Acquisition (WIA) Driver Samples/ C++/ ProdScan/ InitProp.cpp/

/**************************************************************************
*
*  Copyright � Microsoft Corporation
*
*  File Name:   InitProp.cpp
*
*  Description: This file contains code for WIA property initialization
*               for the Production Scanner Driver Sample
*
***************************************************************************/

#include "stdafx.h"

/**************************************************************************\
*
* Initializes the Root item properties
*
* Parameters:
*
*    pWiasContext - pointer to the item context
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/

HRESULT CWiaDriver::InitializeRootItemProperties(
    _In_ BYTE* pWiasContext)
{
    HRESULT hr = S_OK;

    WIAEX_TRACE_BEGIN;

    //
    // Validate input:
    //
    if (!pWiasContext)
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr));
    }

    //
    // Initialize Root item properties:
    //
    if (SUCCEEDED(hr))
    {
        CWIAPropertyManager PropertyManager;

        //
        // WIA_IPA_ITEM_CATEGORY:
        //
        GUID guidItemCategory = WIA_CATEGORY_ROOT;
        hr = PropertyManager.AddProperty(WIA_IPA_ITEM_CATEGORY, WIA_IPA_ITEM_CATEGORY_STR, RN, guidItemCategory);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_ITEM_CATEGORY, hr = 0x%08X", hr));
        }

        //
        // WIA_IPA_ACCESS_RIGHTS
        //
        if (SUCCEEDED(hr))
        {
            LONG lAccessRights = WIA_ITEM_READ;

            hr = PropertyManager.AddProperty(WIA_IPA_ACCESS_RIGHTS, WIA_IPA_ACCESS_RIGHTS_STR, RF, lAccessRights, lAccessRights);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_ACCESS_RIGHTS, hr = 0x%08X", hr));
            }
        }

        //
        // WIA_DPS_DOCUMENT_HANDLING_CAPABILITIES and default WIA_DPS_DOCUMENT_HANDLING_STATUS:
        //

        LONG lDocumentHandlingCapabilities = AUTO_SOURCE | FLAT | FEED | DUP | IMPRINTER | ENDORSER |
            BARCODE_READER | PATCH_CODE_READER | MICR_READER;

        LONG lDocumentHandlingStatus = FLAT_READY |  FEED_READY | DUP_READY | IMPRINTER_READY | ENDORSER_READY |
            BARCODE_READER_READY | PATCH_CODE_READER_READY | MICR_READER_READY;

        LONG lValidDocumentHandlingStatus = FLAT_COVER_UP | FLAT_READY | FEED_READY | DUP_READY | IMPRINTER_READY |
            ENDORSER_READY | BARCODE_READER_READY | PATCH_CODE_READER_READY | MICR_READER_READY |
            PAPER_JAM | PATH_COVER_UP | MULTIPLE_FEED | DEVICE_ATTENTION | LAMP_ERR;

        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.AddProperty(WIA_DPS_DOCUMENT_HANDLING_CAPABILITIES,
                WIA_DPS_DOCUMENT_HANDLING_CAPABILITIES_STR , RN, lDocumentHandlingCapabilities);

            if(FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_DPS_DOCUMENT_HANDLING_CAPABILITIES, hr = 0x%08X", hr));
            }
        }

        //
        // WIA_DPS_DOCUMENT_HANDLING_STATUS:
        //
        if (SUCCEEDED(hr))
        {
            //
            // Initialize with default ready flag values:
            //
            hr = PropertyManager.AddProperty(WIA_DPS_DOCUMENT_HANDLING_STATUS,
                WIA_DPS_DOCUMENT_HANDLING_STATUS_STR, RN, lDocumentHandlingStatus, lValidDocumentHandlingStatus);

            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_DPS_DOCUMENT_HANDLING_STATUS, hr = 0x%08X", hr));
            }
        }

        //
        // WIA_DPA_CONNECT_STATUS
        //
        // The sample device is always available:
        //
        if (SUCCEEDED(hr))
        {
            LONG lDeviceConnected = 1;
            hr = PropertyManager.AddProperty(WIA_DPA_CONNECT_STATUS, WIA_DPA_CONNECT_STATUS_STR, RN, lDeviceConnected);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_DPA_CONNECT_STATUS, hr = 0x%08X", hr));
            }
        }

        //
        // WIA_DPS_SCAN_AVAILABLE_ITEM:
        //
        if (SUCCEEDED(hr))
        {
            //
            // If the global (per driver instance) m_bstrScanAvailableItem is not yet initialized
            // initialize it now to an empty string. Note that because we use here m_bstrScanAvailableItem
            // to initialize the property we do not need to execute UpdateScanAvailableItemProperty:
            //
            if (!m_bstrScanAvailableItem)
            {
                hr = UpdateScanAvailableItemName(NULL);
                if (FAILED(hr))
                {
                    WIAEX_ERROR((g_hInst, "Failed to initialize the scan available item name, hr = 0x%08X", hr));
                }
            }
            else
            {
                WIAS_TRACE((g_hInst, "Scan available from %ws", m_bstrScanAvailableItem));
            }

            if (SUCCEEDED(hr))
            {
                #pragma prefast(suppress:__WARNING_INVALID_PARAM_VALUE_1, "m_bstrScanAvailableItem is allocated to an empty string by the UpdateScanAvailableItemName call above"
                hr = PropertyManager.AddProperty(WIA_DPS_SCAN_AVAILABLE_ITEM, WIA_DPS_SCAN_AVAILABLE_ITEM_STR, RN, m_bstrScanAvailableItem);
                if (FAILED(hr))
                {
                    WIAEX_ERROR((g_hInst, "Failed to initialize WIA_DPS_SCAN_AVAILABLE_ITEM, hr = 0x%08X", hr));
                }
            }
        }

        //
        // Set the properties:
        //
        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.SetItemProperties(pWiasContext);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA root item properties, hr = 0x%08X", hr));
            }
        }
        else
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_ITEM_CATEGORY, hr = 0x%08X", hr));
        }
    }

    WIAEX_TRACE_FUNC_HR;

    return hr;
}

/**************************************************************************\
*
* Wrapper method to initializes the properties for the child items this
* sample driver creates.
*
* Parameters:
*
*    pWiasContext            - pointer to the item context
*    nDocumentHandlingSelect - a WIA_DPS_DOCUMENT_HANDLING_SELECT value (such
*                              as FLAT or FEED (defined in wiadef.h) identifying
*                              the item being initialized
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/

HRESULT CWiaDriver::InitializeChildItemProperties(
    _In_ BYTE*     pWiasContext,
    UINT           nDocumentHandlingSelect)

{
    HRESULT hr = S_OK;
    CWIAPropertyManager PropertyManager;

    WIAEX_TRACE_BEGIN;

    //
    // No need to validate parameters of trace failures here, the called functions
    // do the validation and output full error traces:
    //
    hr = InitializeCommonChildProperties(pWiasContext, nDocumentHandlingSelect);
    if (SUCCEEDED(hr))
    {
        if ((FLAT == nDocumentHandlingSelect) || (FEEDER == nDocumentHandlingSelect))
        {
            hr = InitializeFlatbedFeederProperties(pWiasContext, nDocumentHandlingSelect);
            if (SUCCEEDED(hr) && (FEEDER == nDocumentHandlingSelect))
            {
                hr = InitializeFeederSpecificProperties(pWiasContext);
            }
        }
        else if ((IMPRINTER == nDocumentHandlingSelect) || (ENDORSER == nDocumentHandlingSelect))
        {
            hr = InitializeImprinterEndorserProperties(pWiasContext, nDocumentHandlingSelect);
        }
        else if (BARCODE_READER == nDocumentHandlingSelect)
        {
            hr = InitializeBarcodeReaderProperties(pWiasContext);
        }
        else if (PATCH_CODE_READER == nDocumentHandlingSelect)
        {
            hr = InitializePatchCodeReaderProperties(pWiasContext);
        }
        else if (MICR_READER == nDocumentHandlingSelect)
        {
            hr = InitializeMicrReaderProperties(pWiasContext);
        }
    }

    WIAEX_TRACE_FUNC_HR;

    return hr;
}

/**************************************************************************\
*
* Initializes common child item properties (properties common to all
* data source items this driver creates: Flatbed, Feeder, Auto, Imprinter, etc.
*
* Parameters:
*
*    pWiasContext            - pointer to the item context
*    nDocumentHandlingSelect - a WIA_DPS_DOCUMENT_HANDLING_SELECT value (such
*                              as FLAT or FEED (defined in wiadef.h) identifying
*                              the item being initialized
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/

HRESULT CWiaDriver::InitializeCommonChildProperties(
    _In_ BYTE*     pWiasContext,
    UINT           nDocumentHandlingSelect)

{
    HRESULT hr = S_OK;

    CWIAPropertyManager PropertyManager;

    if (!pWiasContext)
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "CWiaDriver::InitializeCommonChildProperties, invalid item context parameter, hr = 0x%08X", hr));
    }

    WIAEX_TRACE_BEGIN;

    //
    // WIA_IPA_ITEM_CATEGORY
    //
    if (SUCCEEDED(hr))
    {
        GUID guidItemCategory = WIA_CATEGORY_FLATBED;

        switch (nDocumentHandlingSelect)
        {
            case FLAT:
                guidItemCategory = WIA_CATEGORY_FLATBED;
                break;

            case FEED:
                guidItemCategory = WIA_CATEGORY_FEEDER;
                break;

            case AUTO_SOURCE:
                guidItemCategory = WIA_CATEGORY_AUTO;
                break;

            case IMPRINTER:
                guidItemCategory = WIA_CATEGORY_IMPRINTER;
                break;

            case ENDORSER:
                guidItemCategory = WIA_CATEGORY_ENDORSER;
                break;

            case BARCODE_READER:
                guidItemCategory = WIA_CATEGORY_BARCODE_READER;
                break;

            case PATCH_CODE_READER:
                guidItemCategory = WIA_CATEGORY_PATCH_CODE_READER;
                break;

            case MICR_READER:
                guidItemCategory = WIA_CATEGORY_MICR_READER;
                break;

            default:
                hr = E_INVALIDARG;
                WIAEX_ERROR((g_hInst, "CWiaDriver::InitializeCommonChildProperties, invalid item (%u) parameter, hr = 0x%08X",
                    nDocumentHandlingSelect, hr));
        }

        hr = PropertyManager.AddProperty(WIA_IPA_ITEM_CATEGORY, WIA_IPA_ITEM_CATEGORY_STR, RN, guidItemCategory);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_ITEM_CATEGORY for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_ACCESS_RIGHTS
    //
    if (SUCCEEDED(hr))
    {
        LONG lAccessRights = WIA_ITEM_READ;

        hr = PropertyManager.AddProperty(WIA_IPA_ACCESS_RIGHTS, WIA_IPA_ACCESS_RIGHTS_STR, RF, lAccessRights, lAccessRights);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_ACCESS_RIGHTS for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_FORMAT
    //
    // For image transfers, this sample driver supports the DIB (mandatory default), EXIF and Raw image file formats.
    //
    // The sample imprinter and endorser items support the CSV (mandatory default) and TXT for text transfers and
    // DIB (mandatory default) for graphics transfers. Default data transfer mode is text (required).
    //
    // The sample barcode, patch code and MICR reader items support the required XML and Raw metadata transfers.
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<GUID> guidFormatArray;

        if ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect) ||
            (AUTO_SOURCE == nDocumentHandlingSelect))
        {
            guidFormatArray.Append(WiaImgFmt_BMP);
            guidFormatArray.Append(WiaImgFmt_EXIF);
            guidFormatArray.Append(WiaImgFmt_RAW);
        }
        else if ((IMPRINTER == nDocumentHandlingSelect) || (ENDORSER == nDocumentHandlingSelect))
        {
            guidFormatArray.Append(WiaImgFmt_CSV);
            guidFormatArray.Append(WiaImgFmt_TXT);
            guidFormatArray.Append(WiaImgFmt_BMP);
        }
        else if (BARCODE_READER == nDocumentHandlingSelect)
        {
            guidFormatArray.Append(WiaImgFmt_XMLBAR);
            guidFormatArray.Append(WiaImgFmt_RAWBAR);
        }
        else if (PATCH_CODE_READER == nDocumentHandlingSelect)
        {
            guidFormatArray.Append(WiaImgFmt_XMLPAT);
            guidFormatArray.Append(WiaImgFmt_RAWPAT);
        }
        else if (MICR_READER == nDocumentHandlingSelect)
        {
            guidFormatArray.Append(WiaImgFmt_XMLMIC);
            guidFormatArray.Append(WiaImgFmt_RAWMIC);
        }

        hr = PropertyManager.AddProperty(WIA_IPA_FORMAT, WIA_IPA_FORMAT_STR, RWL, guidFormatArray[0], guidFormatArray[0], &guidFormatArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_FORMAT for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_TYMED
    //
    // This sample driver supports only TYMED_FILE (single page files) for image as well as text and metadata data transfers
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lTymedArray;
        lTymedArray.Append(TYMED_FILE);

        hr = PropertyManager.AddProperty(WIA_IPA_TYMED, WIA_IPA_TYMED_STR, RWL, lTymedArray[0], lTymedArray[0], &lTymedArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_TYMED for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_PREFERRED_FORMAT
    //
    // For image transfers, this sample driver reports EXIF as the preferred transfer file format.
    //
    // For printer/endorser transfers, this driver reports CSV as the preferred transfer file format.
    //
    // For barcode, patch code and MICR metadata transfers, this driver reports XML as the preferred transfer file format.
    //
    if (SUCCEEDED(hr))
    {
        GUID guidPreferredFormat = {};

        if ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect) ||
            (AUTO_SOURCE == nDocumentHandlingSelect))
        {
            guidPreferredFormat = WiaImgFmt_EXIF;
        }
        else if ((IMPRINTER == nDocumentHandlingSelect) || (ENDORSER == nDocumentHandlingSelect))
        {
            guidPreferredFormat = WiaImgFmt_CSV;
        }
        else if (BARCODE_READER == nDocumentHandlingSelect)
        {
            guidPreferredFormat = WiaImgFmt_XMLBAR;
        }
        else if (PATCH_CODE_READER == nDocumentHandlingSelect)
        {
            guidPreferredFormat = WiaImgFmt_XMLPAT;
        }
        else if (MICR_READER == nDocumentHandlingSelect)
        {
            guidPreferredFormat = WiaImgFmt_XMLMIC;
        }

        hr = PropertyManager.AddProperty(WIA_IPA_PREFERRED_FORMAT, WIA_IPA_PREFERRED_FORMAT_STR, RN, guidPreferredFormat);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_PREFERRED_FORMAT for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_FILENAME_EXTENSION
    //
    if (SUCCEEDED(hr))
    {
        BSTR bstrFileExtension = NULL;

        //
        // Note that WIA_IPA_FILENAME_EXTENSION must match the WIA_IPA_FORMAT current value, not WIA_IPA_PREFERRED_FORMAT:
        //
        if ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect) ||
            (AUTO_SOURCE == nDocumentHandlingSelect))
        {
            bstrFileExtension = SysAllocString(FILE_EXT_BMP);
        }
        else if ((IMPRINTER == nDocumentHandlingSelect) || (ENDORSER == nDocumentHandlingSelect))
        {
            bstrFileExtension = SysAllocString(FILE_EXT_CSV);
        }
        else if ((BARCODE_READER == nDocumentHandlingSelect) || (PATCH_CODE_READER == nDocumentHandlingSelect) ||
            (MICR_READER == nDocumentHandlingSelect))
        {
            bstrFileExtension = SysAllocString(FILE_EXT_XML);
        }

        if (bstrFileExtension)
        {
            hr = PropertyManager.AddProperty(WIA_IPA_FILENAME_EXTENSION, WIA_IPA_FILENAME_EXTENSION_STR, RN, bstrFileExtension);

            SysFreeString(bstrFileExtension);
            bstrFileExtension = NULL;
        }
        else
        {
            hr = E_OUTOFMEMORY;
            WIAEX_ERROR((g_hInst, "Could not allocate the file name extension property value, hr = 0x%08X", hr));
        }

        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_FILENAME_EXTENSION for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_COMPRESSION
    //
    // For image transfers, this sample driver supports no compression (mandatory default, for DIB and Raw transfers)
    // and JPEG (EEXIF transfers). The sample driver also pretends to support auto-compression (WIA_COMPRESSION_AUTO)
    // but in auto-compression mode JPEG compression is always selected.
    //
    // For all other metadata transfers, this sample driver supports no compression (mandatory default).
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lCompressionArray;

        lCompressionArray.Append(WIA_COMPRESSION_NONE);
        if ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect) || (AUTO_SOURCE == nDocumentHandlingSelect))
        {
            lCompressionArray.Append(WIA_COMPRESSION_JPEG);
            lCompressionArray.Append(WIA_COMPRESSION_AUTO);
        }

        hr = PropertyManager.AddProperty(WIA_IPA_COMPRESSION, WIA_IPA_COMPRESSION_STR, RWL, lCompressionArray[0], lCompressionArray[0], &lCompressionArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_COMPRESSION for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // Apply the property changes to the current session's Application Item Tree:
    //

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.SetItemProperties(pWiasContext);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA item properties for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    WIAEX_TRACE_FUNC_HR;

    return hr;
}

/**************************************************************************\
*
* Initializes the properties common to the Flatbed and Feeder items.
*
* Parameters:
*
*    pWiasContext            - pointer to the item context
*    nDocumentHandlingSelect - FLAT or FEED (defined in wiadef.h)
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/

HRESULT CWiaDriver::InitializeFlatbedFeederProperties(
    _In_ BYTE*     pWiasContext,
    UINT           nDocumentHandlingSelect)

{
    HRESULT hr = S_OK;
    CWIAPropertyManager PropertyManager;

    if ((!pWiasContext) || ((FLAT != nDocumentHandlingSelect) && (FEED != nDocumentHandlingSelect)))
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "CWiaDriver::InitializeFlatbedFeederProperties, invalid parameter, hr = 0x%08X", hr));
    }

    WIAEX_TRACE_BEGIN;

    //
    // WIA_IPA_ITEM_SIZE
    //
    if (SUCCEEDED(hr))
    {
        LONG lItemSize = 0;

        hr = PropertyManager.AddProperty(WIA_IPA_ITEM_SIZE, WIA_IPA_ITEM_SIZE_STR, RN, lItemSize);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_ITEM_SIZE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_PLANAR:
    //
    LONG lPlanar = WIA_PACKED_PIXEL;

    hr = PropertyManager.AddProperty(WIA_IPA_PLANAR, WIA_IPA_PLANAR_STR, RN, lPlanar);
    if (FAILED(hr))
    {
        WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_PLANAR for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
    }

    //
    // WIA_IPA_DATATYPE
    //
    // This sample driver supports 24-bpp RGB color and 8-bpp Grayscale for the image transfers, as well as the auto color mode.
    // When WIA_DATA_AUTO is set the sample driver choses randomly between WIA_DATA_GRAYSCALE and WIA_DATA_COLOR.
    // A real driver should base this decision on the actual document that is scanned:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lDataTypeArray;
        lDataTypeArray.Append(WIA_DATA_GRAYSCALE);
        lDataTypeArray.Append(WIA_DATA_COLOR);
        lDataTypeArray.Append(WIA_DATA_AUTO);

        hr = PropertyManager.AddProperty(WIA_IPA_DATATYPE, WIA_IPA_DATATYPE_STR, RWL, lDataTypeArray[0], lDataTypeArray[0], &lDataTypeArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_DATATYPE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_DEPTH
    //
    // This sample driver supports 24-bpp RGB color and 8-bpp Grayscale, as well as the auto value (WIA_DEPTH_AUTO or 0):
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lDepthArray;
        lDepthArray.Append(8);
        lDepthArray.Append(24);
        lDepthArray.Append(WIA_DEPTH_AUTO);

        hr = PropertyManager.AddProperty(WIA_IPA_DEPTH , WIA_IPA_DEPTH_STR, RWLC, lDepthArray[0], lDepthArray[0], &lDepthArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_DEPTH for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_CHANNELS_PER_PIXEL
    //
    // This sample driver supports 1 and 3 channels (samples) per pixel
    //
    if (SUCCEEDED(hr))
    {
        LONG lChannelsPerPixel = 1; //default value that matches the default WIA_DATA_GRAYSCALE

        hr = PropertyManager.AddProperty(WIA_IPA_CHANNELS_PER_PIXEL, WIA_IPA_CHANNELS_PER_PIXEL_STR, RN, lChannelsPerPixel);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_CHANNELS_PER_PIXEL for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_BITS_PER_CHANNEL
    //
    // This sample driver supports only 8 bits per channel (sample)
    //
    if (SUCCEEDED(hr))
    {
        LONG lBitsPerChannel = 8;

        hr = PropertyManager.AddProperty(WIA_IPA_BITS_PER_CHANNEL, WIA_IPA_BITS_PER_CHANNEL_STR, RN, lBitsPerChannel);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_BITS_PER_CHANNEL for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_RAW_BITS_PER_CHANNEL
    //
    if (SUCCEEDED(hr))
    {
        BYTE bRawBitsPerChannel[] = { 8 }; //to match the default WIA_DATA_GRAYSCALE

        hr = PropertyManager.AddProperty(WIA_IPA_RAW_BITS_PER_CHANNEL, WIA_IPA_RAW_BITS_PER_CHANNEL_STR, RN, &bRawBitsPerChannel[0], 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_RAW_BITS_PER_CHANNEL for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }


    //
    // WIA_IPS_CUR_INTENT
    //
    if (SUCCEEDED(hr))
    {
        LONG lCurrentIntent = WIA_INTENT_NONE;
        LONG lValidIntents = WIA_INTENT_IMAGE_TYPE_COLOR | WIA_INTENT_IMAGE_TYPE_GRAYSCALE | WIA_INTENT_MAXIMIZE_QUALITY | WIA_INTENT_MINIMIZE_SIZE;

        hr = PropertyManager.AddProperty(WIA_IPS_CUR_INTENT, WIA_IPS_CUR_INTENT_STR, RWF, lCurrentIntent, lValidIntents);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_CUR_INTENT for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_OPTICAL_XRES and WIA_IPS_OPTICAL_YRES
    //
    // This sample driver reports OPTICAL_RESOLUTION DPI as optical resolution on both scan directions
    //
    if (SUCCEEDED(hr))
    {
        LONG lOpticalResolution = OPTICAL_RESOLUTION;

        hr = PropertyManager.AddProperty(WIA_IPS_OPTICAL_XRES, WIA_IPS_OPTICAL_XRES_STR, RN, lOpticalResolution);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_OPTICAL_XRES for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }

        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.AddProperty(WIA_IPS_OPTICAL_YRES, WIA_IPS_OPTICAL_YRES_STR, RN, lOpticalResolution);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_OPTICAL_YRES for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
            }
        }
    }

    //
    // WIA_IPS_XRES and WIA_IPS_YRES
    //
    // This sample driver supports OPTICAL_RESOLUTION DPI as the only scan resolution for both scan directions
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lResolutionArray;
        lResolutionArray.Append(OPTICAL_RESOLUTION);

        //
        // Add WIA_IPS_XRES and WIA_IPS_YRES as WIA_PROP_LIST:
        //
        hr = PropertyManager.AddProperty(WIA_IPS_XRES, WIA_IPS_XRES_STR, RWLC, lResolutionArray[0], lResolutionArray[0], &lResolutionArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_XRES for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }

        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.AddProperty(WIA_IPS_YRES, WIA_IPS_YRES_STR, RWLC, lResolutionArray[0], lResolutionArray[0], &lResolutionArray);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_YRES for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
            }
        }
    }

    //
    // WIA_IPS_XSCALING and WIA_IPS_YSCALING
    //
    // This sample driover supports only 100% scaling (which means no actual scaling)
    //
    if (SUCCEEDED(hr))
    {
        LONG lScaling = 100;

        hr = PropertyManager.AddProperty(WIA_IPS_XSCALING, WIA_IPS_XSCALING_STR, RWRC, lScaling, lScaling, lScaling, lScaling, 0);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_XSCALING for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }

        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.AddProperty(WIA_IPS_YSCALING, WIA_IPS_YSCALING_STR, RWRC, lScaling, lScaling, lScaling, lScaling, 0);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_YSCALING for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
            }
        }
    }

    //
    // WIA_IPS_MIN_HORIZONTAL_SIZE, WIA_IPS_MAX_HORIZONTAL_SIZE, WIA_IPS_MIN_VERTICAL_SIZE and WIA_IPS_MAX_VERTICAL_SIZE
    //
    // This sample driver supports for both flatbed and feeder the following:
    //
    // Minimum scan region is MIN_SCAN_AREA_WIDTH x MIN_SCAN_AREA_HEIGHT
    // Maximum scan region is MAX_SCAN_AREA_WIDTH x MAX_SCAN_AREA_HEIGHT
    //
    if (SUCCEEDED(hr))
    {
        LONG lMaximumWidth = MAX_SCAN_AREA_WIDTH;

        hr = PropertyManager.AddProperty(WIA_IPS_MAX_HORIZONTAL_SIZE, WIA_IPS_MAX_HORIZONTAL_SIZE_STR, RN, lMaximumWidth);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_MAX_HORIZONTAL_SIZE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        LONG lMaximumHeight = MAX_SCAN_AREA_HEIGHT;

        hr = PropertyManager.AddProperty(WIA_IPS_MAX_VERTICAL_SIZE, WIA_IPS_MAX_VERTICAL_SIZE_STR, RN, lMaximumHeight);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_MAX_VERTICAL_SIZE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        LONG lMinimumWidth = MIN_SCAN_AREA_WIDTH;

        hr = PropertyManager.AddProperty(WIA_IPS_MIN_HORIZONTAL_SIZE, WIA_IPS_MIN_HORIZONTAL_SIZE_STR, RN, lMinimumWidth);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_MIN_HORIZONTAL_SIZE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        LONG lMinimumHeight = MIN_SCAN_AREA_HEIGHT;

        hr = PropertyManager.AddProperty(WIA_IPS_MIN_VERTICAL_SIZE, WIA_IPS_MIN_VERTICAL_SIZE_STR, RN, lMinimumHeight);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_MIN_VERTICAL_SIZE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_XPOS, WIA_IPS_YPOS, WIA_IPS_XEXTENT and WIA_IPS_YEXTENT
    //
    // In general, for the flatbed item, valid values are to be initialized from
    // (considering current WIA_IPS_X/YRES and WIA_IPS_X/YSCALING):
    //
    // WIA_IPS_MIN_HORIZONTAL_SIZE,
    // WIA_IPS_MIN_VERTICAL_SIZE,
    // WIA_IPS_MAX_HORIZONTAL_SIZE,
    // WIA_IPS_MAX_VERTICAL_SIZE
    //
    // For the feeder item valid values are to be initialized from
    // the size of the currently selected document size, considering
    // orientation and current WIA_IPS_X/YRES/SCALING:
    //
    // WIA_IPS_PAGE_SIZE
    // WIA_IPS_PAGE_WIDTH/HEIGHT (if WIA_IPS_PAGE_SIZE is set to CUSTOM, default)
    // WIA_IPS_ORIENTATION
    //
    // The default scan region should cover the entire available scan area.
    //

    LONG lMinXExtent = 1;
    LONG lMinYExtent = 1;
    LONG lMaxXExtent = 2;
    LONG lMaxYExtent = 2;

    LONG lXResolution = OPTICAL_RESOLUTION;
    LONG lYResolution = OPTICAL_RESOLUTION;

    if (SUCCEEDED(hr) && (AUTO_SOURCE != nDocumentHandlingSelect))
    {
        //
        // Convert back from 1/1000" values x pixels-per-inch:
        //
        lMinXExtent = (MIN_SCAN_AREA_WIDTH * lXResolution) / 1000;
        if (!lMinXExtent)
        {
            lMinXExtent = 1;
        }
        lMinYExtent = (MIN_SCAN_AREA_HEIGHT * lYResolution) / 1000;
        if (!lMinYExtent)
        {
            lMinYExtent = 1;
        }
        lMaxXExtent = (MAX_SCAN_AREA_WIDTH * lXResolution) / 1000;
        lMaxYExtent = (MAX_SCAN_AREA_HEIGHT * lYResolution) / 1000;

        //
        // IMPORTANT: do not round up!
        //
        // lMaxXExtent = (LONG)((((float)MAX_SCAN_AREA_WIDTH * (float)lXResolution) / 1000.0f) + 0.5f);
        // lMaxYExtent = (LONG)((((float)MAX_SCAN_AREA_HEIGHT * (float)lYResolution) / 1000.0f) + 0.5f);
        //

        if ((lMaxXExtent < 1) || (lMaxYExtent < 1) || (lMinXExtent > lMaxXExtent) || (lMinYExtent > lMaxYExtent))
        {
            hr = E_FAIL;
            WIAEX_ERROR((g_hInst, "Invalid resolution and-or minimum and-or maximum scan area size values, hr = 0x%08X", hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_XPOS, WIA_IPS_XPOS_STR, RWRC, 0, 0, 0, lMaxXExtent - lMinXExtent, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_XPOS for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }

        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.AddProperty(WIA_IPS_YPOS, WIA_IPS_YPOS_STR, RWRC, 0, 0, 0, lMaxYExtent - lMinYExtent, 1);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_YPOS for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
            }
        }

        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.AddProperty(WIA_IPS_XEXTENT, WIA_IPS_XEXTENT_STR, RWRC, lMaxXExtent, lMaxXExtent, lMinXExtent, lMaxXExtent, 1);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_XEXTENT for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
            }
        }

        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.AddProperty(WIA_IPS_YEXTENT, WIA_IPS_YEXTENT_STR, RWRC, lMaxYExtent, lMaxYExtent, lMinYExtent, lMaxYExtent, 1);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_YEXTENT for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
            }
        }
    }

    //
    // WIA_IPS_BRIGHTNESS and WIA_IPS_CONTRAST
    //
    // This sample driver simulates brightness and contrast adjustment between
    // a standard range from -1000 to 1000, with a default value of 0.
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_BRIGHTNESS, WIA_IPS_BRIGHTNESS_STR, RWRC, 0, 0, -1000, 1000, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_BRIGHTNESS for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_CONTRAST, WIA_IPS_CONTRAST_STR, RWRC, 0, 0, -1000, 1000, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_CONTRAST for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_ROTATION
    //
    // This sample driver supports only 0 degrees rotation (no actual rotation)
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lRotationArray;
        lRotationArray.Append(0);

        hr = PropertyManager.AddProperty(WIA_IPS_ROTATION, WIA_IPS_ROTATION_STR, RWLC, lRotationArray[0], lRotationArray[0], &lRotationArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_ROTATION for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_THRESHOLD
    //
    // This sample driver supports only the default value of 128
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_THRESHOLD, WIA_IPS_THRESHOLD_STR, RWRC, 128, 128, 128, 128, 0);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_THRESHOLD for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PREVIEW
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lScanModeArray;
        lScanModeArray.Append(WIA_FINAL_SCAN);
        lScanModeArray.Append(WIA_PREVIEW_SCAN);

        hr = PropertyManager.AddProperty(WIA_IPS_PREVIEW, WIA_IPS_PREVIEW_STR, RWL, lScanModeArray[0], lScanModeArray[0], &lScanModeArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PREVIEW for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_SHOW_PREVIEW_CONTROL
    //
    if (SUCCEEDED(hr))
    {
        //
        // There is the option to disable the preview control for Feeder but this sample driver is not using it:
        //
        // lShowPreviewControl = (FLAT == nDocumentHandlingSelect) ? WIA_SHOW_PREVIEW_CONTROL : WIA_DONT_SHOW_PREVIEW_CONTROL;
        //

        LONG lShowPreviewControl = WIA_SHOW_PREVIEW_CONTROL;

        hr = PropertyManager.AddProperty(WIA_IPS_SHOW_PREVIEW_CONTROL, WIA_IPS_SHOW_PREVIEW_CONTROL_STR, RN, lShowPreviewControl);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_SHOW_PREVIEW_CONTROL for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION
    //
    if (SUCCEEDED(hr))
    {
        BOOL lSupportsChildItem = FALSE;

        hr = PropertyManager.AddProperty(WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION, WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION_STR, RN, lSupportsChildItem);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PHOTOMETRIC_INTERP
    //
    // This sample driver supports only the default value of WIA_PHOTO_WHITE_1
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lPhotoInterpArray;
        lPhotoInterpArray.Append(WIA_PHOTO_WHITE_1);

        hr = PropertyManager.AddProperty(WIA_IPS_PHOTOMETRIC_INTERP, WIA_IPS_PHOTOMETRIC_INTERP_STR, RWL, lPhotoInterpArray[0], lPhotoInterpArray[0], &lPhotoInterpArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PHOTOMETRIC_INTERP for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // Even though deprecated the following "image information" properties are still required
    // for compatibility with existing legacy XP applications, including Scanner and Camera Wizard,
    // applications using the default WIA UI (including Paint) and the TWAIN applications using
    // the WIA driver though the TWAIN - WIA compatibility layer:
    //
    // WIA_IPA_PIXELS_PER_LINE - the image width, in pixels, for the final image
    // WIA_IPA_NUMBER_OF_LINES - the image length, in pixels, for the final image
    // WIA_IPA_BYTES_PER_LINE - line width in bytes matching WIA_IPA_PIXELS_PER_LINE and WIA_IPA_DEPTH
    //
    // All these values must match the exact dimensions of the final image to be transferred
    // to the application, a mismatch could cause unpredictable behaviour, including Divide by Zero
    // and Access Violation errors in the application attempting to receive data that doesn't exist.
    //

    if (SUCCEEDED(hr))
    {
        LONG lPixelsPerLine = lMaxXExtent;

        hr = PropertyManager.AddProperty(WIA_IPA_PIXELS_PER_LINE, WIA_IPA_PIXELS_PER_LINE_STR, RN, lPixelsPerLine);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_PIXELS_PER_LINE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        LONG lNumberOfLines = lMaxYExtent;

        hr = PropertyManager.AddProperty(WIA_IPA_NUMBER_OF_LINES, WIA_IPA_NUMBER_OF_LINES_STR, RN, lNumberOfLines);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_NUMBER_OF_LINES for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        //
        // DIB (the default image file transfer format) lines must be DWORD aligned, meaning
        // that each line must be multiple by 4 bytes in length, padded if necessary at the end:
        //
        LONG lBytesPerLine = 2552;

        hr = PropertyManager.AddProperty(WIA_IPA_BYTES_PER_LINE, WIA_IPA_BYTES_PER_LINE_STR, RN, lBytesPerLine);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_BYTES_PER_LINE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_BUFFER_SIZE must be supported in order to be able to increase (if needed) the default 64KB value set
    // by the WIA Compatibility Layer in the WIA Service when the driver is used with a legacy WIA 1.0 application:
    //

    if (SUCCEEDED(hr))
    {
        LONG lBufferSize = DEFAULT_BUFFER_SIZE;

        hr = PropertyManager.AddProperty(WIA_IPA_BUFFER_SIZE, WIA_IPA_BUFFER_SIZE_STR, RN, lBufferSize);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_BUFFER_SIZE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_AUTO_CROP
    //
    // The sample driver implements WIA_AUTO_CROP_SINGLE  but does not support actual image cropping:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lAutoCropArray;
        lAutoCropArray.Append(WIA_AUTO_CROP_DISABLED);
        lAutoCropArray.Append(WIA_AUTO_CROP_SINGLE);

        hr = PropertyManager.AddProperty(WIA_IPS_AUTO_CROP, WIA_IPS_AUTO_CROP_STR, RWL, lAutoCropArray[0], lAutoCropArray[0], &lAutoCropArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_AUTO_CROP for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_OVER_SCAN
    //
    // The sample driver pretends to support overscanning on all directions, however the overscan settings are unfunctional:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lOverScanArray;
        lOverScanArray.Append(WIA_OVER_SCAN_DISABLED);
        lOverScanArray.Append(WIA_OVER_SCAN_TOP_BOTTOM);
        lOverScanArray.Append(WIA_OVER_SCAN_LEFT_RIGHT);
        lOverScanArray.Append(WIA_OVER_SCAN_ALL);

        hr = PropertyManager.AddProperty(WIA_IPS_OVER_SCAN, WIA_IPS_OVER_SCAN_STR, RWL, lOverScanArray[0], lOverScanArray[0], &lOverScanArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_OVER_SCAN for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_OVER_SCAN_LEFT, WIA_IPS_OVER_SCAN_RIGHT, WIA_IPS_OVER_SCAN_TOP and WIA_IPS_OVER_SCAN_BOTTOM
    //
    // The sample driver pretends to support overscanning from 0 to 1" on all document sides, in 0.001" increments:
    //

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_OVER_SCAN_LEFT, WIA_IPS_OVER_SCAN_LEFT_STR, RWRC, 0, 0, 0, 1000, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_OVER_SCAN_LEFT for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_OVER_SCAN_RIGHT, WIA_IPS_OVER_SCAN_RIGHT_STR, RWRC, 0, 0, 0, 1000, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_OVER_SCAN_RIGHT for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_OVER_SCAN_TOP, WIA_IPS_OVER_SCAN_TOP_STR, RWRC, 0, 0, 0, 1000, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_OVER_SCAN_TOP for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_OVER_SCAN_BOTTOM, WIA_IPS_OVER_SCAN_BOTTOM_STR, RWRC, 0, 0, 0, 1000, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_OVER_SCAN_BOTTOM for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_COLOR_DROP
    //
    // The sample driver implements the color-drop properties, however it does not
    // execute any actual color filtering (drop) on the test image:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lColorDropArray;
        lColorDropArray.Append(WIA_COLOR_DROP_DISABLED);
        lColorDropArray.Append(WIA_COLOR_DROP_RED);
        lColorDropArray.Append(WIA_COLOR_DROP_GREEN);
        lColorDropArray.Append(WIA_COLOR_DROP_BLUE);
        lColorDropArray.Append(WIA_COLOR_DROP_RGB);

        hr = PropertyManager.AddProperty(WIA_IPS_COLOR_DROP, WIA_IPS_COLOR_DROP_STR, RWL, lColorDropArray[0], lColorDropArray[0], &lColorDropArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_COLOR_DROP for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_COLOR_DROP_MULTI:
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_COLOR_DROP_MULTI, WIA_IPS_COLOR_DROP_MULTI_STR, RN, g_lMaxDropColors);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_COLOR_DROP_MULTI for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_COLOR_DROP_RED, WIA_IPS_COLOR_DROP_GREEN and WIA_IPS_COLOR_DROP_BLUE:
    //

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_COLOR_DROP_RED, WIA_IPS_COLOR_DROP_RED_STR, RW, g_lMaxDropColors, (LONG *)&g_lDefaultDropColors[0]);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_COLOR_DROP_RED for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_COLOR_DROP_GREEN, WIA_IPS_COLOR_DROP_GREEN_STR, RW, g_lMaxDropColors, (LONG *)&g_lDefaultDropColors[0]);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_COLOR_DROP_GREEN for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_COLOR_DROP_BLUE, WIA_IPS_COLOR_DROP_BLUE_STR, RW, g_lMaxDropColors, (LONG *)&g_lDefaultDropColors[0]);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_COLOR_DROP_BLUE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // Apply the property changes to the current session's Application Item Tree:
    //

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.SetItemProperties(pWiasContext);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA item properties for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    WIAEX_TRACE_FUNC_HR;

    return hr;
}

/**************************************************************************\
*
* Initializes the properties specific to the Feeder item.
*
* Parameters:
*
*    pWiasContext - pointer to the item context
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/

HRESULT CWiaDriver::InitializeFeederSpecificProperties(
    _In_ BYTE* pWiasContext)

{
    HRESULT hr = S_OK;
    CWIAPropertyManager PropertyManager;

    if (!pWiasContext)
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "CWiaDriver::InitializeFeederSpecificProperties, invalid parameter, hr = 0x%08X", hr));
    }

    WIAEX_TRACE_BEGIN;

    //
    // WIA_IPS_DOCUMENT_HANDLING_SELECT
    //
    LONG lDocumentHandlingSelect = FRONT_ONLY;
    LONG lDocumentHandlingSelectValidValues = FRONT_ONLY | DUPLEX;

    hr = PropertyManager.AddProperty(WIA_IPS_DOCUMENT_HANDLING_SELECT, WIA_IPS_DOCUMENT_HANDLING_SELECT_STR, RWF, lDocumentHandlingSelect, lDocumentHandlingSelectValidValues);
    if (FAILED(hr))
    {
        WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_DOCUMENT_HANDLING_SELECT, hr = 0x%08X", hr));
    }

    //
    // WIA_IPS_SHEET_FEEDER_REGISTRATION
    //
    if (SUCCEEDED(hr))
    {
        LONG lFeederRegistration = LEFT_JUSTIFIED;

        hr = PropertyManager.AddProperty(WIA_IPS_SHEET_FEEDER_REGISTRATION, WIA_IPS_SHEET_FEEDER_REGISTRATION_STR, RN, lFeederRegistration);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_SHEET_FEEDER_REGISTRATION, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_PAGES
    //
    // Important: the default value for this property should be ALL_PAGES (0).
    // However legacy XP applications need a WIA_IPS_PAGES > 0 in order to work.
    // For this reason the default WIA_IPS_PAGES is changed to 1. Clients who need
    // to transfer all available images must set WIA_IPS_PAGES to ALL_PAGES.
    //
    if (SUCCEEDED(hr))
    {
        LONG lMaxPages     = 0x7FFFFFFF; //maximum pozitive value for a signed 32-bit integer
        LONG lMinPages     = 0; //ALL_PAGES
        LONG lDefaultPages = 1;

        hr = PropertyManager.AddProperty(WIA_IPS_PAGES, WIA_IPS_PAGES_STR,
            RWR, lDefaultPages, lDefaultPages, lMinPages, lMaxPages, 1);

        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PAGES, hr = 0x%08X", hr));
        }
    }

    LONG lPageWidth = MAX_SCAN_AREA_WIDTH;
    LONG lPageHeight = MAX_SCAN_AREA_HEIGHT;

    //
    // WIA_IPS_PAGE_SIZE
    //
    // This sample driver supports Letter, custom and auto-detect document sizes
    //
    if (SUCCEEDED(hr))
    {
        LONG lDefaultPageSize = WIA_PAGE_CUSTOM;

        hr = PropertyManager.AddProperty(WIA_IPS_PAGE_SIZE, WIA_IPS_PAGE_SIZE_STR, RWL, lDefaultPageSize, lDefaultPageSize, &m_lPortraitSizesArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PAGE_SIZE, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_ORIENTATION
    //
    // This sample driver supports only Portrait orientation
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lOrientationArray;
        lOrientationArray.Append(PORTRAIT);

        hr = PropertyManager.AddProperty(WIA_IPS_ORIENTATION, WIA_IPS_ORIENTATION_STR, RWL, lOrientationArray[0], lOrientationArray[0], &lOrientationArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_ORIENTATION, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_PAGE_WIDTH
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_PAGE_WIDTH, WIA_IPS_PAGE_WIDTH_STR, RN, lPageWidth);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_ORIENTATION, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_PAGE_HEIGHT
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_PAGE_HEIGHT, WIA_IPS_PAGE_HEIGHT_STR, RN, lPageHeight);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_ORIENTATION, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_JOB_SEPARATORS
    //
    // When job separators are enabled, the sample driver simulates a job separator page every JOB_SEPARATOR_AT_PAGE pages scanned:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lJobSeparatorsArray;
        lJobSeparatorsArray.Append(WIA_SEPARATOR_DISABLED);
        lJobSeparatorsArray.Append(WIA_SEPARATOR_DETECT_SCAN_CONTINUE);
        lJobSeparatorsArray.Append(WIA_SEPARATOR_DETECT_SCAN_STOP);
        lJobSeparatorsArray.Append(WIA_SEPARATOR_DETECT_NOSCAN_CONTINUE);
        lJobSeparatorsArray.Append(WIA_SEPARATOR_DETECT_NOSCAN_STOP);

        hr = PropertyManager.AddProperty(WIA_IPS_JOB_SEPARATORS, WIA_IPS_JOB_SEPARATORS_STR, RWL, lJobSeparatorsArray[0], lJobSeparatorsArray[0], &lJobSeparatorsArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_JOB_SEPARATORS, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_LONG_DOCUMENT
    //
    // The sample driver implemenmts the property but does not implement the actual functionality:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lLongDocArray;
        lLongDocArray.Append(WIA_LONG_DOCUMENT_DISABLED);
        lLongDocArray.Append(WIA_LONG_DOCUMENT_ENABLED);
        lLongDocArray.Append(WIA_LONG_DOCUMENT_SPLIT);

        hr = PropertyManager.AddProperty(WIA_IPS_LONG_DOCUMENT, WIA_IPS_LONG_DOCUMENT_STR, RWL, lLongDocArray[0], lLongDocArray[0], &lLongDocArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_LONG_DOCUMENT, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_BLANK_PAGES
    //
    // The sample driver implements the property but does not implement actual blank page detection functionality:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lBlankPagesArray;
        lBlankPagesArray.Append(WIA_BLANK_PAGE_DETECTION_DISABLED);
        lBlankPagesArray.Append(WIA_BLANK_PAGE_DISCARD);
        lBlankPagesArray.Append(WIA_BLANK_PAGE_JOB_SEPARATOR);

        hr = PropertyManager.AddProperty(WIA_IPS_BLANK_PAGES, WIA_IPS_BLANK_PAGES_STR, RWL, lBlankPagesArray[0], lBlankPagesArray[0], &lBlankPagesArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_BLANK_PAGES, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_BLANK_PAGES_SENSITIVITY
    //
    // This sample driver reports a range of supported values (which are not functional)
    // between 0 and 10 inclusive, with 5 being the default sensitivity:
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_BLANK_PAGES_SENSITIVITY, WIA_IPS_BLANK_PAGES_SENSITIVITY_STR, RWR, 5, 5, 1, 10, 1);

        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_BLANK_PAGES_SENSITIVITY, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_MULTI_FEED
    //
    // When multi-feed detection is enabled, the sample driver simulates a multi-feed condition every MULTI_FEED_AT_PAGE pages scanned:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lMultiFeedArray;
        lMultiFeedArray.Append(WIA_MULTI_FEED_DETECT_DISABLED);
        lMultiFeedArray.Append(WIA_MULTI_FEED_DETECT_STOP_ERROR);
        lMultiFeedArray.Append(WIA_MULTI_FEED_DETECT_STOP_SUCCESS);
        lMultiFeedArray.Append(WIA_MULTI_FEED_DETECT_CONTINUE);

        hr = PropertyManager.AddProperty(WIA_IPS_MULTI_FEED, WIA_IPS_MULTI_FEED_STR, RWL, lMultiFeedArray[0], lMultiFeedArray[0], &lMultiFeedArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_MULTI_FEED, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_MULTI_FEED_SENSITIVITY
    //
    // This sample driver reports a range of supported values (which are not functional)
    // between 0 and 10 inclusive, with 5 being the default sensitivity:
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_MULTI_FEED_SENSITIVITY, WIA_IPS_MULTI_FEED_SENSITIVITY_STR, RWR, 5, 5, 1, 10, 1);

        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_MULTI_FEED_SENSITIVITY, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_ALARM
    //
    // This sample driver does pretend to support one kind of audible alarm (beep) to signal
    // when a multi-feed conditions is detected, not functional:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lAlarmArray;
        lAlarmArray.Append(WIA_ALARM_NONE);
        lAlarmArray.Append(WIA_ALARM_BEEP1);

        hr = PropertyManager.AddProperty(WIA_IPS_ALARM, WIA_IPS_ALARM_STR, RWL, lAlarmArray[0], lAlarmArray[0], &lAlarmArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_ALARM, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_SCAN_AHEAD:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lScanAheadArray;
        lScanAheadArray.Append(WIA_SCAN_AHEAD_DISABLED);
        lScanAheadArray.Append(WIA_SCAN_AHEAD_ENABLED);

        hr = PropertyManager.AddProperty(WIA_IPS_SCAN_AHEAD, WIA_IPS_SCAN_AHEAD_STR, RWL, lScanAheadArray[0], lScanAheadArray[0], &lScanAheadArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_SCAN_AHEAD, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_SCAN_AHEAD_CAPACITY:
    //
    if (SUCCEEDED(hr))
    {
        ULONG ulScanAheadCapacity = 0; //undefined

        hr = PropertyManager.AddPropertyUL(WIA_IPS_SCAN_AHEAD_CAPACITY, WIA_IPS_SCAN_AHEAD_CAPACITY_STR, RN, ulScanAheadCapacity);

        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_SCAN_AHEAD_CAPACITY, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_FEEDER_CONTROL
    //
    // The sample driver pretents to support manual feeder motor control
    // (the WIA_COMMAND_START_FEEDER and the WIA_COMMAND_STOP_FEEDER commands):
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lFeederControlArray;
        lFeederControlArray.Append(WIA_FEEDER_CONTROL_AUTO);
        lFeederControlArray.Append(WIA_FEEDER_CONTROL_MANUAL);

        hr = PropertyManager.AddProperty(WIA_IPS_FEEDER_CONTROL, WIA_IPS_FEEDER_CONTROL_STR, RWL, lFeederControlArray[0], lFeederControlArray[0], &lFeederControlArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_SCAN_AHEAD, hr = 0x%08X", hr));
        }
    }

    //
    // Apply the property changes to the current session's Application Item Tree:
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.SetItemProperties(pWiasContext);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA item properties for feeder, hr = 0x%08X", hr));
        }
    }

    WIAEX_TRACE_FUNC_HR;

    return hr;
}

/**************************************************************************\
*
* Initializes the properties specific to the Imprinter and Endorser items.
*
* Parameters:
*
*    pWiasContext            - pointer to the item context
*    nDocumentHandlingSelect - IMPRINTER or ENDORSER (defined in wiadef.h)
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/

HRESULT CWiaDriver::InitializeImprinterEndorserProperties(
    _In_ BYTE*     pWiasContext,
    UINT           nDocumentHandlingSelect)
{
    HRESULT hr = S_OK;
    CWIAPropertyManager PropertyManager;

    if ((!pWiasContext) || ((IMPRINTER != nDocumentHandlingSelect) && (ENDORSER != nDocumentHandlingSelect)))
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "CWiaDriver::InitializeImprinterEndorserProperties, invalid parameter, hr = 0x%08X", hr));
    }

    WIAEX_TRACE_BEGIN;

    //
    // WIA_IPS_PRINTER_ENDORSER
    //
    // This sample driver pretends to have an imprinter on the front side of the feeder and an endorser on the back side
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lPrinterEndorserArray;
        lPrinterEndorserArray.Append(WIA_PRINTER_ENDORSER_DISABLED);
        lPrinterEndorserArray.Append(WIA_PRINTER_ENDORSER_AUTO);
        lPrinterEndorserArray.Append((IMPRINTER == nDocumentHandlingSelect) ? WIA_PRINTER_ENDORSER_FEEDER_FRONT : WIA_PRINTER_ENDORSER_FEEDER_BACK);

        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER, WIA_IPS_PRINTER_ENDORSER_STR, RWL, lPrinterEndorserArray[0], lPrinterEndorserArray[0], &lPrinterEndorserArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_ORDER
    //
    // The sample imprinter operates after scan, the sample endorser operates before scan
    //
    if (SUCCEEDED(hr))
    {
        LONG lPrinterEndorserOrder = (IMPRINTER == nDocumentHandlingSelect) ? WIA_PRINTER_ENDORSER_AFTER_SCAN : WIA_PRINTER_ENDORSER_BEFORE_SCAN;

        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_ORDER, WIA_IPS_PRINTER_ENDORSER_ORDER_STR, RN, lPrinterEndorserOrder);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_ORDER for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_COUNTER
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_COUNTER , WIA_IPS_PRINTER_ENDORSER_COUNTER_STR, RWRC, 0, 0, 0, 0xFFFFFFFF, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_COUNTER for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }

    }

    //
    // WIA_IPS_PRINTER_ENDORSER_STEP
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_STEP, WIA_IPS_PRINTER_ENDORSER_STEP_STR, RWRC, 1, 1, 1, 0xFFFFFFFF, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_STEP for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }

    }

    //
    // WIA_IPS_PRINTER_ENDORSER_XOFFSET and WIA_IPS_PRINTER_ENDORSER_YOFFSET
    //
    // This sample driver pretends to support from 0" to 3" inclusive imprinter and endorser offsets, in 0.001" step increments
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_XOFFSET, WIA_IPS_PRINTER_ENDORSER_XOFFSET_STR, RWRC, 0, 0, 0, 3000, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_XOFFSET for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
        else
        {
            hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_YOFFSET, WIA_IPS_PRINTER_ENDORSER_YOFFSET_STR, RWRC, 0, 0, 0, 3000, 1);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_YOFFSET for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
            }
        }
    }

    //
    // WIA_IPS_ROTATION
    //
    // This sample driver pretends to support all standard 90' rotation values for its imprinter and endorser units
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lRotationArray;
        lRotationArray.Append(PORTRAIT);
        lRotationArray.Append(LANDSCAPE);
        lRotationArray.Append(ROT180);
        lRotationArray.Append(ROT270);

        hr = PropertyManager.AddProperty(WIA_IPS_ROTATION, WIA_IPS_ROTATION_STR, RWL, lRotationArray[0], lRotationArray[0], &lRotationArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_ROTATION for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_NUM_LINES
    //
    // This sample driver pretends that supports only one line of text for the imprinter and for the endorser
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_NUM_LINES, WIA_IPS_PRINTER_ENDORSER_NUM_LINES_STR, RN, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_NUM_LINES for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_STRING
    //
    if (SUCCEEDED(hr))
    {
        BSTR bstrPrinterEndorser = SysAllocString((IMPRINTER == nDocumentHandlingSelect) ? L"Sample imprinter text" : L"Sample endorser text");
        if (bstrPrinterEndorser)
        {
            hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_STRING, WIA_IPS_PRINTER_ENDORSER_STRING_STR, RW, bstrPrinterEndorser);

            SysFreeString(bstrPrinterEndorser);
        }
        else
        {
            hr = E_OUTOFMEMORY;
            WIAEX_ERROR((g_hInst, "Could not allocate memory for the the WIA_IPS_PRINTER_ENDORSER_STRING property value, hr = 0x%08X", hr));
        }

        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_STRING for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_VALID_CHARACTERS
    //
    if (SUCCEEDED(hr))
    {
        BSTR bstrValidChars = SysAllocString((IMPRINTER == nDocumentHandlingSelect) ? SAMPLE_IMPRINTER_VALID_CHARS : SAMPLE_ENDORSER_VALID_CHARS);
        if (bstrValidChars)
        {
            hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_VALID_CHARACTERS, WIA_IPS_PRINTER_ENDORSER_VALID_CHARACTERS_STR, RN, bstrValidChars);

            SysFreeString(bstrValidChars);
            bstrValidChars = NULL;
        }
        else
        {
            hr = E_OUTOFMEMORY;
            WIAEX_ERROR((g_hInst, "Could not allocate memory for the the IA_IPS_PRINTER_ENDORSER_VALID_CHARACTERS property value, hr = 0x%08X", hr));
        }

        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_VALID_CHARACTERS for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_VALID_FORMAT_SPECIFIERS
    //
    // This sample driver implements this optional property only for the imprinter
    // where it implements a sub-set of all the possible standard values.
    //
    if (SUCCEEDED(hr) && (IMPRINTER == nDocumentHandlingSelect))
    {
        LONG lFormatSpecs[] = {
            WIA_PRINT_DATE,
            WIA_PRINT_YEAR,
            WIA_PRINT_MONTH,
            WIA_PRINT_DAY,
            WIA_PRINT_WEEK_DAY,
            WIA_PRINT_TIME_24H,
            WIA_PRINT_HOUR_24H,
            WIA_PRINT_MINUTE,
            WIA_PRINT_SECOND,
            WIA_PRINT_PAGE_COUNT};
        ULONG ulFormatSpecs = ARRAYSIZE(lFormatSpecs);

        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_VALID_FORMAT_SPECIFIERS, WIA_IPS_PRINTER_ENDORSER_VALID_FORMAT_SPECIFIERS_STR, RN, ulFormatSpecs, lFormatSpecs);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_VALID_FORMAT_SPECIFIERS for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_PADDING
    //
    // This sample driver does pretend to support all imprinter/endorser padding values but does not really apply padding:
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lPaddingArray;
        lPaddingArray.Append(WIA_PRINT_PADDING_NONE);
        lPaddingArray.Append(WIA_PRINT_PADDING_ZERO);
        lPaddingArray.Append(WIA_PRINT_PADDING_BLANK);

        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_PADDING, WIA_IPS_PRINTER_ENDORSER_PADDING_STR, RWL, lPaddingArray[0], lPaddingArray[0], &lPaddingArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_PADDING for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_FONT_TYPE
    //
    // This sample driver does support all font type values but does not apply font type changes.
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lFontTypeArray;
        lFontTypeArray.Append(WIA_PRINT_FONT_NORMAL);
        lFontTypeArray.Append(WIA_PRINT_FONT_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_EXTRA_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_ITALIC_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_ITALIC_EXTRA_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_ITALIC);
        lFontTypeArray.Append(WIA_PRINT_FONT_SMALL);
        lFontTypeArray.Append(WIA_PRINT_FONT_SMALL_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_SMALL_EXTRA_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_SMALL_ITALIC_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_SMALL_ITALIC_EXTRA_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_SMALL_ITALIC);
        lFontTypeArray.Append(WIA_PRINT_FONT_LARGE);
        lFontTypeArray.Append(WIA_PRINT_FONT_LARGE_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_LARGE_EXTRA_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_LARGE_ITALIC_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_LARGE_ITALIC_EXTRA_BOLD);
        lFontTypeArray.Append(WIA_PRINT_FONT_LARGE_ITALIC);

        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_FONT_TYPE, WIA_IPS_PRINTER_ENDORSER_FONT_TYPE_STR, RWL, lFontTypeArray[0], lFontTypeArray[0], &lFontTypeArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_FONT_TYPE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_CHARACTER_ROTATION
    //
    // This sample driver pretends to support all possible values, but does not actually apply any character rotation.
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lCharRotatationArray;
        lCharRotatationArray.Append(PORTRAIT);
        lCharRotatationArray.Append(LANDSCAPE);
        lCharRotatationArray.Append(ROT180);
        lCharRotatationArray.Append(ROT270);

        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_CHARACTER_ROTATION, WIA_IPS_PRINTER_ENDORSER_CHARACTER_ROTATION_STR,
            RWL, lCharRotatationArray[0], lCharRotatationArray[0], &lCharRotatationArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_CHARACTER_ROTATION for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }


    //
    // WIA_IPS_PRINTER_ENDORSER_MAX_CHARACTERS
    //
    // This sample driver pretends to support a maximum number of characters of 0xFFFFFFFF (unrealistic) for the imprinter and endorser.
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_MAX_CHARACTERS, WIA_IPS_PRINTER_ENDORSER_MAX_CHARACTERS_STR, RN, 0xFFFFFFFF);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_MAX_CHARACTERS for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_INK
    //
    // This sample driver hard-codes a value of 50% (half capacity remaining) for the imprinter and endorser ink.
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_INK, WIA_IPS_PRINTER_ENDORSER_INK_STR, RN, 50);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_INK for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_TEXT_UPLOAD
    //
    // This sample driver reports to support imprinter/endorser text upload to show how an upload
    // transfer is to be executed, however the uploaded data is not retained/applied.
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_TEXT_UPLOAD, WIA_IPS_PRINTER_ENDORSER_TEXT_UPLOAD_STR, RN, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_TEXT_UPLOAD for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_TEXT_DOWNLOAD
    //
    // This sample driver reports to support imprinter/endorser text download to show how a download
    // transfer is to be executed, however the downloaded data is always the same/fixed, and is not
    // modified to match WIA_IPS_PRINTER_ENDORSER_STRING.
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_TEXT_DOWNLOAD, WIA_IPS_PRINTER_ENDORSER_TEXT_DOWNLOAD_STR, RN, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_TEXT_DOWNLOAD for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_GRAPHICS
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_GRAPHICS, WIA_IPS_PRINTER_ENDORSER_GRAPHICS_STR, RN, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_GRAPHICS for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_GRAPHICS_POSITION
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lPositionArray;
        lPositionArray.Append(WIA_PRINTER_ENDORSER_GRAPHICS_DEVICE_DEFAULT);
        lPositionArray.Append(WIA_PRINTER_ENDORSER_GRAPHICS_LEFT);
        lPositionArray.Append(WIA_PRINTER_ENDORSER_GRAPHICS_RIGHT);
        lPositionArray.Append(WIA_PRINTER_ENDORSER_GRAPHICS_TOP);
        lPositionArray.Append(WIA_PRINTER_ENDORSER_GRAPHICS_BOTTOM);
        lPositionArray.Append(WIA_PRINTER_ENDORSER_GRAPHICS_TOP_LEFT);
        lPositionArray.Append(WIA_PRINTER_ENDORSER_GRAPHICS_TOP_RIGHT);
        lPositionArray.Append(WIA_PRINTER_ENDORSER_GRAPHICS_BOTTOM_LEFT);
        lPositionArray.Append(WIA_PRINTER_ENDORSER_GRAPHICS_BOTTOM_RIGHT);
        lPositionArray.Append(WIA_PRINTER_ENDORSER_GRAPHICS_BACKGROUND);

        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_GRAPHICS_POSITION, WIA_IPS_PRINTER_ENDORSER_GRAPHICS_POSITION_STR, RWL, lPositionArray[0], lPositionArray[0], &lPositionArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_ROTATION for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MIN_WIDTH
    // WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MIN_HEIGHT
    // WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MAX_WIDTH
    // WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MAX_HEIGHT
    //
    // This sample driver supports a fixed/predefined graphics size that match the sample imprinter/endorser test image
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MIN_WIDTH, WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MIN_WIDTH_STR, RN, IMPRINTER_MIN_WIDTH);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MIN_WIDTH for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }

        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MAX_WIDTH, WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MAX_WIDTH_STR, RN, IMPRINTER_MAX_WIDTH);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MIN_WIDTH for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
            }
        }

        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MIN_HEIGHT, WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MIN_HEIGHT_STR, RN, IMPRINTER_MIN_HEIGHT);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MIN_HEIGHT for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
            }
        }

        if (SUCCEEDED(hr))
        {
            hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MAX_HEIGHT, WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MAX_HEIGHT_STR, RN, IMPRINTER_MAX_HEIGHT);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MAX_HEIGHT for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
            }
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_MAX_GRAPHICS
    //
    // This sample driver pretends to support a maximum number of graphics of 1 for its imprinter and endorser.
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_PRINTER_ENDORSER_MAX_GRAPHICS, WIA_IPS_PRINTER_ENDORSER_MAX_GRAPHICS_STR, RN, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_MAX_GRAPHICS for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_GRAPHICS_UPLOAD
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_GRAPHICS_UPLOAD, WIA_IPS_PRINTER_ENDORSER_GRAPHICS_UPLOAD_STR, RN, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_GRAPHICS_UPLOAD for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPS_PRINTER_ENDORSER_GRAPHICS_DOWNLOAD
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddProperty(WIA_IPS_PRINTER_ENDORSER_GRAPHICS_DOWNLOAD, WIA_IPS_PRINTER_ENDORSER_GRAPHICS_DOWNLOAD_STR, RN, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PRINTER_ENDORSER_GRAPHICS_DOWNLOAD for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_DATATYPE
    //
    // The sample driver supports 1-bpp BW graphics data for the imprinter and the endorser.
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lDataTypeArray;
        lDataTypeArray.Append(WIA_DATA_DITHER);

        hr = PropertyManager.AddProperty(WIA_IPA_DATATYPE, WIA_IPA_DATATYPE_STR, RWL, lDataTypeArray[0], lDataTypeArray[0], &lDataTypeArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_DATATYPE for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_DEPTH
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lDepthArray;
        lDepthArray.Append(1);

        hr = PropertyManager.AddProperty(WIA_IPA_DEPTH , WIA_IPA_DEPTH_STR, RWLC, lDepthArray[0], lDepthArray[0], &lDepthArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_DEPTH for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_CHANNELS_PER_PIXEL
    //
    if (SUCCEEDED(hr))
    {
        LONG lChannelsPerPixel = 1;

        hr = PropertyManager.AddProperty(WIA_IPA_CHANNELS_PER_PIXEL, WIA_IPA_CHANNELS_PER_PIXEL_STR, RN, lChannelsPerPixel);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_CHANNELS_PER_PIXEL for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // WIA_IPA_BITS_PER_CHANNEL
    //
    if (SUCCEEDED(hr))
    {
        LONG lBitsPerChannel = 1;

        hr = PropertyManager.AddProperty(WIA_IPA_BITS_PER_CHANNEL, WIA_IPA_BITS_PER_CHANNEL_STR, RN, lBitsPerChannel);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPA_BITS_PER_CHANNEL for item %u, hr = 0x%08X", nDocumentHandlingSelect, hr));
        }
    }

    //
    // Apply the property changes to the current session's Application Item Tree:
    //

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.SetItemProperties(pWiasContext);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA item properties for item %u, hr = 0x%08X",
                nDocumentHandlingSelect, hr));
        }
    }

    WIAEX_TRACE_FUNC_HR;

    return hr;
}

/**************************************************************************\
*
* Initializes the properties specific to the Barcode Reader item.
*
* Parameters:
*
*    pWiasContext - pointer to the item context
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/

HRESULT CWiaDriver::InitializeBarcodeReaderProperties(
    _In_ BYTE* pWiasContext)
{
    HRESULT hr = S_OK;
    CWIAPropertyManager PropertyManager;

    if (!pWiasContext)
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "CWiaDriver::InitializeBarcodeReaderProperties, invalid parameter, hr = 0x%08X", hr));
    }

    WIAEX_TRACE_BEGIN;

    //
    // WIA_IPS_BARCODE_READER
    //
    // This sample driver pretends to support a barcode reader device installed on the front feeder side
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lBarcodeReaderArray;
        lBarcodeReaderArray.Append(WIA_BARCODE_READER_DISABLED);
        lBarcodeReaderArray.Append(WIA_BARCODE_READER_AUTO);
        lBarcodeReaderArray.Append(WIA_BARCODE_READER_FEEDER_FRONT);

        hr = PropertyManager.AddProperty(WIA_IPS_BARCODE_READER, WIA_IPS_BARCODE_READER_STR, RWL, lBarcodeReaderArray[0], lBarcodeReaderArray[0], &lBarcodeReaderArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_BARCODE_READER, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_MAXIMUM_BARCODES_PER_PAGE
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_MAXIMUM_BARCODES_PER_PAGE, WIA_IPS_MAXIMUM_BARCODES_PER_PAGE_STR, RWR, 0, 0, 0, 10, 1);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_MAXIMUM_BARCODES_PER_PAGE, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_BARCODE_SEARCH_DIRECTION
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lBarcodeSearchArray;
        lBarcodeSearchArray.Append(WIA_BARCODE_AUTO_SEARCH);
        lBarcodeSearchArray.Append(WIA_BARCODE_HORIZONTAL_SEARCH);
        lBarcodeSearchArray.Append(WIA_BARCODE_VERTICAL_SEARCH);
        lBarcodeSearchArray.Append(WIA_BARCODE_HORIZONTAL_VERTICAL_SEARCH);
        lBarcodeSearchArray.Append(WIA_BARCODE_VERTICAL_HORIZONTAL_SEARCH);

        hr = PropertyManager.AddProperty(WIA_IPS_BARCODE_SEARCH_DIRECTION, WIA_IPS_BARCODE_SEARCH_DIRECTION_STR, RWL, lBarcodeSearchArray[0], lBarcodeSearchArray[0], &lBarcodeSearchArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_BARCODE_SEARCH_DIRECTION, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_MAXIMUM_BARCODE_SEARCH_RETRIES
    //
    // This sample driver pretends to support no retries (range containing only the value 0)
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_MAXIMUM_BARCODE_SEARCH_RETRIES, WIA_IPS_MAXIMUM_BARCODE_SEARCH_RETRIES_STR, RWR, 0, 0, 0, 0, 0);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_MAXIMUM_BARCODE_SEARCH_RETRIES, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_BARCODE_SEARCH_TIMEOUT
    //
    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.AddPropertyUL(WIA_IPS_BARCODE_SEARCH_TIMEOUT, WIA_IPS_BARCODE_SEARCH_TIMEOUT_STR, RWR, 0, 0, 0, 100, 10);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_BARCODE_SEARCH_TIMEOUT, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_SUPPORTED_BARCODE_TYPES
    //
    // This sample driver pretends to support a multitude of barcode types. This driver
    // ignores this setting when delivering its hard-coded sample barcodes but uses
    // WIA_IPS_SUPPORTED_BARCODE_TYPES to validate WIA_IPS_ENABLED_BARCODE_TYPES
    //
    if (SUCCEEDED(hr))
    {
        ULONG ulBarcodeTypes = ARRAYSIZE(g_lSupportedBarcodeTypes);

        hr = PropertyManager.AddProperty(WIA_IPS_SUPPORTED_BARCODE_TYPES, WIA_IPS_SUPPORTED_BARCODE_TYPES_STR, RN, ulBarcodeTypes, (LONG *)&g_lSupportedBarcodeTypes[0]);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_SUPPORTED_BARCODE_TYPES, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_ENABLED_BARCODE_TYPES
    //
    // By default when barcode detection is enabled there are 3 barcodes enabled, which
    // happen to match the sample, hard-coded, barcode metadata for this driver
    //
    if (SUCCEEDED(hr))
    {
        LONG lDefaultEnabledBarcodeTypes[] = { WIA_BARCODE_UPCA, WIA_BARCODE_CODABAR, WIA_BARCODE_CODE39_FULLASCII };
        ULONG ulBarcodeTypes = ARRAYSIZE(lDefaultEnabledBarcodeTypes);

        hr = PropertyManager.AddProperty(WIA_IPS_ENABLED_BARCODE_TYPES, WIA_IPS_ENABLED_BARCODE_TYPES_STR, RW, ulBarcodeTypes, &lDefaultEnabledBarcodeTypes[0]);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_ENABLED_BARCODE_TYPES, hr = 0x%08X", hr));
        }
    }

    //
    // Apply the property changes to the current session's Application Item Tree:
    //

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.SetItemProperties(pWiasContext);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA item properties for the barcode reader item, hr = 0x%08X", hr));
        }
    }

    WIAEX_TRACE_FUNC_HR;

    return hr;
}

/**************************************************************************\
*
* Initializes the properties specific to the Patch Code Reader item.
*
* Parameters:
*
*    pWiasContext - pointer to the item context
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/

HRESULT CWiaDriver::InitializePatchCodeReaderProperties(
    _In_ BYTE* pWiasContext)
{
    HRESULT hr = S_OK;
    CWIAPropertyManager PropertyManager;

    if (!pWiasContext)
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "CWiaDriver::InitializePatchCodeReaderProperties, invalid parameter, hr = 0x%08X", hr));
    }

    WIAEX_TRACE_BEGIN;

    //
    // WIA_IPS_PATCH_CODE_READER
    //
    // This sample driver pretends to support a patch code reader device installed
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lPatchCodeReaderArray;
        lPatchCodeReaderArray.Append(WIA_PATCH_CODE_READER_DISABLED);
        lPatchCodeReaderArray.Append(WIA_PATCH_CODE_READER_AUTO);

        hr = PropertyManager.AddProperty(WIA_IPS_PATCH_CODE_READER, WIA_IPS_PATCH_CODE_READER_STR, RWL, lPatchCodeReaderArray[0], lPatchCodeReaderArray[0], &lPatchCodeReaderArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_PATCH_CODE_READER, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_SUPPORTED_PATCH_CODE_TYPES
    //
    // This sample driver pretends to support a multitude of barcode types. This driver
    // ignores this setting when delivering its hard-coded sample barcodes but uses
    // WIA_IPS_SUPPORTED_PATCH_CODE_TYPES to validate WIA_IPS_ENABLED_PATCH_CODE_TYPES
    //
    if (SUCCEEDED(hr))
    {
        ULONG ulPatchCodeTypes = ARRAYSIZE(g_lSupportedPatchCodeTypes);

        hr = PropertyManager.AddProperty(WIA_IPS_SUPPORTED_PATCH_CODE_TYPES, WIA_IPS_SUPPORTED_PATCH_CODE_TYPES_STR, RN, ulPatchCodeTypes, (LONG *)&g_lSupportedPatchCodeTypes[0]);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_SUPPORTED_PATCH_CODE_TYPES, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_ENABLED_PATCH_CODE_TYPES
    //
    // By default when barcode detection is enabled there are 2 patch codes enabled, which
    // happen to match the sample, hard-coded, patch code metadata for this driver
    //
    if (SUCCEEDED(hr))
    {
        LONG lDefaultEnabledPatchCodeTypes[] = { WIA_PATCH_CODE_2, WIA_PATCH_CODE_3 };
        ULONG ulPatchCodeTypes = ARRAYSIZE(lDefaultEnabledPatchCodeTypes);

        hr = PropertyManager.AddProperty(WIA_IPS_ENABLED_PATCH_CODE_TYPES, WIA_IPS_ENABLED_PATCH_CODE_TYPES_STR, RW, ulPatchCodeTypes, &lDefaultEnabledPatchCodeTypes[0]);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_ENABLED_PATCH_CODE_TYPES, hr = 0x%08X", hr));
        }
    }

    //
    // WIA_IPS_ALARM
    //
    // This sample driver does pretend to support one kind of audible alarm (beep) to signal
    // when a path code is successfully detected
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lAlarmArray;
        lAlarmArray.Append(WIA_ALARM_NONE);
        lAlarmArray.Append(WIA_ALARM_BEEP1);

        hr = PropertyManager.AddProperty(WIA_IPS_ALARM, WIA_IPS_ALARM_STR, RWL, lAlarmArray[0], lAlarmArray[0], &lAlarmArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_ALARM, hr = 0x%08X", hr));
        }
    }

    //
    // Apply the property changes to the current session's Application Item Tree:
    //

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.SetItemProperties(pWiasContext);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA item properties for the patch code reader item, hr = 0x%08X", hr));
        }
    }

    WIAEX_TRACE_FUNC_HR;

    return hr;
}

/**************************************************************************\
*
* Initializes the properties specific to the MICR Reader item.
*
* Parameters:
*
*    pWiasContext - pointer to the item context
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/

HRESULT CWiaDriver::InitializeMicrReaderProperties(
    _In_ BYTE* pWiasContext)
{
    HRESULT hr = S_OK;
    CWIAPropertyManager PropertyManager;

    if (!pWiasContext)
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "CWiaDriver::InitializeMicrReaderProperties, invalid parameter, hr = 0x%08X", hr));
    }

    WIAEX_TRACE_BEGIN;

   //
    // WIA_IPS_MICR_READER
    //
    // This sample driver pretends to support a MICR reader device installed on the front feeder side
    //
    if (SUCCEEDED(hr))
    {
        CBasicDynamicArray<LONG> lMICRReaderArray;
        lMICRReaderArray.Append(WIA_MICR_READER_DISABLED);
        lMICRReaderArray.Append(WIA_MICR_READER_AUTO);
        lMICRReaderArray.Append(WIA_MICR_READER_FEEDER_FRONT);

        hr = PropertyManager.AddProperty(WIA_IPS_MICR_READER, WIA_IPS_MICR_READER_STR, RWL, lMICRReaderArray[0], lMICRReaderArray[0], &lMICRReaderArray);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to initialize WIA_IPS_MICR_READER, hr = 0x%08X", hr));
        }
    }

    //
    // Apply the property changes to the current session's Application Item Tree:
    //

    if (SUCCEEDED(hr))
    {
        hr = PropertyManager.SetItemProperties(pWiasContext);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA item properties for the MICR reader item, hr = 0x%08X", hr));
        }
    }

    WIAEX_TRACE_FUNC_HR;

    return hr;
}

/**************************************************************************\
*
* Initializes WIA_FORMAT_INFO arrays needed for IWiaMiniDrv::drvGetWiaFormatInfo
*
* Parameters:
*
*    None
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/

HRESULT CWiaDriver::InitializeFormatInfoArrays()
{
    HRESULT hr = S_OK;
    WIA_FORMAT_INFO tFormatInfo = {};

    //
    // This sample driver supports the same WIA_FORMAT_INFO array for Root, Flatbed, Feeder and Auto items:
    //
    // { WiaImgFmt_BMP, TYMED_FILE }
    // { WiaImgFmt_EXIF, TYMED_FILE }
    // { WiaImgFmt_RAW, TYMED_FILE }
    //

    m_tFormatInfo.Destroy();

    tFormatInfo.guidFormatID = WiaImgFmt_BMP;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfo.Append(tFormatInfo);

    tFormatInfo.guidFormatID = WiaImgFmt_EXIF;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfo.Append(tFormatInfo);

    tFormatInfo.guidFormatID = WiaImgFmt_RAW;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfo.Append(tFormatInfo);

    //
    // The Imprinter and Endorser items support:
    //
    // { WiaImgFmt_CSV, TYMED_FILE }
    // { WiaImgFmt_TXT, TYMED_FILE }
    // { WiaImgFmt_BMP, TYMED_FILE }
    //

    m_tFormatInfoImprinterEndorser.Destroy();

    tFormatInfo.guidFormatID = WiaImgFmt_CSV;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfoImprinterEndorser.Append(tFormatInfo);

    tFormatInfo.guidFormatID = WiaImgFmt_TXT;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfoImprinterEndorser.Append(tFormatInfo);

    tFormatInfo.guidFormatID = WiaImgFmt_BMP;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfoImprinterEndorser.Append(tFormatInfo);

    //
    // The Barcode Reader item supports:
    //
    // { WiaImgFmt_XMLBAR, TYMED_FILE }
    // { WiaImgFmt_RAWBAR, TYMED_FILE }
    //

    m_tFormatInfoBarcodeReader.Destroy();

    tFormatInfo.guidFormatID = WiaImgFmt_XMLBAR;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfoBarcodeReader.Append(tFormatInfo);

    tFormatInfo.guidFormatID = WiaImgFmt_RAWBAR;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfoBarcodeReader.Append(tFormatInfo);

    //
    // The Patch Code Reader item supports:
    //
    // { WiaImgFmt_XMLPAT, TYMED_FILE }
    // { WiaImgFmt_RAWPAT, TYMED_FILE }
    //

    m_tFormatInfoPatchCodeReader.Destroy();

    tFormatInfo.guidFormatID = WiaImgFmt_XMLPAT;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfoPatchCodeReader.Append(tFormatInfo);

    tFormatInfo.guidFormatID = WiaImgFmt_RAWPAT;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfoPatchCodeReader.Append(tFormatInfo);

    //
    // The MICR Reader item supports:
    //
    // { WiaImgFmt_XMLMIC, TYMED_FILE }
    // { WiaImgFmt_RAWMIC, TYMED_FILE }
    //

    m_tFormatInfoMicrReader.Destroy();

    tFormatInfo.guidFormatID = WiaImgFmt_XMLMIC;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfoMicrReader.Append(tFormatInfo);

    tFormatInfo.guidFormatID = WiaImgFmt_RAWMIC;
    tFormatInfo.lTymed = TYMED_FILE;
    m_tFormatInfoMicrReader.Append(tFormatInfo);

    return hr;
}

/**************************************************************************\
*
* Updates the following image information properties in auto-detect color mode.
* Because this sample driver does not support cropping (scan region changes)
* and supports only a single/fixed scan resolution this function is not needed
* to be executed in other situations:
*
* WIA_IPA_PIXELS_PER_LINE
* WIA_IPA_NUMBER_OF_LINES
* WIA_IPA_BYTES_PER_LINE
* WIA_IPA_CHANNELS_PER_PIXEL
* WIA_IPA_RAW_CHANNELS_PER_PIXEL
*
* Note that these properties are not implemented/available on the Auto item.
*
* Parameters:
*
*    pWiasContext - pointer to the item context
*    lDataType    - data type; if set to WIA_DATA_AUTO the
*                   function reads the current WIA_IPA_DATATYPE.
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/
HRESULT CWiaDriver::UpdateImageInfoProperties(
    _In_ BYTE *pWiasContext,
    LONG lDataType)
{
    HRESULT hr = S_OK;
    GUID guidItemCategory = WIA_CATEGORY_ROOT;
    LONG lDepth = 8;
    LONG lChannelsPerPixel = 1;
    LONG lCompression = WIA_COMPRESSION_NONE;
    GUID guidFormat = WiaImgFmt_UNDEFINED;
    LONG lXExtent = 0;
    LONG lYExtent = 0;
    LONG lPixelsPerLine = 0;
    LONG lNumberOfLines = 0;
    LONG lBytesPerLine = 0;

    WIAEX_TRACE_BEGIN;

    if (!pWiasContext)
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "CWiaDriver::UpdateImageInfoProperties, invalid parameter, hr = 0x%08X", hr));
    }

    //
    // Read WIA_IPA_ITEM_CATEGORY to identify the current item:
    //
    if (SUCCEEDED(hr))
    {
        hr = wiasReadPropGuid(pWiasContext, WIA_IPA_ITEM_CATEGORY, &guidItemCategory, NULL, TRUE);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_ITEM_CATEGORY, hr = 0x%08X", hr));
        }
    }

    //
    // Cannot validate image information properties on the Root or Auto items:
    //
    if (SUCCEEDED(hr) && ((IsEqualGUID(WIA_CATEGORY_ROOT, guidItemCategory)) ||
        (IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory))))
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "Functionality not supported on this item, hr = 0x%08X", hr));
    }

    //
    // If a data type is not specified, read WIA_IPA_DATATYPE:
    //
    if (SUCCEEDED(hr))
    {
        if (WIA_DATA_AUTO == lDataType)
        {
            LONG lActualDataType = WIA_DATA_GRAYSCALE;

            hr = wiasReadPropLong(pWiasContext, WIA_IPA_DATATYPE, &lActualDataType, NULL, TRUE);
            if (SUCCEEDED(hr))
            {
                if (WIA_DATA_AUTO == lActualDataType)
                {
                    WIAEX_ERROR((g_hInst, "Unspecified data type! Considering 8-bpp grayscale (default) and trying to continue"));
                    lDepth = 8;
                }
                else
                {
                    lDepth = (WIA_DATA_COLOR == lActualDataType) ? 24 : 8;
                }
            }
            else
            {
                WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_DATA_TYPE, hr = 0x%08X", hr));
            }
        }
        else
        {
            lDepth = (WIA_DATA_COLOR == lDataType) ? 24 : 8;
        }
    }

    //
    // Check the current WIA_IPA_COMPRESSION:
    //
    if (SUCCEEDED(hr))
    {
        hr = wiasReadPropLong(pWiasContext, WIA_IPA_COMPRESSION, &lCompression, NULL, TRUE);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_COMPRESSION, hr = 0x%08X", hr));
        }
    }

    //
    // Check the current WIA_IPA_FORMAT:
    //
    if (SUCCEEDED(hr))
    {
        hr = wiasReadPropGuid(pWiasContext, WIA_IPA_FORMAT, &guidFormat, NULL, TRUE);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_FORMAT, hr = 0x%08X", hr));
        }
    }

    //
    // Check the current WIA_IPS_XEXTENT and WIA_IPS_YTEXTENT:
    //
    if (SUCCEEDED(hr))
    {
        hr = wiasReadPropLong(pWiasContext, WIA_IPS_XEXTENT, &lXExtent, NULL, TRUE);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_XEXTENT, hr = 0x%08X", hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = wiasReadPropLong(pWiasContext, WIA_IPS_YEXTENT, &lYExtent, NULL, TRUE);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_YEXTENT, hr = 0x%08X", hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        //
        // The number of bytes per line include the padding necessary to make each uncompressed
        // line (DIB or Raw) DWORD aligned. When data is compressed the number of bytes per line
        // calculated here reflects the original uncompressed image:
        //
        lPixelsPerLine = lXExtent;
        lNumberOfLines = lYExtent;
        lBytesPerLine = BytesPerLine(lPixelsPerLine, lDepth);

        WIAS_TRACE((g_hInst, "Image information: %u PPL, %u lines, %u BPL (compression: %u)",
            lPixelsPerLine, lNumberOfLines, lBytesPerLine, lCompression));
    }

    //
    // Update the following properties, supported for backwards compatibility (with WIA 1.0
    // and TWAIN) on the Flatbed and Feeder item but not on the new Auto item:
    //
    // WIA_IPA_PIXELS_PER_LINE - the image width, in pixels, for the final image
    // WIA_IPA_NUMBER_OF_LINES - the image length, in pixels, for the final image
    // WIA_IPA_BYTES_PER_LINE  - line width in bytes that must match WIA_IPA_PIXELS_PER_LINE and WIA_IPA_DEPTH
    //
    if (SUCCEEDED(hr))
    {
        hr = wiasWritePropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, lPixelsPerLine);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_PIXELS_PER_LINE, hr = 0x%08X", hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = wiasWritePropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, lNumberOfLines);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_NUMBER_OF_LINES, hr = 0x%08X", hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = wiasWritePropLong(pWiasContext, WIA_IPA_BYTES_PER_LINE, lBytesPerLine);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_BYTES_PER_LINE, hr = 0x%08X", hr));
        }
    }

    //
    // Update WIA_IPA_CHANNELS_PER_PIXEL and WIA_IPA_RAW_BITS_PER_CHANNEL top match the bit depth.
    // Note that this saple driver does not need to update WIA_IPA_BITS_PER_CHANNEL, and that
    // WIA_IPA_DEPTH and WIA_IPA_DATA_TYPE are updated during validation (see ValidateFormatProperties):
    //

    if (SUCCEEDED(hr))
    {
        lChannelsPerPixel = (24 == lDepth) ? 3 : 1;
        hr = wiasWritePropLong(pWiasContext, WIA_IPA_CHANNELS_PER_PIXEL, lChannelsPerPixel);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_CHANNELS_PER_PIXEL, hr = 0x%08X", hr));
        }
    }

    if (SUCCEEDED(hr))
    {
        BYTE bRawBitsPerChannel[3] = {};

        for (int i = 0; i < lChannelsPerPixel; i++)
        {
            bRawBitsPerChannel[i] = 8;
        }

        hr = wiasWritePropBin(pWiasContext, WIA_IPA_RAW_BITS_PER_CHANNEL, lChannelsPerPixel, bRawBitsPerChannel);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_RAW_BITS_PER_CHANNEL, hr = 0x%08X", hr));
        }
    }


    WIAEX_TRACE_FUNC_HR;

    return hr;
}

/**************************************************************************\
*
* Updates the globally stored (per driver instance) scan available item
* name indicating that this item is marked for data transfer due to a
* device initiated scan operation, and/or the scanner is not in a scan
* available state.
*
* Parameters:
*
*    wszInputSource - a WIA item name as the name of the input source,
*                     NULL to reset the value to an empty string.
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/
HRESULT CWiaDriver::UpdateScanAvailableItemName(
    _In_opt_ LPCWSTR wszInputSource)
{
    HRESULT hr = S_OK;

    //
    // Clear the current name:
    //
    if (m_bstrScanAvailableItem)
    {
        SysFreeString(m_bstrScanAvailableItem);
        m_bstrScanAvailableItem = NULL;
    }

    //
    // Identify the input source and prepare the value containing the apropriate item name:
    //
    if (wszInputSource)
    {
        if (!wcscmp(WIA_DRIVER_FEEDER_NAME, wszInputSource))
        {
            WIAS_TRACE((g_hInst, "Scan available from feeder (%ws)", wszInputSource));
            m_bstrScanAvailableItem = SysAllocString(WIA_DRIVER_FEEDER_NAME);
        }
        else if (!wcscmp(WIA_DRIVER_FLATBED_NAME, wszInputSource))
        {
            WIAS_TRACE((g_hInst, "Scan available from flatbed (%ws)", wszInputSource));
            m_bstrScanAvailableItem = SysAllocString(WIA_DRIVER_FLATBED_NAME);
        }
        else
        {
            WIAS_TRACE((g_hInst, "Scan available from unknown input source (%ws) - information not recorded",
                wszInputSource));
            m_bstrScanAvailableItem = SysAllocString(L"");
        }
    }
    else
    {
        //
        // A trace message is avoided here on purpose - the following message, if enabled,
        // would be visible both when initializing a new AIT Root with no scan available
        // input source recorded -and- when resetting the scan available soure information
        // from within IWiaMiniDrv::drvAcquireItemData before executing a new scan job.
        //
        m_bstrScanAvailableItem = SysAllocString(L"");
    }

    if (!m_bstrScanAvailableItem)
    {
        hr = E_OUTOFMEMORY;
        WIAEX_ERROR((g_hInst, "Failed to update the scan available item name, out of memory, hr = 0x%08X", hr));
    }

    return hr;
}

/**************************************************************************\
*
* Updates the WIA_DPS_SCAN_AVAILABLE_ITEM property at real-time when an
* application attempts to read a property from its AIT Root item. We cannot
* make this update immediately following a notification that a device initiated
* scan is available because the event comes globally, outside of any application
* session context (possibly at a time when no application session exists).
*
* WARNING: must not be called on other items than Root (WiaItemTypeRoot).
*
* Parameters:
*
*    pWiasContext   - pointer to the item context
*
* Return Value:
*
*    S_OK if successful, an error HRESULT otherwise
*
\**************************************************************************/
HRESULT CWiaDriver::UpdateScanAvailableItemProperty(
    _In_ BYTE *pWiasContext)
{
    HRESULT hr = S_OK;

    if (!pWiasContext)
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr));
    }

    //
    // If no value is initialized yet, initialize it now to an
    // empty string meaning "no scan available source recorded":
    //
    if (SUCCEEDED(hr) && (!m_bstrScanAvailableItem))
    {
        m_bstrScanAvailableItem = SysAllocString(L"");
        if (!m_bstrScanAvailableItem)
        {
            hr = E_OUTOFMEMORY;
            WIAEX_ERROR((g_hInst, "Failed to initialize an empty string in lieu of a scan available item name, hr = 0x%08X", hr));
        }
    }

    //
    // Update the WIA_DPS_SCAN_AVAILABLE_ITEM property:
    //
    if (SUCCEEDED(hr))
    {
        hr = wiasWritePropStr(pWiasContext, WIA_DPS_SCAN_AVAILABLE_ITEM, m_bstrScanAvailableItem);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "wiasWritePropStr(WIA_DPS_SCAN_AVAILABLE_ITEM, '%ws') failed, hr = 0x%08X", m_bstrScanAvailableItem, hr));
        }
    }

    return hr;
}

/**************************************************************************\
*
* Retrieves standard WIA page sizes that fit in the specified scan area
* dimensions considering the specified orientation.
*
* Parameters:
*
*    lMaxWidth               - maximum width of the total scan area, in 1/1000"
*    lMaxHeight              - maximum height of the total scan area, in 1/1000"
*    lMinWidth               - minimum width of the total scan area, in 1/1000"
*    lMinHeight              - minimum height of the total scan area, in 1/1000"
*    bPortrait               - TRUE for portrait, FALSE for landscape orientation
*    arrayPageSizes          - reference for array where to return page sizes
*
* Return Value:
*
*    The number of page sizes found
*
\**************************************************************************/

LONG CWiaDriver::GetValidPageSizes(
    LONG lMaxWidth,
    LONG lMaxHeight,
    LONG lMinWidth,
    LONG lMinHeight,
    BOOL bPortrait,
    CBasicDynamicArray<LONG>& arrayPageSizes)
{
    LONG lNumPageSizesFound = 0;
    LONG lNumKnownPageSizes = sizeof(g_DefinedPageSizeCombinations) / sizeof(g_DefinedPageSizeCombinations[0]);

    //
    // Do not erase page sizes already added to the array,
    // append new values that are not yet in the array:
    //
    // arrayPageSizes.Destroy();
    //

    for (LONG i = 0; i < lNumKnownPageSizes; i++)
    {
        if (bPortrait)
        {
            if ((g_DefinedPageSizeCombinations[i].m_lPageWidth <= lMaxWidth) &&
                (g_DefinedPageSizeCombinations[i].m_lPageHeight <= lMaxHeight) &&
                (g_DefinedPageSizeCombinations[i].m_lPageWidth >= lMinWidth) &&
                (g_DefinedPageSizeCombinations[i].m_lPageHeight >= lMinHeight))
            {
                if (-1 == arrayPageSizes.Find(g_DefinedPageSizeCombinations[i].m_lPageSize))
                {
                    arrayPageSizes.Append(g_DefinedPageSizeCombinations[i].m_lPageSize);
                }
            }
        }
        else
        {
            if ((g_DefinedPageSizeCombinations[i].m_lPageWidth <= lMaxHeight) &&
                (g_DefinedPageSizeCombinations[i].m_lPageHeight <= lMaxWidth) &&
                (g_DefinedPageSizeCombinations[i].m_lPageWidth >= lMinHeight) &&
                (g_DefinedPageSizeCombinations[i].m_lPageHeight >= lMinWidth))
            {
                if (-1 == arrayPageSizes.Find(g_DefinedPageSizeCombinations[i].m_lPageSize))
                {
                    arrayPageSizes.Append(g_DefinedPageSizeCombinations[i].m_lPageSize);
                }
            }
        }
    }

    lNumPageSizesFound = arrayPageSizes.Size();

    return lNumPageSizesFound;
}

/**************************************************************************\
*
* Returns the width and height for the specified standard page size,
* in 1/1000", according with the indicated orientation
*
* Parameters:
*
*    lPageSize   - the page size to return the dimensions for
*    bPortrait   - TRUE for portait orientation, FALSE for landscape
*    lPageWidth  - reference for variable to receive the page width
*    lPageHeight - reference for variable to receive the page height
* Return Value:
*
*    S_OK if successful, E_INVALIDARG if no such standard page size is found
*
\**************************************************************************/

HRESULT CWiaDriver::GetPageDimensions(
    LONG lPageSize,
    BOOL bPortrait,
    LONG& lPageWidth,
    LONG& lPageHeight)
{
    HRESULT hr = E_INVALIDARG;
    LONG lNumKnownPageSizes = sizeof(g_DefinedPageSizeCombinations) / sizeof(g_DefinedPageSizeCombinations[0]);

    for (LONG i = 0; i < lNumKnownPageSizes; i++)
    {
        if (g_DefinedPageSizeCombinations[i].m_lPageSize == lPageSize)
        {
            if (bPortrait)
            {
                lPageWidth = g_DefinedPageSizeCombinations[i].m_lPageWidth;
                lPageHeight = g_DefinedPageSizeCombinations[i].m_lPageHeight;
            }
            else
            {
                lPageWidth = g_DefinedPageSizeCombinations[i].m_lPageHeight;
                lPageHeight = g_DefinedPageSizeCombinations[i].m_lPageWidth;
            }

            hr = S_OK;
            break;
        }
    }

    return hr;
}

Our Services

  • What our customers say about us?

© 2011-2025 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