From 96eb96dfb613e4c745db6bd1f53a92fe7e2290fc Mon Sep 17 00:00:00 2001 From: karlf Date: Thu, 11 Aug 2016 13:28:13 -0700 Subject: Updated for "Windows 10 Anniversary Update" (Version 1607) --- wia/ProdScan/Validate.cpp | 1994 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1994 insertions(+) create mode 100644 wia/ProdScan/Validate.cpp (limited to 'wia/ProdScan/Validate.cpp') diff --git a/wia/ProdScan/Validate.cpp b/wia/ProdScan/Validate.cpp new file mode 100644 index 00000000..44e20b1f --- /dev/null +++ b/wia/ProdScan/Validate.cpp @@ -0,0 +1,1994 @@ +/************************************************************************** +* +* Copyright © Microsoft Corporation +* +* File Name: Validate.cpp +* +* Description: This file contains code for WIA property validation +* performed by the Production Scanning Driver Sample +* for special categories of properties such as "format" +* and "scan region/document size" properties. +* +***************************************************************************/ + +#include "stdafx.h" + +/**************************************************************************\ +* +* Validates new current values for the following dependent WIA properties: +* +* WIA_IPA_DATATYPE (*) +* WIA_IPS_CUR_INTENT (*) +* WIA_IPA_DEPTH (*) +* WIA_IPA_FORMAT +* WIA_IPA_TYMED (skipped since its value cannot be changed for this driver) +* WIA_IPA_COMPRESSION +* +* The current values for the following properties could be changed by the driver +* when one of the above mentioned properties is changed: +* +* WIA_IPA_DATATYPE (*) +* WIA_IPS_CUR_INTENT (*) +* WIA_IPA_DEPTH (*) +* WIA_IPA_CHANNELS_PER_PIXEL (*) +* WIA_IPA_BITS_PER_CHANNEL (*) +* WIA_IPA_FORMAT +* WIA_IPA_TYMED (skipped since its value cannot be changed for this driver) +* WIA_IPA_FILENAME_EXTENSION +* WIA_IPA_COMPRESSION +* +* (*) - These properties are available only on the the Flatbed and Feeder items +* +* Parameters: +* +* pWiasContext - pointer to the item context +* pPropertyContext - pointer to the property context which +* indicates which properties are being written +* nDocumentHandlingSelect - FLAT or FEED (as defined in wiadef.h) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise (E_INVALIDARG if +* an invalid combination is attempted) +* +\**************************************************************************/ + +HRESULT CWiaDriver::ValidateFormatProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nDocumentHandlingSelect) +{ + HRESULT hr = S_OK; + + LONG lDataType = WIA_DATA_COLOR; + LONG lIntent = WIA_INTENT_NONE; + LONG lDepth = 24; + LONG lChannelsPerPixel = 3; + LONG lBitsPerChannel = 8; + GUID guidFormat = WiaImgFmt_UNDEFINED; + LONG lCompression = WIA_COMPRESSION_NONE; + BSTR bstrFileExtension = NULL; + BYTE bRawBitsPerChannel[3] = {}; + + BOOL bDataTypeChanged = FALSE; + BOOL bIntentChanged = FALSE; + BOOL bImageTypeIntentChanged = FALSE; + BOOL bDepthChanged = FALSE; + BOOL bFormatChanged = FALSE; + BOOL bCompressionChanged = FALSE; + + PROPSPEC ps[3] = {}; + ULONG nPropSpec = 0; + + if ((!pWiasContext) || (!pPropertyContext)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameters, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + // + // Check which color properties have been changed (ignore failures). + // Note that the Auto item supports only format, tymed and compression: + // + if ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect)) + { + wiasIsPropChanged(WIA_IPA_DATATYPE, pPropertyContext, &bDataTypeChanged); + wiasIsPropChanged(WIA_IPS_CUR_INTENT, pPropertyContext, &bIntentChanged); + wiasIsPropChanged(WIA_IPA_DEPTH, pPropertyContext, &bDepthChanged); + } + wiasIsPropChanged(WIA_IPA_FORMAT, pPropertyContext, &bFormatChanged); + wiasIsPropChanged(WIA_IPA_COMPRESSION, pPropertyContext, &bCompressionChanged); + + if ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect)) + { + // + // Read the current WIA_IPS_CUR_INTENT value: + // + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_CUR_INTENT, &lIntent, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_CUR_INTENT, hr = 0x%08X", hr)); + } + } + + // + // When the intent is changed check if an image type intent flag is set: + // + if (SUCCEEDED(hr)) + { + bImageTypeIntentChanged = (BOOL)(bIntentChanged && (WIA_INTENT_IMAGE_TYPE_MASK & lIntent)); + } + } + } + + // + // Read the other current property values (no matter if each respective property was changed or not): + // + + if (SUCCEEDED(hr) && (bDataTypeChanged || bIntentChanged || bDepthChanged) && + ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect))) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPA_DATATYPE, &lDataType, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_DATATYPE, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPA_DEPTH, &lDepth, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_DEPTH, hr = 0x%08X", hr)); + } + } + } + + if (SUCCEEDED(hr) && (bFormatChanged || bCompressionChanged)) + { + 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)); + } + + 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)); + } + } + } + + // + // If the application changed the image type intent the driver must consider + // that WIA_IPA_DATA_TYPE was changed to the value apropriate for the new + // intent no matter if the application set WIA_IPA_DATA_TYPE and to what value: + // + if (SUCCEEDED(hr) && bImageTypeIntentChanged) + { + // + // If multiple color intents are set at the same time consider + // just one and give the highest priority to highest bitdepth: + // + if (WIA_INTENT_IMAGE_TYPE_COLOR & lIntent) + { + bDataTypeChanged = TRUE; + lDataType = WIA_DATA_COLOR; + } + else if (WIA_INTENT_IMAGE_TYPE_GRAYSCALE & lIntent) + { + bDataTypeChanged = TRUE; + lDataType = WIA_DATA_GRAYSCALE; + } + } + + // + // Validate the new current values against the total supported values for + // each of the changed properties with write access in this category: + // + // WIA_IPA_DATATYPE + // WIA_IPS_CUR_INTENT + // WIA_IPA_DEPTH + // WIA_IPA_FORMAT + // WIA_IPA_TYMED (skipped here since its value cannot be changed for this driver) + // WIA_IPA_COMPRESSION + // + // This sample driver can validate color and format properties separately + // since none of its color modes (WIA_IPA_DATATYPE and WIA_IPA_DEPTH + // combinations) are dependent on format changes (WIA_IPA_FORMAT, + // WIA_IPA_TYMED -ignored here- and WIA_IPA_COMPRESSION combinations). + // If the driver would also support WIA_DATA_BW, WIA_COMPRESSION_G4 + // and WiaImgFmt_TIFF the driver would need to validate all the color + // and format properties together (for example WIA_DATA_BW and + // WIA_COMPRESSION_G4 do neither work with WiaImgFmt_EXIF). + // + if (SUCCEEDED(hr) && ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect)) && + (bDataTypeChanged || bIntentChanged || bDepthChanged)) + { + nPropSpec = 0; + + if (bDataTypeChanged) + { + ps[nPropSpec].ulKind = PRSPEC_PROPID; + ps[nPropSpec].propid = WIA_IPA_DATATYPE; + nPropSpec++; + } + + if (bIntentChanged) + { + ps[nPropSpec].ulKind = PRSPEC_PROPID; + ps[nPropSpec].propid = WIA_IPS_CUR_INTENT; + nPropSpec++; + } + + if (bDepthChanged) + { + ps[nPropSpec].ulKind = PRSPEC_PROPID; + ps[nPropSpec].propid = WIA_IPA_DEPTH; + nPropSpec++; + } + + hr = wiasValidateItemProperties(pWiasContext, nPropSpec, ps); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Invalid color property value(s) requested, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr) && (bFormatChanged || bCompressionChanged)) + { + nPropSpec = 0; + + if (bFormatChanged) + { + ps[nPropSpec].ulKind = PRSPEC_PROPID; + ps[nPropSpec].propid = WIA_IPA_FORMAT; + nPropSpec++; + } + + if (bCompressionChanged) + { + ps[nPropSpec].ulKind = PRSPEC_PROPID; + ps[nPropSpec].propid = WIA_IPA_COMPRESSION; + nPropSpec++; + } + + hr = wiasValidateItemProperties(pWiasContext, nPropSpec, ps); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Invalid format property value(s) requested, hr = 0x%08X", hr)); + } + } + + // + // Additional validation for WIA_IPA_DATATYPE and WIA_IPA_DEPTH: + // + if (SUCCEEDED(hr) && ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect)) && + (bDataTypeChanged || bDepthChanged)) + { + if (bDataTypeChanged && bDepthChanged) + { + if (((WIA_DATA_COLOR == lDataType) && (8 == lDepth)) || + ((WIA_DATA_GRAYSCALE == lDataType) && (24 == lDepth))) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Unsupported data type (%u) - depth (%u) combination requested, hr = 0x%08X", + lDataType, lDepth, hr)); + } + } + else if (bDataTypeChanged && (!bDepthChanged)) + { + if (WIA_DATA_COLOR == lDataType) + { + lDepth = 24; + } + else if (WIA_DATA_GRAYSCALE == lDataType) + { + lDepth = 8; + } + else if (WIA_DATA_AUTO == lDataType) + { + lDepth = WIA_DEPTH_AUTO; + } + } + else if ((!bDataTypeChanged) && bDepthChanged) + { + if (8 == lDepth) + { + lDataType = WIA_DATA_GRAYSCALE; + } + else if (24 == lDepth) + { + lDataType = WIA_DATA_COLOR; + } + else if (WIA_DEPTH_AUTO == lDepth) + { + lDataType = WIA_DATA_AUTO; + } + } + } + + // + // Additional validation for WIA_IPA_FORMAT and WIA_IPA_COMPRESSION (skipped for the + // sample non-image sources since those do not support compresssed data transfers): + // + if (SUCCEEDED(hr) && ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect) || + (AUTO_SOURCE == nDocumentHandlingSelect)) && (bFormatChanged || bCompressionChanged)) + { + if (bFormatChanged && (!bCompressionChanged)) + { + // + // If WIA_IPA_FORMAT if changed alone, update WIA_IPA_COMPRESSION to match: + // + if (IsEqualGUID(guidFormat, WiaImgFmt_EXIF)) + { + lCompression = WIA_COMPRESSION_JPEG; + } + else if (IsEqualGUID(guidFormat, WiaImgFmt_BMP) || IsEqualGUID(guidFormat, WiaImgFmt_RAW)) + { + lCompression = WIA_COMPRESSION_NONE; + } + } + else if ((!bFormatChanged) && bCompressionChanged) + { + // + // If WIA_IPA_COMPRESSION if changed alone, update WIA_IPA_FORMAT to match: + // + if ((WIA_COMPRESSION_JPEG == lCompression) || (WIA_COMPRESSION_AUTO == lCompression)) + { + guidFormat = WiaImgFmt_EXIF; + } + else if (WIA_COMPRESSION_NONE == lCompression) + { + guidFormat = WiaImgFmt_BMP; + } + } + else if (bFormatChanged && bCompressionChanged) + { + // + // If both WIA_IPA_FORMAT and WIA_IPA_COMPRESSION are changed, verify that their values work together: + // + if (((WIA_COMPRESSION_NONE == lCompression) && IsEqualGUID(guidFormat, WiaImgFmt_EXIF)) || + (((WIA_COMPRESSION_JPEG == lCompression) || (WIA_COMPRESSION_AUTO == lCompression)) && + (IsEqualGUID(guidFormat, WiaImgFmt_BMP) || IsEqualGUID(guidFormat, WiaImgFmt_RAW)))) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Unsupported file format - compression mode combination, hr = 0x%08X", hr)); + } + } + } + + // + // Update current values: + // + + if (SUCCEEDED(hr) && ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect)) && + (bDataTypeChanged || bIntentChanged || bDepthChanged)) + { + // + // WIA_IPA_DATATYPE: + // + hr = wiasWritePropLong(pWiasContext, WIA_IPA_DATATYPE, lDataType); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_DATATYPE, hr = 0x%08X", hr)); + } + else + { + wiasSetPropChanged(WIA_IPA_DATATYPE, pPropertyContext, TRUE); + } + + // + // WIA_IPS_CUR_INTENT + // + // If an image type intent is set we must make sure it matches the current WIA_IPA_DATATYPE. + // Don't do anything if the application changes any of the other intent flags. + // + if (SUCCEEDED(hr) && (lIntent & WIA_INTENT_IMAGE_TYPE_MASK)) + { + // + // Reset all current image type intent flags. + // + lIntent &= ~ WIA_INTENT_IMAGE_TYPE_MASK; + + // + // .. and add just the one apropriate with the current WIA_IPA_DATATYPE value: + // + + switch (lDataType) + { + case WIA_DATA_COLOR: + lIntent |= WIA_INTENT_IMAGE_TYPE_COLOR; + break; + + case WIA_DATA_GRAYSCALE: + lIntent |= WIA_INTENT_IMAGE_TYPE_GRAYSCALE; + } + + hr = wiasWritePropLong(pWiasContext, WIA_IPS_CUR_INTENT, lIntent); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPS_CUR_INTENT, hr = 0x%08X", hr)); + } + else + { + wiasSetPropChanged(WIA_IPS_CUR_INTENT, pPropertyContext, TRUE); + } + } + + // + // WIA_IPA_DEPTH: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPA_DEPTH, lDepth); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_DEPTH, hr = 0x%08X", hr)); + } + else + { + wiasSetPropChanged(WIA_IPA_DEPTH, pPropertyContext, TRUE); + } + } + + // + // WIA_IPA_CHANNELS_PER_PIXEL: + // + 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)); + } + else + { + wiasSetPropChanged(WIA_IPA_CHANNELS_PER_PIXEL, pPropertyContext, TRUE); + } + } + + // + // WIA_IPA_BITS_PER_CHANNEL: + // + if (SUCCEEDED(hr)) + { + lBitsPerChannel = 8; + + hr = wiasWritePropLong(pWiasContext, WIA_IPA_BITS_PER_CHANNEL, lBitsPerChannel); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_BITS_PER_CHANNEL, hr = 0x%08X", hr)); + } + else + { + wiasSetPropChanged(WIA_IPA_BITS_PER_CHANNEL, pPropertyContext, TRUE); + } + } + + // + // WIA_IPA_RAW_BITS_PER_CHANNEL + // + if (SUCCEEDED(hr)) + { + 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)); + } + else + { + wiasSetPropChanged(WIA_IPA_RAW_BITS_PER_CHANNEL, pPropertyContext, TRUE); + } + } + } + + if (SUCCEEDED(hr) && (bFormatChanged || bCompressionChanged)) + { + // + // WIA_IPA_COMPRESSION: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPA_COMPRESSION, lCompression); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_COMPRESSION, hr = 0x%08X", hr)); + } + else + { + wiasSetPropChanged(WIA_IPA_COMPRESSION, pPropertyContext, TRUE); + } + } + + // + // WIA_IPA_FORMAT: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropGuid(pWiasContext, WIA_IPA_FORMAT, guidFormat); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_FORMAT, hr = 0x%08X", hr)); + } + else + { + wiasSetPropChanged(WIA_IPA_COMPRESSION, pPropertyContext, TRUE); + } + } + + // + // WIA_IPA_FILENAME_EXTENSION: + // + + if (SUCCEEDED(hr)) + { + if (IsEqualGUID(guidFormat, WiaImgFmt_BMP)) + { + bstrFileExtension = SysAllocString(FILE_EXT_BMP); + } + else if (IsEqualGUID(guidFormat, WiaImgFmt_EXIF)) + { + bstrFileExtension = SysAllocString(FILE_EXT_JPG); + } + else if (IsEqualGUID(guidFormat, WiaImgFmt_RAW) || IsEqualGUID(guidFormat, WiaImgFmt_RAWBAR) || + IsEqualGUID(guidFormat, WiaImgFmt_RAWPAT) || IsEqualGUID(guidFormat, WiaImgFmt_RAWMIC)) + { + bstrFileExtension = SysAllocString(FILE_EXT_RAW); + } + else if (IsEqualGUID(guidFormat, WiaImgFmt_CSV)) + { + bstrFileExtension = SysAllocString(FILE_EXT_CSV); + } + else if (IsEqualGUID(guidFormat, WiaImgFmt_TXT)) + { + bstrFileExtension = SysAllocString(FILE_EXT_TXT); + } + else if (IsEqualGUID(guidFormat, WiaImgFmt_XMLBAR) || IsEqualGUID(guidFormat, WiaImgFmt_XMLPAT) || + IsEqualGUID(guidFormat, WiaImgFmt_XMLMIC)) + { + bstrFileExtension = SysAllocString(FILE_EXT_XML); + } + else + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Unsupported file format, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr) && (!bstrFileExtension)) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Unable to allocate memory for new file extension, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + hr = wiasWritePropStr(pWiasContext, WIA_IPA_FILENAME_EXTENSION, bstrFileExtension); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_FILENAME_EXTENSION, hr = 0x%08X", hr)); + } + } + } + + if (bstrFileExtension) + { + SysFreeString(bstrFileExtension); + } + + return hr; +} + +/**************************************************************************\ +* +* Helper for IWiaMinIDrv::drvValidateItemProperties. +* +* Updates the following "image information" properties: +* +* WIA_IPA_PIXELS_PER_LINE +* WIA_IPA_NUMBER_OF_LINES +* WIA_IPA_BYTES_PER_LINE +* +* Parameters: +* +* pWiasContext - pointer to the item context +* pPropertyContext - pointer to the property context which +* indicates which properties are being written +* nDocumentHandlingSelect - FLAT or FEED (as defined in wiadef.h) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ +HRESULT CWiaDriver::ValidateImageInfoProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nDocumentHandlingSelect) +{ + HRESULT hr = S_OK; + LONG lXExtent = 0; + LONG lYExtent = 0; + LONG lPixelsPerLine = 0; + LONG lNumberOfLines = 0; + LONG lDepth = 0; + LONG lBytesPerLine = 0; + + if ((!pWiasContext) || (!pPropertyContext) || (AUTO_SOURCE == nDocumentHandlingSelect)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameters, hr = 0x%08X", hr)); + } + + // + // Read the current extent and bit depth values: + // + + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPA_DEPTH, &lDepth, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_DEPTH, hr = 0x%08X", hr)); + } + } + + 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)); + } + } + + // + // 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 + // + + lPixelsPerLine = lXExtent; + lNumberOfLines = lYExtent; + lBytesPerLine = BytesPerLine(lPixelsPerLine, lDepth); + + 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)); + } + } + + return hr; +} + +/**************************************************************************\ +* +* Validates new current values for the following dependent WIA properties: +* +* WIA_IPS_PAGE_SIZE +* WIA_IPS_ORIENTATION +* WIA_IPS_PAGE_WIDTH +* WIA_IPS_PAGE_HEIGHT +* WIA_IPS_XPOS +* WIA_IPS_YPOS +* WIA_IPS_XEXTENT +* WIA_IPS_YEXTENT +* WIA_IPS_XRES +* WIA_IPS_YRES +* WIA_IPS_XSCALING +* WIA_IPS_YSCALING +* WIA_IPS_LONG_DOCUMENT +* +* If the application changes the document size and orientation the driver +* should update the current and valid origin and extent properties to match +* at the current resolution the current full document dimensions. +* +* Resolution changes should also cause updated origins and extents (valid and current). +* +* Orientation changes should result in updated valid page size lists and +* updated current and valid origin and extents values. +* +* The driver is going to consider the origins and extents to configure +* the scan area (crop region) and the current page size to configure +* the physical document size, if needed. +* +* Parameters: +* +* pWiasContext - pointer to the item context +* pPropertyContext - pointer to the property context which +* indicates which properties are being written +* nDocumentHandlingSelect - FLAT or FEED (as defined in wiadef.h) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise (E_INVALIDARG if +* an invalid combination is attempted) +* +\**************************************************************************/ + +HRESULT CWiaDriver::ValidateRegionProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nDocumentHandlingSelect) +{ + HRESULT hr = S_OK; + + if ((!pWiasContext) || (!pPropertyContext) || (AUTO_SOURCE == nDocumentHandlingSelect)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameters, hr = 0x%08X", hr)); + } + + LONG lXRes = 0; + LONG lYRes = 0; + LONG lMinXExtent = (MIN_SCAN_AREA_WIDTH * OPTICAL_RESOLUTION) / 1000; + LONG lMinYExtent = (MIN_SCAN_AREA_HEIGHT * OPTICAL_RESOLUTION) / 1000; + LONG lMaxXExtent = (MAX_SCAN_AREA_WIDTH * OPTICAL_RESOLUTION) / 1000; + LONG lMaxYExtent = (MAX_SCAN_AREA_HEIGHT * OPTICAL_RESOLUTION) / 1000; + + LONG lXPos = 0; + LONG lYPos = 0; + LONG lXExtent = lMaxXExtent; + LONG lYExtent = lMaxYExtent; + + LONG lPageWidth = MAX_SCAN_AREA_WIDTH; + LONG lPageHeight = MAX_SCAN_AREA_HEIGHT; + LONG lPageSize = WIA_PAGE_LETTER; + LONG lOrientation = PORTRAIT; + LONG lMaxWidth = MAX_SCAN_AREA_WIDTH; + LONG lMaxHeight = MAX_SCAN_AREA_HEIGHT; + LONG lLongDocument = WIA_LONG_DOCUMENT_DISABLED; + + BOOL bPageSizeChanged = FALSE; + BOOL bOrientationChanged = FALSE; + BOOL bLongDocumentChanged = FALSE; + + // + // Read the current property values (no matter if they were changed or not): + // + + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_XPOS, &lXPos, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_XPOS, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_YPOS, &lYPos, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_YPOS, hr = 0x%08X", hr)); + } + } + + 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)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_XRES, &lXRes, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_XRES, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_YRES, &lYRes, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_YRES, hr = 0x%08X", hr)); + } + } + + // + // In order to validate scan frame or resolution changes we must know + // the maximum scan area size. For Flatbed this is the total bed size. + // For Feeder this is the size of the currently selected document size. + // + if (SUCCEEDED(hr) &&(FEED == nDocumentHandlingSelect)) + { + wiasIsPropChanged(WIA_IPS_PAGE_SIZE, pPropertyContext, &bPageSizeChanged); + wiasIsPropChanged(WIA_IPS_ORIENTATION, pPropertyContext, &bOrientationChanged); + wiasIsPropChanged(WIA_IPS_LONG_DOCUMENT, pPropertyContext, &bLongDocumentChanged); + + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_ORIENTATION, &lOrientation, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_ORIENTATION, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_PAGE_SIZE, &lPageSize, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_PAGE_SIZE, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_LONG_DOCUMENT, &lLongDocument, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_LONG_DOCUMENT, hr = 0x%08X", hr)); + } + } + + // + // When WIA_LONG_DOCUMENT_ENABLED is set, if the application is not doing this update, + // the driver must update itself the current WIA_IPS_PAGE_SIZE property value to WIA_PAGE_AUTO. + // If WIA_LONG_DOCUMENT_ENABLED is set and the application changes WIA_IPS_PAGE_SIZE to + // another value than WIA_PAGE_AUTO, the driver must self-update the WIA_IPS_LONG_DOCUMENT + // property to WIA_LONG_DOCUMENT_DISABLED. + // + if (SUCCEEDED(hr) && (bPageSizeChanged || bLongDocumentChanged)) + { + if ((WIA_PAGE_AUTO != lPageSize) && (WIA_LONG_DOCUMENT_ENABLED == lLongDocument)) + { + if (bLongDocumentChanged && bPageSizeChanged) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid WIA_IPS_PAGE_SIZE value for WIA_LONG_DOCUMENT_ENABLED, hr = 0x%08X", hr)); + } + else if (bLongDocumentChanged && (!bPageSizeChanged)) + { + lPageSize = WIA_PAGE_AUTO; + bPageSizeChanged = TRUE; + } + else if ((!bLongDocumentChanged) && bPageSizeChanged) + { + lLongDocument = WIA_LONG_DOCUMENT_DISABLED; + bLongDocumentChanged = TRUE; + } + } + } + + // + // Validate the current WIA_IPS_PAGE_SIZE against the valid values + // apropriate with the current WIA_IPS_ORIENTATION: + // + if (SUCCEEDED(hr) && (bPageSizeChanged || bOrientationChanged)) + { + CBasicDynamicArray &lPageSizesArray = (PORTRAIT == lOrientation) ? m_lPortraitSizesArray : m_lLandscapeSizesArray; + + if (-1 == lPageSizesArray.Find(lPageSize)) + { + if (bPageSizeChanged) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid WIA_IPS_PAGE_SIZE value, hr = 0x%08X", hr)); + } + else if (WIA_PAGE_AUTO != lPageSize) + { + // + // This means that the application did not request the page size + // to be changed, just changed the orientation and the current + // page size is not supported in the new orientation so we should + // quietly select WIA_PAGE_CUSTOM: + // + lPageSize = WIA_PAGE_CUSTOM; + lPageWidth = lMaxWidth; + lPageHeight = lMaxHeight; + bPageSizeChanged = TRUE; + } + } + else + { + // + // For WIA_PAGE_CUSTOM the page dimensions are the maximum dimensions of the scan area, + // same for WIA_PAGE_AUTO (real page dimensions being detected here only after the + // document has been scanned and reflected in the final image layout and dimensions): + // + if ((WIA_PAGE_CUSTOM == lPageSize) || (WIA_PAGE_AUTO == lPageSize)) + { + lPageWidth = lMaxWidth; + lPageHeight = lMaxHeight; + } + else + { + // + // The page sizes from the current array are guaranteed to fit in + // the total scan acquisition area limits, minimum and maximum: + // + hr = GetPageDimensions(lPageSize, (BOOL)(PORTRAIT == lOrientation), lPageWidth, lPageHeight); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Unable to retrieve dimensions for the current document size, hr = 0x%08X", hr)); + } + } + } + + // + // For Feeder the actual maximum dimensions for the scan area + // are dictated by the current document size selected: + // + if (SUCCEEDED(hr)) + { + lMaxWidth = lPageWidth; + lMaxHeight = lPageHeight; + } + } + } + + // + // Use wiasUpdateScanRect to validate the current extents and + // resolutions and update all their dependent properties: + // + if (SUCCEEDED(hr)) + { + hr = wiasUpdateScanRect(pWiasContext, pPropertyContext, lMaxWidth, lMaxHeight); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "wiasUpdateScanRect(max width = %u, max height = %u) failed, hr = 0x%08X", lMaxWidth, lMaxHeight, hr)); + } + } + + // + // For feeder special validation must be performed for WIA_IPS_ORIENTATION and WIA_IPS_PAGE_SIZE changes: + // + if (FEED == nDocumentHandlingSelect) + { + // + // Update valid list of values for WIA_IPS_PAGE_SIZE according with the new set WIA_IPS_ORIENTATION: + // + if (SUCCEEDED(hr) && bOrientationChanged) + { + LONG lNumPageSizes = 0; + CBasicDynamicArray &lPageSizesArray = (PORTRAIT == lOrientation) ? m_lPortraitSizesArray : m_lLandscapeSizesArray; + lNumPageSizes = lPageSizesArray.Size(); + + hr = wiasSetValidListLong(pWiasContext, WIA_IPS_PAGE_SIZE, (ULONG)lNumPageSizes, + lPageSize, (LONG *)lPageSizesArray.Array()); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update valid WIA_IPS_PAGE_SIZE values, hr = 0x%08X", hr)); + } + } + + // + // If the current WIA_IPS_PAGE_SIZE is changed updated all the dependent properties: + // + if (SUCCEEDED(hr) && bPageSizeChanged) + { + // + // Update current WIA_IPS_PAGE_SIZE value: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPS_PAGE_SIZE, lPageSize); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPS_PAGE_SIZE, hr = 0x%08X", hr)); + } + } + + // + // Update current WIA_IPS_PAGE_WIDTH: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPS_PAGE_WIDTH, lPageWidth); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPS_PAGE_WIDTH, hr = 0x%08X", hr)); + } + } + + // + // Update current WIA_IPS_LONG_DOCUMENT: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPS_LONG_DOCUMENT, lLongDocument); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPS_PAGE_HEIGHT, hr = 0x%08X", hr)); + } + } + + // + // Update current WIA_IPS_PAGE_HEIGHT: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPS_PAGE_HEIGHT, lPageHeight); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPS_PAGE_HEIGHT, hr = 0x%08X", hr)); + } + } + + // + // If the current page size is changed always update the current and valid + // WIA_IPS_XPOS, WIA_IPS_YPOS, WIA_IPS_XEXTENT and WIA_IPS_YEXTENT to match + // the entire area of the currently selected document size, overwriting any + // direct change for any of these properties requested at the same time with + // the change for WIA_IPS_ORIENTATION or WIA_IPS_PAGESIZE. + // + + // + // Read current WIA_IPS_XRES: + // + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_XRES, &lXRes, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_XRES, hr = 0x%08X", hr)); + } + } + + // + // Read current WIA_IPS_YRES: + // + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_YRES, &lYRes, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_YRES, hr = 0x%08X", hr)); + } + } + + // + // Compute the new extent limits: + // + if (SUCCEEDED(hr)) + { + lMinXExtent = (MIN_SCAN_AREA_WIDTH * lXRes) / 1000; + if (!lMinXExtent) + { + lMinXExtent = 1; + } + lMinYExtent = (MIN_SCAN_AREA_HEIGHT * lYRes) / 1000; + if (!lMinYExtent) + { + lMinYExtent = 1; + } + lMaxXExtent = (lPageWidth * lXRes) / 1000; + lMaxYExtent = (lPageHeight * lYRes) / 1000; + + if ((lMaxXExtent < 1) || (lMaxYExtent < 1) || (lMinXExtent > lMaxXExtent) || (lMinYExtent > lMaxYExtent)) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Unable to update the extent limits to match the new document size, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + // + // The new current scan region, covering the entire document size: + // + lXPos = 0; + lYPos = 0; + lXExtent = lMaxXExtent; + lYExtent = lMaxYExtent; + + // + // Set new valid values for WIA_IPS_XPOS: + // + hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_XPOS, 0, lXPos, lMaxXExtent - lMinXExtent, 1); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update valid WIA_IPS_XPOS, hr = 0x%08X", hr)); + } + + // + // Set new valid values for WIA_IPS_YPOS: + // + if (SUCCEEDED(hr)) + { + hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_YPOS, 0, lYPos, lMaxYExtent - lMinYExtent, 1); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update valid WIA_IPS_YPOS, hr = 0x%08X", hr)); + } + } + + // + // Set new valid values for WIA_IPS_XEXTENT: + // + if (SUCCEEDED(hr)) + { + hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_XEXTENT, lMinXExtent, lXExtent, lMaxXExtent - lXPos, 1); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update valid WIA_IPS_XEXTENT, hr = 0x%08X", hr)); + } + } + + // + // Set new valid values for WIA_IPS_XEXTENT: + // + if (SUCCEEDED(hr)) + { + hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_YEXTENT, lMinYExtent, lYExtent, lMaxYExtent - lYPos, 1); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update valid WIA_IPS_YEXTENT, hr = 0x%08X", hr)); + } + } + + // + // Set new current value for WIA_IPS_XPOS: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPS_XPOS, lXPos); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPS_XPOS, hr = 0x%08X", hr)); + } + } + + // + // Set new current value for WIA_IPS_YPOS: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPS_YPOS, lYPos); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPS_YPOS, hr = 0x%08X", hr)); + } + } + + // + // Set new current value for WIA_IPS_XEXTENT: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPS_XEXTENT, lXExtent); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPS_XEXTENT, hr = 0x%08X", hr)); + } + } + + // + // Set new current value for WIA_IPS_YEXTENT: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPS_YEXTENT, lYExtent); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPS_YEXTENT, hr = 0x%08X", hr)); + } + } + } + } + } + + return hr; +} + +/**************************************************************************\ +* +* Validates new current values for the following dependent WIA properties: +* +* WIA_IPS_DOCUMENT_HANDLING_SELECT: either DUPLEX or FRONT_ONLY can be set +* +* WIA_IPS_PAGES: the valid range and current value are updated to match +* the current WIA_IPS_DOCUMENT_HANDLING_SELECT +* +* Parameters: +* +* pWiasContext - pointer to the item context +* pPropertyContext - pointer to the property context which +* indicates which properties are being written +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise (E_INVALIDARG if +* an invalid combination is attempted) +* +\**************************************************************************/ + +HRESULT CWiaDriver::ValidateFeedProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext) +{ + HRESULT hr = S_OK; + BOOL bHandlingSelectChanged = TRUE; + LONG lFeederHandlingSelect = FRONT_ONLY; + BOOL bPagesChanged = TRUE; + LONG lPages = 1; + LONG lMaxPages = 0x7FFFFFFF; //maximum value for a signed 32-bit integer + LONG lMinPages = 0; //ALL_PAGES + LONG lStepPages = 1; + WIAS_CHANGED_VALUE_INFO wiasValInfo = {}; + + if ((!pWiasContext) || (!pPropertyContext)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameters, hr = 0x%08X", hr)); + } + + // + // Check if WIA_IPS_DOCUMENT_HANDLING_SELECT was changed: + // + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(wiasGetChangedValueLong(pWiasContext, pPropertyContext, TRUE, WIA_IPS_DOCUMENT_HANDLING_SELECT, &wiasValInfo))) + { + lFeederHandlingSelect = wiasValInfo.Current.lVal; + bHandlingSelectChanged = wiasValInfo.bChanged; + } + else + { + bHandlingSelectChanged = FALSE; + } + } + + // + // Check if WIA_IPS_PAGES was changed and read its current value: + // + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(wiasGetChangedValueLong(pWiasContext, pPropertyContext, TRUE, WIA_IPS_PAGES, &wiasValInfo))) + { + lPages = wiasValInfo.Current.lVal; + bPagesChanged = wiasValInfo.bChanged; + } + else + { + bPagesChanged = FALSE; + + if (bHandlingSelectChanged) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_PAGES, &lPages, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_PAGES on the Feeder item, hr = 0x%08X", hr)); + } + } + } + } + + // + // If WIA_IPS_DOCUMENT_HANDLING_SELECT is changed verify that only FRONT_ONLY + // or DUPLEX is requested to be set, only one at a time: + // + if (SUCCEEDED(hr) && bHandlingSelectChanged) + { + if ((DUPLEX != lFeederHandlingSelect) && (FRONT_ONLY != lFeederHandlingSelect)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, + "WIA_IPS_DOCUMENT_HANDLING_SELECT validation failed, only FRONT_ONLY and DUPLEX are valid, only one at a time, hr = 0x%08X", hr)); + } + } + + // + // Read the current WIA_IPS_DOCUMENT_HANDLING_SELECT value if not changed and WIA_IPS_PAGES is changed: + // + if (SUCCEEDED(hr) && (!bHandlingSelectChanged) && bPagesChanged) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_DOCUMENT_HANDLING_SELECT, &lFeederHandlingSelect, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_DOCUMENT_HANDLING_SELECT on the Feeder item, hr = 0x%08X", hr)); + } + } + + // + // If WIA_IPS_DOCUMENT_HANDLING_SELECT is changed and WIA_IPS_PAGES is not, update the valid and, + // if needed, current values for WIA_IPS_PAGES. Note that the step WIA_IPS_PAGES value must remain + // 1 for duplex in order to allow a legacy WIA 1.0 application to indirectly disable duplex by + // settings WIA_DPS_PAGES to 1: + // + if (SUCCEEDED(hr) && bHandlingSelectChanged && (!bPagesChanged)) + { + if (DUPLEX == lFeederHandlingSelect) + { + lMaxPages = 0x7FFFFFFE; //maximum even value for a signed 32-bit integer + lMinPages = 0; //ALL_PAGES + lStepPages = 1; //not 2 + + // + // Round up the current WIA_IPS_PAGES value to the nearest even number: + // + if ((lPages > 0) && (lPages % 2)) + { + if (lPages <= (lMaxPages - 1)) + { + lPages += 1; + } + else if (lPages >= (lMinPages + 2)) + { + lPages -= 1; + } + else + { + lPages = 2; + } + } + } + else + { + lMaxPages = 0x7FFFFFFF; //maximum value for a signed 32-bit integer + lMinPages = 0; //ALL_PAGES + lStepPages = 1; + } + + // + // Update the range of valid WIA_IPS_PAGES values: + // + hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_PAGES, lMinPages, lPages, lMaxPages, lStepPages); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update valid WIA_IPS_PAGES, hr = 0x%08X", hr)); + } + + // + // Update the current WIA_IPS_PAGES value: + // + if (SUCCEEDED(hr)) + { + hr = wiasWritePropLong(pWiasContext, WIA_IPS_PAGES, lPages); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update current WIA_IPS_PAGES, hr = 0x%08X", hr)); + } + } + } + + // + // If WIA_IPS_PAGES is changed and WIA_IPS_DOCUMENT_HANDLING_SELECT is not, check if + // we need to disable duplex as result of a WIA_IPS_PAGES current value change to 1. + // We'll leave duplex enabled if the application changes WIA_IPS_PAGE to another + // odd value, the application being responsible in this case to decide itself if + // these pages are to be scanned duplex (and the last side discarded) or simplex: + // + if (SUCCEEDED(hr) && (!bHandlingSelectChanged) && bPagesChanged) + { + if ((DUPLEX == lFeederHandlingSelect) && (1 == lPages)) + { + lFeederHandlingSelect = FRONT_ONLY; + + hr = wiasWritePropLong(pWiasContext, WIA_IPS_DOCUMENT_HANDLING_SELECT, lFeederHandlingSelect); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update current WIA_IPS_DOCUMENT_HANDLING_SELECT, hr = 0x%08X", hr)); + } + } + } + + // + // If both WIA_IPS_PAGES and WIA_IPS_DOCUMENT_HANDLING_SELECT are changed at the + // same time, check if DUPLEX and an odd WIA_IPS_PAGES value are set. We'll allow + // odd values other than 1 while DUPLEX is set but not 1: + // + if (SUCCEEDED(hr) && bHandlingSelectChanged && bPagesChanged) + { + if ((DUPLEX == lFeederHandlingSelect) && (1 == lPages)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "WIA_IPS_PAGES cannot be set to 1 while setting WIA_IPS_DOCUMENT_HADLING_SELECT to DUPLEX, hr = 0x%08X", hr)); + } + } + + return hr; +} + +/**************************************************************************\ +* +* Helper for IWiaMinIDrv::drvValidateItemProperties. +* +* Executes additional validation for the imprinter/endorser specific properties. +* The only imprinter/enorser property that this sample driver needs to validate +* here is WIA_IPS_PRINTER_ENDORSER_STRING - the characters submitted by the +* application must match WIA_IPS_PRINTER_ENDORSER_VALID_CHARACTERS. Unsupported +* WIA_IPS_PRINTER_ENDORSER_VALID_FORMAT_SPECIFIERS are quietly ignored by the +* driver (pretended to be printed/endorsed as-is). +* +* Parameters: +* +* pWiasContext - pointer to the item context +* pPropertyContext - pointer to the property context which +* indicates which properties are being written +* nDocumentHandlingSelect - IMPRINTER or ENDORSER (defined in wiadef.h) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ +HRESULT CWiaDriver::ValidateImprinterEndorserProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nDocumentHandlingSelect) +{ + HRESULT hr = S_OK; + BOOL bStringChanged = TRUE; + BSTR bstrNewString = NULL; + BSTR bstrOldString = NULL; + WIAS_CHANGED_VALUE_INFO wiasValInfo = {}; + + if ((!pWiasContext) || (!pPropertyContext) || + ((IMPRINTER != nDocumentHandlingSelect) && (ENDORSER != nDocumentHandlingSelect))) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "CWiaDriver::ValidateImprinterEndorserProperties failed, invalid parameter, hr = 0x%08X", hr)); + } + + // + // Check if WIA_IPS_PRINTER_ENDORSER_STRING is changed by the application: + // + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(wiasGetChangedValueStr(pWiasContext, pPropertyContext, TRUE, WIA_IPS_PRINTER_ENDORSER_STRING, &wiasValInfo))) + { + // + // wiasGetChangedValueStr allocates both Current and Old BSTRs, read them both + // even if not using the Old value, we'll need to free both of them when done: + // + bstrNewString = wiasValInfo.Current.bstrVal; + bstrOldString = wiasValInfo.Old.bstrVal; + bStringChanged = wiasValInfo.bChanged; + } + else + { + bStringChanged = FALSE; + } + } + + // + // If WIA_IPS_PRINTER_ENDORSER_STRING is changed, check if all characters are valid: + // + if (SUCCEEDED(hr) && bStringChanged && bstrNewString) + { + PWCHAR szValidChars = (IMPRINTER == nDocumentHandlingSelect) ? SAMPLE_IMPRINTER_VALID_CHARS : SAMPLE_ENDORSER_VALID_CHARS; + ULONG ulValidChars = ((IMPRINTER == nDocumentHandlingSelect) ? ARRAYSIZE(SAMPLE_IMPRINTER_VALID_CHARS) : ARRAYSIZE(SAMPLE_ENDORSER_VALID_CHARS)) - 1; + ULONG i = 0; + BOOL bFound = FALSE; + + while (bstrNewString[i] != NULL) + { + bFound = FALSE; + + for (ULONG j = 0; j < ulValidChars; j++) + { + if (bstrNewString[i] == szValidChars[j]) + { + bFound = TRUE; + i++; + break; + } + } + + if (!bFound) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid character for WIA_IPS_PRINTER_ENDORSER_STRING: 0x%X (%wc), hr = 0x%08X", + bstrNewString[i], bstrNewString[i], hr)); + break; + } + } + } + + // + // This sample driver supports only one line of text for its Imprinter/Endorser. + // Check that the new WIA_IPS_PRINTER_ENDORSER_STRING value does not contain any + // special '$N$'sequences ('new line'). This sample driver will ignore other + // formatting sequences that may be contained by the new string: + // + if (SUCCEEDED(hr) && bStringChanged && bstrNewString) + { + WCHAR szNewLine[] = L"$N$"; + + if (wcsstr(bstrNewString, szNewLine)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid new line ($N$) format sequence for WIA_IPS_PRINTER_ENDORSER_STRING, only one line of text supported, submitted value: %ws, hr = 0x%08X", + bstrNewString, hr)); + } + } + + // + // Important: both the WIAS_CHANGED_VALUE_INFO::Current.bstrVal and + // WIAS_CHANGED_VALUE_INFO::Old.bstrVal BSTRs must be freed. + // + if (bstrNewString) + { + SysFreeString(bstrNewString); + } + if (bstrOldString) + { + SysFreeString(bstrOldString); + } + + return hr; +} + +/**************************************************************************\ +* +* Helper for IWiaMinIDrv::drvValidateItemProperties. +* +* Validates WIA_IPS_ENABLED_BARCODE_TYPES +* +* Parameters: +* +* pWiasContext - pointer to the item context +* pPropertyContext - pointer to the property context which +* indicates which properties are being written +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ +HRESULT CWiaDriver::ValidateBarcodeReaderProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext) +{ + HRESULT hr = S_OK; + BOOL bBarcodeTypesChanged = TRUE; + + if ((!pWiasContext) || (!pPropertyContext)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "CWiaDriver::ValidateImprinterEndorserProperties failed, invalid parameter, hr = 0x%08X", hr)); + } + + // + // Check if WIA_IPS_ENABLED_BARCODE_TYPES is changed by the application: + // + if (SUCCEEDED(hr)) + { + // + // wiasIsPropChanged fails if the property is not changed, do not fail ValidateBarcodeReaderProperties: + // + wiasIsPropChanged(WIA_IPS_ENABLED_BARCODE_TYPES, pPropertyContext, &bBarcodeTypesChanged); + } + + // + // If WIA_IPS_ENABLED_BARCODE_TYPES is changed, read the new (vector) array of values and validate against the valid values: + // + if (SUCCEEDED(hr) && bBarcodeTypesChanged) + { + PROPSPEC ps = {}; + PROPVARIANT pv = {}; + + ps.ulKind = PRSPEC_PROPID; + ps.propid = WIA_IPS_ENABLED_BARCODE_TYPES; + + PropVariantInit(&pv); + + hr = wiasReadMultiple(pWiasContext, 1, &ps, &pv, NULL); + if (SUCCEEDED(hr)) + { + if ((VT_VECTOR | VT_I4) == pv.vt) + { + ULONG ulValidValues = ARRAYSIZE(g_lSupportedBarcodeTypes); + BOOL bFound = FALSE; + + for (ULONG i = 0; i < pv.cal.cElems; i++) + { + bFound = FALSE; + + for (ULONG j = 0; j < ulValidValues; j++) + { + if (g_lSupportedBarcodeTypes[j] == pv.cal.pElems[i]) + { + bFound = TRUE; + break; + } + } + + if (!bFound) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Unsupported barcode type: %u, hr = 0x%08X", pv.cal.pElems[i], hr)); + break; + } + } + + } + else + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid value type for WIA_IPS_ENABLED_BARCODE_TYPES, expected VT_VECTOR | VT_I4 (%u), got %u, hr = 0x%08X", + VT_VECTOR | VT_I4, pv.vt, hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "wiasReadMultiple(WIA_IPS_ENABLED_BARCODE_TYPES) failed, hr = 0x%08X", hr)); + } + + PropVariantClear(&pv); + } + + return hr; +} + +/**************************************************************************\ +* +* Helper for IWiaMinIDrv::drvValidateItemProperties. +* +* Validates WIA_IPS_ENABLED_PATCH_CODE_TYPES +* +* Parameters: +* +* pWiasContext - pointer to the item context +* pPropertyContext - pointer to the property context which +* indicates which properties are being written +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ +HRESULT CWiaDriver::ValidatePatchCodeReaderProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext) +{ + HRESULT hr = S_OK; + BOOL bPatchCodeTypesChanged = TRUE; + + if ((!pWiasContext) || (!pPropertyContext)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "CWiaDriver::ValidateImprinterEndorserProperties failed, invalid parameter, hr = 0x%08X", hr)); + } + + // + // Check if WIA_IPS_ENABLED_PATCH_CODE_TYPES is changed by the application: + // + if (SUCCEEDED(hr)) + { + // + // wiasIsPropChanged fails if the property is not changed, do not fail ValidatePatchCodeReaderProperties: + // + wiasIsPropChanged(WIA_IPS_ENABLED_PATCH_CODE_TYPES, pPropertyContext, &bPatchCodeTypesChanged); + } + + // + // If WIA_IPS_ENABLED_PATCH_CODE_TYPES is changed, read the new (vector) array of values and validate against the valid values: + // + if (SUCCEEDED(hr) && bPatchCodeTypesChanged) + { + PROPSPEC ps = {}; + PROPVARIANT pv = {}; + + ps.ulKind = PRSPEC_PROPID; + ps.propid = WIA_IPS_ENABLED_PATCH_CODE_TYPES; + + PropVariantInit(&pv); + + hr = wiasReadMultiple(pWiasContext, 1, &ps, &pv, NULL); + if (SUCCEEDED(hr)) + { + if ((VT_VECTOR | VT_I4) == pv.vt) + { + ULONG ulValidValues = ARRAYSIZE(g_lSupportedPatchCodeTypes); + BOOL bFound = FALSE; + + for (ULONG i = 0; i < pv.cal.cElems; i++) + { + bFound = FALSE; + + for (ULONG j = 0; j < ulValidValues; j++) + { + if (g_lSupportedPatchCodeTypes[j] == pv.cal.pElems[i]) + { + bFound = TRUE; + break; + } + } + + if (!bFound) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Unsupported patch code type: %u, hr = 0x%08X", pv.cal.pElems[i], hr)); + break; + } + } + + } + else + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid value type for WIA_IPS_ENABLED_PATCH_CODE_TYPES, expected VT_VECTOR | VT_I4 (%u), got %u, hr = 0x%08X", + VT_VECTOR | VT_I4, pv.vt, hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "wiasReadMultiple(WIA_IPS_ENABLED_PATCH_CODE_TYPES) failed, hr = 0x%08X", hr)); + } + + PropVariantClear(&pv); + } + + return hr; +} + +/**************************************************************************\ +* +* Helper for IWiaMinIDrv::drvValidateItemProperties. +* +* Parameters: +* +* pWiasContext - pointer to the item context +* pPropertyContext - pointer to the property context which +* indicates which properties are being written +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ +HRESULT CWiaDriver::ValidateMicrReaderProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext) +{ + HRESULT hr = S_OK; + + if ((!pWiasContext) || (!pPropertyContext)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "CWiaDriver::ValidateMicrReaderProperties failed, invalid parameter, hr = 0x%08X", hr)); + } + + // + // Nothing special to validate here + // + + return hr; +} + +/**************************************************************************\ +* +* Helper for CWiaDriver::ValidateColorDropProperties. +* +* Validates a RGB color drop property WIA_IPS_COLOR_DROP_RED, WIA_IPS_COLOR_DROP_GREEN and +* WIA_IPS_COLOR_DROP_BLUE +* +* Parameters: +* +* pWiasContext - pointer to the item context +* pPropertyContext - pointer to the property context which +* indicates which properties are being written +* nChannel - WIA_COLOR_DROP_RED, WIA_COLOR_DROP_GREEN or +* WIA_COLOR_DROP_BLUE (as defined in wiadef.h) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ +HRESULT CWiaDriver::ValidateColorDropProperty( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nChannel) +{ + HRESULT hr = S_OK; + BOOL bChanged = TRUE; + UINT nProp = 0; + + if ((!pWiasContext) || (!pPropertyContext) || + ((WIA_COLOR_DROP_RED != nChannel) && (WIA_COLOR_DROP_GREEN != nChannel) && (WIA_COLOR_DROP_BLUE != nChannel))) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "CWiaDriver::ValidateColorDropProperty failed, invalid parameter, hr = 0x%08X", hr)); + } + + switch (nChannel) + { + case WIA_COLOR_DROP_RED: + nProp = WIA_IPS_COLOR_DROP_RED; + break; + + case WIA_COLOR_DROP_GREEN: + nProp = WIA_IPS_COLOR_DROP_GREEN; + break; + + case WIA_COLOR_DROP_BLUE: + nProp = WIA_IPS_COLOR_DROP_BLUE; + } + + // + // Check if this WIA_IPS_COLOR_DROP_* property is changed by the application: + // + if (SUCCEEDED(hr)) + { + // + // wiasIsPropChanged fails if the property is not changed, do not fail validation because of this: + // + wiasIsPropChanged(nProp, pPropertyContext, &bChanged); + } + + // + // If this WIA_IPS_COLOR_DROP_* property is changed, read the new (vector) array of values and validate + // both against WIA_IPS_COLOR_DROP_MULTI and the valid range of values (from 0 and 100, inclusive): + // + if (SUCCEEDED(hr) && bChanged) + { + PROPSPEC ps = {}; + PROPVARIANT pv = {}; + + ps.ulKind = PRSPEC_PROPID; + ps.propid = nProp; + + PropVariantInit(&pv); + + hr = wiasReadMultiple(pWiasContext, 1, &ps, &pv, NULL); + if (SUCCEEDED(hr)) + { + if ((VT_VECTOR | VT_I4) == pv.vt) + { + if (pv.cal.cElems > g_lMaxDropColors) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Unsupported number of drop out entries for property %u: %u, supported up to: %u, hr = 0x%08X", + nProp, pv.cal.cElems, g_lMaxDropColors, hr)); + } + else + { + for (ULONG i = 0; i < pv.cal.cElems; i++) + { + if ((pv.cal.pElems[i] < 0) || (pv.cal.pElems[i] > 100)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, + "Unsupported color drop value for property %u at vector position %u: %u, valid range is from 0 to 100 inclusive, hr = 0x%08X", + nProp, i, pv.cal.pElems[i], hr)); + break; + } + } + } + } + else + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid value type for property %u, expected VT_VECTOR | VT_I4 (%u), got %u, hr = 0x%08X", + nProp, VT_VECTOR | VT_I4, pv.vt, hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "wiasReadMultiple(property %u) failed, hr = 0x%08X", nProp, hr)); + } + + PropVariantClear(&pv); + } + + return hr; +} + +/**************************************************************************\ +* +* Helper for IWiaMinIDrv::drvValidateItemProperties. +* +* Validates WIA_IPS_COLOR_DROP_RED, WIA_IPS_COLOR_DROP_GREEN and +* WIA_IPS_COLOR_DROP_BLUE +* +* Parameters: +* +* pWiasContext - pointer to the item context +* pPropertyContext - pointer to the property context which +* indicates which properties are being written +* nDocumentHandlingSelect - FLAT or FEED (as defined in wiadef.h) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ +HRESULT CWiaDriver::ValidateColorDropProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nDocumentHandlingSelect) +{ + HRESULT hr = S_OK; + + if ((!pWiasContext) || (!pPropertyContext) || + ((FLAT != nDocumentHandlingSelect) && (FEED != nDocumentHandlingSelect))) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "CWiaDriver::ValidateColorDropProperties failed, invalid parameter, hr = 0x%08X", hr)); + } + + // + // Validate WIA_IPS_COLOR_DROP_RED (error logging is covered by ValidateColorDropProperty): + // + if (SUCCEEDED(hr)) + { + hr = ValidateColorDropProperty(pWiasContext, pPropertyContext, WIA_COLOR_DROP_RED); + } + + // + // Validate WIA_IPS_COLOR_DROP_GREEN (error logging is covered by ValidateColorDropProperty): + // + if (SUCCEEDED(hr)) + { + hr = ValidateColorDropProperty(pWiasContext, pPropertyContext, WIA_COLOR_DROP_GREEN); + } + + // + // Validate WIA_IPS_COLOR_DROP_BLUE (error logging is covered by ValidateColorDropProperty): + // + if (SUCCEEDED(hr)) + { + hr = ValidateColorDropProperty(pWiasContext, pPropertyContext, WIA_COLOR_DROP_BLUE); + } + + return hr; +} -- cgit v1.3.1