diff options
| author | karlf <[email protected]> | 2016-08-11 13:28:13 -0700 |
|---|---|---|
| committer | karlf <[email protected]> | 2016-08-11 13:28:13 -0700 |
| commit | 96eb96dfb613e4c745db6bd1f53a92fe7e2290fc (patch) | |
| tree | ad5f3ede5cbcd6b598677ce41bcf8318471bdd92 /wia | |
| parent | 687b274aa38fd05c8c26e3068932121876d7f745 (diff) | |
Updated for "Windows 10 Anniversary Update" (Version 1607)
Diffstat (limited to 'wia')
99 files changed, 36206 insertions, 0 deletions
diff --git a/wia/ProdScan/BasicArray.h b/wia/ProdScan/BasicArray.h new file mode 100644 index 00000000..8894dabc --- /dev/null +++ b/wia/ProdScan/BasicArray.h @@ -0,0 +1,381 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: BasicArray.h +* +* Project: Production Scanner Driver Sample +* +* Description: Contains the class declaration of the CBasicDynamicArray class. +* +***************************************************************************/ + +#ifndef __SIMARRAY_H_INCLUDED +#define __SIMARRAY_H_INCLUDED + +template<class T> +class CBasicDynamicArray +{ +private: + + int m_nSize; + int m_nMaxSize; + int m_nGrowSize; + T *m_pArray; + + enum + { + eGrowSize = 10 // The number of items to add each time the array grows. + }; + +public: + + CBasicDynamicArray(void) + : m_nSize(0), + m_nMaxSize(0), + m_nGrowSize(eGrowSize), + m_pArray(NULL) + {} + + CBasicDynamicArray( + int nInitialSize, + int nGrowSize = 0) + : m_nSize(0), + m_nMaxSize(0), + m_nGrowSize(nGrowSize ? nGrowSize : eGrowSize), + m_pArray(NULL) + { + GrowTo(nInitialSize); + } + + CBasicDynamicArray( + const CBasicDynamicArray<T> &other) + : m_nSize(0), + m_nMaxSize(0), + m_nGrowSize(eGrowSize), + m_pArray(NULL) + { + Append(other); + } + + ~CBasicDynamicArray( + void) + { + Destroy(); + } + + CBasicDynamicArray& + operator=( + const CBasicDynamicArray &other) + { + if (this != &other) + { + Destroy(); + Append(other); + } + return *this; + } + + void + Destroy( + void) + { + if (m_pArray) + { + delete[] m_pArray; + m_pArray = NULL; + } + m_nSize = m_nMaxSize = 0; + } + + void + Append( + const CBasicDynamicArray &other) + { + if (GrowTo(m_nSize + other.Size())) + { + for (int i = 0; i < other.Size(); i++) + { + Append(other[i]); + } + } + } + + int + Append( + const T &element) + { + int nResult = -1; + if (GrowTo(m_nSize + 1)) + { + m_pArray[m_nSize] = element; + nResult = m_nSize; + m_nSize++; + } + return nResult; + } + + int + Insert( + const T &element, + int nIndex) + { + // + // Make sure we can accomodate this new item: + // + if (GrowTo(m_nSize + 1)) + { + // + // Make sure the item is within the range we've allocated: + // + if ((nIndex >= 0) && (nIndex <= m_nSize)) + { + // + // Make room for the new item by moving all items above up by one slot: + // + for (int i = Size(); i > nIndex; i--) + { + m_pArray[i] = m_pArray[i-1]; + } + + // + // Save the new item: + // + m_pArray[nIndex] = element; + + // + // We're now one larger: + // + m_nSize++; + + // + // Return the index of the slot we used: + // + return nIndex; + } + } + + // + // Return an error + // + return -1; + } + + void + Delete( + int nItem) + { + if ((nItem >= 0) && (nItem < m_nSize) && (m_pArray)) + { + T *pTmpArray = new T[m_nMaxSize]; + if (pTmpArray) + { + T *pSrc = NULL, *pTgt = NULL; + pSrc = m_pArray; + pTgt = pTmpArray; + + for (int i = 0; i < m_nSize; i++) + { + if (i != nItem) + { + *pTgt = *pSrc; + pTgt++; + } + pSrc++; + } + delete[] m_pArray; + m_pArray = pTmpArray; + m_nSize--; + } + } + } + + bool + GrowTo( + int nSize) + { + // + // If the array is already large enough, just return true: + // + if (nSize < m_nMaxSize) + { + return true; + } + + // + // Save old size, in case we can't allocate a new array: + // + int nOldMaxSize = m_nMaxSize; + + // + // Find the correct size to grow to: + // + while (m_nMaxSize < nSize) + { + m_nMaxSize += m_nGrowSize; + } + + // + // Allocate the array: + // + T *pTmpArray = new T[m_nMaxSize]; + if (pTmpArray) + { + // + // Copy the old array over: + // + for (int i = 0; i < m_nSize; i++) + { + pTmpArray[i] = m_pArray[i]; + } + + // + // Delete the old array: + // + if (m_pArray) + { + delete[] m_pArray; + } + + // + // Assign the new array to the old one and return true: + // + m_pArray = pTmpArray; + return true; + } + else + { + // + // If we couldn't allocate the new array, restore the maximum size and return false: + // + m_nMaxSize = nOldMaxSize; + return false; + } + } + + // + // Simple swap: + // + void + Swap( + T& a, + T& b) + { + T t = a; + a = b; + b = t; + } + + int + Find( + const T& element) const + { + for (int i = 0; i < m_nSize; i++) + { + if (m_pArray[i] == element) + { + return i; + } + } + return -1; + } + + bool + operator==( + const CBasicDynamicArray &other) + { + if (Size() != other.Size()) + { + return false; + } + + for (int i = 0; i < Size(); i++) + { + if (!(m_pArray[i] == other[i])) + { + return false; + } + } + return true; + } + + bool + Contains( + const T& element) + { + return (Find(element) >= 0); + } + + void + Size( + int nSize) + { + m_nSize = nSize; + } + + void + MaxSize( + int nMaxSize) + { + m_nMaxSize = nMaxSize; + } + + void + GrowSize( + int nGrowSize) + { + m_nGrowSize = nGrowSize; + } + + int + Size( + void) const + { + return m_nSize; + } + + int + MaxSize( + void) const + { + return m_nMaxSize; + } + + int + GrowSize( + void) const + { + return m_nGrowSize; + } + + T* + GetBuffer( + int nSize) + { + return GrowTo(nSize) ? m_pArray : NULL; + } + + const T* + Array( + void) const + { + return m_pArray; + } + + const T& + operator[]( + int nIndex) const + { + return m_pArray[nIndex]; + } + + T& + operator[]( + int nIndex) + { + return m_pArray[nIndex]; + } +}; + +#endif + diff --git a/wia/ProdScan/CapMan.cpp b/wia/ProdScan/CapMan.cpp new file mode 100644 index 00000000..9758ad67 --- /dev/null +++ b/wia/ProdScan/CapMan.cpp @@ -0,0 +1,515 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: CapMan.cpp +* +* Project: Production Scanner Driver Sample +* +* Description: Contains the implementation for the CWIACapabilityManager +* class, a helper class for managing WIA capabilities +* +***************************************************************************/ + +#include "stdafx.h" + +/**************************************************************************\ +* +* CWIACapabilityManager constructor +* +\**************************************************************************/ + +CWIACapabilityManager::CWIACapabilityManager() +{ + m_ulEvents = 0; + m_ulCommands = 0; +} + +/**************************************************************************\ +* +* CWIACapabilityManager destructor +* +\**************************************************************************/ + +CWIACapabilityManager::~CWIACapabilityManager() +{ + Destroy(); +} + +/**************************************************************************\ +* +* Parameters: +* +* hInstance - module instance handle used for driver resources +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT +CWIACapabilityManager::Initialize( + _In_ HINSTANCE hInstance) +{ + HRESULT hr = S_OK; + + if (!hInstance) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + m_hInstance = hInstance; + } + + return hr; +} + +/**************************************************************************\ +* +* Parameters: +* +* None +* +* Return Value: +* +* None +* +\**************************************************************************/ + +void +CWIACapabilityManager::Destroy() +{ + INT nCapabilities = m_CapabilityArray.Size(); + + for (INT i = 0; i < nCapabilities; i++) + { + FreeCapability(&m_CapabilityArray[i], TRUE); + } + m_CapabilityArray.Destroy(); + + m_ulEvents = 0; + m_ulCommands = 0; +} + +/**************************************************************************\ +* +* Parameters: +* +* guidCapability - capability identifier +* uiNameResourceID - capability name +* uiDescriptionResourceID - capability description +* ulFlags - capability flags +* wszIcon - capability icon +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT +CWIACapabilityManager::AddCapability( + const GUID guidCapability, + UINT uiNameResourceID, + UINT uiDescriptionResourceID, + ULONG ulFlags, + _In_ LPCWSTR wszIcon) +{ + HRESULT hr = S_OK; + WIA_DEV_CAP_DRV *pWIADeviceCapability = NULL; + WCHAR wCapabilityString[MAX_PATH] = {}; + + if (!wszIcon) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + // + // Allocate memory for the new capability structure: + // + if (SUCCEEDED(hr)) + { + hr = AllocateCapability(&pWIADeviceCapability); + if (SUCCEEDED(hr) && (!pWIADeviceCapability)) + { + hr = E_POINTER; + WIAEX_ERROR((g_hInst, "AllocateCapability failed to return a valid pointer, hr = 0x%08X", hr)); + } + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Cannot allocate memory for capability, hr = 0x%08X", hr)); + } + } + + // + // Copy the capability flags and GUID identifier: + // + if (SUCCEEDED(hr)) + { + pWIADeviceCapability->ulFlags = ulFlags; + *pWIADeviceCapability->guid = guidCapability; + } + + // + // Load and copy the capability name from resources: + // + if (SUCCEEDED(hr)) + { + if (LoadString(m_hInstance, uiNameResourceID, wCapabilityString, ARRAYSIZE(wCapabilityString))) + { + hr = StringCbCopyW(pWIADeviceCapability->wszName, MAX_CAPABILITY_STRING_SIZE_BYTES, wCapabilityString); + if(FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to copy source string (%ws) to destination string, hr = 0x%08X", wCapabilityString, hr)); + } + } + else + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Failed to load the device capability name string %u from resources, hr = 0x%08X", uiNameResourceID, hr)); + } + } + + // + // Load and copy the capability description from resources: + // + if (SUCCEEDED(hr)) + { + memset(wCapabilityString, 0, sizeof(wCapabilityString)); + if (LoadString(m_hInstance, uiDescriptionResourceID, wCapabilityString, ARRAYSIZE(wCapabilityString))) + { + hr = StringCbCopyW(pWIADeviceCapability->wszDescription, MAX_CAPABILITY_STRING_SIZE_BYTES, wCapabilityString); + if(FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to copy source string (%ws) to destination string, hr = 0x%08X", wCapabilityString, hr)); + } + } + else + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Failed to load the device capability description string %u from DLL resource, hr = 0x%08X", + uiDescriptionResourceID, hr)); + } + } + + // + // Copy the icon location: + // + if (SUCCEEDED(hr)) + { + memset(pWIADeviceCapability->wszIcon, 0, MAX_CAPABILITY_STRING_SIZE_BYTES); + + hr = StringCbCopyW(pWIADeviceCapability->wszIcon, MAX_CAPABILITY_STRING_SIZE_BYTES, wszIcon); + if(FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to copy source string (%ws) to destination string, hr = 0x%08X", wszIcon, hr)); + } + } + + // + // Add the new capability item to the array: + // + if(SUCCEEDED(hr)) + { + if ((WIA_NOTIFICATION_EVENT & pWIADeviceCapability->ulFlags) || (WIA_ACTION_EVENT & pWIADeviceCapability->ulFlags)) + { + // + // Event capabilities are inserted at the beginning of the array: + // + m_CapabilityArray.Insert(*pWIADeviceCapability, 0); + + m_ulEvents += 1; + } + else + { + // + // Command capabilities are appended at the end of the array: + // + m_CapabilityArray.Append(*pWIADeviceCapability); + + m_ulCommands += 1; + } + + if ((m_ulEvents + m_ulCommands) != (ULONG)m_CapabilityArray.Size()) + { + WIAEX_ERROR((g_hInst, "Counted %u capabilities (%u events, %u commands), recorded %u..", + m_ulEvents + m_ulCommands, m_ulEvents, m_ulCommands, m_CapabilityArray.Size())); + } + } + + // + // Clean up: + // + + if (pWIADeviceCapability) + { + CoTaskMemFree(pWIADeviceCapability); + pWIADeviceCapability = NULL; + } + + return hr; +} + +/**************************************************************************\ +* +* Parameters: +* +* ppWIADeviceCapability - pointer to capability object to allocate +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT +CWIACapabilityManager::AllocateCapability( + _Out_ WIA_DEV_CAP_DRV **ppWIADeviceCapability) +{ + HRESULT hr = S_OK; + WIA_DEV_CAP_DRV *pWIADeviceCapability = NULL; + + if (!ppWIADeviceCapability) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *ppWIADeviceCapability = NULL; + +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "pWIADeviceCapability is freed with FreeCapability when the call fails") + pWIADeviceCapability = (WIA_DEV_CAP_DRV*)CoTaskMemAlloc(sizeof(WIA_DEV_CAP_DRV)); + if (!pWIADeviceCapability) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate memory for WIA_DEV_CAP_DRV structure, hr = 0x%08X", hr)); + } + else + { + // + // Successfully created WIA_DEV_CAP_DRV, now initialize to 0. + // + memset(pWIADeviceCapability, 0, sizeof(WIA_DEV_CAP_DRV)); + } + } + + if (SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed with FreeCapability when the call fails") + pWIADeviceCapability->guid = (GUID*)CoTaskMemAlloc(sizeof(GUID)); + if (!pWIADeviceCapability->guid) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate memory for GUID member of WIA_DEV_CAP_DRV structure, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed with FreeCapability when the call fails") + pWIADeviceCapability->wszName = (LPOLESTR)CoTaskMemAlloc(MAX_CAPABILITY_STRING_SIZE_BYTES); + if (!pWIADeviceCapability->wszName) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate memory for LPOLESTR (wszName) member of WIA_DEV_CAP_DRV structure, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed with FreeCapability when the call fails") + pWIADeviceCapability->wszDescription = (LPOLESTR)CoTaskMemAlloc(MAX_CAPABILITY_STRING_SIZE_BYTES); + if (!pWIADeviceCapability->wszDescription) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate memory for LPOLESTR (wszDescription) member of WIA_DEV_CAP_DRV structure, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed with FreeCapability when the call fails") + pWIADeviceCapability->wszIcon = (LPOLESTR)CoTaskMemAlloc(MAX_CAPABILITY_STRING_SIZE_BYTES); + if (!pWIADeviceCapability->wszIcon) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate memory for LPOLESTR (wszIcon) member of WIA_DEV_CAP_DRV structure, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + *pWIADeviceCapability->guid = GUID_NULL; + memset(pWIADeviceCapability->wszName, 0, MAX_CAPABILITY_STRING_SIZE_BYTES); + memset(pWIADeviceCapability->wszDescription, 0, MAX_CAPABILITY_STRING_SIZE_BYTES); + memset(pWIADeviceCapability->wszIcon, 0, MAX_CAPABILITY_STRING_SIZE_BYTES); + + *ppWIADeviceCapability = pWIADeviceCapability; + } + else if (pWIADeviceCapability) + { + FreeCapability(pWIADeviceCapability); + pWIADeviceCapability = NULL; + } + + return hr; +} + +/**************************************************************************\ +* +* Parameters: +* +* pWIADeviceCapability - pointer to capability object to free +* bFreeCapabilityContentOnly - TRUE to free only the capability content +* or FALSE to free the entire object instance +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +void +CWIACapabilityManager::FreeCapability( + _In_ WIA_DEV_CAP_DRV *pWIADeviceCapability, + BOOL bFreeCapabilityContentOnly) +{ + if (pWIADeviceCapability) + { + if (pWIADeviceCapability->guid) + { + CoTaskMemFree(pWIADeviceCapability->guid); + pWIADeviceCapability->guid = NULL; + } + + if (pWIADeviceCapability->wszName) + { + CoTaskMemFree(pWIADeviceCapability->wszName); + pWIADeviceCapability->wszName = NULL; + } + + if (pWIADeviceCapability->wszDescription) + { + CoTaskMemFree(pWIADeviceCapability->wszDescription); + pWIADeviceCapability->wszDescription = NULL; + } + + if (pWIADeviceCapability->wszIcon) + { + CoTaskMemFree(pWIADeviceCapability->wszIcon); + pWIADeviceCapability->wszIcon = NULL; + } + + if (!bFreeCapabilityContentOnly) + { + CoTaskMemFree(pWIADeviceCapability); + } + } + else + { + WIAEX_ERROR((g_hInst, "Invalid parameter, caller attempted to free a NULL WIA_DEV_CAP_DRV structure")); + } +} + +/**************************************************************************\ +* +* Parameters: +* +* None +* +* Return Value: +* +* Pointer to the capability manager's list of capabilities +* +\**************************************************************************/ + +WIA_DEV_CAP_DRV* +CWIACapabilityManager::GetCapabilities() +{ + WIA_DEV_CAP_DRV* pCapabilities = NULL; + + if ((!m_ulEvents) && (!m_ulCommands)) + { + WIAEX_ERROR((g_hInst, "No capabilities to return")); + pCapabilities = NULL; + } + else + { + pCapabilities = &m_CapabilityArray[0]; + } + + return pCapabilities; +} + +/**************************************************************************\ +* +* Parameters: +* +* None +* +* Return Value: +* +* Pointer to the capability manager's list of command capabilities +* +\**************************************************************************/ + +WIA_DEV_CAP_DRV* +CWIACapabilityManager::GetCommands() +{ + WIA_DEV_CAP_DRV* pCommands = NULL; + + if (!m_ulCommands) + { + WIAEX_ERROR((g_hInst, "No commands to return")); + pCommands = NULL; + } + else + { + // + // Command capabilities are stored at the end of the capability list, after the event capabilities: + // + pCommands = &m_CapabilityArray[m_ulEvents]; + } + + return pCommands; +} + +/**************************************************************************\ +* +* Parameters: +* +* None +* +* Return Value: +* +* Pointer to the capability manager's list of event capabilities +* +\**************************************************************************/ + +WIA_DEV_CAP_DRV* +CWIACapabilityManager::GetEvents() +{ + WIA_DEV_CAP_DRV* pEvents = NULL; + + if (!m_ulEvents) + { + WIAEX_ERROR((g_hInst, "No events to return")); + pEvents = NULL; + } + else + { + // + // Event capabilities are stored at the beginning of the capability list: + // + pEvents = &m_CapabilityArray[0]; + } + + return pEvents; +} diff --git a/wia/ProdScan/CapMan.h b/wia/ProdScan/CapMan.h new file mode 100644 index 00000000..5147cfef --- /dev/null +++ b/wia/ProdScan/CapMan.h @@ -0,0 +1,81 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: CapMan.h +* +* Project: Production Scanner Driver Sample +* +* Description: Contains the class declaration for CWIACapabilityManager +* +***************************************************************************/ + +#pragma once + +#define MAX_CAPABILITY_STRING_SIZE_BYTES (sizeof(WCHAR) * MAX_PATH) + +class CWIACapabilityManager +{ +public: + CWIACapabilityManager(); + ~CWIACapabilityManager(); + +public: + HRESULT + Initialize( + _In_ HINSTANCE hInstance); + + void + Destroy(); + + HRESULT + AddCapability( + const GUID guidCapability, + UINT uiNameResourceID, + UINT uiDescriptionResourceID, + ULONG ulFlags, + _In_ LPCWSTR wszIcon); + + HRESULT + AllocateCapability( + _Out_ WIA_DEV_CAP_DRV **ppWIADeviceCapability); + + void + FreeCapability( + _In_ WIA_DEV_CAP_DRV *pWIADeviceCapability, + BOOL bFreeCapabilityContentOnly = FALSE); + + WIA_DEV_CAP_DRV* + GetCapabilities(); + + WIA_DEV_CAP_DRV* + GetCommands(); + + WIA_DEV_CAP_DRV* + GetEvents(); + + ULONG + GetNumCapabilities() + { + return (m_ulEvents + m_ulCommands); + } + + ULONG + GetNumEvents() + { + return m_ulEvents; + } + + ULONG + GetNumCommands() + { + return m_ulCommands; + } + +private: + HINSTANCE m_hInstance; + CBasicDynamicArray<WIA_DEV_CAP_DRV> m_CapabilityArray; + + ULONG m_ulEvents; + ULONG m_ulCommands; +}; diff --git a/wia/ProdScan/Constants.h b/wia/ProdScan/Constants.h new file mode 100644 index 00000000..1ef3ebb7 --- /dev/null +++ b/wia/ProdScan/Constants.h @@ -0,0 +1,230 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: Constants.h +* +* Project: Production Scanner Driver Sample +* +* Description: Contains declaration for macro definitions and constant +* variables used internally by the Production Scanner Driver Sample. +* Character string constants declared here represent names +* that should not be localized (i.e. put into resources) +* +***************************************************************************/ + +#pragma once + +// +// Minimum and maximum scan area dimensions are hard-coded for this sample driver +// to a size equivalent with a US Letter page size (8.5" x 11"). Note the minimum +// sizes are configured to the same sizes as maximums, reason for this being that +// the sample driver does not crop the test image to transfer. However, for property +// negotiation only the minimum sizes can be changed to lower values, just that +// the driver will ignore a smaller crop frame when scanning. A real driver should +// not do this and must always configure the real scan area dimensions, min and max: +// +#define MAX_SCAN_AREA_WIDTH 8500 +#define MAX_SCAN_AREA_HEIGHT 11000 +#define MIN_SCAN_AREA_WIDTH MAX_SCAN_AREA_WIDTH +#define MIN_SCAN_AREA_HEIGHT MAX_SCAN_AREA_HEIGHT + +// +// Minimum and maximum imprinter area dimensions are hard-coded as well for this +// sample driver. These dimensions match the sample test imprinter image size: +// +#define IMPRINTER_MAX_WIDTH 640 +#define IMPRINTER_MAX_HEIGHT 480 +#define IMPRINTER_MIN_WIDTH IMPRINTER_MAX_WIDTH +#define IMPRINTER_MIN_HEIGHT IMPRINTER_MAX_HEIGHT + +// +// This sample driver does not support landscape orientation: +// +#define LANDSCAPE_SUPPOPRTED 0 + +// +// The optical/native and only scan resolution for the sample driver is 300 DPI: +// +#define OPTICAL_RESOLUTION 300 + +// +// When scanning from the Feeder with WIA_IPS_PAGES set to ALL_PAGES or from the Auto +// source (when the the WIA_IPS_PAGES is not accessible) this sample driver has +// a hard-coded limit of the number of pages to 'scan' and transfer: +// +#define MAX_SCAN_PAGES 200 + +// +// The following constants define the number of pages "scanned" when the sample +// driver simulates that it detects a job separator page or a multi-feed error +// when job separators and/or multi-feed detection is enabled: +// +#define JOB_SEPARATOR_AT_PAGE 3 +#define MULTI_FEED_AT_PAGE 5 + +// +// WIA Item Tree item names (hard-coded): +// +#define WIA_DRIVER_ROOT_NAME L"Root" +#define WIA_DRIVER_FLATBED_NAME L"Flatbed" +#define WIA_DRIVER_FEEDER_NAME L"Feeder" +#define WIA_DRIVER_AUTO_NAME L"Auto" +#define WIA_DRIVER_IMPRINTER_NAME L"Imprinter" +#define WIA_DRIVER_ENDORSER_NAME L"Endorser" +#define WIA_DRIVER_BARCODE_READER_NAME L"Barcode Reader" +#define WIA_DRIVER_PATCH_CODE_READER_NAME L"Patch Code Reader" +#define WIA_DRIVER_MICR_READER_NAME L"MICR Reader" + +// +// File name extension constants used for WIA_IPA_FILENAME_EXTENSION: +// +#define FILE_EXT_BMP L"BMP" +#define FILE_EXT_JPG L"JPG" +#define FILE_EXT_RAW L"RAW" +#define FILE_EXT_CSV L"CSV" +#define FILE_EXT_TXT L"TXT" +#define FILE_EXT_XML L"XML" + +// +// Valid characters for the pretended imprinter and endorser units for this sample driver: +// +#define SAMPLE_IMPRINTER_VALID_CHARS L"0123456789abcdefghijklmnoprstuvwxzyABCDEFGHIJKLMNOPRSTUVWXZY$~!@#$*%^(){}[]|+-=<>.?_: ," +#define SAMPLE_ENDORSER_VALID_CHARS L"0123456789ademnloprSstx ," + +// +// Byte Order Mark (BOM) for the imprinter/endorser text when packaged in WiaImgFmt_CSV and +// WiaImgFmt_TXT files. This text must be encoded UTF-16 little-endian byte order, double-byte +// fixed size characters only (no surrogate pairs), and must be prefixed with this BOM: +// +const BYTE g_bBOM[] = +{ + 0xFF, + 0xFE +}; + +// +// Valid barcode types claimed for the barcode reader implemented by this sample driver: +// +const LONG g_lSupportedBarcodeTypes[] = +{ + WIA_BARCODE_UPCA, + WIA_BARCODE_UPCE, + WIA_BARCODE_CODABAR, + WIA_BARCODE_NONINTERLEAVED_2OF5, + WIA_BARCODE_INTERLEAVED_2OF5, + WIA_BARCODE_CODE39, + WIA_BARCODE_CODE39_MOD43, + WIA_BARCODE_CODE39_FULLASCII, + WIA_BARCODE_CODE93, + WIA_BARCODE_CODE128, + WIA_BARCODE_CODE128A, + WIA_BARCODE_CODE128B, + WIA_BARCODE_CODE128C, + WIA_BARCODE_GS1128, + WIA_BARCODE_GS1DATABAR, + WIA_BARCODE_ITF14, + WIA_BARCODE_EAN8, + WIA_BARCODE_EAN13, + WIA_BARCODE_POSTNETA, + WIA_BARCODE_POSTNETB, + WIA_BARCODE_POSTNETC, + WIA_BARCODE_POSTNET_DPBC, + WIA_BARCODE_PLANET, + WIA_BARCODE_INTELLIGENT_MAIL, + WIA_BARCODE_POSTBAR, + WIA_BARCODE_RM4SCC, + WIA_BARCODE_HIGH_CAPACITY_COLOR, + WIA_BARCODE_MAXICODE, + WIA_BARCODE_PDF417 +}; + +// +// Valid patch code types claimed for the patch code reader implemented by this sample driver: +// +const LONG g_lSupportedPatchCodeTypes[] = +{ + WIA_PATCH_CODE_1, + WIA_PATCH_CODE_2, + WIA_PATCH_CODE_3, + WIA_PATCH_CODE_4, + WIA_PATCH_CODE_6, + WIA_PATCH_CODE_T +}; + +// +// Constant table of standard WIA document sizes, in Portrait orientation. +// Dimensions are defined in 1/1000ths of an inch. The table is included +// for use in a modified driver based on this sample, the sample driver +// in its current form supporting from this list only WIA_PAGE_LETTER: +// + +typedef struct _WIA_PAGE_SIZE_COMBINATION +{ + LONG m_lPageSize; + LONG m_lPageWidth; + LONG m_lPageHeight; +} WIA_PAGE_SIZE_COMBINATION, *PWIA_WIA_PAGE_SIZE_COMBINATION; + +const WIA_PAGE_SIZE_COMBINATION g_DefinedPageSizeCombinations[] = +{ + { WIA_PAGE_A4, 8267, 11692 }, + { WIA_PAGE_LETTER, 8500, 11000 }, + { WIA_PAGE_USLEGAL, 8500, 14000 }, + { WIA_PAGE_USLEDGER, 11000, 17000 }, + { WIA_PAGE_USSTATEMENT, 5500, 8500 }, + { WIA_PAGE_BUSINESSCARD, 3543, 2165 }, + { WIA_PAGE_ISO_A0, 33110, 46811 }, + { WIA_PAGE_ISO_A1, 23385, 33110 }, + { WIA_PAGE_ISO_A2, 16535, 23385 }, + { WIA_PAGE_ISO_A3, 11692, 16535 }, + { WIA_PAGE_ISO_A5, 5826, 8267 }, + { WIA_PAGE_ISO_A6, 4133, 5826 }, + { WIA_PAGE_ISO_A7, 2913, 4133 }, + { WIA_PAGE_ISO_A8, 2047, 2913 }, + { WIA_PAGE_ISO_A9, 1456, 2047 }, + { WIA_PAGE_ISO_A10, 1023, 1456 }, + { WIA_PAGE_ISO_B0, 39370, 55669 }, + { WIA_PAGE_ISO_B1, 27834, 39370 }, + { WIA_PAGE_ISO_B2, 19685, 27834 }, + { WIA_PAGE_ISO_B3, 13897, 19685 }, + { WIA_PAGE_ISO_B4, 9842, 13897 }, + { WIA_PAGE_ISO_B5, 6929, 9842 }, + { WIA_PAGE_ISO_B6, 4921, 6929 }, + { WIA_PAGE_ISO_B7, 3464, 4921 }, + { WIA_PAGE_ISO_B8, 2440, 3464 }, + { WIA_PAGE_ISO_B9, 1732, 2440 }, + { WIA_PAGE_ISO_B10, 1220, 1732 }, + { WIA_PAGE_ISO_C0, 36102, 51062 }, + { WIA_PAGE_ISO_C1, 25511, 36102 }, + { WIA_PAGE_ISO_C2, 18031, 25511 }, + { WIA_PAGE_ISO_C3, 12755, 18031 }, + { WIA_PAGE_ISO_C4, 9015, 12755 }, + { WIA_PAGE_ISO_C5, 6377, 9015 }, + { WIA_PAGE_ISO_C6, 4488, 6377 }, + { WIA_PAGE_ISO_C7, 3188, 4488 }, + { WIA_PAGE_ISO_C8, 2244, 3188 }, + { WIA_PAGE_ISO_C9, 1574, 2244 }, + { WIA_PAGE_ISO_C10, 1102, 1574 }, + { WIA_PAGE_JIS_B0, 40551, 57322 }, + { WIA_PAGE_JIS_B1, 28661, 40551 }, + { WIA_PAGE_JIS_B2, 20275, 28661 }, + { WIA_PAGE_JIS_B3, 14330, 20275 }, + { WIA_PAGE_JIS_B4, 10118, 14330 }, + { WIA_PAGE_JIS_B5, 7165, 10118 }, + { WIA_PAGE_JIS_B6, 5039, 7165 }, + { WIA_PAGE_JIS_B7, 3582, 5039 }, + { WIA_PAGE_JIS_B8, 2519, 3582 }, + { WIA_PAGE_JIS_B9, 1771, 2519 }, + { WIA_PAGE_JIS_B10, 1259, 1771 }, + { WIA_PAGE_JIS_2A, 46811, 66220 }, + { WIA_PAGE_JIS_4A, 66220, 93622 }, + { WIA_PAGE_DIN_2B, 55669, 78740 }, + { WIA_PAGE_DIN_4B, 78740, 111338 } +}; + +// +// Maximum number of colors for the color dropout feature implemented by this sample driver: +// +const LONG g_lMaxDropColors = 3; +const LONG g_lDefaultDropColors[] = { 0, 0, 0 }; diff --git a/wia/ProdScan/Events.cpp b/wia/ProdScan/Events.cpp new file mode 100644 index 00000000..0960239b --- /dev/null +++ b/wia/ProdScan/Events.cpp @@ -0,0 +1,180 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* Title: Events.cpp +* +* Description: This file contains the IStiUSD methods used for WIA/STI +* events and helper CWiaDriver methods which are event related. +* +***************************************************************************/ + +#include "stdafx.h" + +/**************************************************************************\ +* +* Implements IStiUSD::SetNotificationHandle. Specifies an event handle +* that the driver should use to inform the caller of device events. +* Typically called by the WIA service (the Still Image Event Monitor). +* Also called by the driver itself to control the WIA event mechanism. +* +* The WIA service will pass in a valid handle (created using CreateEvent()), +* indicating that it wants the WIA driver to signal this handle when an +* event occurs in the hardware. +* +* NULL can be passed to this SetNotificationHandle() method. NULL indicates +* that the WIA driver is to STOP all device activity, and exit any event +* wait operations. +* +* Parameters: +* +* hEvent - HANDLE to an event created by the WIA service using CreateEvent() +* This parameter can be NULL, indicating that all previous event +* waiting should be stopped. +* +* Return Value: +* +* If the operation succeeds, the method should return S_OK. +* Otherwise, it should return one of the STIERR-prefixed error +* codes defined in stierr.h. +* +\**************************************************************************/ +HRESULT CWiaDriver::SetNotificationHandle( + _In_opt_ HANDLE hEvent) +{ + if ((hEvent) && (INVALID_HANDLE_VALUE != hEvent)) + { + // + // Enable STI/WIA scan events for this driver: + // + + // + // This event is created and owned by the caller, which may be + // either this driver itself or the WIA service. The owner must + // close the event handle that it owns when calling this method + // with a different parameter. If we attempt to close the event + // handle here we cause an exception on checked builds. In the + // extreme case that the event is not closed by its owner it + // must be closed by the system when the process (in this case + // the WIA service process) terminates. + // + // if (m_hWiaEvent) + // { + // CloseHandle(m_hWiaEvent); + // m_hWiaEvent = NULL; + // } + // + m_hWiaEvent = hEvent; + + // + // Refresh also the backup copy of the event handle: + // + m_hWiaEventStoredCopy = m_hWiaEvent; + } + else + { + // + // Disable STI/WIA scan events for this driver - reset + // the event handle but keep its backup copy, if any + // + m_hWiaEvent = NULL; + + } + + return S_OK; +} + +/**************************************************************************\ +* +* Implements IStiUSD::GetNotificationData. Returns a description of the most +* recent event that occurred on the still image device. If no events have +* occurred since the last time the method was called, the method should return +* STIERR_NOEVENTS. If an event occurred, the driver should return the GUID +* associated with it (STINOTIFY::guidNotificationCode). +* +* GetNotificationData is called both for polled events and interrupt events +* (this driver supports only interrupt events): +* +* 1. [POLLING EVENTS] IStiUSD::GetStatus() reported that there was an event +* pending, by setting the STI_EVENTHANDLING_PENDING flag in the STI_DEVICE_STATUS +* structure. Polling events mechanism is not supported by this driver. +* +* 2. [INTERRUPT EVENTS] The hEvent handle passed in by IStiUSD::SetNotificationHandle() +* was signaled by the hardware, or by calling SetEvent() directly. This is the +* WIA event mechanism this driver supports. +* +* The driver is responsible for filling out the STINOTIFY structure members: +* +* dwSize - size of the STINOTIFY structure. +* +* guidNotificationCode - GUID that represents the event that is to be responded to. +* This should be set to GUID_NULL if no event is to be sent. This will tell the +* WIA service that no event really happened. +* +* abNotificationData - OPTIONAL - vendor specific information. This data is limited +* to 64 bytes of data ONLY. Not used by this driver. +* +* Parameters: +* +* hEvent - caller-supplied handle to a Win32 event, created by calling CreateEvent +* +* Return Value: +* +* If the operation succeeds, the method should return S_OK if there is an event +* signaled or STIERR_NOEVENTS if there are no events. If an error occurrs +* it should return one of the other STIERR-prefixed error codes defined in stierr.h. +* +\**************************************************************************/ +HRESULT CWiaDriver::GetNotificationData( + _Out_ LPSTINOTIFY lpNotify) +{ + HRESULT hr = S_OK; + + if (!lpNotify) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X",hr)); + } + + // + // This sample driver does not signal WIA scan events so we'll return here STIERR_NOEVENTS: + // + if (SUCCEEDED(hr)) + { + hr = STIERR_NOEVENTS; + } + + // + // A real driver would check if the Hardware device signaled a device event + // and if so, fill in the lpNotify response data as following: + // + // if (SUCCEEDED(hr)) + // { + // memset(lpNotify, 0, sizeof(STINOTIFY)); + // lpNotify->dwSize = sizeof(STINOTIFY); + // lpNotify->guidNotificationCode = guidEvent; + // } + // + // where guidEvent would be one of the following: + // + // WIA_EVENT_SCAN_IMAGE + // WIA_EVENT_DEVICE_NOT_READY + // WIA_EVENT_DEVICE_READY + // WIA_EVENT_FLATBED_LID_OPEN + // WIA_EVENT_FLATBED_LID_CLOSED + // WIA_EVENT_FEEDER_LOADED + // WIA_EVENT_FEEDER_EMPTIED + // WIA_EVENT_COVER_OPEN + // WIA_EVENT_COVER_CLOSED + // + // or any other WIA_NOTIFICATION_EVENT and/or WIA_ACTION_EVENT reported to + // IWiaMiniDrv::drvGetCapabilities (see CWiaDriver::drvGetCapabilities). + // + + if (FAILED(hr) && (STIERR_NOEVENTS != hr)) + { + m_hrLastEdviceError = hr; + } + + return hr; +} diff --git a/wia/ProdScan/FileConv.cpp b/wia/ProdScan/FileConv.cpp new file mode 100644 index 00000000..5e3091d2 --- /dev/null +++ b/wia/ProdScan/FileConv.cpp @@ -0,0 +1,730 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* Title: FileConv.cpp +* +* Description: This file contains implementation of utility functions for +* image file format conversions used by the sample driver. +* +***************************************************************************/ + +#include "stdafx.h" + +// +// The GDI+ codec name used for the DIB file format: +// +#define GDIPLUS_BMP_ENCODER L"image/bmp" + +/**************************************************************************\ +* +* Inline function to convert a GDI+ result code to a COM HRESULT, +* similar to the HRESULT_FOM_WIN32 macro. +* +* Parameters: +* +* status - GDI+ return code value +* +* Return Value: +* +* HRESULT describing the GDI+ status, E_FAIL if conversion is possible +* +\**************************************************************************/ + +inline HRESULT +GDISTATUS_TO_HRESULT( + Gdiplus::Status status) +{ + HRESULT hr = E_FAIL; + DWORD dwErr = NO_ERROR; + + switch (status) + { + case Gdiplus::Ok: + hr = S_OK; + break; + + case Gdiplus::InvalidParameter: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::InvalidParameter")); + hr = E_INVALIDARG; + break; + + case Gdiplus::OutOfMemory: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::OutOfMemory")); + hr = E_OUTOFMEMORY; + break; + + case Gdiplus::InsufficientBuffer: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::InsufficientBuffer")); + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + break; + + case Gdiplus::Aborted: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::Aborted")); + hr = E_ABORT; + break; + + case Gdiplus::ObjectBusy: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::ObjectBusy")); + hr = E_PENDING; + break; + + case Gdiplus::FileNotFound: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::FileNotFound")); + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + break; + + case Gdiplus::AccessDenied: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::AccessDenied")); + hr = E_ACCESSDENIED; + break; + + case Gdiplus::UnknownImageFormat: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::UnknownImageFormat")); + hr = HRESULT_FROM_WIN32(ERROR_INVALID_PIXEL_FORMAT); + break; + + case Gdiplus::NotImplemented: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::NotImplemented")); + hr = E_NOTIMPL; + break; + + case Gdiplus::Win32Error: + dwErr = GetLastError(); + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::Win32Error, last error: 0x%08X", dwErr)); + hr = HRESULT_FROM_WIN32(dwErr); + break; + + case Gdiplus::ValueOverflow: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::ValueOverflow")); + hr = E_FAIL; + break; + + case Gdiplus::FontFamilyNotFound: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::FontFamilyNotFound")); + hr = E_FAIL; + break; + + case Gdiplus::FontStyleNotFound: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::FontFamilyNotFound")); + hr = E_FAIL; + break; + + case Gdiplus::NotTrueTypeFont: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::NotTrueTypeFont")); + hr = E_FAIL; + break; + + case Gdiplus::UnsupportedGdiplusVersion: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::UnsupportedGdiplusVersion")); + hr = E_FAIL; + break; + + case Gdiplus::GdiplusNotInitialized: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::GdiplusNotInitialized")); + hr = E_FAIL; + break; + + case Gdiplus::WrongState: + WIAEX_ERROR((g_hInst, "GDI+: Gdiplus::WrongState")); + hr = E_FAIL; + break; + + default: + WIAEX_ERROR((g_hInst, "GDI+: unknown Gdiplus status code (%u)", (ULONG)status)); + hr = E_FAIL; + } + + return hr; +} + +/**************************************************************************\ +* +* Executes GdiplusStartup to initialize the GDI+ engine. Must be called +* before calling ConvertImageToDIB. A matching ShutdownGDIPlus call +* must be always made to stop the GDI+ engine started by this function. +* +* Parameters: +* +* ppToken - token returned by GDI+, must be used when calling ShutdownGDIPlus +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT +InitializeGDIPlus( + _Out_ ULONG_PTR *ppToken) +{ + HRESULT hr = S_OK; + GdiplusStartupInput gdiplusStartupInput; + + if (!ppToken) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + // + // Start the GDI+ engine: + // + if (SUCCEEDED(hr)) + { + hr = GDISTATUS_TO_HRESULT(GdiplusStartup(ppToken, &gdiplusStartupInput, NULL)); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Gdiplus::GdiplusStartup failed, hr = 0x%08X", hr)); + } + } + + return hr; +} + +/**************************************************************************\ +* +* Executes GdiplusShutdown to shutdown the GDI+ engine. +* +* Parameters: +* +* pToken - token obtained from a previous InitializeGDIPlus call +* +* Return Value: +* +* E_INVALIDARG if called with a NULL pToken parameter or S_OK +* (GDI+ does not return a result code for GdiplusShutdown) +* +\**************************************************************************/ + +HRESULT +ShutdownGDIPlus( + _In_ ULONG_PTR pToken) +{ + HRESULT hr = S_OK; + + if (!pToken) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + // + // Shutdown the GDI+ engine: + // + if (SUCCEEDED(hr)) + { + GdiplusShutdown(pToken); + } + + return hr; +} + +/**************************************************************************\ +* +* Internal helper for ConvertImageToDIB. Enumerates available GDI+ image +* format encoders and returns the CLSID of the specified encoder, if available. +* +* Parameters: +* +* wszFormat - GDI+ format name, e.g. "image/bmp" for DIB +* pClisid - returns the CLSID of the GDI+ encoder +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT +_GetEncoderCLSID( + _In_ LPCWSTR wszFormat, + _Out_ CLSID *pClsid) +{ + HRESULT hr = S_OK; + UINT nNumEncoders = 0; + UINT cbEncoderSize = 0; + ImageCodecInfo *pImageCodecInfo = NULL; + + if ((!wszFormat) || (!pClsid)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + hr = GDISTATUS_TO_HRESULT(GetImageEncodersSize(&nNumEncoders, &cbEncoderSize)); + if (SUCCEEDED(hr) && (!cbEncoderSize)) + { + hr = E_FAIL; + } + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Gdiplus::GetImageEncodersSize(%ws) failed, hr = 0x%08X", wszFormat, hr)); + } + } + + if (SUCCEEDED(hr)) + { + pImageCodecInfo = (ImageCodecInfo*)new BYTE[cbEncoderSize]; + if (!pImageCodecInfo) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate memory for the encoder info, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = GDISTATUS_TO_HRESULT(GetImageEncoders(nNumEncoders, cbEncoderSize, pImageCodecInfo)); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Gdiplus::GetImageEncoders(%u encoders) failed, hr = 0x%08X", nNumEncoders, hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + + for (UINT j = 0; j < nNumEncoders; ++j) + { + _Analysis_assume_(cbEncoderSize >= nNumEncoders * sizeof(ImageCodecInfo)); + _Analysis_assume_(wcslen(wszFormat) < (cbEncoderSize / sizeof(WCHAR))); + + if (!wcscmp(pImageCodecInfo[j].MimeType, wszFormat)) + { + *pClsid = pImageCodecInfo[j].Clsid; + hr = S_OK; + break; + } + } + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "No %ws encoder found in %u available GDI+ encoders, hr = 0x%08X", wszFormat, nNumEncoders, hr)); + } + } + + if (pImageCodecInfo) + { + delete[] pImageCodecInfo; + } + + return hr; +} + +/**************************************************************************\ +* +* Converts a GDI+ compatible image to a Windows DIB. +* +* Parameters: +* +* pInputImage - GDI+ Image object containing the image to be converted +* ppOutputStream - returns a new global memory IStream containing the +* converted DIB image file (must be released by caller) +* plImageWidth - (optional) returns the width of the image, in pixels +* plImageHeight - (optional) returns the height of the image, in pixels +* plOutputImageBPL - (optional) returns the estimated number of bytes +* per line for the converted DIB image +* +* Remarks: +* +* The caller is responsible to release the returned IStream object to +* free the memory after successful execution of this function. +* +* The caller must execute InitializeGDIPlus before calling this function. +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT +ConvertImageToDIB( + _In_ Image *pInputImage, + _Outptr_ IStream **ppOutputStream, + _Out_opt_ LONG *plImageWidth, + _Out_opt_ LONG *plImageHeight, + _Out_opt_ LONG *plOutputImageBPL) +{ + HRESULT hr = S_OK; + CLSID clsidBmpEncoder = {}; + LONG lImageWidth = 0; + LONG lImageHeight = 0; + LONG lOutputBPL = 0; + LONG lBitDepth = 0; + + WIAEX_TRACE_BEGIN; + + if ((!pInputImage) || (!ppOutputStream)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + // + // Read the dimensions of the input image: + // + if (SUCCEEDED(hr)) + { + *ppOutputStream = NULL; + + lImageWidth = pInputImage->GetWidth(); + lImageHeight = pInputImage->GetHeight(); + lBitDepth = GetPixelFormatSize(pInputImage->GetPixelFormat()); + + if ((lImageWidth > 0) && (lImageHeight > 0) && (lBitDepth > 0)) + { + lOutputBPL = BytesPerLine(lImageWidth, lBitDepth); + + WIAS_TRACE((g_hInst, "Input image is %u x %u pixels, %u bpp, %u BPL (estimated) on output", + lImageWidth, lImageHeight, lBitDepth, lOutputBPL)); + } + else + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Incorrect image dimensions reported by GDI+ (%d x %d pixels, %d bpp), hr = 0x%08X", + lImageWidth, lImageHeight, lBitDepth, hr)); + } + } + + // + // Retrieve the GDI+ encoder necessary to convert the input image to a DIB: + // + if (SUCCEEDED(hr)) + { + hr = _GetEncoderCLSID(GDIPLUS_BMP_ENCODER, &clsidBmpEncoder); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "The GDI+ %ws encoder appears to be missing or improperly installed, hr = 0x%08X", + GDIPLUS_BMP_ENCODER, hr)); + } + } + + // + // Create the output stream in global memory: + // + if (SUCCEEDED(hr)) + { + hr = CreateStreamOnHGlobal(NULL, TRUE, ppOutputStream); + if (SUCCEEDED(hr) && (!(*ppOutputStream))) + { + hr = E_FAIL; + } + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "CreateStreamOnHGlobal failed, hr = 0x%08X", hr)); + } + } + + // + // Convert and save the image stored in the Image object to the output stream as a DIB: + // + if (SUCCEEDED(hr)) + { + hr = GDISTATUS_TO_HRESULT(pInputImage->Save(*ppOutputStream, &clsidBmpEncoder)); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Image::Save(%ws) failed, hr = 0x%08X", GDIPLUS_BMP_ENCODER, hr)); + } + } + + if (FAILED(hr)) + { + if (ppOutputStream && *ppOutputStream) + { + (*ppOutputStream)->Release(); + *ppOutputStream = NULL; + } + } + + if (SUCCEEDED(hr)) + { + if (plImageWidth) + { + *plImageWidth = lImageWidth; + } + if (plImageHeight) + { + *plImageHeight = lImageHeight; + } + if (plOutputImageBPL) + { + *plOutputImageBPL = lOutputBPL; + } + } + + WIAEX_TRACE_FUNC_HR; + + return hr; +} + +/**************************************************************************\ +* +* Converts a 8-bpp grayscale or 24-bpp RGB color DIB to a WIA Raw image. +* +* Parameters: +* +* ppInputStream - input stream containing the DIB to be converted +* ppOutputStream - returns a new global memory IStream containing the +* converted Raw image file (must be released by caller) +* +* Remarks: +* +* The current form of this function for simplicty supports only 8-bpp +* Grayscale and 24-bpp RGB color images. Palettes are not supported. +* +* The caller is responsible to release the returned IStream object to +* free the memory after successful execution of this function. +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT +ConvertDibToRaw( + _In_ IStream *pInputStream, + _Out_ IStream **ppOutputStream) +{ + HRESULT hr = S_OK; + LARGE_INTEGER liOffset = {}; + WIA_RAW_HEADER wiaRawHeader = {}; + BYTE bGrayPalette[256] = {}; + BITMAPINFOHEADER bih = {}; + ULONG ulDataSize = 0; + ULONG ulDataWritten = 0; + ULONG ulPaletteSize = 0; + + WIAEX_TRACE_BEGIN; + + if ((!pInputStream) || (!ppOutputStream)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08.8X", hr)); + } + else + { + *ppOutputStream = NULL; + } + + liOffset.LowPart = sizeof(BITMAPFILEHEADER); + hr = pInputStream->Seek(liOffset, STREAM_SEEK_SET, NULL); + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "IStream::Seek(%u, STREAM_SEEK_SET, NULL) failed, hr = 0x%08X", liOffset.LowPart, hr)); + } + + if (S_OK == hr) + { + // + // Extract the DIB header from the input stream: + // + hr = pInputStream->Read((void *)&bih, sizeof(bih), &ulDataSize); + if ((S_OK == hr) && (ulDataSize != sizeof(bih))) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Expected to read %u bytes for the DIB header, got %u bytes, hr = 0x%08X", + sizeof(bih), ulDataSize, hr)); + } + + // + // Validate the input DIB and fill in the output Raw header: + // + if (S_OK == hr) + { + if ((bih.biBitCount != 24) && (bih.biBitCount != 8)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Test image must be either 8-bpp Grayscale or 24-bpp RGB Color, hr = 0x%08X", + sizeof(bih), ulDataSize, hr)); + } + else + { + const char szRawSignature[] = "WRAW"; + memcpy(&wiaRawHeader.Tag, szRawSignature, sizeof(DWORD)); + + wiaRawHeader.Version = 0x00010000; + wiaRawHeader.HeaderSize = sizeof(wiaRawHeader); + + wiaRawHeader.XExtent = bih.biWidth; + wiaRawHeader.YExtent = bih.biHeight; + wiaRawHeader.LineOrder = (bih.biHeight < 0) ? WIA_LINE_ORDER_TOP_TO_BOTTOM : WIA_LINE_ORDER_BOTTOM_TO_TOP; + wiaRawHeader.BitsPerPixel = bih.biBitCount; + wiaRawHeader.BytesPerLine = BytesPerLine(bih.biWidth, bih.biBitCount); + wiaRawHeader.ChannelsPerPixel = (8 == bih.biBitCount) ? 1 : 3; + wiaRawHeader.DataType = (8 == bih.biBitCount) ? WIA_DATA_GRAYSCALE : WIA_DATA_RAW_BGR; + wiaRawHeader.BitsPerChannel[0] = 8; + wiaRawHeader.BitsPerChannel[1] = (8 == bih.biBitCount) ? 0 : 8; + wiaRawHeader.BitsPerChannel[2] = (8 == bih.biBitCount) ? 0 : 8; + wiaRawHeader.Compression = WIA_COMPRESSION_NONE; + wiaRawHeader.PhotometricInterp = WIA_PHOTO_WHITE_1; + + // + // The scan resolution is fixed for this sample driver: + // + wiaRawHeader.XRes = OPTICAL_RESOLUTION; + wiaRawHeader.YRes = OPTICAL_RESOLUTION; + + ulDataSize = wiaRawHeader.BytesPerLine * wiaRawHeader.YExtent; + ulPaletteSize = (8 == bih.biBitCount) ? (256 * sizeof(BYTE)) : 0; + + wiaRawHeader.RawDataSize = ulDataSize; + wiaRawHeader.RawDataOffset = ulPaletteSize; + wiaRawHeader.PaletteOffset = 0; + wiaRawHeader.PaletteSize = ulPaletteSize; + + // + // For 8-bpp Grayscale data prepare a standard grayscale palette with entries sorted + // in increasing or decreasing order depending on the photometric interpretation: + // + if (8 == bih.biBitCount) + { + for (UINT i = 0; i < 256; i++) + { + bGrayPalette[i] = (WIA_PHOTO_WHITE_1 == wiaRawHeader.PhotometricInterp) ? (BYTE)i : (255 - (BYTE)i); + } + } + + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.Version = 0x%08X", wiaRawHeader.Version)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.HeaderSize = %u bytes", wiaRawHeader.HeaderSize)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.XExtent = %u pixels", wiaRawHeader.XExtent)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.YExtent = %u pixels", wiaRawHeader.YExtent)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.LineOrder = %u", wiaRawHeader.LineOrder)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.BitsPerPixel = %u bpp", wiaRawHeader.BitsPerPixel)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.BytesPerLine = %u BPL", wiaRawHeader.BytesPerLine)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.ChannelsPerPixel = %u", wiaRawHeader.ChannelsPerPixel)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.DataType = %u", wiaRawHeader.DataType)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.BitsPerChannel[0] = %u bps", wiaRawHeader.BitsPerChannel[0])); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.BitsPerChannel[1] = %u bps", wiaRawHeader.BitsPerChannel[1])); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.BitsPerChannel[2] = %u bps", wiaRawHeader.BitsPerChannel[2])); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.Compression = %u", wiaRawHeader.Compression)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.PhotometricInterp = %u", wiaRawHeader.PhotometricInterp)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.XRes = %u DPI", wiaRawHeader.XRes)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.YRes = %u DPI", wiaRawHeader.YRes)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.RawDataOffset = %u bytes", wiaRawHeader.RawDataOffset)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.RawDataSize = %u bytes", wiaRawHeader.RawDataSize)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.PaletteOffset = %u bytes", wiaRawHeader.PaletteOffset)); + WIAS_TRACE((g_hInst, "WIA_RAW_HEADER.PaletteSize = %u bytes", wiaRawHeader.PaletteSize)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to read the DIB header for the test image, hr = 0x%08X", hr)); + } + + // + // If there is a grayscale palette, jump the input stream pointer past it: + // + if ((S_OK == hr) && (8 == bih.biBitCount)) + { + liOffset.LowPart = 256 * sizeof(RGBQUAD); + hr = pInputStream->Seek(liOffset, STREAM_SEEK_CUR, NULL); + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "IStream::Seek(%u, STREAM_SEEK_SET, NULL) failed, hr = 0x%08X", liOffset.LowPart, hr)); + } + } + + // + // Create the output stream in memory: + // + if (S_OK == hr) + { + hr = CreateStreamOnHGlobal(NULL, TRUE, ppOutputStream); + if (SUCCEEDED(hr) && (!(*ppOutputStream))) + { + hr = E_FAIL; + } + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "CreateStreamOnHGlobal failed, hr = 0x%08X", hr)); + } + } + + // + // Write the Raw header to the output stream: + // + if (S_OK == hr) + { + hr = (*ppOutputStream)->Write(&wiaRawHeader, sizeof(wiaRawHeader), &ulDataWritten); + if (SUCCEEDED(hr) && (sizeof(wiaRawHeader) != ulDataWritten)) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Expected to write %u bytes for the raw header, wrote %u bytes, hr = 0x%08X", + sizeof(wiaRawHeader), ulDataWritten, hr)); + } + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "IStream::Write(%u bytes) failed, hr = 0x%08X", sizeof(wiaRawHeader), hr)); + } + } + + // + // Write the palette (if one) to the output stream: + // + if ((S_OK == hr) && (8 == bih.biBitCount)) + { + hr = (*ppOutputStream)->Write(&bGrayPalette[0], ulPaletteSize, &ulDataWritten); + if (SUCCEEDED(hr) && (ulPaletteSize != ulDataWritten)) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Expected to write %u bytes for the raw palette, wrote %u bytes, hr = 0x%08X", + ulPaletteSize, ulDataWritten, hr)); + } + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "IStream::Write(%u bytes) failed, hr = 0x%08X", ulPaletteSize, hr)); + } + } + + // + // Write the Raw image data to the output stream: + // + if (S_OK == hr) + { + ULARGE_INTEGER uliDataSize = {}, uliRead = {}, uliWritten = {}; + + uliDataSize.LowPart = ulDataSize; + + hr = pInputStream->CopyTo(*ppOutputStream, uliDataSize, &uliRead, &uliWritten); + if ((S_OK == hr) && ((ulDataSize != uliRead.LowPart) || (ulDataSize != uliWritten.LowPart))) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Expected to stream copy %u bytes for the raw image data, copied %u bytes, hr = 0x%08X", + ulDataSize, uliWritten.LowPart, hr)); + } + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "IStream::CopyTo(%u bytes) failed, hr = 0x%08X", ulDataSize, hr)); + } + } + + // + // Reset the output stream seek pointer at the beginning of the stream: + // + if (S_OK == hr) + { + liOffset.LowPart = 0; + hr = (*ppOutputStream)->Seek(liOffset, STREAM_SEEK_SET, NULL); + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "IStream::Seek(0, STREAM_SEEK_SET, NULL) failed, hr = 0x%08X", hr)); + } + } + } + + if ((S_OK != hr) && ppOutputStream && *ppOutputStream) + { + (*ppOutputStream)->Release(); + *ppOutputStream = NULL; + } + + WIAEX_TRACE_FUNC_HR; + + return hr; +} diff --git a/wia/ProdScan/FileConv.h b/wia/ProdScan/FileConv.h new file mode 100644 index 00000000..13e0de97 --- /dev/null +++ b/wia/ProdScan/FileConv.h @@ -0,0 +1,37 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: FileConv.h +* +* Project: Production Scanner Driver Sample +* +* Description: This file contains definitions for the utility functions +* used by the sample driver for image file format conversions. +* +***************************************************************************/ + +#pragma once + +HRESULT +InitializeGDIPlus( + _Out_ ULONG_PTR *ppToken); + +HRESULT +ShutdownGDIPlus( + _In_ ULONG_PTR pToken); + +HRESULT +ConvertImageToDIB( + _In_ Image *pInputImage, + _Outptr_ IStream **ppOutputStream, + _Out_opt_ LONG *plImageWidth = NULL, + _Out_opt_ LONG *plImageHeight = NULL, + _Out_opt_ LONG *plOutputImageBPL = NULL); + +HRESULT +ConvertDibToRaw( + _In_ IStream *pInputStream, + _Out_ IStream **ppOutputStream); + + diff --git a/wia/ProdScan/InitProp.cpp b/wia/ProdScan/InitProp.cpp new file mode 100644 index 00000000..0254112d --- /dev/null +++ b/wia/ProdScan/InitProp.cpp @@ -0,0 +1,3134 @@ +/************************************************************************** +* +* 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; +} diff --git a/wia/ProdScan/MiniDrv.cpp b/wia/ProdScan/MiniDrv.cpp new file mode 100644 index 00000000..3a00291b --- /dev/null +++ b/wia/ProdScan/MiniDrv.cpp @@ -0,0 +1,2619 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* Title: MiniDrv.cpp +* +* Description: This file contains the IWiaMiniDrv interface implementation +* for the Production Scanner Driver Sample, plus C++ constructor and +* destructor code for the main driver's objects, CWiaDriver. +* +***************************************************************************/ + +#include "stdafx.h" + +HINSTANCE g_hInst = NULL; + +/**************************************************************************\ +* +* CWiaDriver constructor +* +\**************************************************************************/ + +CWiaDriver::CWiaDriver( + _In_opt_ LPUNKNOWN punkOuter) : + m_cRef(1), + m_punkOuter(NULL), + m_pIDrvItemRoot(NULL), + m_lClientsConnected(0), + m_bstrDeviceID(NULL), + m_bstrRootFullItemName(NULL), + m_pIStiDevice(NULL), + m_hDeviceKey(NULL), + m_bFeederStarted(FALSE) +{ + // + // See if we are aggregated. If we are (almost always the case) + // save the pointer to the controlling IUnknown, so subsequent + // calls will be delegated. If not, set the same pointer to "this": + // + if (punkOuter) + { + m_punkOuter = punkOuter; + } + else + { + // + // This cast is needed in order to point to right virtual table: + // + m_punkOuter = reinterpret_cast<IUnknown*>(static_cast<INonDelegatingUnknown*>(this)); + } + + memset(m_wszDevicePath, 0, sizeof(m_wszDevicePath)); + + + // + // Warning: do not initialize the entire contents of m_config and m_status to 0, + // this will erase the function pointer tables for the CBasicDynamicArray members! + // + + m_hrLastEdviceError = STI_ERROR_NO_ERROR; + + m_hWiaEvent = NULL; + m_hWiaEventStoredCopy = NULL; + m_bstrScanAvailableItem = NULL; + + // + // IStiUSD::Initialize not executed yet: + // + m_bInitialized = FALSE; + + // + // Initialize the critical section for DestroyDriverItemTree: + // + InitializeCriticalSection(&m_csDestroyDriverItemTree); + + WIAS_TRACE((g_hInst, "Driver object (%p, process: %u) created", this, GetCurrentProcessId())); +} + +/**************************************************************************\ +* +* CWiaDriver destructor +* +\**************************************************************************/ + +CWiaDriver::~CWiaDriver() +{ + DWORD dwProcessId = GetCurrentProcessId(); + DWORD dwThreadId = GetCurrentThreadId(); + + WIAS_TRACE((g_hInst, "Destroying driver object (%p, process: %u, thread: %u)..", + this, dwProcessId, dwThreadId)); + + // + // Free the memory allocated for the global device ID and root item name: + // + if (m_bstrDeviceID) + { + SysFreeString(m_bstrDeviceID); + m_bstrDeviceID = NULL; + } + + if (m_bstrRootFullItemName) + { + SysFreeString(m_bstrRootFullItemName); + m_bstrRootFullItemName = NULL; + } + + // + // Free WIA_FORMAT_INFO arrays: + // + m_tFormatInfo.Destroy(); + m_tFormatInfoImprinterEndorser.Destroy(); + m_tFormatInfoBarcodeReader.Destroy(); + m_tFormatInfoPatchCodeReader.Destroy(); + m_tFormatInfoMicrReader.Destroy(); + + // + // Free cached driver capability array: + // + m_tCapabilityManager.Destroy(); + + // + // Unlink and release the cached IWiaDrvItem root item interface: + // + DestroyDriverItemTree(); + + // + // The driver item tree is destroyed, the critical section can be deleted. + // Make sure there is no concurrent thread releasing the Root item from + // within IWiaMiniDrv::drvUnInitializeWia and delete the critical section: + // + EnterCriticalSection(&m_csDestroyDriverItemTree); + LeaveCriticalSection(&m_csDestroyDriverItemTree); + DeleteCriticalSection(&m_csDestroyDriverItemTree); + + if (m_bstrScanAvailableItem) + { + SysFreeString(m_bstrScanAvailableItem); + m_bstrScanAvailableItem = NULL; + } + + // + // The WIA service may release the driver object during a scanner status update + // operation, for example following an unexpected device disconnect event. + // When this happens we must wait for the critical section to be released before + // deleting it, otherwise the thread owning the CS may remain in an undefined state: + // + + m_bInitialized = FALSE; + + WIAS_TRACE((g_hInst, "Driver object (%p, process: %u, thread: %u) destroyed", this, dwProcessId, dwThreadId)); +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvInitializeWia. Initializes the mini-driver in +* the context of a new WIA application session and creates if needed the +* unique Driver Item Tree describing the item architecture and item names +* that the WIA service will use to create duplicate Application Item Trees +* for each new WIA application session opened with the driver. When the WIA +* service executes this method the driver must receive a character string +* containing the device�s unique identifier along with the IStiDevice COM +* interface pointer describing the current device. The driver must create +* the driver item tree if it hasn�t been built yet. Finally, the driver +* must return back to the WIA service the pointer to the Root item in the +* Driver Item Tree. +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* bstrDeviceID - string containing the device's unique identifier +* bstrRootFullItemName - string containing the full name of the root item +* pStiDevice - points to an IStiDevice interface +* pIUnknownOuter - (optional) to receive an IUnknown interface address +* ppIDrvItemRoot - receives the address of the IWiaDrvItem interface +* for the root item +* ppIUnknownInner - unsupported and always set to NULL (all this driver's WIA +* functionality is covered through its IWiaMiniDrv interface) +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvInitializeWia( + _Inout_ BYTE* pWiasContext, + LONG lFlags, + _In_ BSTR bstrDeviceID, + _In_ BSTR bstrRootFullItemName, + _In_ IUnknown* pStiDevice, + _In_ IUnknown* pIUnknownOuter, + _Out_ IWiaDrvItem** ppIDrvItemRoot, + _Out_ IUnknown** ppIUnknownInner, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(pIUnknownOuter); + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = S_OK; + + // + // (1/2) Uncomment the code below to enable a basic safety guard against premature + // drvInitializeWia call made by WIA Service before IStiUSD::Initialize completes: + // + // If IWiaMiniDrv::drvInitializeWia is called before IStiUSD::Initialize + // is complete wait up to 1 minute (10 msec x 6000 times) and retry: + // + // const LONG lMaxWaitCycles = 6000; + // const LONG lWaitInterval = 10; + // LONG lWaitCycles = 0; + // + + WIAEX_TRACE_BEGIN; + + if ((!pWiasContext) || (!plDevErrVal)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *plDevErrVal = 0; + *ppIDrvItemRoot = NULL; + *ppIUnknownInner = NULL; + + if (!m_bstrDeviceID) + { + m_bstrDeviceID = SysAllocString(bstrDeviceID); + if (!m_bstrDeviceID) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate BSTR DeviceID string, hr = 0x%08X", hr)); + } + } + } + + if (SUCCEEDED(hr)) + { + if (!m_pIStiDevice) + { + m_pIStiDevice = reinterpret_cast<IStiDevice*>(pStiDevice); + } + + if (!m_bstrRootFullItemName) + { + m_bstrRootFullItemName = SysAllocString(bstrRootFullItemName); + if (!m_bstrRootFullItemName) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate BSTR Root full item name string, hr = 0x%08X", hr)); + } + } + } + + if (SUCCEEDED(hr)) + { + if (!m_pIDrvItemRoot) + { + // + // (2/2) Uncomment the code below to enable a basic safety guard against premature + // drvInitializeWia call made by WIA Service before IStiUSD::Initialize completes: + // + // The WIA service may call IWiaMiniDrv::drvInitializeWia before the + // IStiUSD::Initialize call is completed. Temporarily block creating the Driver Item + // Tree until IStiUSD::Initialize is complete: + // + // if (!m_bInitialized) + // { + // WIAS_TRACE((g_hInst, "Driver not intialized yet, wait..")); + // + // // + // // Wait up to 10 msec x 6000 = 1 minute for IStiUSD::Initialize to complete: + // // + // while ((!m_bInitialized) && ((++lWaitCycles) <= lMaxWaitCycles)) + // { + // Sleep(lWaitInterval); + // } + // + // if (m_bInitialized) + // { + // WIAS_TRACE((g_hInst, "Driver intialized now")); + // } + // else + // { + // WIAEX_ERROR((g_hInst, "Maxmimum timeout reached, driver still not initialized")); + // } + // } + // + + // + // Create the Driver Item Tree matching the current scanner configuration: + // + hr = BuildDriverItemTree(); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create the Driver Item Tree, hr = 0x%08X", hr)); + } + } + else + { + // + // The Driver Item Tree already exists. The root item of this item tree + // should be returned to the WIA service: + // + hr = S_OK; + } + } + + // + // Increment the client connection count only when the driver has + // successfully created all the necessary Driver Item Tree items: + // + if (SUCCEEDED(hr)) + { + *ppIDrvItemRoot = m_pIDrvItemRoot; + InterlockedIncrement(&m_lClientsConnected); + WIAS_TRACE((g_hInst,"drvInitializeWia, %d client(s) are currently connected to this driver", m_lClientsConnected)); + } + + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvInitializeWia 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvInitItemProperties. The WIA service builds the +* Application Item Tree and then asks the driver to initialize each item +* executing IWiaMiniDvr::drvInitItemProperties on each before to hand the +* entire tree over to the application (when completing the IWiaDevMgr:: +* CreateDevice or IWiaDevMgr2::CreateDevice call the application makes +* to open a new WIA session). When this method is called the driver is given +* the context of the Application Tree Item to be initialized. The driver must +* populate the item with WIA properties, fully initialized with their names, +* access flags, valid and current values. +* +* This driver supports to create and initialize one of each of the following items: +* +* Root (WIA_CATEGORY_ROOT) +* Flatbed (WIA_CATEGORY_FLATBED, no children) +* Feeder (WIA_CATEGORY_FEEDER, no children) +* Auto (WIA_CATEGORY_AUTO) +* Imprinter (WIA_CATEGORY_IMPRINTER) +* Endorser (WIA_CATEGORY_ENDORSER) +* Barcode Reader (WIA_CATEGORY_BARCODE_READER) +* Patch Code Reader (WIA_CATEGORY_PATCH_CODE_READER) +* MICR Reader (WIA_CATEGORY_MICR_READER) +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvInitItemProperties( + _Inout_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = S_OK; + LONG lItemFlags = 0; + + WIAEX_TRACE_BEGIN; + + if ((!pWiasContext) || (!plDevErrVal)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *plDevErrVal = 0; + + // + // Read WIA_IPA_ITEM_FLAGS to identify the item to be initialized: + // + hr = wiasReadPropLong(pWiasContext, WIA_IPA_ITEM_FLAGS, &lItemFlags, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to read WIA_IPA_ITEM_FLAGS property, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + if (lItemFlags & WiaItemTypeRoot) + { + // + // This is the Root item, initialize the Root item properties as well as the + // Root mini-driver item context containing the scan destination names: + // + + WIAS_TRACE((g_hInst,"IWiaMiniDrv::drvInitItemProperties called for Root..")); + + hr = InitializeRootItemProperties(pWiasContext); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize root item properties, hr = 0x%08X", hr)); + } + } + else if ((lItemFlags & WiaItemTypeProgrammableDataSource) && + (lItemFlags & WiaItemTypeTransfer) && + (lItemFlags & WiaItemTypeFile)) + { + // + // This is a child programmable data source item - detect which one from the item name: + // + + IWiaDrvItem *pIWiaDrvItem = NULL; + BSTR bstrItemName = NULL; + + hr = wiasGetDrvItem(pWiasContext, &pIWiaDrvItem); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to retrieve the current driver item to initialize, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaDrvItem->GetItemName(&bstrItemName); + if (FAILED (hr)) + { + WIAEX_ERROR((g_hInst, "Failed to get the item name, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + if (!wcscmp(WIA_DRIVER_FLATBED_NAME, bstrItemName)) + { + WIAS_TRACE((g_hInst,"IWiaMiniDrv::drvInitItemProperties called for Flatbed..")); + + hr = InitializeChildItemProperties(pWiasContext, FLAT); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize the flatbed item's property set, hr = 0x%08X", hr)); + } + } + else if (!wcscmp(WIA_DRIVER_FEEDER_NAME, bstrItemName)) + { + WIAS_TRACE((g_hInst,"IWiaMiniDrv::drvInitItemProperties called for Feeder..")); + + hr = InitializeChildItemProperties(pWiasContext, FEED); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize the feeder item's property set, hr = 0x%08X", hr)); + } + } + else if (!wcscmp(WIA_DRIVER_AUTO_NAME, bstrItemName)) + { + WIAS_TRACE((g_hInst,"IWiaMiniDrv::drvInitItemProperties called for Auto..")); + + hr = InitializeChildItemProperties(pWiasContext, AUTO_SOURCE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize the automatic input source item's property set, hr = 0x%08X", hr)); + } + } + else if (!wcscmp(WIA_DRIVER_IMPRINTER_NAME, bstrItemName)) + { + WIAS_TRACE((g_hInst,"IWiaMiniDrv::drvInitItemProperties called for Imprinter..")); + + hr = InitializeChildItemProperties(pWiasContext, IMPRINTER); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize the imprinter item's property set, hr = 0x%08X", hr)); + } + } + else if (!wcscmp(WIA_DRIVER_ENDORSER_NAME, bstrItemName)) + { + WIAS_TRACE((g_hInst,"IWiaMiniDrv::drvInitItemProperties called for Endorser..")); + + hr = InitializeChildItemProperties(pWiasContext, ENDORSER); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize the endorser item's property set, hr = 0x%08X", hr)); + } + } + else if (!wcscmp(WIA_DRIVER_BARCODE_READER_NAME, bstrItemName)) + { + WIAS_TRACE((g_hInst,"IWiaMiniDrv::drvInitItemProperties called for Barcode Reader..")); + + hr = InitializeChildItemProperties(pWiasContext, BARCODE_READER); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize the barcode reader item's property set, hr = 0x%08X", hr)); + } + } + else if (!wcscmp(WIA_DRIVER_PATCH_CODE_READER_NAME, bstrItemName)) + { + WIAS_TRACE((g_hInst,"IWiaMiniDrv::drvInitItemProperties called for Patch Code Reader..")); + + hr = InitializeChildItemProperties(pWiasContext, PATCH_CODE_READER); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize the patch code reader item's property set, hr = 0x%08X", hr)); + } + } + else if (!wcscmp(WIA_DRIVER_MICR_READER_NAME, bstrItemName)) + { + WIAS_TRACE((g_hInst,"IWiaMiniDrv::drvInitItemProperties called for MICR Reader..")); + + hr = InitializeChildItemProperties(pWiasContext, MICR_READER); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize the MICR reader item's property set, hr = 0x%08X", hr)); + } + } + else + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Unsupported item (item name: %ws), hr = 0x%08X", bstrItemName, hr)); + } + + if (bstrItemName) + { + SysFreeString(bstrItemName); + } + } + } + else if (lItemFlags & WiaItemTypeGenerated) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "WiaItemTypeGenerated items are not supported by this driver, hr = 0x%08X", hr)); + } + else + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Unsupported item (item flags: 0x%X), hr = 0x%08X", lItemFlags, hr)); + } + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvInitItemProperties 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvValidateItemProperties. The WIA Service calls +* IWiaMinIDrv::drvValidateItemProperties for properties that an application +* requested to be changed through a IWiaPropertyStorage::WriteMultiple call. +* The driver should validate each individual set request against the set of +* valid property values in the current context and if validation is successful +* it must update all dependent properties. +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* nPropSpec - indicates the number of properties in the pPropSpec array +* pPropSpec - list of PROPSPEC elements for the properties to be validated +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvValidateItemProperties( + _Inout_ BYTE *pWiasContext, + LONG lFlags, + ULONG nPropSpec, + _In_reads_(nPropSpec) const PROPSPEC *pPropSpec, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = S_OK; + WIA_PROPERTY_CONTEXT PropertyContext = {}; + PROPID *pPropID = NULL; + BOOL bPropertyContext = FALSE; + LONG lDocumentHandlingSelect = FLAT; + LONG lItemType = 0; + + WIAEX_TRACE_BEGIN; + + if ((!pWiasContext) || (!pPropSpec) || (!plDevErrVal) || (!nPropSpec)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *plDevErrVal = 0; + + hr = wiasGetItemType(pWiasContext, &lItemType); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to get item type, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + if (lItemType & WiaItemTypeRoot) + { + // + // Root item properties for this sample driver do not need any additional validation: + // + hr = S_OK; + } + else + { + GUID guidItemCategory = {}; + + // + // Read WIA_IPA_ITEM_CATEGORY to figure out which child item this is + // (the item names can be also used for this identification purpose, + // and should be used if there is more than one item with the same + // item category): + // + 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)); + } + + // + // We need to create an array of property IDs for the properties to be added to the default + // ones existing in the property context to be built with wiasCreatePropContext + // + if (SUCCEEDED(hr)) + { + pPropID = (PROPID*) CoTaskMemAlloc(sizeof(PROPID) * nPropSpec); + if (pPropID) + { + for (ULONG i = 0; i < nPropSpec; i++) + { + pPropID[i] = pPropSpec[i].propid; + } + } + else + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Out of memory, hr = 0x%08X", hr)); + } + } + + // + // Create a propery context for the properties being validated: + // + if (SUCCEEDED(hr)) + { + if (IsEqualGUID(WIA_CATEGORY_FLATBED, guidItemCategory)) + { + lDocumentHandlingSelect = FLAT; + } + else if (IsEqualGUID(WIA_CATEGORY_FEEDER, guidItemCategory)) + { + lDocumentHandlingSelect = FEED; + } + else if (IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory)) + { + lDocumentHandlingSelect = AUTO_SOURCE; + } + else if (IsEqualGUID(WIA_CATEGORY_IMPRINTER, guidItemCategory)) + { + lDocumentHandlingSelect = IMPRINTER; + } + else if (IsEqualGUID(WIA_CATEGORY_ENDORSER, guidItemCategory)) + { + lDocumentHandlingSelect = ENDORSER; + } + else if (IsEqualGUID(WIA_CATEGORY_BARCODE_READER, guidItemCategory)) + { + lDocumentHandlingSelect = BARCODE_READER; + } + else if (IsEqualGUID(WIA_CATEGORY_PATCH_CODE_READER, guidItemCategory)) + { + lDocumentHandlingSelect = PATCH_CODE_READER; + } + else if (IsEqualGUID(WIA_CATEGORY_MICR_READER, guidItemCategory)) + { + lDocumentHandlingSelect = MICR_READER; + } + + hr = wiasCreatePropContext(nPropSpec, (PROPSPEC*)pPropSpec, nPropSpec, pPropID, &PropertyContext); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create WIA property context to validate %u properties, hr = 0x%08X", nPropSpec, hr)); + } + else + { + bPropertyContext = TRUE; + } + } + + // + // Validate format properties and update as necessary: + // + // WIA_IPA_DATATYPE + // WIA_IPA_DEPTH + // WIA_IPA_CHANNELS_PER_PIXEL + // WIA_IPA_BITS_PER_CHANNEL + // WIA_IPA_FORMAT + // WIA_IPA_FILENAME_EXTENSION + // WIA_IPA_TYMED + // WIA_IPA_COMPRESSION + // + if (SUCCEEDED(hr)) + { + hr = ValidateFormatProperties(pWiasContext, &PropertyContext, lDocumentHandlingSelect); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to validate format properties, hr = 0x%08X", hr)); + } + } + + if ((FLAT == lDocumentHandlingSelect) || (FEED == lDocumentHandlingSelect)) + { + // + // Validate scan region/document size 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 (SUCCEEDED(hr)) + { + hr = ValidateRegionProperties(pWiasContext, &PropertyContext, lDocumentHandlingSelect); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to validate region properties, hr = 0x%08X", hr)); + } + } + + // + // Validate image information properties: + // + // WIA_IPA_PIXELS_PER_LINE + // WIA_IPA_NUMBER_OF_LINES + // WIA_IPA_BYTES_PER_LINE + // + if (SUCCEEDED(hr)) + { + hr = ValidateImageInfoProperties(pWiasContext, &PropertyContext, lDocumentHandlingSelect); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to validate image information properties, hr = 0x%08X", hr)); + } + } + + // + // Validate color drop properties: + // + // WIA_IPS_COLOR_DROP_RED + // WIA_IPS_COLOR_DROP_GREEN and + // WIA_IPS_COLOR_DROP_BLUE + // + if (SUCCEEDED(hr)) + { + hr = ValidateColorDropProperties(pWiasContext, &PropertyContext, lDocumentHandlingSelect); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to validate color drop properties, hr = 0x%08X", hr)); + } + } + + // + // Validate other feeder specific properties: + // + // WIA_IPS_DOCUMENT_HANDLING_SELECT + // WIA_IPS_PAGES + // + if (SUCCEEDED(hr) && (FEED == lDocumentHandlingSelect)) + { + hr = ValidateFeedProperties(pWiasContext, &PropertyContext); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to validate feeder specific properties, hr = 0x%08X", hr)); + } + } + } + else if ((IMPRINTER == lDocumentHandlingSelect) || (ENDORSER == lDocumentHandlingSelect)) + { + hr = ValidateImprinterEndorserProperties(pWiasContext, &PropertyContext, lDocumentHandlingSelect); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to validate imprinter/endorser specific properties, hr = 0x%08X", hr)); + } + } + else if (BARCODE_READER == lDocumentHandlingSelect) + { + hr = ValidateBarcodeReaderProperties(pWiasContext, &PropertyContext); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to validate barcode reader specific properties, hr = 0x%08X", hr)); + } + } + else if (PATCH_CODE_READER == lDocumentHandlingSelect) + { + hr = ValidatePatchCodeReaderProperties(pWiasContext, &PropertyContext); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to validate patch code reader specific properties, hr = 0x%08X", hr)); + } + } + else if (MICR_READER == lDocumentHandlingSelect) + { + hr = ValidateMicrReaderProperties(pWiasContext, &PropertyContext); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to validate MICR reader specific properties, hr = 0x%08X", hr)); + } + } + + // + // Validate all changed properties against their (for some of the above properties) updated valid values: + // + if (SUCCEEDED(hr)) + { + hr = wiasValidateItemProperties(pWiasContext, nPropSpec, pPropSpec); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to validate properties using wiasValidateItemProperties, hr = 0x%08X", hr)); + } + } + + // + // Free the property context created, if any: + // + if (bPropertyContext) + { + HRESULT FreePropContextHR = wiasFreePropContext(&PropertyContext); + if (FAILED(FreePropContextHR)) + { + WIAEX_ERROR((g_hInst, "wiasFreePropContext failed, hr = 0x%08X", FreePropContextHR)); + } + } + } + } + + if (pPropID) + { + CoTaskMemFree(pPropID); + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvValidateItemProperties 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvWriteItemProperties. When this method is called +* the driver is given the chance to send to the scanner device the settings +* dictated by the current property values. +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* pmdtc - the device transfer context +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvWriteItemProperties( + _Inout_ BYTE* pWiasContext, + LONG lFlags, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = S_OK; + LONG lItemType = 0; + + WIAEX_TRACE_BEGIN; + + if ((!pWiasContext) || (!pmdtc) || (!plDevErrVal)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *plDevErrVal = 0; + + hr = wiasGetItemType(pWiasContext, &lItemType); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to get item type, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr) && (lItemType & WiaItemTypeRoot)) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Acquisitions are not supported from the Root item, hr = 0x%08X", hr)); + } + + // + // Apply to the device the scan settings described by the current WIA property configuration. + // Note that this is not the best time to ask the scanner device to validate settings: validation + // should be performed during IWiaMiniDrv/CWiaDriver::drvValidateItemProperties. + // + // ... + // + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvWriteItemProperties 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvReadItemProperties. Reads the device item +* properties. When a client application tries to read a WIA item's properties +* the WIA service will first notify the driver by calling this method. +* The driver should then update any property values that need to be updated +* in real-time from the device every time the application attempts to read +* them (e.g. WIA_DPS_DOCUMENT_HANDLING_STATUS). +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* nPropSpec - number of properties in pPropSpec array +* pPropSpec - list of properties to be read +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvReadItemProperties( + _In_ BYTE* pWiasContext, + LONG lFlags, + ULONG nPropSpec, + _In_ const PROPSPEC* pPropSpec, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(nPropSpec); + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = S_OK; + LONG lItemFlags = 0; + + // + // Omitted on pupose, not really usefull without full property information: + // + // WIAEX_TRACE_BEGIN; + // + + if ((!pWiasContext) || (!pPropSpec) || (!plDevErrVal)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *plDevErrVal = 0; + + hr = wiasReadPropLong(pWiasContext, WIA_IPA_ITEM_FLAGS, &lItemFlags, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to read WIA_IPA_ITEM_FLAGS property, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + // + // The following properties require to be updated at run-time: + // + // For the Root item: + // + // WIA_DPS_DOCUMENT_HANDLING_STATUS (*) + // WIA_DPA_CONNECT_STATUS (*) + // WIA_DPS_SCAN_AVAILABLE_ITEM + // + // * - not updated by this sample driver since no HW device connection exists, + // but should be updated by a real scanner driver + // + // For the Flatbed and Feeder items: + // + // None + // + + if (lItemFlags & WiaItemTypeRoot) + { + // + // Update WIA_DPS_SCAN_AVAILABLE_ITEM with the last globally stored + // (per driver instance) item name signaled with an unconsumed scan ready event: + // + hr = UpdateScanAvailableItemProperty(pWiasContext); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update the WIA_DPS_SCAN_AVAILABLE_ITEM property (%ws), hr = 0x%08X", + m_bstrScanAvailableItem ? m_bstrScanAvailableItem : L"<empty string>", hr)); + } + } + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvReadItemProperties 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvLockWiaDevice. The IWiaMiniDrv::drvLockWiaDevice +* method locks the hardware device so that only the current minidriver can +* access it. This sample driver returns S_OK without doing anything special. +* Note that the WIA Service expects this method to succeed for a properly +* installed driver and a working scanner device. See also IStiUSD::LockDevice. +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvLockWiaDevice( + _In_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(pWiasContext); + UNREFERENCED_PARAMETER(lFlags); + + *plDevErrVal = 0; + + return S_OK; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvUnLockWiaDevice. The sample driver returns S_OK. +* The WIA Service expects this method to succeed for a properly installed +* driver and a working scanner device). See also IStiUSD::UnlockDevice. +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvUnLockWiaDevice( + _In_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(pWiasContext); + UNREFERENCED_PARAMETER(lFlags); + + *plDevErrVal = 0; + + return S_OK; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvAnalyzeItem. This sample driver returns +* E_NOTIMPL as it does not support image item analysis. +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* E_NOTIMPL +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvAnalyzeItem( + _In_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(pWiasContext); + UNREFERENCED_PARAMETER(lFlags); + + WIAEX_ERROR((g_hInst, "IWiaMiniDrv::drvAnalyzeItem, this method is not implemented or supported for this driver")); + + m_hrLastEdviceError = STIERR_UNSUPPORTED; + + *plDevErrVal = 0; + + return E_NOTIMPL; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvGetDeviceErrorStr. This driver returns +* E_NOTIMPL because no localized text descriptions of the generic errors +* signaled by IWiaMiniDrv calls are available. +* +* Parameters: +* +* lFlags - reserved (set to 0) +* lDevErrVal - the device error value to be mapped to a string +* ppszDevErrStr - receives the address of a string describing the error +* plDevErr - a status code for this method +* +* Return Value: +* +* E_NOTIMPL +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvGetDeviceErrorStr( + LONG lFlags, + LONG lDevErrVal, + _Out_ LPOLESTR* ppszDevErrStr, + _Out_ LONG* plDevErr) +{ + UNREFERENCED_PARAMETER(lFlags); + UNREFERENCED_PARAMETER(lDevErrVal); + + WIAEX_ERROR((g_hInst, "IWiaMiniDrv::drvGetDeviceErrorStr, this method is not implemented or supported for this driver")); + + if (plDevErr) + { + *plDevErr = WIA_ERROR_INVALID_COMMAND; + } + + if (ppszDevErrStr) + { + *ppszDevErrStr = NULL; + } + + m_hrLastEdviceError = STIERR_UNSUPPORTED; + + return E_NOTIMPL; +} + +/**************************************************************************\ +* +* Helper for CWiaDriver::drvUnInitializeWia. Destroys the Driver Item Tree. +* +* Parameters: +* +* None +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::DestroyDriverItemTree() +{ + HRESULT hr = S_OK; + + WIAEX_TRACE_BEGIN; + + // + // By design the WIA service allows an application to release the Root item at the + // same time as the WIA service releases the WIA driver object following a device + // disconnection. If there are no other applications connected to the driver the + // driver would attempt to unlink and release the Root item concurrently from two + // different threads - one thread executing IWiaMiniDrv::drvUnInitializeWia, the + // other thread executing INonDelegating::NonDelegatingRelease: + // + EnterCriticalSection(&m_csDestroyDriverItemTree); + + if (m_pIDrvItemRoot) + { + WIAS_TRACE((g_hInst,"Unlinking WIA item tree")); + + hr = m_pIDrvItemRoot->UnlinkItemTree(WiaItemTypeDisconnected); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to unlink WIA item tree before being released, hr = 0x%08X", hr)); + } + + // + // Proceed releasing the Root item even if the tree could not be unlinked: + // + + WIAS_TRACE((g_hInst, "Releasing IDrvItemRoot interface")); + + __try + { + m_pIDrvItemRoot->Release(); + } +#pragma prefast(suppress:__WARNING_EXCEPTIONEXECUTEHANDLER, "Note that EXCEPTION_EXECUTE_HANDLER may mask exceptions that may be individually handled otherwise") + __except (EXCEPTION_EXECUTE_HANDLER) + { + hr = WIA_ERROR_ITEM_DELETED; + WIAEX_ERROR((g_hInst, "Exception 0x%08X when calling Release on the Root item, item no longer valid, hr = 0x%08X", + GetExceptionCode(), hr)); + } + + m_pIDrvItemRoot = NULL; + + // + // Keep the current scanner configuration data as well as the transfer format + // information array initialized after it, until the scanner device signals + // that the configuration has been changed or the driver is unloaded. + // + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + LeaveCriticalSection(&m_csDestroyDriverItemTree); + + WIAEX_TRACE_FUNC_HR; + + return hr; +} + +/**************************************************************************\ +* +* Helper for CWiaDriver::drvInitializeWia. Creates the Driver Item Tree. +* Called during IWiaMiniDrv::drvInitializeWia when no Driver Item Tree exists +* and also during IWiaMiniDrv::drvDeviceCommand for WIA_CMD_SYNCHRONIZE and +* WIA_CMD_BUILD_DEVICE_TREE. Note that the scanner configuration can be read +* for the first time (in this driver session) during IStiUSD::Initialize. +* +* Parameters: +* +* None +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::BuildDriverItemTree() +{ + HRESULT hr = S_OK; + BSTR bstrRootItemName = NULL; + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; + + // + // All child items implemented by this sample driver except the Auto, Barcode, Patch Code and MICR Reader + // items, support all item flags as the Flatbed and Feeder items do minus the WiaItemTypeImage flag. The + // Imprinter and Endorser items support the same item flags as Flatbed and Feeder, including WiaItemTypeImage, + // since these sample Imprinter and Endorser items support graphics data transfers. + // + const LONG lRootItemFlags = WiaItemTypeFolder | WiaItemTypeDevice | WiaItemTypeRoot; + const LONG lCommonChildItemFlags = WiaItemTypeTransfer | WiaItemTypeFile | WiaItemTypeProgrammableDataSource; + + WIAEX_TRACE_BEGIN; + + // + // The method creates the Driver Item Tree only if it doesn't exist: + // + if (!m_pIDrvItemRoot) + { + WIAS_TRACE((g_hInst, "Building Driver Item Tree....")); + + if (!m_bInitialized) + { + hr = E_UNEXPECTED; + WIAEX_ERROR((g_hInst, "Driver not fully initialized, cannot create Driver Item Tree, hr = 0x%08X", hr)); + } + + // + // Reinitialize the WIA_FORMAT_INFO arrays: + // + if (SUCCEEDED(hr)) + { + hr = InitializeFormatInfoArrays(); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize WIA_FORMAT_INFO array, hr = 0x%08X", hr)); + } + } + + // + // Create the default WIA root item. Note that we need item context data for the root item as well as children: + // + + if (SUCCEEDED(hr)) + { + bstrRootItemName = SysAllocString(WIA_DRIVER_ROOT_NAME); + if (!bstrRootItemName) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate memory for the root item name, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = wiasCreateDrvItem(lRootItemFlags, bstrRootItemName, m_bstrRootFullItemName, + (IWiaMiniDrv*)this, sizeof(WIA_DRIVER_ITEM_CONTEXT), + (BYTE **)&pWiaDriverItemContext, &m_pIDrvItemRoot); + if (SUCCEEDED(hr) && ((!pWiaDriverItemContext) || (!m_pIDrvItemRoot))) + { + hr = E_POINTER; + } + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create the WIA root item (hr = 0x%08X)", hr)); + } + } + + // + // Initialize the item context data for the root item: + // + if (SUCCEEDED(hr)) + { + memset(pWiaDriverItemContext, 0, sizeof(WIA_DRIVER_ITEM_CONTEXT)); + + // + // The Root item is not using this image cache as it does not allow uploads (or download transfers): + // + pWiaDriverItemContext->m_pUploadedImage = NULL; + } + + // + // Create child items that represent programmable data sources: + // + + if (SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(WIA_DRIVER_FLATBED_NAME, (IWiaMiniDrv*)this, m_pIDrvItemRoot, + WiaItemTypeImage | lCommonChildItemFlags, WIA_CATEGORY_FLATBED, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create the Flatbed item, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(WIA_DRIVER_FEEDER_NAME, (IWiaMiniDrv*)this, m_pIDrvItemRoot, + WiaItemTypeImage | lCommonChildItemFlags, WIA_CATEGORY_FEEDER, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create the Feeder item, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(WIA_DRIVER_AUTO_NAME, (IWiaMiniDrv*)this, m_pIDrvItemRoot, + lCommonChildItemFlags, WIA_CATEGORY_AUTO, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create the Auto item, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(WIA_DRIVER_IMPRINTER_NAME, (IWiaMiniDrv*)this, m_pIDrvItemRoot, + WiaItemTypeImage | lCommonChildItemFlags, WIA_CATEGORY_IMPRINTER, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create the Imprinter item, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(WIA_DRIVER_ENDORSER_NAME, (IWiaMiniDrv*)this, m_pIDrvItemRoot, + WiaItemTypeImage | lCommonChildItemFlags, WIA_CATEGORY_ENDORSER, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create the Endorser item, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(WIA_DRIVER_BARCODE_READER_NAME, (IWiaMiniDrv*)this, m_pIDrvItemRoot, + lCommonChildItemFlags, WIA_CATEGORY_BARCODE_READER, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create the Barcode Reader item, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(WIA_DRIVER_PATCH_CODE_READER_NAME, (IWiaMiniDrv*)this, m_pIDrvItemRoot, + lCommonChildItemFlags, WIA_CATEGORY_PATCH_CODE_READER, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create the Path Code Reader item, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(WIA_DRIVER_MICR_READER_NAME, (IWiaMiniDrv*)this, m_pIDrvItemRoot, + lCommonChildItemFlags, WIA_CATEGORY_MICR_READER, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to create the MICR Reader item, hr = 0x%08X", hr)); + } + } + + if (bstrRootItemName) + { + SysFreeString(bstrRootItemName); + } + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE_FUNC_HR; + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvDeviceCommand. The method IWiaMiniDrv:: +* drvDeviceCommand is called by the WIA service to issue a WIA service +* or application generated command to the driver. The WIA service only +* calls the IWiaMiniDrv::drvDeviceCommand method for a command that the +* driver reports to be supported during IWiaMiniDrv::drvGetCapabilities. +* This driver creates or destroys the Driver Item Tree as requested. +* +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* pguidCommand - WIA command GUID +* ppWiaDrvItem - always set to NULL (this driver does not need to create +* an additional item when a WIA command is executed) +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvDeviceCommand( + _Inout_ BYTE* pWiasContext, + LONG lFlags, + _In_ const GUID* pguidCommand, + _Out_ IWiaDrvItem** ppWiaDrvItem, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = S_OK; + + WIAEX_TRACE_BEGIN; + + if ((!pWiasContext) || (!pguidCommand) || (!plDevErrVal)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + // + // The following commands are supported by this driver: + // + // WIA_CMD_SYNCHRONIZE: deletes and recreates the Driver Item Tree + // WIA_CMD_DELETE_DEVICE_TREE: deletes the Driver Item Tree + // WIA_CMD_BUILD_DEVICE_TREE: creates the Driver Item Tree + // WIA_CMD_START_FEEDER: starts the scanner feeder motor, preparing for scan + // WIA_CMD_STOP_FEEDER: stops the scanner feeder motor + // + if (SUCCEEDED(hr)) + { + *plDevErrVal = 0; + *ppWiaDrvItem = NULL; + + if (IsEqualGUID(WIA_CMD_SYNCHRONIZE, *pguidCommand)) + { + WIAS_TRACE((g_hInst, "WIA_CMD_SYNCHRONIZE")); + + // + // Delete the current Driver Item Tree: + // + hr = DestroyDriverItemTree(); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to delete the current DIT for WIA_CMD_SYNCHRONIZE, hr = 0x%08X", hr)); + } + + // + // Re-create the Driver Item Tree according with the current device configuration: + // + if (SUCCEEDED(hr)) + { + hr = BuildDriverItemTree(); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to re-create the DIT for WIA_CMD_SYNCHRONIZE, hr = 0x%08X", hr)); + } + + // + // Queue tree updated event, regardless of whether BuildDriverItemTree succeeded, + // since we can't guarantee that the tree was left in the same condition: + // + QueueWIAEvent(pWiasContext, WIA_EVENT_TREE_UPDATED); + } + } + else if (IsEqualGUID(WIA_CMD_DELETE_DEVICE_TREE, *pguidCommand)) + { + WIAS_TRACE((g_hInst, "WIA_CMD_DELETE_DEVICE_TREE")); + + if (!m_pIDrvItemRoot) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "WIA_CMD_DELETE_DEVICE_TREE called when no DIT exists, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + hr = DestroyDriverItemTree(); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to delete the current DIT for WIA_CMD_DELETE_DEVICE_TREE, hr = 0x%08X", hr)); + } + } + } + else if (IsEqualGUID(WIA_CMD_BUILD_DEVICE_TREE, *pguidCommand)) + { + WIAS_TRACE((g_hInst, "WIA_CMD_BUILD_DEVICE_TREE")); + + if (m_pIDrvItemRoot) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "WIA_CMD_BUILD_DEVICE_TREE called when DIT already exists, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + hr = BuildDriverItemTree(); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to re-create the DIT for WIA_CMD_BUILD_DEVICE_TREE, hr = 0x%08X", hr)); + } + + // + // Queue tree updated event, regardless ofwhether BuildDriverItemTree succeeded, + // since we can't guarantee that the tree was left in the same condition: + // + QueueWIAEvent(pWiasContext, WIA_EVENT_TREE_UPDATED); + } + } + else if (IsEqualGUID(WIA_CMD_START_FEEDER, *pguidCommand) || IsEqualGUID(WIA_CMD_STOP_FEEDER, *pguidCommand)) + { + GUID guidItemCategory = GUID_NULL; + LONG lFeederMotorControl = WIA_FEEDER_CONTROL_AUTO; + + if (IsEqualGUID(WIA_CMD_START_FEEDER, *pguidCommand)) + { + WIAS_TRACE((g_hInst, "WIA_CMD_START_FEEDER")); + } + else + { + WIAS_TRACE((g_hInst, "WIA_CMD_STOP_FEEDER")); + } + + // + // The feeder motor commands are valid only on the Feeder item: + // + hr = wiasReadPropGuid(pWiasContext, WIA_IPA_ITEM_CATEGORY, &guidItemCategory, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to read WIA_IPA_ITEM_CATEGORY, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr) && (!IsEqualGUID(guidItemCategory, WIA_CATEGORY_FEEDER))) + { + hr = WIA_ERROR_INVALID_COMMAND; + WIAEX_ERROR((g_hInst, "WIA_CMD_START/STOP_FEEDER commands are valid only on the Feeder item, hr = 0x%08X", hr)); + } + + // + // WIA_IPS_FEEDER_CONTROL must be set to WIA_FEEDER_CONTROL_MANUAL: + // + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_FEEDER_CONTROL, &lFeederMotorControl, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to read WIA_IPS_FEEDER_CONTROL property, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr) && (WIA_FEEDER_CONTROL_MANUAL != lFeederMotorControl)) + { + hr = WIA_ERROR_INVALID_COMMAND; + WIAEX_ERROR((g_hInst, "WIA_CMD_START/STOP_FEEDER commands are valid only when WIA_IPS_FEEDER_CONTROL is set to WIA_FEEDER_CONTROL_MANUAL, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + if (IsEqualGUID(WIA_CMD_START_FEEDER, *pguidCommand)) + { + hr = StartFeeder(); + } + else + { + hr = StopFeeder(); + } + } + } + else + { + hr = E_NOTIMPL; + WIAEX_ERROR((g_hInst, "The requested WIA command is not implemented or supported by this driver")); + } + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvDeviceCommand 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvGetCapabilities. The WIA service calls +* IWiaMiniDrv::drvGetCapabilities to obtain a list of hardware command +* capabilities and/or STI/WIA device events supported by the driver. +* +* Parameters: +* +* pWiasContext - pointer to the item context (may be NULL) +* lFlags - reserved (set to 0) +* pcelt - receives the number of elements in the array +* pointed to by the ppCapabilities parameter +* ppCapabilities - receives the address of the first element +* of an array of WIA_DEV_CAP_DRV structures that +* contain the GUIDs of events and commands that +* the device supports +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK if successful, an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvGetCapabilities( + _In_opt_ BYTE* pWiasContext, + LONG ulFlags, + _Out_ LONG* pcelt, + _Out_ WIA_DEV_CAP_DRV** ppCapabilities, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(pWiasContext); + UNREFERENCED_PARAMETER(ulFlags); + + HRESULT hr = S_OK; + BOOL bAddCapabilities = FALSE; + BOOL bGetCommands = FALSE; + BOOL bGetEvents = FALSE; + + WIAEX_TRACE_BEGIN; + + // + // Note that pWiasContext may be NULL when the driver signals an event + // before the Driver Item Tree is created and WIA service makes this call. + // It is also unused so we won't verify it: + // + if ((!pcelt) || (!ppCapabilities) || (!plDevErrVal)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *plDevErrVal = 0; + *pcelt = 0; + *ppCapabilities = NULL; + + bAddCapabilities = (BOOL)(!m_tCapabilityManager.GetNumCapabilities()); + } + + // + // Add WIA_EVENT_DEVICE_CONNECTED: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_DEVICE_CONNECTED, IDS_EVENT_DEVICE_CONNECTED_NAME, IDS_EVENT_DEVICE_CONNECTED_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_DEVICE_CONNECTED); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_DEVICE_CONNECTED to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_DEVICE_DISCONNECTED: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_DEVICE_DISCONNECTED, IDS_EVENT_DEVICE_DISCONNECTED_NAME, + IDS_EVENT_DEVICE_DISCONNECTED_DESCRIPTION, WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_DEVICE_DISCONNECTED); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_DEVICE_DISCONNECTED to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_POWER_SUSPEND: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_POWER_SUSPEND, IDS_EVENT_POWER_SUSPEND_NAME, IDS_EVENT_POWER_SUSPEND_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_DEVICE_DISCONNECTED); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_POWER_SUSPEND to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_POWER_RESUME: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_POWER_RESUME, IDS_EVENT_POWER_RESUME_NAME, IDS_EVENT_POWER_RESUME_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_DEVICE_CONNECTED); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_POWER_RESUME to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_TREE_UPDATED: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_TREE_UPDATED, IDS_EVENT_TREE_UPDATED_NAME, + IDS_EVENT_TREE_UPDATED_DESCRIPTION, WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_TREE_UPDATED); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_TREE_UPDATED to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // The sample driver does not signal at run time any of the events initialized below: + // + // WIA_EVENT_SCAN_IMAGE + // WIA_EVENT_DEVICE_NOT_READY + // WIA_EVENT_DEVICE_READY + // WIA_EVENT_FLATBED_LID_OPEN + // WIA_EVENT_FLATBED_LID_CLOSED + // WIA_EVENT_FEEDER_LOADED + // WIA_EVENT_FEEDER_EMPTIED + // WIA_EVENT_COVER_OPEN + // WIA_EVENT_COVER_CLOSED + // + // To signal one of these events, set the m_hWiaEvent and then WIA will issue a IStiUSD::GetNotificationData + // to receive the GUID of the particular event that is signaled: + // + // if (!SetEvent(m_hWiaEvent)) + // { + // dwErr = ::GetLastError(); + // hr = HRESULT_FROM_WIN32(dwErr); + // if (SUCCEEDED(hr)) + // { + // hr = E_FAIL; + // } + // WIAEX_ERROR((g_hInst, "SetEvent(WiaEvent) failed (0x%08X), hr = 0x%08X", dwErr, hr)); + // } + // + // + + // + // Add WIA_EVENT_SCAN_IMAGE: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_SCAN_IMAGE, IDS_EVENT_SCAN_IMAGE_NAME, IDS_EVENT_SCAN_IMAGE_DESCRIPTION, + WIA_NOTIFICATION_EVENT | WIA_ACTION_EVENT, (LPCWSTR)WIA_ICON_SCAN_BUTTON_PRESS); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_SCAN_IMAGE to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_DEVICE_NOT_READY: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_DEVICE_NOT_READY, IDS_EVENT_DEVICE_NOT_READY_NAME, IDS_EVENT_DEVICE_NOT_READY_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_DEVICE_NOT_READY); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_DEVICE_NOT_READY to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_DEVICE_READY: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_DEVICE_READY, IDS_EVENT_DEVICE_READY_NAME, IDS_EVENT_DEVICE_READY_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_DEVICE_READY); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_DEVICE_READY to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_FLATBED_LID_OPEN: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_FLATBED_LID_OPEN, IDS_EVENT_FLATBED_LID_OPEN_NAME, IDS_EVENT_FLATBED_LID_OPEN_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_FLATBED_LID_OPEN); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_FLATBED_LID_OPEN to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_FLATBED_LID_CLOSED: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_FLATBED_LID_CLOSED, IDS_EVENT_FLATBED_LID_CLOSED_NAME, IDS_EVENT_FLATBED_LID_CLOSED_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_FLATBED_LID_CLOSED); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_FLATBED_LID_CLOSED to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_FEEDER_LOADED: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_FEEDER_LOADED, IDS_EVENT_FEEDER_LOADED_NAME, IDS_EVENT_FEEDER_LOADED_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_FEEDER_LOADED); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_FEEDER_LOADED to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_FEEDER_EMPTIED: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_FEEDER_EMPTIED, IDS_EVENT_FEEDER_EMPTIED_NAME, IDS_EVENT_FEEDER_EMPTIED_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_FEEDER_EMPTIED); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_FEEDER_EMPTIED to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_COVER_OPEN: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_COVER_OPEN, IDS_EVENT_COVER_OPEN_NAME, IDS_EVENT_COVER_OPEN_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_COVER_OPEN); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_COVER_OPEN to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_EVENT_COVER_CLOSED: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_EVENT_COVER_CLOSED, IDS_EVENT_COVER_CLOSED_NAME, IDS_EVENT_COVER_CLOSED_DESCRIPTION, + WIA_NOTIFICATION_EVENT, (LPCWSTR)WIA_ICON_COVER_CLOSED); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_EVENT_COVER_CLOSED to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_CMD_SYNCRONIZE: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_CMD_SYNCHRONIZE, IDS_CMD_SYNCHRONIZE_NAME, + IDS_CMD_SYNCHRONIZE_DESCRIPTION, 0, (LPCWSTR)WIA_ICON_SYNCHRONIZE); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_CMD_SYNCHRONIZE to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_CMD_DELETE_DEVICE_TREE: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_CMD_DELETE_DEVICE_TREE, IDS_CMD_DELETE_DEVICE_TREE_NAME, + IDS_CMD_DELETE_DEVICE_TREE_DESCRIPTION, 0, (LPCWSTR)WIA_ICON_DELETE_DEVICE_TREE); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_CMD_DELETE_DEVICE_TREE to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_CMD_BUILD_DEVICE_TREE: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_CMD_BUILD_DEVICE_TREE, IDS_CMD_BUILD_DEVICE_TREE_NAME, + IDS_CMD_BUILD_DEVICE_TREE_DESCRIPTION, 0, (LPCWSTR)WIA_ICON_BUILD_DEVICE_TREE); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_CMD_BUILD_DEVICE_TREE to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_CMD_START_FEEDER: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_CMD_START_FEEDER, IDS_CMD_START_FEEDER_NAME, + IDS_CMD_START_FEEDER_DESCRIPTION, 0, (LPCWSTR)WIA_ICON_START_FEEDER); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_CMD_START_FEEDER to the list of capabilities, hr = 0x%08X", hr)); + } + } + + // + // Add WIA_CMD_STOP_FEEDER: + // + if (SUCCEEDED(hr) && bAddCapabilities) + { + hr = m_tCapabilityManager.AddCapability(WIA_CMD_STOP_FEEDER, IDS_CMD_STOP_FEEDER_NAME, + IDS_CMD_STOP_FEEDER_DESCRIPTION, 0, (LPCWSTR)WIA_ICON_STOP_FEEDER); + + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add WIA_CMD_STOP_FEEDER to the list of capabilities, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + bGetCommands = (BOOL)(WIA_DEVICE_COMMANDS == (ulFlags & WIA_DEVICE_COMMANDS)); + bGetEvents = (BOOL)(WIA_DEVICE_EVENTS == (ulFlags & WIA_DEVICE_EVENTS)); + + if ((bGetCommands) && (bGetEvents)) + { + *ppCapabilities = m_tCapabilityManager.GetCapabilities(); + *pcelt = m_tCapabilityManager.GetNumCapabilities(); + WIAS_TRACE((g_hInst, "drvGetCapabilities, application is asking for Commands and Events, we have %d total capabilities", *pcelt)); + } + else if (bGetCommands) + { + *ppCapabilities = m_tCapabilityManager.GetCommands(); + *pcelt = m_tCapabilityManager.GetNumCommands(); + WIAS_TRACE((g_hInst, "drvGetCapabilities, application is asking for Commands, we have %d", *pcelt)); + } + else if (bGetEvents) + { + *ppCapabilities = m_tCapabilityManager.GetEvents(); + *pcelt = m_tCapabilityManager.GetNumEvents(); + WIAS_TRACE((g_hInst,"drvGetCapabilities, application is asking for Events, we have %d", *pcelt)); + } + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvGetCapabilities 0x%08X (%u events, %u commands)", + hr, m_tCapabilityManager.GetNumEvents(), m_tCapabilityManager.GetNumCommands())); + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvDeleteItem. Deletes a driver item. The items +* supported by this sample driver cannot be deleted by the application. +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* STG_E_ACCESSDENIED to signal access denied (items cannot be deleted) +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvDeleteItem( + _Inout_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + UNREFERENCED_PARAMETER(pWiasContext); + + HRESULT hr = STG_E_ACCESSDENIED; + + WIAEX_ERROR((g_hInst, "This item cannot be deleted, hr = 0x%08X", hr)); + + m_hrLastEdviceError = hr; + + *plDevErrVal = 0; + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvDeleteItem 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvFreeDrvItemContext. When a driver item is +* deleted, the WIA service frees the driver item context. This method +* informs the driver that the context is ready to be freed. The driver +* must free any memory allocated for the given driver item context. +* The driver won�t support items that can be deleted by the application +* but this method is going to be called by the WIA service the entire +* item tree is released at the end of a session. +* +* Parameters: +* +* lFlags - reserved (set to 0) +* pSpecContext - points to a device-specific context +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvFreeDrvItemContext( + LONG lFlags, + _In_reads_bytes_(sizeof(WIA_DRIVER_ITEM_CONTEXT)) + BYTE *pSpecContext, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + *plDevErrVal = 0; + + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = (WIA_DRIVER_ITEM_CONTEXT *)pSpecContext; + + if (pWiaDriverItemContext && pWiaDriverItemContext->m_pUploadedImage) + { + pWiaDriverItemContext->m_pUploadedImage->Release(); + pWiaDriverItemContext->m_pUploadedImage = NULL; + } + + WIAS_TRACE((g_hInst, "IWiaMiniDrv::drvFreeDrvItemContext 0x%08X", S_OK)); + + // + // This method must not fail + // + + return S_OK; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvGetWiaFormatInfo. This method creates an array +* of WIA_FORMAT_INFO structures that describe the media types and image +* formats that the driver supports. +* +* Parameters: +* +* pWiasContext - points to a device-specific context +* lFlags - reserved (set to 0) +* pcelt - receives the number of items in the ppwfi array +* ppwfi - array of WIA_FORMAT_INFO structures filled on return +* plDevErrVal - always set to 0 by this driver (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK if succeeds, a standard COM error code otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvGetWiaFormatInfo( + _In_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* pcelt, + _Out_ WIA_FORMAT_INFO** ppwfi, + _Out_ LONG* plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = S_OK; + GUID guidItemCategory = WIA_CATEGORY_ROOT; + LONG lNumFormats = 0; + WIA_FORMAT_INFO *pFormatInfo = NULL; + + WIAEX_TRACE_BEGIN; + + if ((!plDevErrVal) || (!pcelt) || (!ppwfi)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *plDevErrVal = 0; + } + + if (pWiasContext) + { + 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)); + } + } + + // + // This method is allowed to be called only on a transfer capable child item: + // + if (SUCCEEDED(hr)) + { + if (IsEqualGUID(WIA_CATEGORY_FEEDER, guidItemCategory)) + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for the Feeder..", hr)); + } + else if (IsEqualGUID(WIA_CATEGORY_FLATBED, guidItemCategory)) + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for the Flatbed..", hr)); + } + else if (IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory)) + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for the Auto image source..", hr)); + } + else if (IsEqualGUID(WIA_CATEGORY_IMPRINTER, guidItemCategory)) + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for the Imprinter..", hr)); + } + else if (IsEqualGUID(WIA_CATEGORY_ENDORSER, guidItemCategory)) + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for the Endorser..", hr)); + } + else if (IsEqualGUID(WIA_CATEGORY_BARCODE_READER, guidItemCategory)) + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for the Barcode Reader..", hr)); + } + else if (IsEqualGUID(WIA_CATEGORY_PATCH_CODE_READER, guidItemCategory)) + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for the Patch Code Reader..", hr)); + } + else if (IsEqualGUID(WIA_CATEGORY_MICR_READER, guidItemCategory)) + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for the MICR Reader..", hr)); + } + else + { + if (IsEqualGUID(WIA_CATEGORY_ROOT, guidItemCategory)) + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for Root..", hr)); + } + else + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for an unknown item, assuming Root..", hr)); + } + guidItemCategory = WIA_CATEGORY_ROOT; + } + } + } + else + { + WIAS_TRACE((g_hInst, "drvGetWiaFormatInfo called for a NULL item context, assuming Root..", hr)); + guidItemCategory = WIA_CATEGORY_ROOT; + } + + // + // Check the number of available formats + // + if (SUCCEEDED(hr)) + { + // + // Note that the format info arrays are initialized on IStiUSD::Initialize + // so they may be available even before the Driver Item Tree is created: + // + if (IsEqualGUID(WIA_CATEGORY_FEEDER, guidItemCategory) || + IsEqualGUID(WIA_CATEGORY_FLATBED, guidItemCategory) || + IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory) || + IsEqualGUID(WIA_CATEGORY_ROOT, guidItemCategory)) + { + lNumFormats = m_tFormatInfo.Size(); + pFormatInfo = (WIA_FORMAT_INFO *)m_tFormatInfo.Array(); + } + else if (IsEqualGUID(WIA_CATEGORY_IMPRINTER, guidItemCategory) || + IsEqualGUID(WIA_CATEGORY_ENDORSER, guidItemCategory)) + { + lNumFormats = m_tFormatInfoImprinterEndorser.Size(); + pFormatInfo = (WIA_FORMAT_INFO *)m_tFormatInfoImprinterEndorser.Array(); + } + else if (IsEqualGUID(WIA_CATEGORY_BARCODE_READER, guidItemCategory)) + { + lNumFormats = m_tFormatInfoBarcodeReader.Size(); + pFormatInfo = (WIA_FORMAT_INFO *)m_tFormatInfoBarcodeReader.Array(); + } + else if (IsEqualGUID(WIA_CATEGORY_PATCH_CODE_READER, guidItemCategory)) + { + lNumFormats = m_tFormatInfoPatchCodeReader.Size(); + pFormatInfo = (WIA_FORMAT_INFO *)m_tFormatInfoPatchCodeReader.Array(); + } + else if (IsEqualGUID(WIA_CATEGORY_MICR_READER, guidItemCategory)) + { + lNumFormats = m_tFormatInfoMicrReader.Size(); + pFormatInfo = (WIA_FORMAT_INFO *)m_tFormatInfoMicrReader.Array(); + } + + if ((!lNumFormats) || (!pFormatInfo)) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Unexpected, the format array must be initialized first, hr = 0x%08X", hr)); + } + } + + // + // Return the requested list: + // + if (SUCCEEDED(hr)) + { + *pcelt = lNumFormats; + *ppwfi = pFormatInfo; + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvGetWiaFormatInfo 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvNotifyPnpEvent. The WIA service notifies the +* driver of a supported PnP system event by calling this method. +* A real driver could respond to these events for example by releasing and +* redoing its connection with the Hardware device (and possibly signaling +* to a locally connected device that it can enter or resume power saving itself) +* when the computer goes into and exists stand-by and hibernation. +* +* The driver must check the pEventGUID parameter to determine what event +* is being processed. The events that are processed by the driver are: +* +* WIA_EVENT_POWER_SUSPEND - system is going to suspend/sleep mode +* WIA_EVENT_POWER_RESUME - system is waking up from suspend/sleep mode +* WIA_EVENT_DEVICE_DISCONNECTED - device is disconnected, driver will be unloaded +* WIA_EVENT_CANCEL_IO - pending IO is being cancelled +* +* The driver does not execute any special action on the following events: +* +* WIA_EVENT_DEVICE_CONNECTED (*)- driver initialization is being done on IStiUSD::Initialize +* +* (* - The driver logs a trace message following WIA_EVENT_DEVICE_CONNECTED +* and ensures the current device connection state is correctly recorded) +* +* Parameters: +* +* pEventGUI - GUID identifying the event +* bstrDeviceID - string containing the device's unique identifier +* ulReserved - reserved for system use +* +* Return Value: +* +* S_OK if succeeds, a standard COM error code otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvNotifyPnpEvent( + _In_ const GUID* pEventGUID, + _In_ BSTR bstrDeviceID, + ULONG ulReserved) +{ + UNREFERENCED_PARAMETER(ulReserved); + + HRESULT hr = S_OK; + + WIAEX_TRACE_BEGIN; + + if (!pEventGUID) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + if (bstrDeviceID) + { + WIAS_TRACE((g_hInst, "PnP event notification received for device ID %ws", bstrDeviceID)); + } + + if (WIA_EVENT_POWER_SUSPEND == *pEventGUID) + { + WIAS_TRACE((g_hInst, "WIA_EVENT_POWER_SUSPEND")); + + // + // Disable WIA events: + // + SetNotificationHandle(NULL); + } + else if (WIA_EVENT_POWER_RESUME == *pEventGUID) + { + WIAS_TRACE((g_hInst, "WIA_EVENT_POWER_RESUME")); + + if ((!m_hWiaEventStoredCopy) || (INVALID_HANDLE_VALUE == m_hWiaEventStoredCopy)) + { + hr = E_UNEXPECTED; + WIAEX_ERROR((g_hInst, "Failed to re-enable WIA events for WIA_EVENT_POWER_RESUME, invalid event handle, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + // + // Re-enable WIA events: + // + hr = SetNotificationHandle(m_hWiaEventStoredCopy); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to re-enable WIA events on WIA_EVENT_POWER_RESUME, hr = 0x%08X", hr)); + } + } + } + else if (WIA_EVENT_DEVICE_CONNECTED == *pEventGUID) + { + WIAS_TRACE((g_hInst, "WIA_EVENT_DEVICE_CONNECTED")); + + // + // When the driver receives this event the driver is already loaded and initialized + // and a new driver object is already created. Ensure the correct connection state + // is recorded - note that this is not required as when the driver is reloaded + // SetDeviceConnected(TRUE) is already executed from within the CWiaDriver + // constructor when the new driver object instance is created. + // + } + else if (WIA_EVENT_DEVICE_DISCONNECTED == *pEventGUID) + { + WIAS_TRACE((g_hInst, "WIA_EVENT_DEVICE_DISCONNECTED")); + + // + // The driver is notified that the scanner device is disconnected and that the WIA + // service will soon unload the driver. The device communication interface will be + // uninitialized when the driver will be unloaded. The SetDeviceConnected(FALSE) call + // below will record the current state so when the device communication interface will + // be uninitialized (when the driver object will be released by the WIA service before + // unloading the driver) the driver won't log excessive errors to the WIA trace log + // when device operation requests will fail because the device won't be available): + // + + // + // Disable WIA events: + // + SetNotificationHandle(NULL); + } + else if (WIA_EVENT_CANCEL_IO == *pEventGUID) + { + WIAS_TRACE((g_hInst, "WIA_EVENT_CANCEL_IO")); + } + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvNotifyPnpEvent 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvUnInitializeWia. The WIA service calls the +* IWiaMiniDrv::drvUnInitializeWia method when the resources associated +* with an application item tree are no longer needed. The driver must +* free all resources allocated for this application session. +* +* Parameters: +* +* pWiasContext - points to a device-specific context +* +* Return Value: +* +* S_OK if succeeds, a standard COM error code otherwise +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvUnInitializeWia( + _Inout_ BYTE* pWiasContext) +{ + HRESULT hr = S_OK; + + WIAEX_TRACE_BEGIN; + + // + // Watch out to not prematurely fail this request... we must + // succeed freeing resources when this is called no matter what. + // + + if (InterlockedDecrement(&m_lClientsConnected) < 0) + { + WIAS_TRACE((g_hInst, + "drvUnInitializeWia, the client connection counter decremented below zero. Assuming no clients are currently connected and automatically setting to 0")); + m_lClientsConnected = 0; + } + + WIAS_TRACE((g_hInst, "drvUnInitializeWia, %d client(s) are currently connected to this driver", m_lClientsConnected)); + + if (!m_lClientsConnected) + { + // + // When the last client disconnects, destroy the WIA item tree. + // This should reduce the idle memory foot print of this driver: + // + DestroyDriverItemTree(); + } + + if (!pWiasContext) + { + WIAEX_ERROR((g_hInst, "drvUnInitializeWia called with NULL item context parameter (!!!); still, request completed, hr = 0x%08X", hr)); + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvUnInitializeWia 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Helper for CWiaDriver::drvDeviceCommand.Starts the scanner feeder. +* +* Parameters: +* +* None +* +* Return Value: +* +* S_OK if successful or an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT +CWiaDriver::StartFeeder() +{ + HRESULT hr = S_OK; + + if (!m_bFeederStarted) + { + // + // Start feeder + // + // ... + // + + m_bFeederStarted = TRUE; + WIAS_TRACE((g_hInst, "Feeder started")); + } + + return hr; +} + +/**************************************************************************\ +* +* Helper for CWiaDriver::drvDeviceCommand.Stops the scanner feeder. +* +* Parameters: +* +* None +* +* Return Value: +* +* S_OK if successful or an error HRESULT otherwise +* +\**************************************************************************/ + +HRESULT +CWiaDriver::StopFeeder() +{ + HRESULT hr = S_OK; + + if (m_bFeederStarted) + { + // + // Stop feeder + // + // ... + // + + m_bFeederStarted = FALSE; + WIAS_TRACE((g_hInst, "Feeder stopped")); + } + + return hr; +} diff --git a/wia/ProdScan/MiniDrv.h b/wia/ProdScan/MiniDrv.h new file mode 100644 index 00000000..4c4eb3f1 --- /dev/null +++ b/wia/ProdScan/MiniDrv.h @@ -0,0 +1,611 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: MiniDrv.h +* +* Project: Production Scanner Driver Sample +* +* Description: Contains the declaration for the CWiaDriver class +* implementing the main driver object +* +***************************************************************************/ + +#pragma once + +extern HINSTANCE g_hInst; + +// +// WIA mini-driver item context data, customized for this sample driver: +// +typedef struct _WIA_DRIVER_ITEM_CONTEXT +{ + // + // In-memory stream holding an images optionally uploaded by + // the WIA application to the Imprinter or the Endorser item. + // If such images are not uploaded by the application in the + // current WIA app session, when a image download is requested + // from one of these items, the driver loads its test image + // from resources: + // + IStream* m_pUploadedImage; + +} WIA_DRIVER_ITEM_CONTEXT, *PWIA_DRIVER_ITEM_CONTEXT; + +// +// INonDelegatingUnknown +// + +class INonDelegatingUnknown +{ +public: + virtual STDMETHODIMP + NonDelegatingQueryInterface(REFIID riid,LPVOID *ppvObj) = 0; + + virtual STDMETHODIMP_(ULONG) + NonDelegatingAddRef() = 0; + + virtual STDMETHODIMP_(ULONG) + NonDelegatingRelease() = 0; +}; + +// +// CWiaDriver class implementing INonDelegatingUnknown, +// IStiUSD (STI USD interface) and IWiaMiniDrv (WIA mini-driver interface): +// + +class CWiaDriver : + public INonDelegatingUnknown, + public IStiUSD, + public IWiaMiniDrv +{ +public: + + // + // Construction/Destruction Section + // + + CWiaDriver( + _In_opt_ LPUNKNOWN punkOuter); + + ~CWiaDriver(); + +private: + + // + // WIA driver internals + // + + LONG m_cRef; // Device object reference count. + LPUNKNOWN m_punkOuter; // Pointer to outer unknown. + IStiDevice* m_pIStiDevice; // STI device interface + IWiaDrvItem* m_pIDrvItemRoot; // WIA root item + IWiaLog* m_pIWiaLog; // WIA logging object + LONG m_lClientsConnected; // number of applications connected + BSTR m_bstrDeviceID; // WIA device ID + BSTR m_bstrRootFullItemName; // WIA root item (full item name) + HRESULT m_hrLastEdviceError; // Used for IStiUSD::GetLastError + + // + // Device path received by IStiUSD::Initialize, recorded for late initialization: + // + WCHAR m_wszDevicePath[MAX_PATH]; + + // + // Device Registry key path received by IStiUSD::Initialize, recorded for late initialization: + // + HKEY m_hDeviceKey; + + // + // Supported transfer file format - tymed combinations: + // + CBasicDynamicArray<WIA_FORMAT_INFO> m_tFormatInfo; + CBasicDynamicArray<WIA_FORMAT_INFO> m_tFormatInfoImprinterEndorser; + CBasicDynamicArray<WIA_FORMAT_INFO> m_tFormatInfoBarcodeReader; + CBasicDynamicArray<WIA_FORMAT_INFO> m_tFormatInfoPatchCodeReader; + CBasicDynamicArray<WIA_FORMAT_INFO> m_tFormatInfoMicrReader; + + // + // Driver capabilities (events and commands): + // + CWIACapabilityManager m_tCapabilityManager; + + // + // WIA event handle to signal to the WIA service + // when notifications from scanner device arrive. + // Currently used for scan events only: + // + HANDLE m_hWiaEvent; + HANDLE m_hWiaEventStoredCopy; + + // + // The last input source signaled for an unconsumed + // ScanAvailable event, if any, or an empty string + // otherwise (scanner not in scan available state + // -or- scan available input source unknown). + // When set the value is the format of a WIA item + // name (as reported by WIA_IPA_ITEM_NAME): + // + BSTR m_bstrScanAvailableItem; + + // + // Flag indicating if driver initialization performed + // during IStiUSD::Initialize is complete: + // + BOOL m_bInitialized; + + // + // Critical section to prevent race conditions when calling + // DestroyDriverItemTree from multiple threads (for example + // when the device is disconnected at the same time as the + // only WIA application accessing the driver ends its WIA + // session releasing its Application Item Tree root item): + // + CRITICAL_SECTION m_csDestroyDriverItemTree; + +public: + + // + // IUnknown methods: + // + + STDMETHODIMP + QueryInterface( + REFIID riid, + _COM_Outptr_ LPVOID *ppvObj); + + STDMETHODIMP_(ULONG) + AddRef(); + + STDMETHODIMP_(ULONG) + Release(); + + // + // IStiUSD methods: + // + + STDMETHOD(Initialize)(THIS_ + _In_ PSTIDEVICECONTROL pIStiDevControl, + DWORD dwStiVersion, + _In_ HKEY hParametersKey); + + STDMETHOD(GetCapabilities)(THIS_ + _Out_ PSTI_USD_CAPS pDevCaps); + + STDMETHOD(GetStatus)(THIS_ + _Inout_ PSTI_DEVICE_STATUS pDevStatus); + + STDMETHOD(DeviceReset)(THIS); + + STDMETHOD(Diagnostic)(THIS_ + _Inout_ LPDIAG pBuffer); + + STDMETHOD(Escape)(THIS_ + STI_RAW_CONTROL_CODE EscapeFunction, + _In_reads_bytes_(cbInDataSize) LPVOID lpInData, + DWORD cbInDataSize, + _Out_writes_bytes_(cbOutDataSize) LPVOID pOutData, + DWORD cbOutDataSize, + _Out_ LPDWORD pdwActualData); + + STDMETHOD(GetLastError)(THIS_ + _Out_ LPDWORD pdwLastDeviceError); + + STDMETHOD(LockDevice)(); + + STDMETHOD(UnLockDevice)(); + + STDMETHOD(RawReadData)(THIS_ + _Out_writes_bytes_(*lpdwNumberOfBytes) LPVOID lpBuffer, + _Inout_ LPDWORD lpdwNumberOfBytes, + _In_opt_ LPOVERLAPPED lpOverlapped); + + STDMETHOD(RawWriteData)(THIS_ + _In_reads_bytes_(dwNumberOfBytes) LPVOID lpBuffer, + DWORD dwNumberOfBytes, + _In_opt_ LPOVERLAPPED lpOverlapped); + + STDMETHOD(RawReadCommand)(THIS_ + _Out_writes_bytes_(*lpdwNumberOfBytes) LPVOID lpBuffer, + _Inout_ LPDWORD lpdwNumberOfBytes, + _In_opt_ LPOVERLAPPED lpOverlapped); + + STDMETHOD(RawWriteCommand)(THIS_ + _In_reads_bytes_(dwNumberOfBytes) LPVOID lpBuffer, + DWORD dwNumberOfBytes, + _In_opt_ LPOVERLAPPED lpOverlapped); + + STDMETHOD(SetNotificationHandle)(THIS_ + _In_opt_ HANDLE hEvent); + + STDMETHOD(GetNotificationData)(THIS_ + _Out_ LPSTINOTIFY lpNotify); + + STDMETHOD(GetLastErrorInfo)(THIS_ + _Out_ STI_ERROR_INFO *pLastErrorInfo); + + // + // IWiaMiniDrv methods: + // + + STDMETHOD(drvInitializeWia)(THIS_ + _Inout_ BYTE* pWiasContext, + LONG lFlags, + _In_ BSTR bstrDeviceID, + _In_ BSTR bstrRootFullItemName, + _In_ IUnknown* pStiDevice, + _In_ IUnknown* pIUnknownOuter, + _Out_ IWiaDrvItem** ppIDrvItemRoot, + _Out_ IUnknown** ppIUnknownInner, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvAcquireItemData)(THIS_ + _In_ BYTE* pWiasContext, + LONG lFlags, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvInitItemProperties)(THIS_ + _Inout_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvValidateItemProperties)(THIS_ + _Inout_ BYTE* pWiasContext, + LONG lFlags, + ULONG nPropSpec, + _In_reads_(nPropSpec) + const PROPSPEC *pPropSpec, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvWriteItemProperties)(THIS_ + _Inout_ BYTE* pWiasContext, + LONG lFlags, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvReadItemProperties)(THIS_ + _In_ BYTE* pWiasContext, + LONG lFlags, + ULONG nPropSpec, + _In_ const PROPSPEC* pPropSpec, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvLockWiaDevice)(THIS_ + _In_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvUnLockWiaDevice)(THIS_ + _In_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvAnalyzeItem)(THIS_ + _In_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvGetDeviceErrorStr)(THIS_ + LONG lFlags, + LONG lDevErrVal, + _Out_ LPOLESTR* ppszDevErrStr, + _Out_ LONG* plDevErr); + + STDMETHOD(drvDeviceCommand)(THIS_ + _Inout_ BYTE* pWiasContext, + LONG lFlags, + _In_ const GUID* plCommand, + _Out_ IWiaDrvItem** ppWiaDrvItem, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvGetCapabilities)(THIS_ + _In_opt_ BYTE* pWiasContext, + LONG ulFlags, + _Out_ LONG* pcelt, + _Out_ WIA_DEV_CAP_DRV** ppCapabilities, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvDeleteItem)(THIS_ + _Inout_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvFreeDrvItemContext)(THIS_ + LONG lFlags, + _In_reads_bytes_(sizeof(WIA_DRIVER_ITEM_CONTEXT)) + BYTE *pSpecContext, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvGetWiaFormatInfo)(THIS_ + _In_ BYTE* pWiasContext, + LONG lFlags, + _Out_ LONG* pcelt, + _Out_ WIA_FORMAT_INFO** ppwfi, + _Out_ LONG* plDevErrVal); + + STDMETHOD(drvNotifyPnpEvent)(THIS_ + _In_ const GUID* pEventGUID, + _In_ BSTR bstrDeviceID, + ULONG ulReserved); + + STDMETHOD(drvUnInitializeWia)(THIS_ + _Inout_ BYTE* pWiasContext); + +public: + + // + // INonDelegating Interface Section: + // + + STDMETHODIMP + NonDelegatingQueryInterface( + REFIID riid, + LPVOID* ppvObj); + + STDMETHODIMP_(ULONG) + NonDelegatingAddRef(); + + STDMETHODIMP_(ULONG) + NonDelegatingRelease(); + +private: + + // + // WIA_IPS_PAGE_SIZE valid values, kept in separate arrays for each orientation. + // This sample driver supports a single standard page size and a single orientation + // (portrait) but a real device driver should use all standard page sizes that + // fit into the available physical scan document dimensions for the feeder: + // + CBasicDynamicArray<LONG> m_lPortraitSizesArray; + CBasicDynamicArray<LONG> m_lLandscapeSizesArray; + + // + // Member that keeps track of the scanner's feeder control status: + // + BOOL m_bFeederStarted; + + // + // Mini-driver private methods: + // + + HRESULT InitializeDeviceConnection( + _In_ LPCWSTR wszDevicePath, + _In_ HKEY hDeviceKey); + + HRESULT + BuildDriverItemTree(); + + HRESULT + DestroyDriverItemTree(); + + // + // Property initialization methods: + // + + HRESULT + InitializeRootItemProperties( + _In_ BYTE* pWiasContext); + + HRESULT + InitializeChildItemProperties( + _In_ BYTE* pWiasContext, + UINT nDocumentHandlingSelect); + + HRESULT + InitializeCommonChildProperties( + _In_ BYTE* pWiasContext, + UINT nDocumentHandlingSelect); + + HRESULT + InitializeFlatbedFeederProperties( + _In_ BYTE* pWiasContext, + UINT nDocumentHandlingSelect); + + HRESULT + InitializeFeederSpecificProperties( + _In_ BYTE* pWiasContext); + + HRESULT + InitializeImprinterEndorserProperties( + _In_ BYTE* pWiasContext, + UINT nDocumentHandlingSelect); + + HRESULT + InitializeBarcodeReaderProperties( + _In_ BYTE* pWiasContext); + + HRESULT + InitializePatchCodeReaderProperties( + _In_ BYTE* pWiasContext); + + HRESULT + InitializeMicrReaderProperties( + _In_ BYTE* pWiasContext); + + HRESULT + InitializeFormatInfoArrays(); + + // + // Property validation methods: + // + + HRESULT + ValidateFormatProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nDocumentHandlingSelect); + + HRESULT + ValidateRegionProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nDocumentHandlingSelect); + + HRESULT + ValidateImageInfoProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nDocumentHandlingSelect); + + HRESULT + ValidateFeedProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext); + + HRESULT + ValidateImprinterEndorserProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nDocumentHandlingSelect); + + HRESULT + ValidateBarcodeReaderProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext); + + HRESULT + ValidatePatchCodeReaderProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext); + + HRESULT + ValidateMicrReaderProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext); + + HRESULT + ValidateColorDropProperty( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nChannel); + + HRESULT + ValidateColorDropProperties( + _In_ BYTE* pWiasContext, + _In_ WIA_PROPERTY_CONTEXT* pPropertyContext, + UINT nDocumentHandlingSelect); + + HRESULT + UpdateImageInfoProperties( + _In_ BYTE *pWiasContext, + LONG lDataType); + + HRESULT + UpdateScanAvailableItemName( + _In_opt_ LPCWSTR wszInputSource); + + HRESULT + UpdateScanAvailableItemProperty( + _In_ BYTE *pWiasContext); + + LONG + GetValidPageSizes( + LONG lMaxWidth, + LONG lMaxHeight, + LONG lMinWidth, + LONG lMinHeight, + BOOL bPortrait, + CBasicDynamicArray<LONG>& arrayPageSizes); + + HRESULT + GetPageDimensions( + LONG lPageSize, + BOOL bPortrait, + LONG& lPageWidth, + LONG& lPageHeight); + + // + // Data transfer methods: + // + + HRESULT + Download( + _In_ BYTE* pWiasContext, + GUID guidItemCategory, + _In_ BSTR bstrItemName, + _In_ BSTR bstrFullItemName, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + _In_reads_bytes_(ulBufferSize) BYTE* pTransferBuffer, + ULONG ulBufferSize, + _In_ IWiaMiniDrvTransferCallback* pTransferCallback, + _In_ WiaTransferParams* pCallbackTransferParams, + _In_ WIA_DRIVER_ITEM_CONTEXT* pWiaDriverItemContext); + + HRESULT + Upload( + _In_ BYTE* pWiasContext, + GUID guidItemCategory, + _In_ BSTR bstrItemName, + _In_ BSTR bstrFullItemName, + _In_reads_bytes_(ulBufferSize) BYTE* pTransferBuffer, + ULONG ulBufferSize, + _In_ IWiaMiniDrvTransferCallback* pTransferCallback, + _In_ WiaTransferParams* pCallbackTransferParams, + _In_ WIA_DRIVER_ITEM_CONTEXT* pWiaDriverItemContext); + + HRESULT + TransferFile( + _In_ IStream* pInputStream, + _In_ IStream* pDestinationStream, + _In_reads_bytes_(ulBufferSize) BYTE * pTransferBuffer, + ULONG ulBufferSize, + _In_opt_ IWiaMiniDrvTransferCallback* pTransferCallback, + _In_opt_ WiaTransferParams* pCallbackTransferParams, + ULONG ulEstimatedFileSize, + _Out_ BOOL* pbCancelTransfer); + + HRESULT + IsDibValid( + _In_ IStream* pStream, + LONG lBitDepth, + LONG lWidth, + LONG lHeight); + + HRESULT + IsImprinterEndorserTextValid( + _In_ BYTE* pWiasContext, + _In_ IStream* pStream, + LONG nDocumentHandlingSelect); + + HRESULT + LoadTestDataResourceToStream( + ULONG ulResourceId, + _In_ IStream* pStream, + _Out_ ULONG* pulDataSize); + + HRESULT + LoadTestDataToStream( + _In_ BYTE* pWiasContext, + GUID guidItemCategory, + GUID guidFormat, + _In_ IStream* pStream, + _Out_ ULONG* pulDataSize); + + inline void + ComputeTransferProgress( + _Inout_ ULONG *pulPercentComplete, + ULONG ulEstimatedFileSize, + ULONG ulFileBytesWritten, + BOOL bDirectWIATransfer = TRUE, + ULONG ulResumeFrom = 0); + + // + // Manual feeder control methods: + // + + HRESULT + StartFeeder(); + + HRESULT + StopFeeder(); +}; + +// +// Simple inline function that converts an HRESULT to a Win32 error code: +// +inline DWORD +WIN32_FROM_HRESULT(HRESULT hr) +{ + return ((SUCCEEDED(hr) ? ERROR_SUCCESS : (HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : (hr)))); +} diff --git a/wia/ProdScan/ProdScan.def b/wia/ProdScan/ProdScan.def new file mode 100644 index 00000000..992d4052 --- /dev/null +++ b/wia/ProdScan/ProdScan.def @@ -0,0 +1,9 @@ +LIBRARY PRODSCAN + +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + + diff --git a/wia/ProdScan/ProdScan.inf b/wia/ProdScan/ProdScan.inf new file mode 100644 index 00000000..9ff8d18b --- /dev/null +++ b/wia/ProdScan/ProdScan.inf @@ -0,0 +1,78 @@ +; +; ProdScan.inf - installation file for the Production Scanner Driver Sample +; +; Copyright (c) Microsoft Corporation. All rights reserved. +; +; Manufacturer: Microsoft +; +[Version] +Signature="$WINDOWS NT$" +Class=Image +ClassGUID={6bdd1fc6-810f-11d0-bec7-08002be2092f} +Provider=%ProviderString% +DriverVer=10/16/2015,1.0.0.2 +CatalogFile = prodscan.cat + +[SourceDisksFiles] +ProdScan.dll=1 + +[SourceDisksNames] +1=%Location%,,, + +[DestinationDirs] +DefaultDestDir = 11 + +[Manufacturer] +%ManufacturerName%=Models,NTx86,NTAMD64,NTIA64,NTARM,NTARM64 + +[Models.NTx86] +%ProdScan.DeviceDesc% = ProdScan.Device, WIADRIVER_PNP_ID, USB\MS_COMP_SCAN&MS_SUBCOMP_WIAPNPID + +[Models.NTAMD64] +%ProdScan.DeviceDesc% = ProdScan.Device, WIADRIVER_PNP_ID, USB\MS_COMP_SCAN&MS_SUBCOMP_WIAPNPID + +[Models.NTIA64] +%ProdScan.DeviceDesc% = ProdScan.Device, WIADRIVER_PNP_ID, USB\MS_COMP_SCAN&MS_SUBCOMP_WIAPNPID + +[Models.NTARM] +%ProdScan.DeviceDesc% = ProdScan.Device, WIADRIVER_PNP_ID, USB\MS_COMP_SCAN&MS_SUBCOMP_WIAPNPID + +[Models.NTARM64] +%ProdScan.DeviceDesc% = ProdScan.Device, WIADRIVER_PNP_ID, USB\MS_COMP_SCAN&MS_SUBCOMP_WIAPNPID + +[ProdScan.Device] +Include = sti.inf +Needs = STI.SerialSection +PortSelect = no +SubClass = StillImage +DeviceType = 1 +DeviceSubType = 1 +Capabilities = 0x31 +Events = ProdScan.Events +AddReg = ProdScan.AddReg +CopyFiles = ProdScan.CopyFiles +ICMProfiles = "sRGB Color Space Profile.icm" + +[ProdScan.CopyFiles] +ProdScan.dll + +[ProdScan.AddReg] +HKR,,HardwareConfig,1,1 +HKR,,USDClass,,"{EB135F56-B088-4bc7-9733-422F324B3A09}" +HKCR,CLSID\{EB135F56-B088-4bc7-9733-422F324B3A09},,,"Production Scanner Driver Sample" +HKCR,CLSID\{EB135F56-B088-4bc7-9733-422F324B3A09}\InProcServer32,,0x00020000,%%SystemRoot%%\System32\ProdScan.dll +HKCR,CLSID\{EB135F56-B088-4bc7-9733-422F324B3A09}\InProcServer32,ThreadingModel,,"Both" + +[ProdScan.Events] +ScanEvent = %ScanEvent.Desc%,{A6C5A715-8C6E-11d2-977A-0000F87A926F},* + +[ProdScan.Device.Services] +Include = sti.inf +Needs = STI.SerialSection.Services + +[Strings] +ManufacturerName="TODO-Set-Manufacturer" +ProviderString="TODO-Set-Provider" +Location="Production Scanner Driver Sample Installation Source" +ProdScan.DeviceDesc = "Production Scanner Test Driver" +ScanEvent.Desc="Scan" diff --git a/wia/ProdScan/ProdScan.rc b/wia/ProdScan/ProdScan.rc new file mode 100644 index 00000000..deaaff20 --- /dev/null +++ b/wia/ProdScan/ProdScan.rc @@ -0,0 +1,103 @@ +#include "resource.h" +#include <windows.h> +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Production Scanner Driver Sample DLL" +#define VER_INTERNALNAME_STR "ProdScan" +#define VER_LEGALCOPYRIGHT_YEARS "2010" +#define VER_ORIGINALFILENAME_STR "ProdScan.dll" + +#include <common.ver> + +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + +IDS_EVENT_DEVICE_CONNECTED_NAME "Device connected" +IDS_EVENT_DEVICE_CONNECTED_DESCRIPTION "This PnP event is sent when the device is initially connected to the computer" + +IDS_EVENT_DEVICE_DISCONNECTED_NAME "Device disconnected" +IDS_EVENT_DEVICE_DISCONNECTED_DESCRIPTION "This PnP event is sent when the device is disconnected from the computer" + +IDS_EVENT_POWER_SUSPEND_NAME "Power suspend" +IDS_EVENT_POWER_SUSPEND_DESCRIPTION "This PnP event is sent when the computer enters stand-by or hibernation" + +IDS_EVENT_POWER_RESUME_NAME "Power resume" +IDS_EVENT_POWER_RESUME_DESCRIPTION "This PnP event is sent when the computer recovers from stand-by or hibernation" + +IDS_EVENT_TREE_UPDATED_NAME "Tree updated" +IDS_EVENT_TREE_UPDATED_DESCRIPTION "This event is sent by the driver when the item tree is updated" + +IDS_CMD_SYNCHRONIZE_NAME "Synchronize" +IDS_CMD_SYNCHRONIZE_DESCRIPTION "This command requests to the driver to rebuild its driver item tree" + +IDS_CMD_BUILD_DEVICE_TREE_NAME "Build item tree" +IDS_CMD_BUILD_DEVICE_TREE_DESCRIPTION "This command requests to the driver to build the driver item tree" + +IDS_CMD_DELETE_DEVICE_TREE_NAME "Delete item tree" +IDS_CMD_DELETE_DEVICE_TREE_DESCRIPTION "This command requests to the driver to delete the driver item tree" + +IDS_EVENT_SCAN_IMAGE_NAME "Scan" +IDS_EVENT_SCAN_IMAGE_DESCRIPTION "This event is sent when the device is ready to transfer an image file" + +IDS_EVENT_DEVICE_NOT_READY_NAME "Device not ready" +IDS_EVENT_DEVICE_NOT_READY_DESCRIPTION "This event is sent when the device becomes not ready to scan" + +IDS_EVENT_DEVICE_READY_NAME "Device ready" +IDS_EVENT_DEVICE_READY_DESCRIPTION "This event is sent when the device becomes ready to scan" + +IDS_EVENT_FLATBED_LID_OPEN_NAME "Flatbed lid open" +IDS_EVENT_FLATBED_LID_OPEN_DESCRIPTION "This event is sent when the device's flatbed lid is opened" + +IDS_EVENT_FLATBED_LID_CLOSED_NAME "Flatbed lid closed" +IDS_EVENT_FLATBED_LID_CLOSED_DESCRIPTION "This event is sent when the device's flatbed lid is closed" + +IDS_EVENT_FEEDER_LOADED_NAME "Feeder loaded" +IDS_EVENT_FEEDER_LOADED_DESCRIPTION "This event is sent when the device's feeder is loaded by the scanner operator" + +IDS_EVENT_FEEDER_EMPTIED_NAME "Feeder emptied" +IDS_EVENT_FEEDER_EMPTIED_DESCRIPTION "This event is sent when the device's feeder is unloaded by the scanner operator" + +IDS_EVENT_COVER_OPEN_NAME "Cover open" +IDS_EVENT_COVER_OPEN_DESCRIPTION "This event is sent when a device's scan path cover is opened" + +IDS_EVENT_COVER_CLOSED_NAME "Cover closed" +IDS_EVENT_COVER_CLOSED_DESCRIPTION "This event is sent when the last device's scan path cover is closed" + + +IDS_CMD_START_FEEDER_NAME "Start feeder" +IDS_CMD_START_FEEDER_DESCRIPTION "This command requests the driver to start the scanner feeder motor and prepare for scanning" + +IDS_CMD_STOP_FEEDER_NAME "Stop feeder" +IDS_CMD_STOP_FEEDER_DESCRIPTION "This command requests the driver to stop the scanner feeder motor" + +END + +// +// Test images (equivalent to the image obtained from scanning a 8.5" x 11" document at 300 DPI): +// +IDB_TESTIMAGE_GRAY RCDATA "Res\\TestGray.jpg" +IDB_TESTIMAGE_COLOR RCDATA "Res\\TestRGB.jpg" + +// +// Sample imprinter/endorser image for graphics data download: +// +IDB_TEST_IMPRINTER_IMAGE RCDATA "Res\\Printer.bmp" + +// +// Sample XML metadata files for barcode, patch code and MICR: +// +IDB_BARCODE_SAMPLE RCDATA "Res\\Barcodes.xml" +IDB_PATCH_CODE_SAMPLE RCDATA "Res\\PatchCod.xml" +IDB_MICR_SAMPLE RCDATA "Res\\Micr.xml" + + + + + + diff --git a/wia/ProdScan/ProdScan.vcxproj b/wia/ProdScan/ProdScan.vcxproj new file mode 100644 index 00000000..2b14d9a8 --- /dev/null +++ b/wia/ProdScan/ProdScan.vcxproj @@ -0,0 +1,229 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{041FE80B-1F18-4CF6-90DD-59C690C11A32}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{78CBD2C6-4539-4DE9-A02B-C6F72068B9BD}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>ProdScan</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>ProdScan</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>ProdScan</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>ProdScan</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;wiaservc.lib;ADVAPI32.lib;GDI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shlwapi.lib;sti.lib;gdiplus.lib;Rpcrt4.lib</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /ignore:4070</AdditionalOptions> + <ModuleDefinitionFile>ProdScan.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;wiaservc.lib;ADVAPI32.lib;GDI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shlwapi.lib;sti.lib;gdiplus.lib;Rpcrt4.lib</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /ignore:4070</AdditionalOptions> + <ModuleDefinitionFile>ProdScan.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;wiaservc.lib;ADVAPI32.lib;GDI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shlwapi.lib;sti.lib;gdiplus.lib;Rpcrt4.lib</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /ignore:4070</AdditionalOptions> + <ModuleDefinitionFile>ProdScan.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WIA_DEBUG</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;wiaservc.lib;ADVAPI32.lib;GDI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shlwapi.lib;sti.lib;gdiplus.lib;Rpcrt4.lib</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /ignore:4070</AdditionalOptions> + <ModuleDefinitionFile>ProdScan.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="capman.cpp" /> + <ClCompile Include="events.cpp" /> + <ClCompile Include="fileconv.cpp" /> + <ClCompile Include="initprop.cpp" /> + <ClCompile Include="minidrv.cpp" /> + <ClCompile Include="propman.cpp" /> + <ClCompile Include="scanjobs.cpp" /> + <ClCompile Include="server.cpp" /> + <ClCompile Include="stiusd.cpp" /> + <ClCompile Include="validate.cpp" /> + <ClCompile Include="wiautil.cpp" /> + <ResourceCompile Include="prodscan.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/wia/ProdScan/ProdScan.vcxproj.Filters b/wia/ProdScan/ProdScan.vcxproj.Filters new file mode 100644 index 00000000..4c4d310b --- /dev/null +++ b/wia/ProdScan/ProdScan.vcxproj.Filters @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{ECCF4056-E569-4826-9D38-531DFB8C6CCD}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{73D904EF-DF55-4DAA-8742-42AC29EDC98C}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{CFB16486-5B70-43CB-B3FF-E78C405F0399}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="capman.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="events.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="fileconv.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="initprop.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="minidrv.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="propman.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="scanjobs.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="server.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="stiusd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="validate.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="wiautil.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="ProdScan.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="prodscan.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/wia/ProdScan/PropMan.cpp b/wia/ProdScan/PropMan.cpp new file mode 100644 index 00000000..6dc0e86f --- /dev/null +++ b/wia/ProdScan/PropMan.cpp @@ -0,0 +1,1499 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: PropMan.cpp +* +* Project: Production Scanner Driver Sample +* +* Description: Contains the class implementation of the +* CWIAPropertyManager class that encapsulates +* WIA property creation for this driver. +* +***************************************************************************/ + +#include "stdafx.h" + +/**************************************************************************\ +* +* CWIAPropertyManager constructor +* +\**************************************************************************/ + +CWIAPropertyManager::CWIAPropertyManager() +{ + return; +} + +/**************************************************************************\ +* +* CWIAPropertyManager destructor +* +\**************************************************************************/ + +CWIAPropertyManager::~CWIAPropertyManager() +{ + // + // Cleanup any items contained in the property list before exiting: + // + for (INT i = 0; i < m_List.Size(); i++) + { + PWIA_PROPERTY_INFO_DATA pPropertyData = m_List[i]; + + if (pPropertyData) + { + // + // Delete contents: + // + DeletePropertyData(pPropertyData); + + // + // Delete container: + // + delete pPropertyData; + } + } +} + + +/**************************************************************************\ +* +* This function finds the specified property, and removes it +* from the list of properties +* +* Parameters: +* +* lPropertyID - Property ID of the property to find +* +* Return Value: +* +* Pointer to property information list, NULL if error +* +\**************************************************************************/ + +PWIA_PROPERTY_INFO_DATA CWIAPropertyManager::FindProperty( + LONG lPropertyID) +{ + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + for (INT i = 0; i< m_List.Size(); i++) + { + PWIA_PROPERTY_INFO_DATA pPropertyData = m_List[i]; + + if (pPropertyData->pid == (ULONG)lPropertyID) + { + pInfo = pPropertyData; + break; + } + } + + return pInfo; +} + +/**************************************************************************\ +* +* This function deletes the contents of a WIA_PROPERTY_DATA structure +* +* Parameters: +* +* pInfo - pointer containing the property data +* +* Return Value: +* +* S_OK or a a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::DeletePropertyData( + _Inout_ PWIA_PROPERTY_INFO_DATA pInfo) +{ + HRESULT hr = E_INVALIDARG; + + if (pInfo) + { + // + // Delete any allocated lists: + // + if (pInfo->wpi.lAccessFlags & WIA_PROP_LIST) + { + if (pInfo->pv.vt & VT_I4) + { + if (pInfo->wpi.ValidVal.List.pList) + { + LocalFree(pInfo->wpi.ValidVal.List.pList); + pInfo->wpi.ValidVal.List.pList = NULL; + } + } + + if (pInfo->pv.vt & VT_CLSID) + { + if (pInfo->wpi.ValidVal.ListGuid.pList) + { + LocalFree(pInfo->wpi.ValidVal.ListGuid.pList); + pInfo->wpi.ValidVal.ListGuid.pList = NULL; + } + } + } + + // + // Free any allocated BSTRs: + // + + if (VT_BSTR == pInfo->pv.vt) + { + SysFreeString(pInfo->pv.bstrVal); + pInfo->pv.bstrVal = NULL; + } + + // + // Delete any allocated GUIDs: + // + + if (VT_CLSID == pInfo->pv.vt) + { + delete pInfo->pv.puuid; + pInfo->pv.puuid = NULL; + } + + hr = S_OK; + } + return hr; +} + +/**************************************************************************\ +* +* This function allocates a WIA_PROPERTY_INFO_DATA strucuture +* and initializes the members. +* +* Parameters: +* +* none +* +* Return Value: +* +* Pointer to the new structure +* +\**************************************************************************/ + +PWIA_PROPERTY_INFO_DATA CWIAPropertyManager::AllocatePropertyData() +{ + + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + pInfo = new WIA_PROPERTY_INFO_DATA; + + if (pInfo) + { + // + // Erase all values in newly allocated property data structure: + // + memset(pInfo, 0, sizeof(WIA_PROPERTY_INFO_DATA)); + + // + // Properly initialize the property variant: + // + PropVariantInit(&pInfo->pv); + } + + return pInfo; +} + +/**************************************************************************\ +* +* This function finds the property specified by lPropertyID and deletes the +* contents of the WIA_PROPERTY_INFO_DATA. +* +* Parameters: +* +* lPropertyID - Property ID of the property to remove and delete +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::RemovePropertyAndDeleteData( + LONG lPropertyID) +{ + + // + // Find any existing property with the same ID, and remove it from the list: + // + + PWIA_PROPERTY_INFO_DATA pInfo = FindProperty(lPropertyID); + + if (pInfo) + { + // + // Find and remove the property info from the list and delete the contents: + // + m_List.Delete(m_List.Find(pInfo)); + delete pInfo; + pInfo = NULL; + } + + return S_OK; +} + +/**************************************************************************\ +* +* This function adds a new property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* lCurrValue - Current Property Value +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + LONG lCurrValue) +{ + + HRESULT hr = E_INVALIDARG; + + if (pszName) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + + // + // Populate the data in the structure, and add it to the property list: + // + + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.lVal = lCurrValue; + pInfo->pv.vt = VT_I4; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + + m_List.Append(pInfo); + + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + + return hr; +} + +/**************************************************************************\ +* +* This function adds a new array-of-LONG single-value property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* ulCurrValueItems - Number of VT_I4 items in the current value array +* pCurrValue - Current Property Value, as an array of VT_I4 (LONG) +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + ULONG ulCurrValueItems, + _In_reads_(ulCurrValueItems) + LONG *pCurrValue) +{ + + HRESULT hr = E_INVALIDARG; + + if (pszName && pCurrValue && ulCurrValueItems) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + // + // Populate the data in the structure, and add it to the property list + // + // For a VT_VECTOR | VT_I4 the correct PROPVARIANT member is: cal (type: CAL) + // + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.cal.cElems = ulCurrValueItems; + pInfo->pv.cal.pElems = pCurrValue; + pInfo->pv.vt = VT_I4 | VT_VECTOR; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + + m_List.Append(pInfo); + + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + + return hr; +} + +/**************************************************************************\ +* +* This function adds a new VT_VECTOR | VT_UI1 (array-of-BYTEs single-value) +* property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* pbCurrValue - Current Property Value (BYTE vector) +* ulNumItems - Number of items in the current propery value vector +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + _In_reads_(ulNumItems) + BYTE* pbCurrValue, + ULONG ulNumItems) +{ + HRESULT hr = E_INVALIDARG; + + if (pszName) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + // + // Populate the data in the structure, and add it to the property list + // + // Note: for a VT_VECTOR | VT_UI1 the correct PROPVARIANT member is: caub (type: CAUB) + // + // From MSDN: + // + // "If the type indicator is combined with VT_VECTOR by using an OR operator, the value is one of the counted array values. + // This creates a DWORD count of elements, followed by a pointer to the specified repetitions of the value. + // For example, a type indicator of VT_LPSTR | VT_VECTOR has a DWORD element count, followed by a pointer to an array of LPSTR elements. + // VT_VECTOR can be combined by an OR operator with the following types: VT_I1, VT_UI1, VT_I2, VT_UI2, VT_BOOL, VT_I4, VT_UI4, VT_R4, + // VT_R8, VT_ERROR, VT_I8, VT_UI8, VT_CY, VT_DATE, VT_FILETIME, VT_CLSID, VT_CF, VT_BSTR, VT_LPSTR, VT_LPWSTR, and VT_VARIANT". + // + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.caub.cElems = ulNumItems; + pInfo->pv.caub.pElems = pbCurrValue; + pInfo->pv.vt = VT_UI1 | VT_VECTOR; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + +/**************************************************************************\ +* +* This function adds a new property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* lCurrValue - Current Property Value +* lValidBits - Valid bit values +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + LONG lCurrValue, + LONG lValidBits) +{ + + HRESULT hr = E_INVALIDARG; + if (pszName) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // when a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // allocate a property info structure + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + + // + // populate the data in the structure, and add it to the property list + // + + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.lVal = lCurrValue; + pInfo->pv.vt = VT_I4; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + pInfo->wpi.ValidVal.Flag.Nom = lCurrValue; + pInfo->wpi.ValidVal.Flag.ValidBits = lValidBits; + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + +/**************************************************************************\ +* +* This function adds a new property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* lCurrValue - Current Property Value +* lNomValue - Property Nominal Value +* lMinValue - Property Minimum Value +* lMaxValue - Property Maximum Value +* lInc - Property Increment Value +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + LONG lCurrValue, + LONG lNomValue, + LONG lMinValue, + LONG lMaxValue, + LONG lInc) +{ + HRESULT hr = E_INVALIDARG; + + if (pszName && + (lMinValue <= lMaxValue) && + (lNomValue >= lMinValue) && + (lNomValue <= lMaxValue) && + (lCurrValue >= lMinValue) && + (lCurrValue <= lMaxValue)) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + // + // Populate the data in the structure, and add it to the property list: + // + + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.lVal = lCurrValue; + pInfo->pv.vt = VT_I4; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + pInfo->wpi.ValidVal.Range.Inc = lInc; + pInfo->wpi.ValidVal.Range.Min = lMinValue; + pInfo->wpi.ValidVal.Range.Max = lMaxValue; + pInfo->wpi.ValidVal.Range.Nom = lNomValue; + + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_INVALIDARG; + } + } + + return hr; +} + +/**************************************************************************\ +* +* This function adds a new property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* lCurrValue - Current Property Value +* lNomValue - Property Nominal Value +* pValueList - List of Valid Values +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + LONG lCurrValue, + LONG lNomValue, + _In_ CBasicDynamicArray<LONG>* pValueList) +{ + + HRESULT hr = E_INVALIDARG; + + if (pszName && pValueList && pValueList->Size()) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + LONG *pLongList = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + LONG lNumValues = (LONG)pValueList->Size(); + if (lNumValues) + { + pLongList = (LONG*)LocalAlloc(LPTR, (sizeof(LONG) * lNumValues)); + if (pLongList) + { + for(INT iIndex = 0; iIndex < lNumValues; iIndex++) + { + pLongList[iIndex] = ((*pValueList)[iIndex]); + } + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + + // + // Populate the data in the structure, and add it to the property list: + // + + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.lVal = lCurrValue; + pInfo->pv.vt = VT_I4; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + pInfo->wpi.ValidVal.List.pList = (BYTE*)pLongList; + pInfo->wpi.ValidVal.List.Nom = lNomValue; + pInfo->wpi.ValidVal.List.cNumList = lNumValues; + + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + } + else + { + hr = E_INVALIDARG; + } + + if (FAILED(hr)) + { + if (pLongList) + { + LocalFree(pLongList); + pLongList = NULL; + } + } + } + return hr; +} + +/**************************************************************************\ +* +* This function adds a new VT_UI4 single value property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* ulCurrValue - Current Property Value +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddPropertyUL( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + ULONG ulCurrValue) +{ + + HRESULT hr = E_INVALIDARG; + + if (pszName) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + + // + // Populate the data in the structure, and add it to the property list: + // + + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.lVal = ulCurrValue; + pInfo->pv.vt = VT_UI4; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + + m_List.Append(pInfo); + + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + + return hr; +} + +/**************************************************************************\ +* +* This function adds a new VT_UI4 range property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* ulCurrValue - Current Property Value +* ulNomValue - Property Nominal Value +* ulMinValue - Property Minimum Value +* ulMaxValue - Property Maximum Value +* ulInc - Property Increment Value +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddPropertyUL( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + ULONG ulCurrValue, + ULONG ulNomValue, + ULONG ulMinValue, + ULONG ulMaxValue, + ULONG ulInc) +{ + HRESULT hr = E_INVALIDARG; + + if (pszName && + (ulMinValue <= ulMaxValue) && + (ulNomValue >= ulMinValue) && + (ulNomValue <= ulMaxValue) && + (ulCurrValue >= ulMinValue) && + (ulCurrValue <= ulMaxValue)) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + // + // Populate the data in the structure, and add it to the property list: + // + + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.lVal = ulCurrValue; + pInfo->pv.vt = VT_UI4; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + pInfo->wpi.ValidVal.Range.Inc = ulInc; + pInfo->wpi.ValidVal.Range.Min = ulMinValue; + pInfo->wpi.ValidVal.Range.Max = ulMaxValue; + pInfo->wpi.ValidVal.Range.Nom = ulNomValue; + + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_INVALIDARG; + } + } + + return hr; +} + +/**************************************************************************\ +* +* This function adds a new property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* bstrCurrValue - Current Property Value +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + _In_ BSTR bstrCurrValue) +{ + HRESULT hr = E_INVALIDARG; + + if (pszName && bstrCurrValue) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + // + // Populate the data in the structure, and add it to the property list: + // + + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.bstrVal = SysAllocString(bstrCurrValue); + pInfo->pv.vt = VT_BSTR; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + +/**************************************************************************\ +* +* This function adds a new array-of-BSTR single-value property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* ulCurrValueItems - Number of VT_BSTR items in the current value array +* pCurrValue - Current Property Value, as an array of VT_BSTR +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + ULONG ulCurrValueItems, + _In_reads_(ulCurrValueItems) + BSTR *pCurrValue) +{ + + HRESULT hr = E_INVALIDARG; + + if (pszName && pCurrValue && ulCurrValueItems) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + // + // Populate the data in the structure, and add it to the property list + // + // For a VT_VECTOR | VT_BSTR the correct PROPVARIANT member is: cabstr (type: CABSTR) + // + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.cabstr.cElems = ulCurrValueItems; + pInfo->pv.cabstr.pElems = pCurrValue; + pInfo->pv.vt = VT_VECTOR | VT_BSTR; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + + m_List.Append(pInfo); + + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + + return hr; +} + +/**************************************************************************\ +* +* This function adds a new property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* guidCurrValue - Current Property Value +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + GUID guidCurrValue) +{ + HRESULT hr = E_INVALIDARG; + + if (pszName) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // Allocate memory for a new GUID value and copy the data to it. + // This memory is going to be freed when DeletePropertyData will + // be called for this VT_CLSID property: + // +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "pguid is not leaked") + GUID *pguid = new GUID; + if (pguid) + { + memcpy(pguid, &guidCurrValue, sizeof(GUID)); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + // + // Populate the data in the structure, and add it to the property list: + // + + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.puuid = pguid; + pInfo->pv.vt = VT_CLSID; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + } + + return hr; +} + +/**************************************************************************\ +* +* This function adds a new property to the property list. +* +* If a property exists with the same property ID: +* +* 1. The old property is removed from the list, and the contents destroyed +* 2. The new property is added to the list. +* +* Parameters: +* +* lPropertyID - Property ID +* pszName - Property NAME +* lAccessFlags - Property Access Flags +* guidCurrValue - Current Property Value +* guidNomValue - Property Nominal Value +* pValueList - List of Valid Values +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + GUID guidCurrValue, + GUID guidNomValue, + _In_ CBasicDynamicArray<GUID>* pValueList) +{ + + HRESULT hr = E_INVALIDARG; + + if (pszName && pValueList) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + GUID *pguid = NULL; + GUID *pguidList = NULL; + + // + // When a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the latest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + LONG lNumValues = (LONG)pValueList->Size(); + if (lNumValues) + { + pguidList = (GUID*)LocalAlloc(LPTR,(sizeof(GUID) * lNumValues)); + if (pguidList) + { + for (INT iIndex = 0; iIndex < lNumValues; iIndex++) + { + pguidList[iIndex] = ((*pValueList)[iIndex]); + } + + hr = S_OK; + + if (SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "pguid is not leaked") + pguid = new GUID; + if (pguid) + { + *pguid = guidCurrValue; + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + } + + if (SUCCEEDED(hr)) + { + // + // Allocate a property info structure: + // + + pInfo = AllocatePropertyData(); + if (pInfo) + { + + // + // Populate the data in the structure, and add it to the property list: + // + + pInfo->pszName = pszName; + pInfo->pid = lPropertyID; + pInfo->pv.puuid = pguid; + pInfo->pv.vt = VT_CLSID; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + pInfo->wpi.ValidVal.ListGuid.pList = pguidList; + pInfo->wpi.ValidVal.ListGuid.Nom = guidNomValue; + pInfo->wpi.ValidVal.ListGuid.cNumList = lNumValues; + + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + else + { + hr = E_OUTOFMEMORY; + } + } + else + { + hr = E_INVALIDARG; + } + + if (FAILED(hr)) + { + // + // Free memory any allocated memory if failure occurs: + // + + if (pguidList) + { + LocalFree(pguidList); + pguidList = NULL; + } + + if (pguid) + { + delete pguid; + pguid = NULL; + } + } + } + return hr; +} + +/**************************************************************************\ +* +* This function removes a property from the property list. +* +* Parameters: +* +* lPropertyID - Property ID +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::RemoveProperty( + LONG lPropertyID) +{ + return RemovePropertyAndDeleteData(lPropertyID); +} + +/**************************************************************************\ +* +* This function uses WIA helper functions to upload the properties +* to the Application Item Tree item created by the WIA service. +* +* Parameters: +* +* pWiasContext - WIA Context provided by the WIA service +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CWIAPropertyManager::SetItemProperties( + _Inout_ BYTE* pWiasContext) +{ + HRESULT hr = E_INVALIDARG; + + if (pWiasContext) + { + hr = S_OK; + + // + // Get current number of properties in the list: + // + + LONG lNumProps = m_List.Size(); + if (lNumProps > 0) + { + LONG lIndex = 0; + LPOLESTR *pszName = NULL; + PROPID *ppid = NULL; + PROPVARIANT *ppv = NULL; + PROPSPEC *pps = NULL; + WIA_PROPERTY_INFO *pwpi = NULL; + + // + // Allocate arrays of structures needed to contain the property data: + // + + #pragma prefast(suppress:__WARNING_MEMORY_LEAK_EXCEPTION, "When using a new operator that throws this can leak:") + pszName = new LPOLESTR[lNumProps]; + #pragma prefast(suppress:__WARNING_MEMORY_LEAK_EXCEPTION, "When using a new operator that throws this can leak:") + ppid = new PROPID[lNumProps]; + #pragma prefast(suppress:__WARNING_MEMORY_LEAK_EXCEPTION, "When using a new operator that throws this can leak:") + ppv = new PROPVARIANT[lNumProps]; + #pragma prefast(suppress:__WARNING_MEMORY_LEAK_EXCEPTION, "When using a new operator that throws this can leak:") + pps = new PROPSPEC[lNumProps]; + #pragma prefast(suppress:__WARNING_MEMORY_LEAK_EXCEPTION, "When using a new operator that throws this can leak:") + pwpi = new WIA_PROPERTY_INFO[lNumProps]; + + if (pszName && ppid && ppv && pps && pwpi) + { + // + // Copy the property data into the proper structures: + // + for(INT i = 0; i < lNumProps; i++) + { + PWIA_PROPERTY_INFO_DATA pPropertyData = m_List[i]; + if (pPropertyData) + { + pszName[lIndex] = pPropertyData->pszName; + ppid[lIndex] = pPropertyData->pid; + memcpy(&ppv[lIndex], &pPropertyData->pv, sizeof(PROPVARIANT)); + memcpy(&pps[lIndex], &pPropertyData->ps, sizeof(PROPSPEC)); + memcpy(&pwpi[lIndex], &pPropertyData->wpi, sizeof(WIA_PROPERTY_INFO)); + lIndex++; + } + } + + // + // Send the property names to the WIA service: + // + #pragma prefast(suppress:__WARNING_USING_UNINIT_VAR, "ppid, *ppid, pszName and *pszName are initialized above" + hr = wiasSetItemPropNames(pWiasContext, lNumProps, ppid, pszName); + if (SUCCEEDED(hr)) + { + // + // Send the property values to the WIA service: + // + #pragma prefast(suppress:__WARNING_USING_UNINIT_VAR, "pps and *pps are initialized above" + hr = wiasWriteMultiple(pWiasContext, lNumProps, pps, ppv); + if (SUCCEEDED(hr)) + { + // + // Send the property valid values to the WIA service: + // + #pragma prefast(suppress:__WARNING_USING_UNINIT_VAR, "pwpi and *pvpi are initialized above" + hr = wiasSetItemPropAttribs(pWiasContext, lNumProps, pps, pwpi); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties, wiasSetItemPropAttribs failed")); + } + } + else + { + WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties, wiasWriteMultiple failed")); + } + } + else + { + WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties, wiasSetItemPropNames failed")); + } + } + else + { + WIAEX_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties, failed to allocate memory for property arrays")); + hr = E_OUTOFMEMORY; + } + + // + // Always delete any temporary memory allocated before exiting the function. + // The WIA service makes a copy of the information during the "wias" helper calls. + // + + if (pszName) + { + delete [] pszName; + pszName = NULL; + } + + if (ppid) + { + delete [] ppid; + ppid = NULL; + } + + if (ppv) + { + delete [] ppv; + ppid = NULL; + } + + if (pps) + { + delete [] pps; + ppid = NULL; + } + + if (pwpi) + { + delete [] pwpi; + ppid = NULL; + } + } + } + + return hr; +} diff --git a/wia/ProdScan/PropMan.h b/wia/ProdScan/PropMan.h new file mode 100644 index 00000000..c7436b92 --- /dev/null +++ b/wia/ProdScan/PropMan.h @@ -0,0 +1,205 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: PropMan.h +* +* Project: Production Scanner Driver Sample +* +* Description: This file contains the class definition of the +* CWIAPropertyManager class that encapsulates +* WIA property creation for this driver. +* +***************************************************************************/ + +#pragma once + + +// +// Structure definitions: +// + +typedef struct _WIA_PROPERTY_INFO_DATA{ + LPOLESTR pszName; // property name + PROPID pid; // property id + PROPVARIANT pv; // property variant + PROPSPEC ps; // property spec + WIA_PROPERTY_INFO wpi; // property info +} WIA_PROPERTY_INFO_DATA,*PWIA_PROPERTY_INFO_DATA; + +// +// WIA access flag combinations: +// + +#define RN (WIA_PROP_READ | WIA_PROP_NONE) +#define RF (WIA_PROP_READ | WIA_PROP_FLAG) +#define RW (WIA_PROP_READ | WIA_PROP_WRITE | WIA_PROP_NONE) +#define RWL (WIA_PROP_READ | WIA_PROP_WRITE | WIA_PROP_LIST) +#define RWR (WIA_PROP_READ | WIA_PROP_WRITE | WIA_PROP_RANGE) +#define RWF (WIA_PROP_READ | WIA_PROP_WRITE | WIA_PROP_FLAG) +#define RWLC (WIA_PROP_READ | WIA_PROP_WRITE | WIA_PROP_LIST|WIA_PROP_CACHEABLE) +#define RWRC (WIA_PROP_READ | WIA_PROP_WRITE | WIA_PROP_RANGE|WIA_PROP_CACHEABLE) +#define RWFC (WIA_PROP_READ | WIA_PROP_WRITE | WIA_PROP_FLAG|WIA_PROP_CACHEABLE) + +// +// CWIAPropertyManager class: +// + +class CWIAPropertyManager +{ +private: + CBasicDynamicArray<PWIA_PROPERTY_INFO_DATA> m_List; + + PWIA_PROPERTY_INFO_DATA + FindProperty( + LONG lPropertyID); + + HRESULT + DeletePropertyData( + _Inout_ PWIA_PROPERTY_INFO_DATA pInfo); + + PWIA_PROPERTY_INFO_DATA + AllocatePropertyData(); + + HRESULT + RemovePropertyAndDeleteData( + LONG lPropertyID); + +public: + CWIAPropertyManager(); + ~CWIAPropertyManager(); + + // + // LONG type property creation: + // + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + LONG lCurrValue); + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + ULONG ulCurrValueItems, + _In_reads_(ulCurrValueItems) LONG *pCurrValue); + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + _In_reads_(ulNumItems) BYTE *pbCurrValue, + ULONG ulNumItems); + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + LONG lCurrValue, + LONG lNomValue, + LONG lMinValue, + LONG lMaxValue, + LONG lInc); + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + LONG lCurrValue, + LONG lNomValue, + _In_ LONG *plValues, + LONG lNumValues); + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + LONG lCurrValue, + LONG lNomValue, + _In_ CBasicDynamicArray<LONG> *pValueList); + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + LONG lCurrValue, + LONG lValidBits); + + // + // ULONG type property creation + // + + HRESULT + AddPropertyUL( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + ULONG ulCurrValue); + + HRESULT + AddPropertyUL( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + ULONG ulCurrValue, + ULONG ulNomValue, + ULONG ulMinValue, + ULONG ulMaxValue, + ULONG ulInc); + + // + // BSTR type property creation: + // + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + _In_ BSTR bstrCurrValue); + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + ULONG ulCurrValueItems, + _In_reads_(ulCurrValueItems) BSTR *pCurrValue); + + // + // GUID type property creation: + // + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + GUID guidCurrValue); + + HRESULT + AddProperty( + LONG lPropertyID, + _In_ LPOLESTR pszName, + LONG lAccessFlags, + GUID guidCurrValue, + GUID guidNomValue, + _In_ CBasicDynamicArray<GUID> *pValueList); + + HRESULT + RemoveProperty( + LONG lPropertyID); + + HRESULT + SetItemProperties( + _Inout_ BYTE *pWiasContext); +}; diff --git a/wia/ProdScan/Res/Barcodes.xml b/wia/ProdScan/Res/Barcodes.xml new file mode 100644 index 00000000..6d63d8ca --- /dev/null +++ b/wia/ProdScan/Res/Barcodes.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<catalog xmlns:wbar="http://schemas.microsoft.com/windows/2010/04/wia/barcode"> + <wbar:BarcodeDetectionReport> + <wbar:Count>3</wbar:Count> + <wbar:ListOfBarcodes> + <wbar:BarcodeInfo> + <wbar:Type>0</wbar:Type> + <wbar:Page>0</wbar:Page> + <wbar:Confidence>5</wbar:Confidence> + <wbar:XOffset>0</wbar:XOffset> + <wbar:YOffset>0</wbar:YOffset> + <wbar:Rotation>90</wbar:Rotation> + <wbar:Text>036000291452</wbar:Text> + </wbar:BarcodeInfo> + <wbar:BarcodeInfo> + <wbar:Type>2</wbar:Type> + <wbar:Page>0</wbar:Page> + <wbar:Confidence>9</wbar:Confidence> + <wbar:XOffset>2</wbar:XOffset> + <wbar:YOffset>1000</wbar:YOffset> + <wbar:Rotation>0</wbar:Rotation> + <wbar:Text>3117013206375</wbar:Text> + </wbar:BarcodeInfo> + <wbar:BarcodeInfo> + <wbar:Type>7</wbar:Type> + <wbar:Page>0</wbar:Page> + <wbar:Confidence>10</wbar:Confidence> + <wbar:XOffset>0</wbar:XOffset> + <wbar:YOffset>2000</wbar:YOffset> + <wbar:Rotation>0</wbar:Rotation> + <wbar:Text>This is a Full ASCII Code 39 example</wbar:Text> + </wbar:BarcodeInfo> + </wbar:ListOfBarcodes> + </wbar:BarcodeDetectionReport> +</catalog> + diff --git a/wia/ProdScan/Res/Micr.xml b/wia/ProdScan/Res/Micr.xml new file mode 100644 index 00000000..50b8b969 --- /dev/null +++ b/wia/ProdScan/Res/Micr.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> +<catalog xmlns:wmicr="http://schemas.microsoft.com/windows/2010/04/wia/micr"> + <wmicr:MicrDetectionReport> + <wmicr:Count>2</wmicr:Count> + <wmicr:Placeholder>?</wmicr:Placeholder> + <wmicr:ListOfMicrStrings> + <wmicr:MicrInfo> + <wmicr:Page>0</wmicr:Page> + <wmicr:Text>1234567890</wmicr:Text> + </wmicr:MicrInfo> + <wmicr:MicrInfo> + <wmicr:Page>1</wmicr:Page> + <wmicr:Text>987?543?10</wmicr:Text> + </wmicr:MicrInfo> + </wmicr:ListOfMicrStrings> + </wmicr:MicrDetectionReport> +</catalog> diff --git a/wia/ProdScan/Res/PatchCod.xml b/wia/ProdScan/Res/PatchCod.xml new file mode 100644 index 00000000..ad465aa5 --- /dev/null +++ b/wia/ProdScan/Res/PatchCod.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<catalog xmlns:wpat="http://schemas.microsoft.com/windows/2010/04/wia/patchcode"> + <wpat:PatchCodeDetectionReport> + <wpat:Count>2</wpat:Count> + <wpat:ListOfPatchCodes> + <wpat:PatchCodeInfo> + <wpat:Type>2</wpat:Type> + </wpat:PatchCodeInfo> + <wpat:PatchCodeInfo> + <wpat:Type>1</wpat:Type> + </wpat:PatchCodeInfo> + </wpat:ListOfPatchCodes> + </wpat:PatchCodeDetectionReport> +</catalog> diff --git a/wia/ProdScan/Res/Printer.bmp b/wia/ProdScan/Res/Printer.bmp Binary files differnew file mode 100644 index 00000000..6371a918 --- /dev/null +++ b/wia/ProdScan/Res/Printer.bmp diff --git a/wia/ProdScan/Res/TestGray.jpg b/wia/ProdScan/Res/TestGray.jpg Binary files differnew file mode 100644 index 00000000..02bd768d --- /dev/null +++ b/wia/ProdScan/Res/TestGray.jpg diff --git a/wia/ProdScan/Res/TestRGB.jpg b/wia/ProdScan/Res/TestRGB.jpg Binary files differnew file mode 100644 index 00000000..dab44312 --- /dev/null +++ b/wia/ProdScan/Res/TestRGB.jpg diff --git a/wia/ProdScan/ScanJobs.cpp b/wia/ProdScan/ScanJobs.cpp new file mode 100644 index 00000000..ad5b51ea --- /dev/null +++ b/wia/ProdScan/ScanJobs.cpp @@ -0,0 +1,2531 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* Title: ScanJobs.cpp +* +* Description: This file contains the implementation of the IWiaMiniDrv:: +* drvAcquireItemData method and its helper methods used to +* execute scan job requests and transfer image and metadata +* files from or to the Production Scanner Driver Sample. +* +***************************************************************************/ + +#include "stdafx.h" + +/**************************************************************************\ +* +* Implements IWiaMiniDrv::drvAcquireItemData. This method is called by the +* WIA service when the driver must transfer image data to the application. +* This driver implements the Stream based WIA 2.0 transfer model introduced +* in Windows Vista. This call correponds to one scan job executed at the device +* (scaner starts, scan documents and transfers data, scanner stops). +* +* Parameters: +* +* pWiasContext - pointer to the item context +* lFlags - reserved (set to 0) +* pmdtc - pointer to a MINIDRV_TRANSFER_CONTEXT structure +* containing the device transfer context +* plDevErrVal - unused (drvGetDeviceErrorStr unsupported) +* +* Return Value: +* +* S_OK if successful, S_FALSE if the transfer is canceled +* or an error HRESULT if an error occurrs +* +\**************************************************************************/ + +HRESULT CWiaDriver::drvAcquireItemData( + _In_ BYTE* pWiasContext, + LONG lFlags, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + _Out_ LONG* plDevErrVal) +{ + HRESULT hr = S_OK; + + GUID guidItemCategory = GUID_NULL; + BSTR bstrItemName = NULL; + BSTR bstrFullItemName = NULL; + + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; + IWiaMiniDrvTransferCallback *pTransferCallback = NULL; + WiaTransferParams *pCallbackTransferParams = NULL; + + BYTE *pTransferBuffer = NULL; + ULONG ulBufferSize = 0; + + BOOL bImageTransfer = TRUE; + + WIAEX_TRACE_BEGIN; + + // + // Validate parameters: + // + if ((!pWiasContext) || (!pmdtc) || (!plDevErrVal) || (!pmdtc->pIWiaMiniDrvCallBack)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + // + // Identify the item to execute the acquisition for checking WIA_IPA_ITEM_CATEGORY: + // + if (SUCCEEDED(hr)) + { + hr = wiasReadPropGuid(pWiasContext, WIA_IPA_ITEM_CATEGORY, &guidItemCategory, NULL, TRUE); + if (SUCCEEDED(hr)) + { + bImageTransfer = (IsEqualGUID(WIA_CATEGORY_FLATBED, guidItemCategory) || + IsEqualGUID(WIA_CATEGORY_FEEDER, guidItemCategory) || IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory)); + } + else + { + WIAEX_ERROR((g_hInst, "Failed to read WIA_IPA_ITEM_CATEGORY property, hr = 0x%08X", hr)); + } + } + + // + // Get the item names, we will need them when requesting a new WIA transfer stream: + // + if (SUCCEEDED(hr)) + { + hr = wiasReadPropStr(pWiasContext, WIA_IPA_ITEM_NAME, &bstrItemName, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed reading WIA_IPA_ITEM_NAME, hr = 0x%08X", hr)); + } + } + if (SUCCEEDED(hr)) + { + hr = wiasReadPropStr(pWiasContext, WIA_IPA_FULL_ITEM_NAME, &bstrFullItemName, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed reading WIA_IPA_FULL_ITEM_NAME, hr = 0x%08X", hr)); + } + } + + // + // Transfers from the Root item are not supported: + // + if (SUCCEEDED(hr) && (IsEqualGUID(WIA_CATEGORY_ROOT, guidItemCategory))) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Acquisition not supported from the Root item, hr = 0x%08X", hr)); + } + + + // + // Get the private context data for this item. This sample driver stores in this data + // an image that the WIA application uploads in this session to the Imprinter or the + // Endorser and that should be used in subsequent downloads from the respective item: + // + if (SUCCEEDED(hr)) + { + hr = wiasGetDriverItemPrivateContext(pWiasContext, (BYTE**)&pWiaDriverItemContext); + if (SUCCEEDED(hr) && (!pWiaDriverItemContext)) + { + hr = E_POINTER; + } + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to retrieve the driver item context data, hr = 0x%08X", hr)); + } + } + + // + // Check the requested direction for this data transfer. Download means from the driver to the + // application (from the scanner device to the PC). Upload means from the application to the + // driver (from the PC to the scanner device). For a stream upload the flag value is + // WIA_MINIDRV_TRANSFER_UPLOAD while for a WIA 1.0 tymed-style transfer the flag value is 0: + // + if (SUCCEEDED(hr) && (bImageTransfer || IsEqualGUID(WIA_CATEGORY_BARCODE_READER, guidItemCategory) || + IsEqualGUID(WIA_CATEGORY_PATCH_CODE_READER, guidItemCategory) || + IsEqualGUID(WIA_CATEGORY_MICR_READER, guidItemCategory)) && (!(lFlags & WIA_MINIDRV_TRANSFER_DOWNLOAD))) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, + "Invalid transfer flag parameter requested, this driver supports only download transfer direction for image data, barcode, patch code and MICR metadata, hr = 0x%08X", + hr)); + } + + if (SUCCEEDED(hr)) + { + *plDevErrVal = 0; + } + + // + // Get the WIA transfer callback interface to use for these transfers: + // + if (SUCCEEDED(hr)) + { + hr = pmdtc->pIWiaMiniDrvCallBack->QueryInterface(IID_IWiaMiniDrvTransferCallback, (void**)&pTransferCallback); + if (SUCCEEDED(hr) && (!pTransferCallback)) + { + hr = E_POINTER; + } + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to retrieve IID_IWiaMiniDrvTransferCallback interface, scan failed, hr = 0x%08X", hr)); + } + } + + // + // Allocate memory for the WIA transfer parameters structure and the transfer buffer: + // + if (SUCCEEDED(hr)) + { + pCallbackTransferParams = (WiaTransferParams*)CoTaskMemAlloc(sizeof(WiaTransferParams)); + if (!pCallbackTransferParams) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Memory allocation for transfer parameters failed, scan failed, hr = 0x%08X", hr)); + } + else + { + memset(pCallbackTransferParams, 0, sizeof(WiaTransferParams)); + } + } + if (SUCCEEDED(hr)) + { + hr = AllocateTransferBuffer(&pTransferBuffer, &ulBufferSize); + if (!pTransferBuffer) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Memory allocation for transfer buffer failed, scan failed, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + // + // The CWiaDriver::Download and CWiaDriver::Upload methods called below + // fully trace their execution, no need to trace additionally here. + // Also note that the pInputStrem stream is released by these functions: + // + if (lFlags & WIA_MINIDRV_TRANSFER_DOWNLOAD) + { + // + // 'Download' transfer direction (driver to application) + // + hr = Download(pWiasContext, guidItemCategory, bstrItemName, bstrFullItemName, pmdtc, pTransferBuffer, + ulBufferSize, pTransferCallback, pCallbackTransferParams, pWiaDriverItemContext); + } + else if (lFlags & WIA_MINIDRV_TRANSFER_UPLOAD) + { + // + // 'Upload' transfer direction (application to driver) + // + hr = Upload(pWiasContext, guidItemCategory, bstrItemName, bstrFullItemName, pTransferBuffer, + ulBufferSize, pTransferCallback, pCallbackTransferParams, pWiaDriverItemContext); + + } + } + + // + // Note that WIA_TRANSFER_MSG_END_OF_STREAM and WIA_TRANSFER_MSG_END_OF_TRANSFER + // are sent to the WIA application by the WIA service itself (first when the driver + // asks for a new stream), the driver should not send these itself. + // + + // + // Clean-up for this scan job: + // + + if (bstrItemName) + { + SysFreeString(bstrItemName); + } + + if (bstrFullItemName) + { + SysFreeString(bstrFullItemName); + } + + if (pTransferBuffer) + { + FreeTransferBuffer(pTransferBuffer); + } + + if (pCallbackTransferParams) + { + CoTaskMemFree(pCallbackTransferParams); + } + + if (pTransferCallback) + { + pTransferCallback->Release(); + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IWiaMiniDrv::drvAcquireItemData 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Helper for CWiaDriver::drvAcquireItemData. Executes the download data +* transfer sequence for the current scan job, +* +* Parameters: +* +* pWiasContext - item context +* guidItemCategory - item category +* bstrItemName - item name +* bstrFullItemName - full item name +* pmdc - driver transfer context data +* pTransferBuffer - pre-allocated transfer buffer +* ulBufferSize - size of the pre-allocated transfer buffer, in bytes +* pTransferCallback - IWiaMiniDrvTransferCallback* for WIA status +* pCallbackTransferParams - WiaTransferParams* for WIA status callbacks +* ulEstimatedFileSize - estimated file size, in bytes (0 if unknown) +* +* Return Value: +* +* S_OK if successful, S_FALSE if the transfer is canceled +* or an error HRESULT if an error occurrs +* +\**************************************************************************/ + +HRESULT +CWiaDriver::Download( + _In_ BYTE *pWiasContext, + GUID guidItemCategory, + _In_ BSTR bstrItemName, + _In_ BSTR bstrFullItemName, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + _In_reads_bytes_(ulBufferSize) BYTE *pTransferBuffer, + ULONG ulBufferSize, + _In_ IWiaMiniDrvTransferCallback *pTransferCallback, + _In_ WiaTransferParams *pCallbackTransferParams, + _In_ WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext) +{ + HRESULT hr = S_OK; + + IStream *pInputStream = NULL; + IStream *pOutputStream = NULL; + + LONG lPagesToScan = 1; + LONG lJobSeparators = WIA_SEPARATOR_DISABLED; + LONG lMultiFeed = WIA_MULTI_FEED_DETECT_DISABLED; + LONG lDataType = WIA_DATA_GRAYSCALE; + LONG lCompression = WIA_COMPRESSION_NONE; + + LONG lPixelsPerLine = 0; + LONG lNumberOfLines = 0; + LONG lBytesPerLine = 0; + + LONG lFilesToProcess = 1; + LONG lFilesProcessed = 0; + ULONG ulEstimatedFileSize = 0; + ULONG ulFileSize = 0; + + ULONG_PTR pGDIPlusToken = NULL; + LONG lGDIPlus_PixelsPerLine = 0; + LONG lGDIPlus_NumberOfLines = 0; + LONG lGDIPlus_BytesPerLine = 0; + + DWORD dwJobStart = 0; + + IStream *pWiaStream = NULL; + BOOL bCancelTransfer = FALSE; + BOOL bSkipTransfer = FALSE; + + BOOL bImageTransfer = (IsEqualGUID(WIA_CATEGORY_FLATBED, guidItemCategory) || + IsEqualGUID(WIA_CATEGORY_FEEDER, guidItemCategory) || IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory)); + + + WIAEX_TRACE_BEGIN; + + if ((!pWiasContext) || (!bstrItemName) || (!bstrFullItemName) || (!pmdtc) || (!pTransferBuffer) || (!pTransferCallback) || (!pCallbackTransferParams)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + // + // Reset the recorded scan available input source, if any, ignoring failures: + // + if (SUCCEEDED(hr) && bImageTransfer) + { + UpdateScanAvailableItemName(NULL); + } + + // + // For image transfers from feeder, use WIA_IPS_PAGES to know the number of images expected to transfer in this job: + // + if (SUCCEEDED(hr)) + { + if (IsEqualGUID(guidItemCategory, WIA_CATEGORY_FEEDER)) + { + // + // When WIA_IPS_PAGES is set to 0 (ALL_PAGES) meaning "scan as + // many documents as there may be loaded into the feeder" this + // sample driver will transfer up to MAX_SCAN_PAGES: + // + hr = wiasReadPropLong(pWiasContext, WIA_IPS_PAGES, &lPagesToScan, NULL, TRUE); + if (SUCCEEDED(hr)) + { + if (ALL_PAGES == lPagesToScan) + { + lPagesToScan = MAX_SCAN_PAGES; + } + } + else + { + lPagesToScan = 1; + WIAEX_ERROR((g_hInst, "Failed reading the WIA_IPS_PAGES property, hr = 0x%08X", hr)); + } + } + else if (IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory)) + { + // + // In full automatic mode scan as many pages as the device decides to allow: + // + lPagesToScan = MAX_SCAN_PAGES; + } + else + { + // + // One single document page to scan from the flatbed or one single metadata file: + // + lPagesToScan = 1; + } + } + + if (SUCCEEDED(hr) && bImageTransfer) + { + WIAS_TRACE((g_hInst, "Pages to scan: %u (0 means all)", lPagesToScan)); + } + + // + // For feeder acquisitions, this sample driver simulates a job separator every + // JOB_SEPARATOR_AT_PAGE page and a multi-feed every MULTI_FEED_AT_PAGE pages: + // + if (SUCCEEDED(hr) && IsEqualGUID(guidItemCategory, WIA_CATEGORY_FEEDER)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_JOB_SEPARATORS, &lJobSeparators, NULL, TRUE); + if (SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_MULTI_FEED, &lMultiFeed, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed reading the WIA_IPS_MULTI_FEED property, hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed reading the WIA_IPS_JOB_SEPARATORS property, hr = 0x%08X", hr)); + } + } + + // + // For feeder acquisitions, if WIA_IPS_FEEDER_CONTROL is set to WIA_FEEDER_CONTROL_MANUAL + // and the feeder is not running, start the feeder and reset the feeder control to automatic + // mode, updating WIA_IPS_FEEDER_CONTROL to WIA_FEEDER_CONTROL_AUTO: + // + if (SUCCEEDED(hr) && IsEqualGUID(guidItemCategory, WIA_CATEGORY_FEEDER)) + { + LONG lFeederControl = WIA_FEEDER_CONTROL_AUTO; + + hr = wiasReadPropLong(pWiasContext, WIA_IPS_FEEDER_CONTROL, &lFeederControl, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed reading the WIA_IPS_FEEDER_CONTROL property, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr) && (WIA_FEEDER_CONTROL_MANUAL == lFeederControl) && (!m_bFeederStarted)) + { + hr = StartFeeder(); + if (SUCCEEDED(hr)) + { + lFeederControl = WIA_FEEDER_CONTROL_AUTO; + + hr = wiasWritePropLong(pWiasContext, WIA_IPS_FEEDER_CONTROL, lFeederControl); + if (SUCCEEDED(hr)) + { + WIAS_TRACE((g_hInst, "Reverted to WIA_FEEDER_CONTROL_AUTO")); + } + else + { + WIAEX_ERROR((g_hInst, "Failed to reset the WIA_IPS_FEEDER_CONTROL property, hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Cannot start the feeder, hr = 0x%08X", hr)); + } + } + } + + // + // Read the current data type configured for this image source: + // + if (SUCCEEDED(hr) && bImageTransfer && (!IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory))) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPA_DATATYPE, &lDataType, NULL, TRUE); + if (SUCCEEDED(hr)) + { + if (WIA_DATA_AUTO == lDataType) + { + // + // 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 scan document, + // each document page preferrably. This sample driver uses the same test image to transfer + // all single-file page scans in a job so this initialization is only performed once, for + // the entire job: + // + lDataType = (rand() % 2) ? WIA_DATA_GRAYSCALE : WIA_DATA_COLOR; + WIAS_TRACE((g_hInst, "Detected data type in automatic mode: %ws", + (WIA_DATA_GRAYSCALE == lDataType) ? L"8-bpp grayscale" : L"24-bpp RGB color")); + + // + // Updated dependent image information properties: + // + hr = UpdateImageInfoProperties(pWiasContext, lDataType); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to update dependent image information properties, hr = 0x%08X", hr)); + } + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to read WIA_IPA_DATATYPE property, hr = 0x%08X", hr)); + } + } + + // + // How many files and transfer streams the driver needs for this drvAcquireItemData call: + // + // a) For transfers from Feeder WIA_IPS_PAGES indicates the number of files. + // b) For transfers from Flatbed there is always just one file. + // c) For multi-page transfers (which this sample driver doesn't support) there would be just one file. + // + if (SUCCEEDED(hr)) + { + if ((IsEqualGUID(guidItemCategory, WIA_CATEGORY_FEEDER)) || (IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory))) + { + lFilesToProcess = lPagesToScan; + } + else + { + lFilesToProcess = 1; + } + + WIAS_TRACE((g_hInst, "Files to transfer: %u", lFilesToProcess)); + } + + if (SUCCEEDED(hr)) + { + // + // Check first if we have a (previously uploaded in this session) imprinter/endorser image to use: + // + if (pWiaDriverItemContext->m_pUploadedImage) + { + pInputStream = pWiaDriverItemContext->m_pUploadedImage; + } + else + { + // + // Create a new global memory stream to store the transfer data file: + // + hr = CreateStreamOnHGlobal(NULL, TRUE, &pInputStream); + if (SUCCEEDED(hr) && (!pInputStream)) + { + hr = E_FAIL; + } + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "CreateStreamOnHGlobal failed, hr = 0x%08X", hr)); + } + + // + // Read from resources or generate the test data file (image or metadata) to be downloaded + // to the application, storing this data into the new memory stream: + // + if (SUCCEEDED(hr)) + { + ULONG ulResource = 0; + + if (bImageTransfer) + { + ulResource = (WIA_DATA_COLOR == lDataType) ? IDB_TESTIMAGE_COLOR : IDB_TESTIMAGE_GRAY; + } + else if ((IsEqualGUID(WIA_CATEGORY_IMPRINTER, guidItemCategory) || IsEqualGUID(WIA_CATEGORY_ENDORSER, guidItemCategory)) + && IsEqualGUID(WiaImgFmt_BMP, pmdtc->guidFormatID)) + { + // + // The sample driver will generate itself the WiaImgFmt_CSV and WiaImgFmt_TXT files: + // + ulResource = IDB_TEST_IMPRINTER_IMAGE; + } + else if (IsEqualGUID(WIA_CATEGORY_BARCODE_READER, guidItemCategory) && IsEqualGUID(WiaImgFmt_XMLBAR, pmdtc->guidFormatID)) + { + // + // The sample driver hard-codes the sample WiaImgFmt_RAWBAR file: + // + ulResource = IDB_BARCODE_SAMPLE; + } + else if (IsEqualGUID(WIA_CATEGORY_PATCH_CODE_READER, guidItemCategory) && IsEqualGUID(WiaImgFmt_XMLPAT, pmdtc->guidFormatID)) + { + // + // The sample driver hard-codes the sample WiaImgFmt_RAWPAT file: + // + ulResource = IDB_PATCH_CODE_SAMPLE; + } + else if (IsEqualGUID(WIA_CATEGORY_MICR_READER, guidItemCategory) && IsEqualGUID(WiaImgFmt_XMLMIC, pmdtc->guidFormatID)) + { + // + // The sample driver hard-codes the sample WiaImgFmt_RAWMIC file: + // + ulResource = IDB_MICR_SAMPLE; + } + + if (ulResource) + { + hr = LoadTestDataResourceToStream(ulResource, pInputStream, &ulFileSize); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to load the test data file from resource %u, hr = 0x%08X", ulResource, hr)); + } + } + else + { + hr = LoadTestDataToStream(pWiasContext, guidItemCategory, pmdtc->guidFormatID, pInputStream, &ulFileSize); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to load the test data file from resource %u, hr = 0x%08X", ulResource, hr)); + } + } + } + } + } + + // + // For image transfers, if the application asks for DIB (which the driver must always support) or Raw + // this sample driver converts the image from the attached EXIF test image to obtain the uncompressed + // image before the first image transfer takes place. For this the driver first runs the test image + // through the GDI+ DIB encoder to generate the DIB image to transfer to the WIA application. + // + if (S_OK == hr) + { + if (bImageTransfer && IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_BMP) || IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_RAW)) + { + // + // Initialize GDI+ if the driver must translate scanned images to the DIB format: + // + if (S_OK == hr) + { + WIAS_TRACE((g_hInst, "Initialize GDI++..")); + hr = InitializeGDIPlus(&pGDIPlusToken); + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "Failed to initialize GDI+, hr = 0x%08X", hr)); + } + } + + // + // Load the image to a GDI+ Image object (GDI+ cannot convert the image directly from the stream): + // + Image *pInputImage = NULL; + if (S_OK == hr) + { + pInputImage = Image::FromStream(pInputStream); + if (!pInputImage) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Image::FromStream failed, hr = 0x%08X", hr)); + } + } + + // + // Release the input stream now, no longer needed, the same image is held by the Image object: + // + pInputStream->Release(); + pInputStream = NULL; + + // + // Hand the Image object to GDI+ to generate the DIB image: + // + if (S_OK == hr) + { + hr = ConvertImageToDIB(pInputImage, &pOutputStream, + &lGDIPlus_PixelsPerLine, &lGDIPlus_NumberOfLines, &lGDIPlus_BytesPerLine); + + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "Failed to convert scanned image file to DIB, hr = 0x%08X", hr)); + } + } + + // + // Free the GDI+ Image copy: + // + if (pInputImage) + { + delete pInputImage; + } + + // + // Done with file format conversions, if any. Shutdown GDI+, no longer needed: + // + if (pGDIPlusToken) + { + WIAS_TRACE((g_hInst, "Shutdown GDI++..")); + ShutdownGDIPlus(pGDIPlusToken); + pGDIPlusToken = NULL; + } + + // + // For a Raw image transfer, further convert the DIB to an uncompressed Raw image file: + // + if ((S_OK == hr) && IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_RAW)) + { + IStream *pTempOutputStream = NULL; + + hr = ConvertDibToRaw(pOutputStream, &pTempOutputStream); + if (S_OK == hr) + { + // + // Release pOutputStream then reset its pointer to the new stream: + // + pOutputStream->Release(); + pOutputStream = pTempOutputStream; + pTempOutputStream = NULL; + } + } + + // + // If not in auto-config mode check the actual image dimensions reported by GDI+. + // In both programmed and auto-config mode update the estimated file size from + // the image dimensions and depth reported by GDI+ during the conversion process: + // + if (S_OK == hr) + { + if (!IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory)) + { + HRESULT hrTemp = S_OK; + + // + // Update WIA_IPA_PIXELS_PER_LINE, WIA_IPA_NUMBER_OF_LINES and WIA_IPA_BYTES_PER_LINE: + // + hrTemp = wiasWritePropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, lGDIPlus_PixelsPerLine); + if (FAILED(hrTemp)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_PIXELS_PER_LINE to %u, hr = 0x%08X", + lGDIPlus_PixelsPerLine, hrTemp)); + } + if (SUCCEEDED(hrTemp)) + { + hrTemp = wiasWritePropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, lGDIPlus_NumberOfLines); + if (FAILED(hrTemp)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_NUMBER_OF_LINES to %u, hr = 0x%08X", + lGDIPlus_NumberOfLines, hrTemp)); + } + } + if (SUCCEEDED(hrTemp)) + { + hrTemp = wiasWritePropLong(pWiasContext, WIA_IPA_BYTES_PER_LINE, lGDIPlus_BytesPerLine); + if (FAILED(hrTemp)) + { + WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_BYTES_PER_LINE to %u, hr = 0x%08X", + lGDIPlus_BytesPerLine, hrTemp)); + } + } + } + } + } + } + + // + // Estimate the size of uncompressed data we need to transfer for each file, assuming + // all images in the current acquisition sequence will be scanned using the same scan + // parameters. The estimate is relatively accurate for uncompressed data. Cannot use + // this kind of estimate for compressed data because of the unknown compression ratio: + // + if ((S_OK == hr) && bImageTransfer && (!IsEqualGUID(WIA_CATEGORY_AUTO, guidItemCategory))) + { + // + // Read the image information properties: + // + hr = wiasReadPropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, &lNumberOfLines, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed reading WIA_IPA_NUMBER_OF_LINES, hr = 0x%08X", hr)); + } + + if (S_OK == hr) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPA_BYTES_PER_LINE, &lBytesPerLine, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed reading WIA_IPA_BYTES_PER_LINE, hr = 0x%08X", hr)); + } + } + + if (S_OK == hr) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, &lPixelsPerLine, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed reading WIA_IPA_PIXELS_PER_LINE, hr = 0x%08X", hr)); + } + } + + if (S_OK == hr) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPA_COMPRESSION, &lCompression, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed reading WIA_IPA_COMPRESSION, hr = 0x%08X", hr)); + } + } + + if ((S_OK == hr) && (lBytesPerLine > 0) && (WIA_COMPRESSION_NONE == lCompression)) + { + ulEstimatedFileSize = lBytesPerLine * lNumberOfLines; + + if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_BMP)) + { + ulEstimatedFileSize += sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + } + else if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_RAW)) + { + ulEstimatedFileSize += sizeof(WIA_RAW_HEADER); + } + + WIAS_TRACE((g_hInst, "Transfer file size for uncompressed image data: %02.2f KB (%u BPL, %u lines)", + ulEstimatedFileSize / 1024.0f, lBytesPerLine, lNumberOfLines)); + } + else + { + ulEstimatedFileSize = ulFileSize; + WIAS_TRACE((g_hInst, "Transfer file size for compressed image data: %02.2f KB (%u uncompreessed BPL, %u lines)", + ulEstimatedFileSize / 1024.0f, lBytesPerLine, lNumberOfLines)); + } + } + + if ((S_OK == hr) && (!bImageTransfer)) + { + ulEstimatedFileSize = ulFileSize; + WIAS_TRACE((g_hInst, "Transfer file size for metadata: %02.2f bytes", ulEstimatedFileSize)); + } + + // + // Begin the actual data transfer procedure to the WIA application: + // + // + #pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "A sample scan job duration does not exceed 49 days. If there is risk to exceed, use GetTickCount64 instead:" + dwJobStart = GetTickCount(); + lFilesProcessed = 0; + while (S_OK == hr) + { + bSkipTransfer = FALSE; + + // + // Request a new WIA stream from the WIA client application: + // + if (S_OK == hr) + { + _Analysis_assume_nullterminated_(bstrItemName); + hr = pTransferCallback->GetNextStream(0, bstrItemName, bstrFullItemName, &pWiaStream); + if (S_FALSE == hr) + { + bCancelTransfer = TRUE; + WIAS_TRACE((g_hInst, "IWiaMiniDrvTransferCallback::GetNextStream returned S_FALSE (0x%08X), transfer must be canceled", hr)); + } + else if (WIA_STATUS_SKIP_ITEM == hr) + { + bSkipTransfer = TRUE; + WIAS_TRACE((g_hInst, "IWiaMiniDrvTransferCallback::GetNextStream returned WIA_STATUS_SKIP_ITEM (0x%08X), transfer must be skipped", hr)); + hr = S_OK; + } + else if (SUCCEEDED(hr) && (S_OK != hr)) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::GetNextStream returned an unknown success value, hr = 0x%08X", hr)); + hr = E_UNEXPECTED; + } + else if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::GetNextStream failed, hr = 0x%08X", hr)); + } + } + + // + // Signal start of data transfer to the WIA application and check + // if the application asks already for the transfers to be cancelled: + // + if ((S_OK == hr) && (!bSkipTransfer)) + { + pCallbackTransferParams->lMessage = WIA_TRANSFER_MSG_STATUS; + pCallbackTransferParams->hrErrorStatus = 0; + pCallbackTransferParams->lPercentComplete = 0; + pCallbackTransferParams->ulTransferredBytes = 0; + + WIAS_TRACE((g_hInst, "Transfer callback: WIA_TRANSFER_MSG_STATUS, 0 bytes")); + hr = pTransferCallback->SendMessage(0, pCallbackTransferParams); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::SendMessage failed, hr = 0x%08X", hr)); + } + else if (S_FALSE == hr) + { + bCancelTransfer = TRUE; + } + else if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::SendMessage returned unknown success value, hr = 0x%08X", hr)); + bCancelTransfer = TRUE; + hr = S_FALSE; + } + } + + if (S_OK == hr) + { + if (bSkipTransfer) + { + WIAS_TRACE((g_hInst, "Discarding data to skip the current file transfer (%u)..", lFilesProcessed + 1)); + } + else + { + // + // Read the test file and transfer it to the WIA application: + // + if ((S_OK == hr) && (!bCancelTransfer)) + { + hr = TransferFile(pOutputStream ? pOutputStream : pInputStream, pWiaStream, pTransferBuffer, ulBufferSize, + pTransferCallback, pCallbackTransferParams, ulEstimatedFileSize, &bCancelTransfer); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "File transfer to WIA stream failed, hr = 0x%08X", hr)); + } + } + } + } + + // + // The transfer of one file was successfully completed, reset WIA_STATUS_END_OF_MEDIA: + // + if (WIA_STATUS_END_OF_MEDIA == hr) + { + WIAS_TRACE((g_hInst, "File transfer complete (WIA_STATUS_END_OF_MEDIA)")); + hr = S_OK; + } + + // + // Signal 100% transfer complete to the WIA client application (pCallbackTransferParams->ulTransferredBytes + // contains the total number of bytes transferred to this stream): + // + if ((S_OK == hr) && (!bSkipTransfer)) + { + pCallbackTransferParams->lMessage = WIA_TRANSFER_MSG_STATUS; + pCallbackTransferParams->hrErrorStatus = 0; + pCallbackTransferParams->lPercentComplete = 100; + + WIAS_TRACE((g_hInst, "Transfer callback: WIA_TRANSFER_MSG_STATUS, transfer complete, %02.2f KB total (%u)", + pCallbackTransferParams->ulTransferredBytes / 1024.0f, pCallbackTransferParams->lPercentComplete)); + + hr = pTransferCallback->SendMessage(0, pCallbackTransferParams); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::SendMessage(WIA_TRANSFER_MSG_STATUS, transfer complete) failed, hr = 0x%08X", hr)); + } + else if (S_FALSE == hr) + { + bCancelTransfer = TRUE; + } + else if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::SendMessage(WIA_TRANSFER_MSG_STATUS, transfer complete) returned unknown success value, hr = 0x%08X", hr)); + bCancelTransfer = TRUE; + hr = S_FALSE; + } + } + + // + // If the transfer was canceled from the client application send a CancelJob + // to the scanner device to ensure scanning is stopped and all scanned image + // data (not read yet) is discarded from the scanner internal buffer: + // + if (bCancelTransfer) + { + WIAS_TRACE((g_hInst, "Transfer cancelled from WIA application..")); + + // + // Make sure hr is left set to S_FALSE (cancelled): + // + hr = S_FALSE; + } + // + // The current job must be canceled at the device if there is an error during the data + // transfer phase, error which may result in leaving the current job in a processing + // state and risk to block the scanner from accepting new jobs until this job times out: + // + else if (FAILED(hr)) + { + WIAS_TRACE((g_hInst, "Transfer failed (hr = 0x%08X), abort job..", hr)); + } + + // + // Clean-up after finishing each individual WIA file transfer: + // + + pCallbackTransferParams->lPercentComplete = 0; + pCallbackTransferParams->ulTransferredBytes = 0; + + // + // Release the current WIA transfer stream: + // + if (pWiaStream) + { + pWiaStream->Release(); + pWiaStream = NULL; + } + + // + // Note the loop ends when hr != S_OK. + // + // Increment the number of streams (files) transferred + // and check if we must end the transfers here: + // + if (S_OK == hr) + { + // + // If a finite number of files must be processed (transferred and/or skipped): + // + lFilesProcessed++; + + WIAS_TRACE((g_hInst, "Successfully transferred %u file(s)", lFilesProcessed)); + + if (lFilesToProcess && (lFilesProcessed >= lFilesToProcess)) + { + // + // Note that in general for the Feeder item the driver must signal + // end of paper, not S_OK (as documented by MSDN), to ensure that the + // application does not request another drvAcquireItemData. In this + // case however we transfer multiple files in a single call so we + // won't do this: + // + // if (IsEqualGUID(WIA_CATEGORY_FEEDER, guidItemCategory)) + // { + // hr = WIA_ERROR_PAPER_EMPTY; + // } + // + + // + // Do not transfer another file for this call: + // + hr = WIA_STATUS_END_OF_MEDIA; + } + // + // For feeder acquisitions, if job separators and/or multi-feed detection is enabled, + // check if the sample driver needs to perform an action here (such as stopping the scan): + // + else if ((!(lFilesProcessed % JOB_SEPARATOR_AT_PAGE)) && (WIA_SEPARATOR_DISABLED != lJobSeparators)) + { + WIAS_TRACE((g_hInst, "Job separator detected")); + if ((WIA_SEPARATOR_DETECT_SCAN_STOP == lJobSeparators) || (WIA_SEPARATOR_DETECT_NOSCAN_STOP == lJobSeparators)) + { + WIAS_TRACE((g_hInst, "End of scan job due to job separator")); + hr = WIA_STATUS_END_OF_MEDIA; + } + } + else if ((!(lFilesProcessed % MULTI_FEED_AT_PAGE)) && (WIA_MULTI_FEED_DETECT_DISABLED != lMultiFeed)) + { + WIAS_TRACE((g_hInst, "Multi-feed detected")); + if (WIA_MULTI_FEED_DETECT_STOP_SUCCESS == lMultiFeed) + { + WIAS_TRACE((g_hInst, "End of scan job due to multi-feed")); + hr = WIA_STATUS_END_OF_MEDIA; + } + else if (WIA_MULTI_FEED_DETECT_STOP_ERROR == lMultiFeed) + { + WIAS_TRACE((g_hInst, "Failed scan job due to multi-feed")); + hr = WIA_ERROR_MULTI_FEED; + } + } + + // + // For image transfers, if lFileToTransfer is 0 (ALL_PAGES) the transfers end (with S_OK) when either: + // + // 1) an error occurrs; + // 2) a file transfer is canceled (either from the app or the scanner); + // 3) when RetrieveImage would return WIA_ERROR_PAPER_EMPTY. + // + } + } + + // + // Compute the number of pages per minute (PPM) transferred for this job: + // + if ((lFilesProcessed > 0) && bImageTransfer) + { + #pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "A sample scan job duration does not exceed 49 days. If there is risk to exceed, use GetTickCount64 instead:" + DWORD dwJobEnd = GetTickCount(); + + if (dwJobEnd > dwJobStart) + { + float fSecondsElapsed = (dwJobEnd - dwJobStart) / 1000.0f; + + if (lFilesProcessed > 1) + { + DWORD dwPagesPerMinute = (DWORD)((60 * lFilesProcessed) / fSecondsElapsed); + WIAS_TRACE((g_hInst, "Measured scan performance for this job is %u PPM (%u single-page image files transferred in %0.2f seconds)", + dwPagesPerMinute, lFilesProcessed, fSecondsElapsed)); + } + else + { + WIAS_TRACE((g_hInst, "1 image file transferred in %0.2f seconds", fSecondsElapsed)); + } + } + } + + // + // Keep the image in the item context, if there is one: + // + if (pWiaDriverItemContext->m_pUploadedImage) + { + pInputStream = NULL; + } + + // + // Clean-up for memory streams (set to automatically free memory on release) + // used for the test image: + // + if (pInputStream) + { + pInputStream->Release(); + } + if (pOutputStream) + { + pOutputStream->Release(); + } + + // + // The transfers (of all files) were successfully completed, reset WIA_STATUS_END_OF_MEDIA: + // + if (WIA_STATUS_END_OF_MEDIA == hr) + { + WIAS_TRACE((g_hInst, "All files successfully transferred")); + + hr = S_OK; + } + + // + // If this job call is about to return WIA_ERROR_PAPER_EMPTY we have to consider + // first the following conditions: + // + // - if an undefined number of transfers had to be performed and at least + // one file was transferred the return code must be changed to S_OK; + // + // - if a finite number of transfers had to be performed and all these + // transfers have been done the return code must be changed to S_OK; + // + // - if a finite number of transfers had to be performed and at least one + // of these transfers - but not all of them - has been done the return + // code must be changed to WIA_STATUS_END_OF_MEDIA; + // + // - WIA_ERROR_PAPER_EMPTY must be returned only when no transfers could + // be completed in the current drvAcquireItemData call. + // + if (WIA_ERROR_PAPER_EMPTY == hr) + { + if (((!lFilesToProcess) && (lFilesProcessed >= 1)) || + ((lFilesToProcess > 0) && (lFilesProcessed >= lFilesToProcess))) + { + WIAS_TRACE((g_hInst, "Running out of paper, returning S_OK for drvAcquireItemData..")); + hr = S_OK; + } + else if ((lFilesToProcess > 0) && (lFilesProcessed < lFilesToProcess) && (lFilesProcessed >= 1)) + { + WIAS_TRACE((g_hInst, "Running out of paper, returning WIA_STATUS_END_OF_MEDIA for drvAcquireItemData..")); + hr = WIA_STATUS_END_OF_MEDIA; + } + else + { + WIAS_TRACE((g_hInst, "Running out of paper, returning WIA_ERROR_PAPER_EMPTY for drvAcquireItemData..")); + } + } + else if (WIA_ERROR_MULTI_FEED == hr) + { + WIAS_TRACE((g_hInst, "Multi-feed error, returning WIA_ERROR_MULTI_FEED for drvAcquireItemData..")); + } + + WIAEX_TRACE_FUNC_HR; + + return hr; +} + +/**************************************************************************\ +* +* Helper for CWiaDriver::drvAcquireItemData. Executes the upload data +* transfer sequence for the current scan job, +* +* Parameters: +* +* pWiasContext - item context +* guidItemCategory - item category +* bstrItemName - item name +* bstrFullItemName - full item name +* pmdc - driver transfer context data +* pTransferBuffer - pre-allocated transfer buffer +* ulBufferSize - size of the pre-allocated transfer buffer, in bytes +* pTransferCallback - IWiaMiniDrvTransferCallback* for WIA status +* pCallbackTransferParams - WiaTransferParams* for WIA status callbacks +* ulEstimatedFileSize - estimated file size, in bytes (0 if unknown) +* +* Return Value: +* +* S_OK if successful, S_FALSE if the transfer is canceled +* or an error HRESULT if an error occurrs +* +\**************************************************************************/ + +HRESULT +CWiaDriver::Upload( + _In_ BYTE *pWiasContext, + GUID guidItemCategory, + _In_ BSTR bstrItemName, + _In_ BSTR bstrFullItemName, + _In_reads_bytes_(ulBufferSize) BYTE *pTransferBuffer, + ULONG ulBufferSize, + _In_ IWiaMiniDrvTransferCallback *pTransferCallback, + _In_ WiaTransferParams *pCallbackTransferParams, + _In_ WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext) +{ + HRESULT hr = S_OK; + + IStream *pInputStream = NULL; + IStream *pWiaStream = NULL; + BOOL bCancelTransfer = FALSE; + BOOL bSkipTransfer = FALSE; + GUID guidUploadFormat = GUID_NULL; + + WIAEX_TRACE_BEGIN; + + if ((!pWiasContext) || (!bstrItemName) || (!bstrFullItemName) || (!pTransferBuffer) || (!pTransferCallback) || (!pCallbackTransferParams)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if ((!IsEqualGUID(WIA_CATEGORY_IMPRINTER, guidItemCategory)) && (!IsEqualGUID(WIA_CATEGORY_ENDORSER, guidItemCategory))) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "This driver does not support upload transfer direction for the requested item, hr = 0x%08X", hr)); + } + + // + // Create a new global memory stream to store the transfer data file: + // + if (SUCCEEDED(hr)) + { + hr = CreateStreamOnHGlobal(NULL, TRUE, &pInputStream); + if (SUCCEEDED(hr) && (!pInputStream)) + { + hr = E_FAIL; + } + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "CreateStreamOnHGlobal failed, hr = 0x%08X", hr)); + } + } + + // + // This sample driver executes a very simple data transfer upload for the imprinter/endorser data. + // + // For WiaImgFmt_BMP transfers the driver validates that the image dimensions match + // WIA_IPS_PRINTER_ENDORSER_GRAPHICS_MIN/MAX_WIDTH/HEIGHT dimensions. + // + // For WiaImgFmt_TXT and WiaImgFmt_CSV transfers the driver loads the transferred text and + // attempts to update the current WIA_IPS_PRINTER_ENDORSER_STRING value with it, performing + // validation as if the application would directly set WIA_IPS_PRINTER_ENDORSER_STRING. + // + // It was already validated that WIA_MINIDRV_TRANSFER_UPLOAD works only for + // WIA_CATEGORY_IMPRINTER and WIA_CATEGORY_ENDORSER. + // + + // + // Request the WIA transfer stream from the WIA client application: + // + if (SUCCEEDED(hr)) + { + _Analysis_assume_nullterminated_(bstrItemName); + hr = pTransferCallback->GetNextStream(0, bstrItemName, bstrFullItemName, &pWiaStream); + if (S_FALSE == hr) + { + bCancelTransfer = TRUE; + WIAS_TRACE((g_hInst, "IWiaMiniDrvTransferCallback::GetNextStream returned S_FALSE (0x%08X), transfer must be canceled", hr)); + } + else if (WIA_STATUS_SKIP_ITEM == hr) + { + bSkipTransfer = TRUE; + WIAS_TRACE((g_hInst, "IWiaMiniDrvTransferCallback::GetNextStream returned WIA_STATUS_SKIP_ITEM (0x%08X), transfer must be skipped", hr)); + hr = S_OK; + } + else if (SUCCEEDED(hr) && (S_OK != hr)) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::GetNextStream returned an unknown success value, hr = 0x%08X", hr)); + hr = E_UNEXPECTED; + } + else if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::GetNextStream failed, hr = 0x%08X", hr)); + } + } + + // + // Signal start of data transfer from the WIA application and check if the application asks for the transfer to be cancelled: + // + if ((S_OK == hr) && (!bSkipTransfer)) + { + pCallbackTransferParams->lMessage = WIA_TRANSFER_MSG_STATUS; + pCallbackTransferParams->hrErrorStatus = 0; + pCallbackTransferParams->lPercentComplete = 0; + pCallbackTransferParams->ulTransferredBytes = 0; + + WIAS_TRACE((g_hInst, "Transfer callback: WIA_TRANSFER_MSG_STATUS, 0 bytes")); + hr = pTransferCallback->SendMessage(0, pCallbackTransferParams); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::SendMessage failed, hr = 0x%08X", hr)); + } + else if (S_FALSE == hr) + { + bCancelTransfer = TRUE; + } + else if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::SendMessage returned unknown success value, hr = 0x%08X", hr)); + bCancelTransfer = TRUE; + hr = S_FALSE; + } + } + + if ((S_OK == hr) && (!bSkipTransfer)) + { + // + // Transfer the file from the WIA application: + // + if ((S_OK == hr) && (!bCancelTransfer)) + { + hr = TransferFile(pWiaStream, pInputStream, pTransferBuffer, ulBufferSize, + pTransferCallback, pCallbackTransferParams, 0, &bCancelTransfer); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "File transfer from the WIA stream failed, hr = 0x%08X", hr)); + } + } + } + + // + // The transfer of one file was successfully completed, reset WIA_STATUS_END_OF_MEDIA: + // + if (WIA_STATUS_END_OF_MEDIA == hr) + { + WIAS_TRACE((g_hInst, "File transfer complete (WIA_STATUS_END_OF_MEDIA)")); + hr = S_OK; + } + + // + // Signal 100% transfer complete to the WIA client application (pCallbackTransferParams->ulTransferredBytes + // contains the total number of bytes transferred to this stream): + // + if ((S_OK == hr) && (!bSkipTransfer)) + { + pCallbackTransferParams->lMessage = WIA_TRANSFER_MSG_STATUS; + pCallbackTransferParams->hrErrorStatus = 0; + pCallbackTransferParams->lPercentComplete = 100; + + WIAS_TRACE((g_hInst, "Transfer callback: WIA_TRANSFER_MSG_STATUS, transfer complete, %02.2f KB total (%u)", + pCallbackTransferParams->ulTransferredBytes / 1024.0f, pCallbackTransferParams->lPercentComplete)); + + hr = pTransferCallback->SendMessage(0, pCallbackTransferParams); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::SendMessage(WIA_TRANSFER_MSG_STATUS, transfer complete) failed, hr = 0x%08X", hr)); + } + } + + + // + // Clean-up after finishing each individual WIA file transfer: + // + + pCallbackTransferParams->lPercentComplete = 0; + pCallbackTransferParams->ulTransferredBytes = 0; + + // + // Release the current WIA transfer stream: + // + if (pWiaStream) + { + pWiaStream->Release(); + pWiaStream = NULL; + } + + // + // For upload transfers we need to check the current WIA_IPA_FORMAT to see what + // format is the file that was uploaded by the application, the MINIDRV_TRANSFER_CONTEXT + // structure not being initialized with the right file format in this case. + // Remember that the WIA application needs to set WIA_IPA_FORMAT before calling + // IWiaTransfer::Upload: + // + if (S_OK == hr) + { + hr = wiasReadPropGuid(pWiasContext, WIA_IPA_FORMAT, &guidUploadFormat, NULL, TRUE); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to read WIA_IPA_FORMAT, hr = 0x%08X", hr)); + } + } + + if (S_OK == hr) + { + // + // At this point pInputStream contains the data uploaded by the application + // + if (IsEqualGUID(WiaImgFmt_BMP, guidUploadFormat)) + { + if (SUCCEEDED(IsDibValid(pInputStream, 1, IMPRINTER_MAX_WIDTH, IMPRINTER_MAX_HEIGHT))) + { + if (pWiaDriverItemContext->m_pUploadedImage) + { + IStream *pTemp = pWiaDriverItemContext->m_pUploadedImage; + pWiaDriverItemContext->m_pUploadedImage = NULL; + pTemp->Release(); + } + pWiaDriverItemContext->m_pUploadedImage = pInputStream; + pInputStream = NULL; + } + else + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, + "The uploaded WiaImgFmt_BMP (DIB) image is invalid. This item accepts only a 1-bpp %ux%u pixels image, bottom to top line order, hr = 0x%08X", + IMPRINTER_MAX_WIDTH, IMPRINTER_MAX_HEIGHT, hr)); + } + } + else if (IsEqualGUID(WiaImgFmt_TXT, guidUploadFormat) || IsEqualGUID(WiaImgFmt_CSV, guidUploadFormat)) + { + if (FAILED(IsImprinterEndorserTextValid(pWiasContext, pInputStream, IsEqualGUID(WIA_CATEGORY_IMPRINTER, guidItemCategory) ? IMPRINTER : ENDORSER))) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "The uploaded text data is invalid, hr = 0x%08X", hr)); + } + } + else + { + USHORT *pUUID = NULL; + hr = E_INVALIDARG; + + if (RPC_S_OK == UuidToStringW(&guidUploadFormat, &pUUID)) + { + WIAEX_ERROR((g_hInst, "Unsupported upload transfer file format (%ws), hr = 0x%08X", pUUID, hr)); + RpcStringFreeW(&pUUID); + } + else + { + WIAEX_ERROR((g_hInst, "Unsupported upload transfer file format, hr = 0x%08X", hr)); + } + } + } + + if (pInputStream) + { + pInputStream->Release(); + } + + + WIAEX_TRACE_FUNC_HR; + + return hr; +} + +/**************************************************************************\ +* +* Helper for CWiaDriver::drvAcquireItemData. Transfers one file (image or +* metadata) to the WIA transfer stream provided by the aplication. Note that +* for image file transfers it is not a good solution to let GDI+ to write the +* image directly to the WIA transfer stream as the WIA stream has special +* requirements such as predetermined buffer size, reposition of the write +* cursor at the beginning of the stream between writes and WIA notifications. +* +* Parameters: +* +* pInputStream - IStream object to read the file from +* pDestinationStream - IStream object to write the file to +* pTransferBuffer - pre-allocated transfer buffer +* ulBufferSize - size of the pre-allocated transfer buffer, in bytes +* pTransferCallback - optional IWiaMiniDrvTransferCallback* for WIA status +* pCallbackTransferParams - optional WiaTransferParams* for WIA status callbacks +* ulEstimatedFileSize - estimated file size, in bytes (0 if unknown) +* pbCancelTransfer - on return indicates if the WIA client canceled +* the operation +* +* Remarks: +* +* The caller may specify a non zero pCallbackTransferParams->lPercentComplete +* value (between 0% and 49%) to have this function resume incrementing the +* percent complete starting from this value. An invalid value is set to 0% +* and does not cause the function to fail (still, the caller must not do this). +* +* Return Value: +* +* WIA_STATUS_END_OF_MEDIA if successful, S_FALSE if the transfer +* is canceled or an error HRESULT if an error occurrs +* +\**************************************************************************/ + +HRESULT +CWiaDriver::TransferFile( + _In_ IStream *pInputStream, + _In_ IStream *pDestinationStream, + _In_reads_bytes_(ulBufferSize) + BYTE *pTransferBuffer, + ULONG ulBufferSize, + _In_opt_ IWiaMiniDrvTransferCallback *pTransferCallback, + _In_opt_ WiaTransferParams *pCallbackTransferParams, + ULONG ulEstimatedFileSize, + _Out_ BOOL *pbCancelTransfer) +{ + HRESULT hr = S_OK; + HRESULT hrTemp = S_OK; + + ULONG ulBytesToRead = 0; + ULONG ulBytesRead = 0; + ULONG ulBytesToWrite = 0; + ULONG ulBytesWritten = 0; + ULONG ulFileBytesWritten = 0; + ULONG ulPercentComplete = 0; + ULONG ulStartProgressFrom = 0; + + const LARGE_INTEGER liZeroOffset = {}; + + WIAEX_TRACE_BEGIN; + + if ((!pInputStream) || (!pDestinationStream) || (!pTransferBuffer) || (!pbCancelTransfer)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + else + { + *pbCancelTransfer = FALSE; + } + + if ((S_OK == hr) && pTransferCallback && pCallbackTransferParams && pCallbackTransferParams->lPercentComplete) + { + if ((pCallbackTransferParams->lPercentComplete < 0) || (pCallbackTransferParams->lPercentComplete > 49)) + { + WIAEX_ERROR((g_hInst, "Invalid WiaTransferParams::lPercentComplete parameter (%d), reset to 0", + pCallbackTransferParams->lPercentComplete)); + ulStartProgressFrom = 0; + } + else + { + ulStartProgressFrom = (ULONG)pCallbackTransferParams->lPercentComplete; + WIAS_TRACE((g_hInst, "Resuming progress indicator from %u", ulStartProgressFrom)); + } + } + + if (S_OK == hr) + { + // + // Make sure the input stream pointer is at the beginning of the stream before reading from it: + // + hr = pInputStream->Seek(liZeroOffset, STREAM_SEEK_SET, NULL); + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "IStream::Seek(0, STREAM_SEEK_SET, NULL) failed, hr = 0x%08X", hr)); + } + } + + + // + // Resume from current pCallbackTransferParams->lPercentComplete, + // do not reset to 0 pCallbackTransferParams->lPercentComplete: + // + if ((S_OK == hr) && pCallbackTransferParams) + { + pCallbackTransferParams->ulTransferredBytes = 0; + } + + while (S_OK == hr) + { + ulBytesRead = 0; + ulBytesToRead = ulBufferSize; + ulBytesWritten = 0; + ulBytesToWrite = 0; + *pbCancelTransfer = FALSE; + + // + // Read one buffer of data from the input stream. Note the source IStream + // may return S_OK and no data when the transfer is complete: + // + hr = pInputStream->Read(pTransferBuffer, ulBytesToRead, &ulBytesRead); + if ((S_FALSE == hr) || ((S_OK == hr) && (!ulBytesRead))) + { + // + // End of file, transfer of this file should be complete: + // + hr = WIA_STATUS_END_OF_MEDIA; + WIAS_TRACE((g_hInst, "IStream::Read: end of media, data transfer complete")); + } + else if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "IStream::Read failed, hr = 0x%08X", hr)); + } + else if (ulBytesRead > ulBytesToRead) + { + hr = E_UNEXPECTED; + WIAEX_ERROR((g_hInst, "IStream::Read caused a possible buffer overflow (%u bytes over %u limit), hr = 0x%08X", + ulBytesRead - ulBytesToRead, ulBytesToRead, hr)); + } + + // + // Write the the read buffer content to the destination stream: + // + if ((S_OK == hr) || ((WIA_STATUS_END_OF_MEDIA == hr) && (ulBytesRead > 0))) + { + // + // Make sure the write stream pointer is at the end of the stream before writing to it: + // + hrTemp = pDestinationStream->Seek(liZeroOffset, STREAM_SEEK_END, NULL); + if (FAILED(hrTemp)) + { + WIAEX_ERROR((g_hInst, "IStream::Seek(0, STREAM_SEEK_END, NULL) failed, hr = 0x%08X", hrTemp)); + } + + // + // Write the buffer to the destination stream: + // + if (S_OK == hrTemp) + { + ulBytesToWrite = ulBytesRead; + + hrTemp = pDestinationStream->Write(pTransferBuffer, ulBytesToWrite, &ulBytesWritten); + if (FAILED(hrTemp)) + { + WIAEX_ERROR((g_hInst, "IStream::Write(%u bytes) failed, hr = 0x%08X", ulBytesToWrite, hrTemp)); + } + } + + // + // Make progress callback to the WIA client application and check for a cancel transfer request: + // + if (S_OK == hrTemp) + { + if (pTransferCallback && pCallbackTransferParams) + { + ulFileBytesWritten += ulBytesWritten; + + // + // Indicate to ComputeTransferProgress a direct/full transfer (0% .. 99%): + // + ComputeTransferProgress(&ulPercentComplete, ulEstimatedFileSize, ulFileBytesWritten, TRUE, ulStartProgressFrom); + + pCallbackTransferParams->lMessage = WIA_TRANSFER_MSG_STATUS; + pCallbackTransferParams->ulTransferredBytes = ulFileBytesWritten; + pCallbackTransferParams->lPercentComplete = ulPercentComplete; + + WIAS_TRACE((g_hInst, "Transfer callback: WIA_TRANSFER_MSG_STATUS, %u bytes, %02.2f KB total (%u)", + ulBytesWritten, pCallbackTransferParams->ulTransferredBytes / 1024.0f, ulPercentComplete)); + + hrTemp = pTransferCallback->SendMessage(0, pCallbackTransferParams); + if (FAILED(hrTemp)) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::SendMessage(%u bytes written) failed, hr = 0x%08X", + ulBytesWritten, hrTemp)); + } + else if (S_FALSE == hrTemp) + { + *pbCancelTransfer = TRUE; + } + else if (S_OK != hrTemp) + { + WIAEX_ERROR((g_hInst, "IWiaMiniDrvTransferCallback::SendMessage(%u bytes written) returned unknown success value, hr = 0x%08X", + ulBytesWritten, hrTemp)); + *pbCancelTransfer = TRUE; + hrTemp = S_FALSE; + } + } + else + { + WIAS_TRACE((g_hInst, "Transferred %u bytes, %02.2f KB total (%u)", ulBytesWritten, + ulFileBytesWritten / 1024.0f, ulPercentComplete)); + } + } + + // + // Preserve WIA_STATUS_END_OF_MEDIA to allow this loop to normally end, unless a failure was encountered: + // + if ((S_OK != hrTemp) || (WIA_STATUS_END_OF_MEDIA != hr)) + { + hr = hrTemp; + } + } + } + + WIAEX_TRACE_FUNC_HR; + + return hr; +} + +/**************************************************************************\ +* +* Helper for IWiaMiniDrv::drvAcquireItemData. Executes a simple validation +* for the WiaImgFmt_BMP (DIB) image uploaded by the application and stored +* in the specified stream. +* +* Parameters: +* +* pStream - stream source for the image to be validated +* lBitDepth - expected pixel bit depth (e.g. 24) +* lWidth - expected image width, in pixels +* lHeight - expected image height, in pixels; also describes +* the DIB line order (if negative the image data is +* top to bottom, positive means bottom to top) +* +* Return Value: +* +* S_OK if successful and the image is valid, E_INVALIDARG if the image is +* invalid or another error HRESULT if another error occurrs and the image +* cannot be validated +* +\**************************************************************************/ + +HRESULT +CWiaDriver::IsDibValid( + _In_ IStream* pStream, + LONG lBitDepth, + LONG lWidth, + LONG lHeight) +{ + HRESULT hr = S_OK; + LARGE_INTEGER lStart = {}; + BITMAPINFO bi = {}; + + WIAEX_TRACE_BEGIN; + + if (!pStream) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + lStart.LowPart = sizeof(BITMAPFILEHEADER); + + hr = pStream->Seek(lStart, STREAM_SEEK_SET, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to reset the input stream, hr = 0x%08X", hr)); + } + } + + if (S_OK == hr) + { + hr = pStream->Read(&bi, sizeof(bi), NULL); + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "Failed to read the DIB header from the image, hr = 0x%08X", hr)); + if (SUCCEEDED(hr)) + { + hr = E_INVALIDARG; + } + } + } + + if (SUCCEEDED(hr) && (bi.bmiHeader.biBitCount != lBitDepth)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid DIB pixel bit depth, got %u bits, expected %u bit(s), hr = 0x%08X", + bi.bmiHeader.biBitCount, lBitDepth, hr)); + } + + if (SUCCEEDED(hr) && (bi.bmiHeader.biWidth != lWidth)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid DIB width, got %u pixels, expected %u pixels, hr = 0x%08X", + bi.bmiHeader.biWidth, lWidth, hr)); + } + + if (SUCCEEDED(hr) && (bi.bmiHeader.biHeight != lHeight)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid DIB height and/or line order, got %l pixels, expected %l pixels, hr = 0x%08X", + bi.bmiHeader.biHeight, lHeight, hr)); + } + + if (S_OK == hr) + { + lStart.LowPart = 0; + + hr = pStream->Seek(lStart, STREAM_SEEK_SET, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to reset the input stream, hr = 0x%08X", hr)); + } + } + + WIAEX_TRACE_FUNC_HR; + + return hr; + +} + +/**************************************************************************\ +* +* Helper for IWiaMiniDrv::drvAcquireItemData. Executes a simple validation +* for the WiaImgFmt_TXT and WiaImgFmt_CSV imprinter/endorser text uploaded +* by the application and stored in the specified stream and if the text is +* valid it updates WIA_IPS_PRINTER_ENDORSER_STRING. +* +* Parameters: +* +* pWiasContext - item context +* pStream - stream source for the image to be validated +* nDocumentHandlingSelect - IMPRINTER or ENDORSER (defined in wiadef.h) +* +* Return Value: +* +* S_OK if successful and the image is valid, E_INVALIDARG or another +* error HRESULT if validation fails or if it cannot be performed +* +\**************************************************************************/ + +HRESULT +CWiaDriver::IsImprinterEndorserTextValid( + _In_ BYTE* pWiasContext, + _In_ IStream* pStream, + LONG nDocumentHandlingSelect) +{ + HRESULT hr = S_OK; + LARGE_INTEGER liZero = {}; + ULARGE_INTEGER ui = {}; + ULONG ulNumChars = 0; + ULONG ulDataSize = 0; + PWCHAR pwData = NULL; + BSTR bstrData = NULL; + + WIAEX_TRACE_BEGIN; + + if (!pStream) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + hr = IStream_Size(pStream, &ui); + if (SUCCEEDED(hr)) + { + WIAS_TRACE((g_hInst, "Stream size, low: %u bytes, high: %u bytes", + ui.LowPart, ui.HighPart)); + + if (ui.HighPart > 0) + { + WIAS_TRACE((g_hInst, "Stream size exceeeds maximum accepted by this item, last %u bytes will be ignored", ui.HighPart)); + } + + // + // Data must contain the two bytes BOM and at least one double-byte character: + // + if (ui.LowPart >= (2 * sizeof(WCHAR))) + { + ulDataSize = ui.LowPart; + } + else + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Insufficient data (less than one actual character), hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "IStream_Size failed, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = pStream->Seek(liZero, STREAM_SEEK_SET, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to reset memory stream, hr = 0x%08X", hr)); + } + } + + // + // Read first the BOM bytes and validate: + // + if (S_OK == hr) + { + BYTE bBOM[2] = {}; + + hr = pStream->Read(bBOM, 2, NULL); + if (S_OK == hr) + { + if ((0xFF != bBOM[0]) || (0xFE != bBOM[1])) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid BOM. Expected 0xFF 0xFE, received 0x%X 0x%X, hr = 0x%08X", bBOM[0], bBOM[1], hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to read the BOM from the stream, hr = 0x%08X", hr)); + if (SUCCEEDED(hr)) + { + hr = E_INVALIDARG; + } + } + } + + // + // Alocate memory for the NULL terminated WCHAR string. The NULL string terminator is not + // expected in the stream, however the stream must contain the BOM "character" instead, + // thus we need to allocate space for the same number of whole double byte characters + // that are in the stream: + // + if (SUCCEEDED(hr)) + { + ulNumChars = ulDataSize / sizeof(WCHAR); + pwData = new WCHAR[ulNumChars]; + if (pwData) + { + // + // NULL terminate the string: + // + pwData[ulNumChars - 1] = 0; + } + else + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Out of memory when trying to allocate %u bytes, hr = 0x%08X", ulDataSize, hr)); + } + } + + // + // Read the actual imprinter/endorser characters: + // + if (S_OK == hr) + { + // + // ulNumChars includes the length of the NULL terminator: + // + ulNumChars -= 1; + + hr = pStream->Read((PBYTE)pwData, ulNumChars * sizeof(WCHAR), NULL); + if (S_OK != hr) + { + WIAEX_ERROR((g_hInst, "Failed to read from the stream, hr = 0x%08X", hr)); + if (SUCCEEDED(hr)) + { + hr = E_INVALIDARG; + } + } + } + + // + // Validate each character against the set of valid characters for the source: + // + if (SUCCEEDED(hr)) + { + 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; + BOOL bFound = FALSE; + + for (ULONG i = 0; i < ulNumChars; i++) + { + bFound = FALSE; + + for (ULONG j = 0; j < ulValidChars; j++) + { + if (pwData[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", pwData[i], pwData[i], hr)); + break; + } + } + } + + if (SUCCEEDED(hr)) + { + bstrData = SysAllocString(pwData); + if (!bstrData) + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Out of memory when trying to allocate a BSTR of %u characters in length, hr = 0x%08X", ulNumChars, hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = wiasWritePropStr(pWiasContext, WIA_IPS_PRINTER_ENDORSER_STRING, bstrData); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to set WIA_IPS_PRINTER_ENDORSER_STRING, hr = 0x%08X", hr)); + } + } + + if (bstrData) + { + SysFreeString(bstrData); + } + + if (pwData) + { + delete[] pwData; + } + + WIAEX_TRACE_FUNC_HR; + + return hr; + +} + +/**************************************************************************\ +* +* Helper for IWiaMiniDrv::drvAcquireItemData. Loads a test data file (image +* or metadata) from resources. A test image is expected to be in EXIF format +* and match the dimensions described by the MIN/MAX_TEST_SCAN_WIDTH/HEIGHT. +* The function does not attempt to validate the contents of data loaded from +* resources, it only copies the whole data file to the specified stream. +* +* Parameters: +* +* ulResourceId - resource identifier +* pStream - stream destination for the test image +* pulDataSize - returns the size in bytes of the data loaded from +* resources and written to the destination stream +* +* Return Value: +* +* S_OK if successful or an error HRESULT if an error occurrs +* +\**************************************************************************/ + +HRESULT +CWiaDriver::LoadTestDataResourceToStream( + ULONG ulResourceId, + _In_ IStream *pStream, + _Out_ ULONG *pulDataSize) +{ + HRESULT hr = S_OK; + + WIAEX_TRACE_BEGIN; + + if ((!pStream) && (!pulDataSize)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *pulDataSize = 0; + + HRSRC hResourceInfo = FindResource(g_hInst, MAKEINTRESOURCE(ulResourceId), RT_RCDATA); + if (hResourceInfo) + { + ULONG ulWrittenData = 0; + + ULONG ulDataSize = (ULONG)SizeofResource(g_hInst, hResourceInfo); + if (ulDataSize > 0) + { + HGLOBAL hTestData = LoadResource(g_hInst, hResourceInfo); + if (hTestData) + { + PBYTE pTestData = (PBYTE)LockResource(hTestData); + if (pTestData) + { + LARGE_INTEGER lZero = {}; + + hr = pStream->Seek(lZero, STREAM_SEEK_SET, NULL); + if (S_OK == hr) + { + hr = pStream->Write(pTestData, ulDataSize, &ulWrittenData); + if (S_OK == hr) + { + if (ulWrittenData != ulDataSize) + { + hr = E_FAIL; + WIAEX_ERROR((g_hInst, "Failed to load data (%u) from resources, expected %u bytes, got %u bytes, hr = 0x%08X", + ulResourceId, ulDataSize, ulWrittenData, hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to load data (%u) from resources, hr = 0x%08X", ulResourceId, hr)); + } + + HRESULT hrTemp = pStream->Seek(lZero, STREAM_SEEK_SET, NULL); + if (S_OK != hrTemp) + { + if (S_OK == hr) + { + hr = hrTemp; + } + + WIAEX_ERROR((g_hInst, "Failed to reset memory stream, hr = 0x%08X", hrTemp)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to reset memory stream, hr = 0x%08X", hr)); + } + + } + DeleteObject(hTestData); + } + + if (S_OK == hr) + { + *pulDataSize = ulDataSize; + } + } + else + { + hr = HRESULT_FROM_WIN32(::GetLastError()); + WIAEX_ERROR((g_hInst, "Bad resource (%u), hr = 0x%08X", ulResourceId, hr)); + } + } + else + { + hr = HRESULT_FROM_WIN32(::GetLastError()); + WIAEX_ERROR((g_hInst, "Cannot find resource (%u), hr = 0x%08X", ulResourceId, hr)); + } + } + + WIAEX_TRACE_FUNC_HR; + + return hr; +} + +/**************************************************************************\ +* +* Helper for IWiaMiniDrv::drvAcquireItemData. Writes generated or hard-coded +* sample metadata to the specified download stream. This data is to be +* transferred from this sample driver to the WIA application client as an +* imprinter/endorser text/CSV file, or raw barcode/patch code/MICR metadata. +* +* Parameters: +* +* pWiasContext - item context +* guidItemCategory - item category (WIA_CATEGORY_ value) +* guidFormat - trasfer file format (WiaImgFmt_ value) +* pStream - stream destination for the test image +* pulDataSize - returns the size in bytes of the data loaded from +* resources and written to the destination stream +* +* Return Value: +* +* S_OK if successful or an error HRESULT if an error occurrs +* +\**************************************************************************/ + +HRESULT +CWiaDriver::LoadTestDataToStream( + _In_ BYTE *pWiasContext, + GUID guidItemCategory, + GUID guidFormat, + _In_ IStream *pStream, + _Out_ ULONG *pulDataSize) +{ + HRESULT hr = S_OK; + ULONG ulDataSize = 0; + + WIAEX_TRACE_BEGIN; + + if ((!pWiasContext) || (!pStream) && (!pulDataSize)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + if ((IsEqualGUID(WIA_CATEGORY_IMPRINTER, guidItemCategory) || IsEqualGUID(WIA_CATEGORY_ENDORSER, guidItemCategory)) && + (!IsEqualGUID(WiaImgFmt_BMP, guidFormat))) + { + if (IsEqualGUID(WiaImgFmt_TXT, guidFormat) || IsEqualGUID(WiaImgFmt_CSV, guidFormat)) + { + BSTR bstrData = NULL; + + // + // Read the current WIA_IPS_PRINTER_ENDORSER_STRING character string value + // and prepare to write it to the destination stream, for simplicity without + // expanding any special formatting sequences. Note the NULL string terminator + // is not to be written to the stream (which for this sample it will end up + // as a TXT or CSV file): + // + hr = wiasReadPropStr(pWiasContext, WIA_IPS_PRINTER_ENDORSER_STRING, &bstrData, NULL, TRUE); + if (SUCCEEDED(hr)) + { + hr = pStream->Write(g_bBOM, sizeof(g_bBOM), NULL); + if (SUCCEEDED(hr)) + { + ulDataSize = (ULONG)(wcslen((PWCHAR)bstrData) * sizeof(WCHAR)); + + hr = pStream->Write((PBYTE)bstrData, ulDataSize, NULL); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "IStream::Write(data) failed, hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "IStream::Write(prefix) failed, hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to read the current WIA_IPS_PRINTER_ENDORSER_STRING value, hr = 0x%08X", hr)); + } + + if (bstrData) + { + SysFreeString(bstrData); + } + } + else + { + hr = E_INVALIDARG; + } + } + else if (IsEqualGUID(WIA_CATEGORY_BARCODE_READER, guidItemCategory) && IsEqualGUID(WiaImgFmt_RAWBAR, guidFormat)) + { + WIA_BARCODES bc = {}; + WIA_BARCODE_INFO bi = {}; + + // + // 3 hard-coded sample barcodes to report. These sample barcodes match the XML sample metadata (Barcodes.xml): + // + + WCHAR szBarcodeOne[] = L"036000291452"; + WCHAR szBarcodeTwo[] = L"3117013206375"; + WCHAR szBarcodeThree[] = L"This is a Full ASCII Code 39 example"; + + // + // When computing the data size take into account the following important details: + // + // WIA_BARCODES includes a WIA_BARCODE_INFO structure element as a placeholder. + // WIA_BARCODE_INFO includes a WCHAR pleceholder for the text. + // Make sure the size of these fields are not counted twice. + // + // Do not include the length of the NULL string terminators for the character sequences, + // they and not NULL terminated. + // + // Do not compute the fixed size (excluding the text) of a WIA_BARCODE_INFO structure + // doing sizeof(WIA_BARCODE_INFO) - sizeof(WCHAR), this will incorrectly add compiler + // padding for the data structure (2 additional bytes by default). Instead compute + // the length of the fixed WIA_BARCODE_INFO size as 8 * sizeof(DWORD). + // + ULONG ulFixedSize = 4 * sizeof(DWORD); //not: sizeof(WIA_BARCODES - sizeof(WIA_BARCODES_INFO) + ULONG ulFixedInfoSize = 8 * sizeof(DWORD); //not: sizeof(WIA_BARCODES_INFO) - sizeof(WCHAR) + ulDataSize = ulFixedSize + (3 * ulFixedInfoSize) + sizeof(szBarcodeOne) + sizeof(szBarcodeTwo) + sizeof(szBarcodeThree) - (3 * sizeof(WCHAR)); + + const char szSignature[] = "WBAR"; + memcpy(&bc.Tag, szSignature, sizeof(DWORD)); + + bc.Version = 0x00010000; + bc.Size = ulDataSize; + bc.Count = 3; + + hr = pStream->Write(&bc, ulFixedSize, NULL); + if (SUCCEEDED(hr)) + { + bi.Size = ulFixedInfoSize + sizeof(szBarcodeOne) - sizeof(WCHAR); + bi.Type = 0; + bi.Page = 0; + bi.Confidence = 5; + bi.XOffset = 0; + bi.YOffset = 0; + bi.Rotation = 90; + bi.Length = (DWORD)wcslen(szBarcodeOne); + + hr = pStream->Write(&bi, ulFixedInfoSize, NULL); + if (SUCCEEDED(hr)) + { + hr = pStream->Write(szBarcodeOne, sizeof(szBarcodeOne) - sizeof(WCHAR), NULL); + } + } + + if (SUCCEEDED(hr)) + { + bi.Size = ulFixedInfoSize + sizeof(szBarcodeTwo) - sizeof(WCHAR); + bi.Type = 2; + bi.Page = 0; + bi.Confidence = 9; + bi.XOffset = 2; + bi.YOffset = 1000; + bi.Rotation = 0; + bi.Length = (DWORD)wcslen(szBarcodeTwo); + + hr = pStream->Write(&bi, ulFixedInfoSize, NULL); + if (SUCCEEDED(hr)) + { + hr = pStream->Write(szBarcodeTwo, sizeof(szBarcodeTwo) - sizeof(WCHAR), NULL); + } + } + + if (SUCCEEDED(hr)) + { + bi.Size = ulFixedInfoSize + sizeof(szBarcodeThree) - sizeof(WCHAR); + bi.Type = 7; + bi.Page = 0; + bi.Confidence = 10; + bi.XOffset = 0; + bi.YOffset = 2000; + bi.Rotation = 0; + bi.Length = (DWORD)wcslen(szBarcodeThree); + + hr = pStream->Write(&bi, ulFixedInfoSize, NULL); + if (SUCCEEDED(hr)) + { + hr = pStream->Write(szBarcodeThree, sizeof(szBarcodeThree) - sizeof(WCHAR), NULL); + } + } + } + else if (IsEqualGUID(WIA_CATEGORY_PATCH_CODE_READER, guidItemCategory) && IsEqualGUID(WiaImgFmt_RAWPAT, guidFormat)) + { + WIA_PATCH_CODES pc = {}; + WIA_PATCH_CODE_INFO pi = {}; + + // + // 2 hard-coded sample patch codes to report. These sample codes match the XML sample metadata (PatchCod.xml): + // + + ULONG ulFixedSize = 4 * sizeof(DWORD); + ULONG ulFixedInfoSize = sizeof(DWORD); + ulDataSize = ulFixedSize + (2 * ulFixedInfoSize); + + const char szSignature[] = "WPAT"; + memcpy(&pc.Tag, szSignature, sizeof(DWORD)); + + pc.Version = 0x00010000; + pc.Size = ulDataSize; + pc.Count = 2; + + hr = pStream->Write(&pc, ulFixedSize, NULL); + if (SUCCEEDED(hr)) + { + pi.Type = 2; + + hr = pStream->Write(&pi, ulFixedInfoSize, NULL); + } + + if (SUCCEEDED(hr)) + { + pi.Type = 1; + + hr = pStream->Write(&pi, ulFixedInfoSize, NULL); + } + } + else if (IsEqualGUID(WIA_CATEGORY_MICR_READER, guidItemCategory) && IsEqualGUID(WiaImgFmt_RAWMIC, guidFormat)) + { + WIA_MICR micr = {}; + WIA_MICR_INFO mi = {}; + + // + // 2 hard-coded sample MICR codes to report. These sample codes match the XML sample metadata (Micr.xml): + // + + WCHAR szMicrOne[] = L"1234567890"; + WCHAR szMicrTwo[] = L"987?543?10"; + + // + // When computing the data size take into account the following important details: + // + // WIA_MICR includes a WIA_MICR_INFO structure element as a placeholder. + // WIA_MICR_INFO includes a WCHAR pleceholder for the text. + // Make sure the size of these fields are not counted twice. + // + // Do not include the length of the NULL string terminators for the character sequences, + // they and not NULL terminated. + // + // Do not compute the fixed size (excluding the text) of a WIA_MICR_INFO structure + // doing sizeof(WIA_MICR_INFO) - sizeof(WCHAR), this may add compiler padding for + // the data structure. Instead compute the length of the fixed WIA_MICR_INFO size + // as 3 * sizeof(DWORD). + // + ULONG ulFixedSize = 5 * sizeof(DWORD); //not: sizeof(WIA_MICR - sizeof(WIA_MICR_INFO) + ULONG ulFixedInfoSize = 3 * sizeof(DWORD); //not: sizeof(WIA_MICR_INFO) - sizeof(WCHAR) + ulDataSize = ulFixedSize + (2 * ulFixedInfoSize) + sizeof(szMicrOne) + sizeof(szMicrTwo) - (2 * sizeof(WCHAR)); + + const char szSignature[] = "WMIC"; + memcpy(&micr.Tag, szSignature, sizeof(DWORD)); + + micr.Version = 0x00010000; + micr.Size = ulDataSize; + micr.Count = 2; + micr.Placeholder = L'?'; + + hr = pStream->Write(&micr, ulFixedSize, NULL); + if (SUCCEEDED(hr)) + { + mi.Size = ulFixedInfoSize + sizeof(szMicrOne) - sizeof(WCHAR); + mi.Page = 0; + mi.Length = (DWORD)wcslen(szMicrOne); + + hr = pStream->Write(&mi, ulFixedInfoSize, NULL); + if (SUCCEEDED(hr)) + { + hr = pStream->Write(szMicrOne, sizeof(szMicrOne) - sizeof(WCHAR), NULL); + } + } + + if (SUCCEEDED(hr)) + { + mi.Size = ulFixedInfoSize + sizeof(szMicrTwo) - sizeof(WCHAR); + mi.Page = 1; + mi.Length = (DWORD)wcslen(szMicrTwo); + + hr = pStream->Write(&mi, ulFixedInfoSize, NULL); + if (SUCCEEDED(hr)) + { + hr = pStream->Write(szMicrTwo, sizeof(szMicrTwo) - sizeof(WCHAR), NULL); + } + } + } + else + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid item - transfer format combination, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + *pulDataSize = ulDataSize; + } + + WIAEX_TRACE_FUNC_HR; + + return hr; +} + +/**************************************************************************\ +* +* Helper for TransferFile. Computes the transfer completion relative to the +* specified size of data written and the estimated target file size. +* +* Parameters: +* +* pulPercentComplete - percent complete value to be updated +* ulEstimatedFileSize - estimated file size, in bytes (0 if unknown) +* ulFileBytesWritten - number of bytes of data written +* bDirectWiaTransfer - TRUE if this is a full WIA transfer when the +* percent complete must be incremented from 0% +* to 99%, FALSE if this is a transfer of a file +* already read from the scanner when the percent +* complete is set from ulResumeFrom to 99% -or- +* if this is a transfer from scanner to the driver +* when the percent complete is set from 0% to 49%. +* ulResumeFrom - if bDirectWiaTransfer is FALSE this parameter +* indicates a start value between 0% and 49% for +* a transfer from the driver to the WIA app -or- +* 0 to indicate a transfer from the scanner to driver +* Return Value: +* +* None +* +\**************************************************************************/ + +void +CWiaDriver::ComputeTransferProgress( + _Inout_ ULONG *pulPercentComplete, + ULONG ulEstimatedFileSize, + ULONG ulFileBytesWritten, + BOOL bDirectWIATransfer, + ULONG ulResumeFrom) +{ + ULONG ulStartPos = 0; + double dMax = 100.0; + ULONG ulLimit = 99; + + if (!bDirectWIATransfer) + { + if (!ulResumeFrom) + { + // + // If this is an indirect (translated) transfer and the indicated + // start position is 0 we will compute the transfer complete on a + // 0% to 50% scale up to a maximum value of 49%: + // + ulStartPos = 0; + dMax = 50.0; + ulLimit = 49; + + } + else + { + // + // If a non-zero value is indicated to start the progress indicator + // from we will resume incrementing the transfer complete from here: + // + if (ulResumeFrom < 50) + { + ulStartPos = ulResumeFrom + 1; + } + else + { + ulStartPos = 50; + } + + dMax = 100.0 - (double)ulStartPos; + ulLimit = 99 - ulStartPos; + } + } + + if (pulPercentComplete) + { + // + // Note that we do not know in advance the exact size of the file to be transferred. + // In order to allow the WIA client application to see activity (other than the + // amount of data that is being transferred with each write) we will use the estimated + // uncompressed data size (if available) or simply increment the percent complete until + // 99 or end of file transfer (and then set it to 100%): + // + if (ulEstimatedFileSize > 0) + { + *pulPercentComplete = (ULONG)(dMax * (((double)ulFileBytesWritten) / ((double)ulEstimatedFileSize))); + if ((*pulPercentComplete) > ulLimit) + { + *pulPercentComplete = ulLimit; + } + } + else + { + if ((*pulPercentComplete) < ulLimit) + { + *pulPercentComplete += 1; + } + } + + if (!bDirectWIATransfer) + { + *pulPercentComplete += ulStartPos; + } + } +} diff --git a/wia/ProdScan/Server.cpp b/wia/ProdScan/Server.cpp new file mode 100644 index 00000000..95debdf8 --- /dev/null +++ b/wia/ProdScan/Server.cpp @@ -0,0 +1,476 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Name: Server.cpp +* +* Description: Contains various COM server infrastructure implemented by +* the Production Scanner Driver Sample: INonDelegating and +* IUnknown implementations, IClassFactory interface declaration +* and implementation, DLL entry points including DllMain. +* +***************************************************************************/ + +#include "stdafx.h" + +extern HINSTANCE g_hInst; + +// +// Production Scanner Driver Sample GUID +// +// {EB135F56-B088-4bc7-9733-422F324B3A09} +// +DEFINE_GUID(CLSID_ProdScan, 0xeb135f56, 0xb088, 0x4bc7, 0x97, 0x33, 0x42, 0x2f, 0x32, 0x4b, 0x3a, 0x9); + +// +// CWiaDriver::INonDelegating interface implementation +// + +HRESULT CWiaDriver::NonDelegatingQueryInterface( + REFIID riid, + LPVOID* ppvObj) +{ + HRESULT hr = S_OK; + + if (!ppvObj) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *ppvObj = NULL; + + // + // The Production Scanner Driver Sample object exports the standard WIA mini-driver COM interfaces: + // + // - IUnknown + // - IStiUSD + // - IWiaMiniDrv + // + if (IsEqualIID(riid, IID_IUnknown)) + { + *ppvObj = static_cast<INonDelegatingUnknown*>(this); + } + else if (IsEqualIID(riid, IID_IStiUSD)) + { + *ppvObj = static_cast<IStiUSD*>(this); + } + else if (IsEqualIID(riid, IID_IWiaMiniDrv)) + { + *ppvObj = static_cast<IWiaMiniDrv*>(this); + } + else + { + hr = E_NOINTERFACE; + WIAEX_ERROR((g_hInst, + "Unsupported interface (0x%08X, 0x%04X, 0x%04X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X), hr = 0x%08X", + riid.Data1, riid.Data2, riid.Data3, riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3], + riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7], hr)); + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppvObj)->AddRef(); + } + + return hr; +} + +ULONG CWiaDriver::NonDelegatingAddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +ULONG CWiaDriver::NonDelegatingRelease() +{ + ULONG ulRef = InterlockedDecrement(&m_cRef); + if (!ulRef) + { + WIAS_TRACE((g_hInst, "INonDelegating::NonDelegatingRelease, deleting main driver object (%p, process: %u)..", + this, GetCurrentProcessId())); + delete this; + } + + return ulRef; +} + +// +// CWiaDriver::IClassFactory interface declaration and implementation +// + +class CWiaDriverClassFactory : public IClassFactory +{ +public: + CWiaDriverClassFactory() + : m_cRef(1) + { + return; + } + + ~CWiaDriverClassFactory() + { + return; + } + + HRESULT __stdcall + QueryInterface( + REFIID riid, + _COM_Outptr_ LPVOID* ppv) + { + HRESULT hr = S_OK; + + if (!ppv) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *ppv = NULL; + if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) + { + *ppv = static_cast<IClassFactory*>(this); + reinterpret_cast<IUnknown*>(*ppv)->AddRef(); + } + else + { + hr = E_NOINTERFACE; + WIAEX_ERROR((g_hInst, + "Unsupported interface (0x%08X, 0x%04X, 0x%04X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X), hr = 0x%08X", + riid.Data1, riid.Data2, riid.Data3, riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3], + riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7], hr)); + + } + } + + return hr; + } + + ULONG __stdcall + AddRef() + { + return InterlockedIncrement(&m_cRef); + } + + ULONG __stdcall + Release() + { + ULONG ulRef = InterlockedDecrement(&m_cRef); + if (!ulRef) + { + WIAS_TRACE((g_hInst, "IClassFactory::Release, deleting driver class factory object..")); + delete this; + } + return ulRef; + } + + HRESULT __stdcall +#pragma prefast(suppress:__WARNING_INVALID_PARAM_VALUE_2, "Set ppvObject to NULL if failed.") + CreateInstance( + _In_opt_ IUnknown* pUnkOuter, + _In_ REFIID riid, + _COM_Outptr_ void** ppvObject) + { + HRESULT hr = S_OK; + CWiaDriver *pNewDriverObject = NULL; + + WIAEX_TRACE_BEGIN; + + if (!ppvObject) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *ppvObject = NULL; + + if ((pUnkOuter) && (!IsEqualIID(riid, IID_IUnknown))) + { + hr = CLASS_E_NOAGGREGATION; + WIAEX_ERROR((g_hInst, + "NULL outer IUnknown* and not requesting IID_IUnknown, hr = 0x%08X (CLASS_E_NOAGGREGATION)", hr)); + } + } + + if (SUCCEEDED(hr)) + { + #pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "The main driver object instance is freed when the driver is unloaded") + pNewDriverObject = new CWiaDriver(pUnkOuter); + if (pNewDriverObject) + { + hr = pNewDriverObject->NonDelegatingQueryInterface(riid, ppvObject); + pNewDriverObject->NonDelegatingRelease(); + + if (SUCCEEDED(hr)) + { + WIAS_TRACE((g_hInst, "IClassFactory::CreateInstance, created main driver object (%p, process: %u)", + pNewDriverObject, GetCurrentProcessId())); + } + } + else + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate WIA driver class object, hr = 0x%08X", hr)); + } + } + + WIAEX_TRACE_FUNC_HR; + + return hr; + } + + HRESULT __stdcall + LockServer( + BOOL fLock) + { + UNREFERENCED_PARAMETER(fLock); + return S_OK; + } + +private: + LONG m_cRef; +}; + +// +// IUnknown implementation for CWiaDriver: +// + +HRESULT CWiaDriver::QueryInterface( + REFIID riid, + _COM_Outptr_ LPVOID *ppvObj) +{ + HRESULT hr = S_OK; + + if (!ppvObj) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *ppvObj = NULL; + + if (!m_punkOuter) + { + hr = E_NOINTERFACE; + WIAEX_ERROR((g_hInst, "NULL outer IUnknown*, hr = 0x%08X", hr)); + } + } + + if (SUCCEEDED(hr)) + { + hr = m_punkOuter->QueryInterface(riid, ppvObj); + } + + return hr; +} + +ULONG CWiaDriver::AddRef() +{ + ULONG ulRef = 0; + + if (!m_punkOuter) + { + WIAEX_ERROR((g_hInst, "NULL outer IUnknown*, returning 0")); + } + else + { + ulRef = m_punkOuter->AddRef(); + } + + return ulRef; +} + +ULONG CWiaDriver::Release() +{ + ULONG ulRef = 0; + + if (!m_punkOuter) + { + WIAEX_ERROR((g_hInst, "NULL outer IUnknown*, returning 0")); + } + else + { + ulRef = m_punkOuter->Release(); + } + + return ulRef; +} + +/**************************************************************************\ +* DllMain +* +* Main DLL entry point +* +* Parameters: +* +* hInst - handle to the DLL module +* dwReason - indicates why the DLL entry-point function is being called +* lpReserved - if fdwReason is DLL_PROCESS_ATTACH lpvReserved is NULL for +* dynamic loads and non-NULL for static loads; if fdwReason +* is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has +* been called by using FreeLibrary and non-NULL if DllMain +* has been called during process termination. +* +* Return Value: +* +* When the system calls the DllMain function with the DLL_PROCESS_ATTACH +* value in this particular case the function returns TRUE every time +* indicating it succeeds. +* +\**************************************************************************/ + +extern "C" __declspec(dllexport) BOOL APIENTRY DllMain( + HINSTANCE hInst, + DWORD dwReason, + _Reserved_ LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(lpReserved); + + g_hInst = hInst; + + switch(dwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(g_hInst); + WIAS_TRACE((g_hInst, "DLL_PROCESS_ATTACH (process: %u, thread: %u)", + GetCurrentProcessId(), GetCurrentThreadId())); + break; + + case DLL_PROCESS_DETACH: + WIAS_TRACE((g_hInst, "DLL_PROCESS_DETACH (process: %u, thread: %u)", + GetCurrentProcessId(), GetCurrentThreadId())); + break; + } + + return TRUE; +} + +/**************************************************************************\ +* DllCanUnloadNow +* +* Parameters: none +* +* Determines whether the DLL that implements this function is in use. +* If not, the caller can unload the DLL from memory. +* +* Return Value: S_OK (indicating the DLL can be unloaded at any time) +* +\**************************************************************************/ + +extern "C" HRESULT __stdcall DllCanUnloadNow(void) +{ + return S_OK; +} + +/**************************************************************************\ +* DllGetClassObject +* +* Retrieves the class object from a DLL object handler or object application. +* DllGetClassObject is called from within the CoGetClassObject function +* when the class context is a DLL. +* +* Parameters: +* +* rclsid - CLSID that will associate the correct data and code +* riid - reference to the identifier of the interface that the caller +* is to use to communicate with the class object. Usually, this +* is IID_IClassFactory (the interface identifier for IClassFactory) +* ppv - [out] address of pointer variable that receives the interface +* pointer requested in riid; upon successful return, *ppv contains +* the requested interface pointer; if an error occurs, this is NULL. +* +* Return Values: +* +* S_OK +* E_INVALIDARG +* CLASS_E_CLASSNOTAVAILABLE +* E_OUTOFMEMORY +* +\**************************************************************************/ + +extern "C" HRESULT __stdcall DllGetClassObject( + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ LPVOID* ppv) +{ + HRESULT hr = S_OK; + CWiaDriverClassFactory *pNewClassFactory = NULL; + + WIAEX_TRACE_BEGIN; + + if (!ppv) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameters, hr = 0x%08X", hr)); + } + + if (SUCCEEDED(hr)) + { + *ppv = NULL; + + if (IsEqualCLSID(rclsid, CLSID_ProdScan)) + { + #pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "The final CWiaDriverClassFactory::Release frees the memory") + pNewClassFactory = new CWiaDriverClassFactory; + if (pNewClassFactory) + { + hr = pNewClassFactory->QueryInterface(riid, ppv); + pNewClassFactory->Release(); + } + else + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate WIA driver class factory object, hr = 0x%08X", hr)); + } + } + else + { + hr = CLASS_E_CLASSNOTAVAILABLE; + WIAEX_ERROR((g_hInst, "Class not available, hr = 0x%08X (CLASS_E_CLASSNOTAVAILABLE)", hr)); + } + } + + return hr; +} + +/**************************************************************************\ +* DllRegisterServer +* +* Instructs an in-process server to create its registry entries for all +* classes supported in this server module. +* +* Parameters: none +* +* Return Value: S_OK (registry entries - none - were created successfully) +* +\**************************************************************************/ + +extern "C" HRESULT __stdcall DllRegisterServer() +{ + return S_OK; +} + +/**************************************************************************\ +* DllUnregisterServer +* +* Instructs an in-process server to remove only those entries created +* through DllRegisterServer. +* +* Parameters: none +* +* Return Value: S_OK (registry entries - none - were removed successfully) +* +\**************************************************************************/ + +extern "C" HRESULT __stdcall DllUnregisterServer() +{ + return S_OK; +} diff --git a/wia/ProdScan/StiUSD.cpp b/wia/ProdScan/StiUSD.cpp new file mode 100644 index 00000000..7fd61b8a --- /dev/null +++ b/wia/ProdScan/StiUSD.cpp @@ -0,0 +1,821 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Name: StiUSD.cpp +* +* Description: Contains the IStiUSD interface implementation for +* the Production Scanner Driver Sample +* +* +***************************************************************************/ + +#include "stdafx.h" + + +/**************************************************************************\ +* +* Helper for IStiUSD::Initialize implementation. Placeholder where the driver +* would initialize its communication interface with the scanner device (register +* itself to receive event notifications from the device, read the scanner device +* configuration). Also initializes the the available transfer formats and the +* capabilities needed for the sample driver. +* +* Parameters: +* +* wszDevicePath - device path name +* hDeviceKey - device key in Registry +* +* Return Value: +* +* S_OK if it suceeds, a standard COM error code if initialization fails +* +\**************************************************************************/ + +HRESULT CWiaDriver::InitializeDeviceConnection( + _In_ LPCWSTR wszDevicePath, + _In_ HKEY hDeviceKey) +{ + HRESULT hr = S_OK; + + WIAEX_TRACE_BEGIN; + + // + // Validate parameters: + // + if ((!wszDevicePath) || (!hDeviceKey)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + // + // Initialize here the connection with the scanner device identified by wszDevicePath. + // + // For example: + // + // if (SUCCEEDED(hr)) + // { + // hr = m_ScannerDevice.Initialize(wszDevicePath); + // if (FAILED(hr)) + // { + // WIAEX_ERROR((g_hInst, "Failed to initialize connection with scanner device described by %ws, hr = 0x%08X", wszDevicePath, hr)); + // } + // } + // + + // + // Initialize the valid format information arrays, matching the current scanner configuration if available: + // + if (SUCCEEDED(hr)) + { + hr = InitializeFormatInfoArrays(); + if(FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize WIA_FORMAT_INFO arrays, hr = 0x%08X", hr)); + } + } + + // + // Initialize the page size array used by this driver (only one list, for portrait orientation). + // + // This sample driver supports Letter, and also pretends (without actually doing it) custom + // and auto-detect document sizes: + // + if (SUCCEEDED(hr)) + { + // + // WIA_PAGE_CUSTOM is always supported: + // + m_lPortraitSizesArray.Append(WIA_PAGE_CUSTOM); + + // + // WIA_PAGE_AUTO is also supported if the scanner reports that it supports automatic document size detection: + // + m_lPortraitSizesArray.Append(WIA_PAGE_AUTO); + + // + // Other standard page sizes: + // + GetValidPageSizes(MAX_SCAN_AREA_WIDTH, MAX_SCAN_AREA_HEIGHT, MIN_SCAN_AREA_WIDTH, MIN_SCAN_AREA_HEIGHT, TRUE, m_lPortraitSizesArray); + } + + // + // Create the capability manager which will be initialized (uniquely per + // driver session) during the first IWiaMiniDrv::drvGetCapabilities call: + // + if (SUCCEEDED(hr)) + { + hr = m_tCapabilityManager.Initialize(g_hInst); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to initialize the WIA driver capability manager object, hr = 0x%08X", hr)); + } + } + + WIAEX_TRACE_FUNC_HR; + + return hr; +} + + +/**************************************************************************\ +* +* Implements IStiUSD::Initialize. Initializes an instance of the COM object +* that defines the IStiUSD interface. When this method is called the driver +* receives a pointer to an IStiDeviceControl COM interface. +* +* Parameters: +* +* pIStiDevControl - caller-supplied pointer to the IStiDeviceControl interface +* dwStiVersion - caller-supplied STI version number +* (value defined as STI_VERSION_x in sti.h) +* hParametersKey - caller-supplied handle to the registry key under +* which device-specific information is to be stored. +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. +* +\**************************************************************************/ + +HRESULT CWiaDriver::Initialize( + _In_ PSTIDEVICECONTROL pIStiDevControl, + DWORD dwStiVersion, + _In_ HKEY hParametersKey) +{ + UNREFERENCED_PARAMETER(dwStiVersion); + + HRESULT hr = S_OK; + DWORD cchDevicePath = sizeof(m_wszDevicePath) / sizeof(WCHAR); + + WIAEX_TRACE_BEGIN; + + // + // Validate parameters: + // + if ((!pIStiDevControl) || (!hParametersKey)) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + + // + // Get the device path name from PnP: + // + if (SUCCEEDED(hr)) + { + memset(m_wszDevicePath, 0, sizeof(m_wszDevicePath)); + + hr = pIStiDevControl->GetMyDevicePortName(m_wszDevicePath, cchDevicePath); + + if(FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "IStiDeviceControl::GetMyDevicePortName failed, hr = 0x%08X", hr)); + } + } + + // + // Initialize the connection with the scanner: + // + if (SUCCEEDED(hr)) + { + m_hDeviceKey = hParametersKey; + + hr = InitializeDeviceConnection(m_wszDevicePath, m_hDeviceKey); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "InitializeDeviceConnection for DevicePath %ws failed, hr = 0x%08X", m_wszDevicePath, hr)); + } + } + + if (SUCCEEDED(hr)) + { + m_hrLastEdviceError = STI_ERROR_NO_ERROR; + m_bInitialized = TRUE; + } + else + { + m_hrLastEdviceError = hr; + m_bInitialized = FALSE; + } + + WIAEX_TRACE((g_hInst, "IStiUSD::Initialize 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IStiUSD::GetCapabilities. Returns the still image +* device's capabilities. +* +* Parameters: +* +* pDevCaps - caller-supplied pointer to an empty STI_USD_CAPS structure +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. +* +\**************************************************************************/ + +HRESULT CWiaDriver::GetCapabilities( + _Out_ PSTI_USD_CAPS pDevCaps) +{ + HRESULT hr = S_OK; + + WIAEX_TRACE_BEGIN; + + if (!pDevCaps) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X",hr)); + } + + if (SUCCEEDED(hr)) + { + // + // The sample driver supports device notifications (required), known also as interrupt events. + // Polling (optional) it is not needed so STI_GENCAP_POLLING_NEEDED is not reported here: + // + + memset(pDevCaps, 0, sizeof(STI_USD_CAPS)); + + pDevCaps->dwVersion = STI_VERSION_3; + pDevCaps->dwGenericCaps = STI_GENCAP_WIA | STI_USD_GENCAP_NATIVE_PUSHSUPPORT | STI_GENCAP_NOTIFICATIONS; + + WIAS_TRACE((g_hInst, "Device capabilities: 0x%08X", pDevCaps->dwGenericCaps)); + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAEX_TRACE((g_hInst, "IStiUSD::GetCapabilities 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IStiUSD::GetStatus. Returns the status for the still image device. +* GetStatus is called by the WIA service for two major operations: +* +* 1. Checking device ON-LINE status. +* 2. Polling for device events (like a push button event) +* +* Parameters: +* +* pDevStatus - caller-supplied pointer to an STI_DEVICE_STATUS structure +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. +* +\**************************************************************************/ + +HRESULT CWiaDriver::GetStatus( + _Inout_ PSTI_DEVICE_STATUS pDevStatus) +{ + HRESULT hr = S_OK; + + if (!pDevStatus) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X",hr)); + } + + // + // A driver may be requested to report one or both of the following: + // + // STI_DEVSTATUS_EVENTS_STATE - The driver should fill in the dwEventHandlingState member + // STI_DEVSTATUS_ONLINE_STATE - The driver should fill in the dwOnlineState member + // + // In this case STI_DEVSTATUS_EVENTS_STATE is not expected nor supported as this driver + // does not support polling events (if the driver previously set the STI_GENCAP_POLLING_NEEDED + // flag in the device's STI_DEV_CAPS structure, the IStiUSD::GetStatus method is the means + // by which the Event Monitor determines if a still image device event has occurred; + // the Event Monitor will call the method, specifying STI_DEVSTATUS_EVENT_STATE + // in the supplied STI_DEVICE_STATUS structure; the driver must poll the device + // and set STI_EVENTHANDLING_PENDING if an event has occurred) + // + // If the caller specifies STI_DEVSTATUS_ONLINE_STATE in the supplied + // STI_DEVICE_STATUS structure, the driver should set the appropriate flag + // in the STI_DEVICE_STATUS structure's dwOnlineState member. + // + + if (SUCCEEDED(hr)) + { + pDevStatus->dwOnlineState = 0; + pDevStatus->dwHardwareStatusCode = 0; + pDevStatus->dwEventHandlingState = 0; + + // + // STI_DEVSTATUS_ONLINE_STATE: + // + if (pDevStatus->StatusMask & STI_DEVSTATUS_ONLINE_STATE) + { + // + // This sample driver is always online and ready: + // + pDevStatus->dwOnlineState = STI_ONLINESTATE_OPERATIONAL; + } + + // + // STI_DEVSTATUS_EVENTS_STATE: + // + else if (pDevStatus->StatusMask & STI_DEVSTATUS_EVENTS_STATE) + { + // + // Polled events are not supported so we don't have to return anyting here: + // + pDevStatus->dwEventHandlingState &= ~STI_EVENTHANDLING_PENDING; + } + } + + if (FAILED(hr)) + { + m_hrLastEdviceError = hr; + } + + WIAS_TRACE((g_hInst, "IStiUSD::GetStatus 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IStiUSD::DeviceReset. Resets the still image device to a known, +* initialized state. The sample driver will return S_OK without to execute +* any reset operation. The success-do-nothing approach is needed to ensure +* compatibility with the requirements for the IStiUSD interface implementation. +* +* Parameters: +* +* None +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. The sample driver always returns S_OK. +* +\**************************************************************************/ + +HRESULT CWiaDriver::DeviceReset() +{ + WIAS_TRACE((g_hInst, "IStiUSD::DeviceReset 0x%08X", S_OK)); + return S_OK; +} + +/**************************************************************************\ +* +* Implements IStiUSD::Diagnostic. If the driver is initialized when Diagnostic +* is called the driver should attempt to communicate with the device and +* determine if the device is online and operational. This sample driver +* does not do any special device validation. +* +* Parameters: +* +* pBuffer - caller-supplied pointer to an STI_DIAG structure to receive +* testing status information +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. +* +\**************************************************************************/ + +HRESULT CWiaDriver::Diagnostic( + _Inout_ LPDIAG pBuffer) +{ + HRESULT hr = S_OK; + + WIAEX_TRACE((g_hInst, "IStiUSD::Diagnostic..")); + + if ((!pBuffer) || (pBuffer->dwSize < sizeof(STI_DIAG)) || (pBuffer->sErrorInfo.dwSize < sizeof(STI_ERROR_INFO))) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter (buffer: %p, size: %u bytes (needed: %u), error: %u bytes (needed: %u)), hr = 0x%08X", + pBuffer, pBuffer ? pBuffer->dwSize : 0, sizeof(STI_DIAG), + pBuffer ? pBuffer->sErrorInfo.dwSize : 0, sizeof(STI_ERROR_INFO), hr)); + m_hrLastEdviceError = STIERR_INVALID_PARAM; + } + + if (SUCCEEDED(hr)) + { + pBuffer->dwVendorDiagCode = 0; + pBuffer->dwStatusMask = 0; + pBuffer->sErrorInfo.dwGenericError = NOERROR; + pBuffer->sErrorInfo.dwVendorError = 0; + memset(pBuffer->sErrorInfo.szExtendedErrorText, 0, sizeof(pBuffer->sErrorInfo.szExtendedErrorText)); + + if (STI_DIAGCODE_HWPRESENCE == pBuffer->dwBasicDiagCode) + { + WIAEX_TRACE((g_hInst, "STI_DIAGCODE_HWPRESENCE..")); + } + else + { + WIAEX_ERROR((g_hInst, "Unknown basic diag code requested (and ignored): %u", pBuffer->dwBasicDiagCode)); + } + } + + WIAEX_TRACE((g_hInst, "IStiUSD::Diagnostic 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IStiUSD::Escape. This method allows an application to send +* directly to the device a proprietary command ID and optionally send +* and receive data. +* +* The sample driver returns STIERR_UNSUPPORTED. +* +* Parameters: +* +* EscapeFunction - caller-supplied, vendor-defined, DWORD-sized value +* representing an I/O operation +* lpInData - caller-supplied pointer to a buffer containing data +* sent to the device +* cbInDataSize - caller-supplied length, in bytes, of the buffer +* pointed to by lpInData +* pOutData - caller-supplied pointer to a memory buffer to +* receive data from the device +* cbOutDataSize - caller-supplied length, in bytes, of the buffer +* pointed to by lpOutData +* pdwActualData - receives the number of bytes actually written to pOutData +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. This driver returns STIERR_UNSUPPORTED. +* +\**************************************************************************/ + +HRESULT CWiaDriver::Escape( + STI_RAW_CONTROL_CODE EscapeFunction, + _In_reads_bytes_(cbInDataSize) + LPVOID lpInData, + DWORD cbInDataSize, + _Out_writes_bytes_(cbOutDataSize) + LPVOID pOutData, + DWORD cbOutDataSize, + _Out_ LPDWORD pdwActualData) +{ + UNREFERENCED_PARAMETER(EscapeFunction); + UNREFERENCED_PARAMETER(cbInDataSize); + UNREFERENCED_PARAMETER(lpInData); + UNREFERENCED_PARAMETER(cbOutDataSize); + UNREFERENCED_PARAMETER(pOutData); + + WIAEX_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + + HRESULT hr = STIERR_UNSUPPORTED; + + if (pdwActualData) + { + *pdwActualData = 0; + } + + m_hrLastEdviceError = hr; + + WIAEX_TRACE((g_hInst, "IStiUSD::Escape 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IStiUSD::LockDevice. The sample driver returns S_OK. This is +* a must considering that the driver cannot function otherwise (the WIA Service +* expects this method to succeed for a properly installed driver and a working +* scanner device). +* +* Parameters: +* +* None +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. This sample driver returns S_OK. +* +\**************************************************************************/ + +HRESULT CWiaDriver::LockDevice() +{ + return S_OK; +} + +/**************************************************************************\ +* +* Implements IStiUSD::UnLockDevice. The sample driver returns S_OK. This is +* a must considering that the driver cannot function otherwise (the WIA Service +* expects this method to succeed for a properly installed driver and a +* working scanner device). +* +* Parameters: +* +* None +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. This sample driver returns S_OK. +* +\**************************************************************************/ + +HRESULT CWiaDriver::UnLockDevice() +{ + return S_OK; +} + +/**************************************************************************\ +* +* Implements IStiUSD::RawReadData. Reads data from the still image device. +* +* Parameters: +* +* lpBuffer - caller-supplied pointer to a buffer to receive data +* read from the device. +* lpdwNumberOfBytes - caller-supplied pointer to a DWORD. The caller loads +* the DWORD with the number of bytes in the buffer pointed +* to by lpBuffer. The driver must replace this value with +* the number of bytes actually read. +* lpOverlapped - optional, caller-supplied pointer to an OVERLAPPED structure +* (described in the Microsoft Windows SDK documentation). +* +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. This driver returns STIERR_UNSUPPORTED. +* +\**************************************************************************/ + +HRESULT CWiaDriver::RawReadData( + _Out_writes_bytes_(*lpdwNumberOfBytes) + LPVOID lpBuffer, + _Inout_ LPDWORD lpdwNumberOfBytes, + _In_opt_ LPOVERLAPPED lpOverlapped) +{ + UNREFERENCED_PARAMETER(lpBuffer); + UNREFERENCED_PARAMETER(lpdwNumberOfBytes); + UNREFERENCED_PARAMETER(lpOverlapped); + + WIAEX_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + + HRESULT hr = STIERR_UNSUPPORTED; + + m_hrLastEdviceError = hr; + + WIAEX_TRACE((g_hInst, "IStiUSD::RawReadData 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IStiUSD::RawWriteData. Writes data to the still image device. +* +* Parameters: +* +* lpBuffer - caller-supplied pointer to a buffer containing data +* to be sent to the device. +* dwNumberOfBytes - caller-supplied number of bytes to be written; this is +* the number of bytes in the buffer pointed to by lpBuffer. +* lpOverlapped - optional, caller-supplied pointer to an OVERLAPPED structure +* (described in the Microsoft Windows SDK documentation). +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. This driver returns STIERR_UNSUPPORTED. +* +\**************************************************************************/ + +HRESULT CWiaDriver::RawWriteData( + _In_reads_bytes_(dwNumberOfBytes) + LPVOID lpBuffer, + DWORD dwNumberOfBytes, + _In_opt_ LPOVERLAPPED lpOverlapped) +{ + UNREFERENCED_PARAMETER(lpBuffer); + UNREFERENCED_PARAMETER(dwNumberOfBytes); + UNREFERENCED_PARAMETER(lpOverlapped); + + WIAEX_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + + HRESULT hr = STIERR_UNSUPPORTED; + + m_hrLastEdviceError = hr; + + WIAEX_TRACE((g_hInst, "IStiUSD::RawWriteData 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IStiUSD::RawReadCommand. Reads command information from +* the still image device. +* +* Parameters: +* +* lpBuffer - caller-supplied pointer to a buffer to receive the +* command read from the device. +* lpdwNumberOfBytes - caller-supplied pointer to a DWORD. The caller loads +* the DWORD with the number of bytes in the buffer pointed +* to by lpBuffer; The driver must replace this value with +* the number of bytes actually read. +* lpOverlapped - optional, caller-supplied pointer to an OVERLAPPED structure +* (described in the Microsoft Windows SDK documentation). +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. This driver returns STIERR_UNSUPPORTED. +* +\**************************************************************************/ + +HRESULT CWiaDriver::RawReadCommand( + _Out_writes_bytes_(*lpdwNumberOfBytes) + LPVOID lpBuffer, + _Inout_ LPDWORD lpdwNumberOfBytes, + _In_opt_ LPOVERLAPPED lpOverlapped) +{ + UNREFERENCED_PARAMETER(lpBuffer); + UNREFERENCED_PARAMETER(lpdwNumberOfBytes); + UNREFERENCED_PARAMETER(lpOverlapped); + + WIAEX_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + + HRESULT hr = STIERR_UNSUPPORTED; + + m_hrLastEdviceError = hr; + + WIAEX_TRACE((g_hInst, "IStiUSD::RawReadCommand 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IStiUSD::RawWriteCommand. Writes command information to +* the still image device. +* +* Parameters: +* +* lpBuffer - caller-supplied pointer to a buffer containing data +* to be sent to the device. +* dwNumberOfBytes - caller-supplied number of bytes to be written; this is +* the number of bytes in the buffer pointed to by lpBuffer. +* lpOverlapped - optional, caller-supplied pointer to an OVERLAPPED structure +* (described in the Microsoft Windows SDK documentation). +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. This driver returns STIERR_UNSUPPORTED. +* +\**************************************************************************/ + +HRESULT CWiaDriver::RawWriteCommand( + _In_reads_bytes_(dwNumberOfBytes) + LPVOID lpBuffer, + DWORD dwNumberOfBytes, + _In_opt_ LPOVERLAPPED lpOverlapped) +{ + UNREFERENCED_PARAMETER(lpBuffer); + UNREFERENCED_PARAMETER(dwNumberOfBytes); + UNREFERENCED_PARAMETER(lpOverlapped); + + WIAEX_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + + HRESULT hr = STIERR_UNSUPPORTED; + + m_hrLastEdviceError = hr; + + WIAEX_TRACE((g_hInst, "IStiUSD::RawWriteCommand 0x%08X", hr)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IStiUSD::GetLastError. Returns the last known error associated +* with the still image device. The driver should record the last STIERR_ error +* code (defined in stierr.h) or generic Win32 error code (retrieved using the +* GetLastError Win32 API) encountered during its operation. +* +* Parameters: +* +* pdwLastDeviceError - caller-supplied pointer to a buffer in which +* the error code will be stored +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. +* +\**************************************************************************/ + +HRESULT CWiaDriver::GetLastError( + _Out_ LPDWORD pdwLastDeviceError) +{ + // + // When this method is called the driver should also check the scanner state + // (as when re-initializing the current WIA_DPS_DOCUMENT_HANDLING_STATUS). + // + HRESULT hr = S_OK; + + if (!pdwLastDeviceError) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + m_hrLastEdviceError = STIERR_INVALID_PARAM; + } + + if (SUCCEEDED(hr)) + { + *pdwLastDeviceError = WIN32_FROM_HRESULT(m_hrLastEdviceError); + } + + WIAEX_TRACE((g_hInst, "IStiUSD::GetLastError 0x%08X (%u, 0x%08X)", hr, m_hrLastEdviceError, m_hrLastEdviceError)); + + return hr; +} + +/**************************************************************************\ +* +* Implements IStiUSD::GetLastErrorInfo. Returns information about the last +* known error associated with a still image device. The driver should record +* the last STIERR_ error code (defined in stierr.h) or generic Win32 error code +* (retrieved using the GetLastError Win32 API) encountered during its operation. +* This error code would be the only information packaged in the STI_ERROR_INFO +* to be returned by this method for the sample driver. The sample driver does +* not provide a vendor error ID and no additional text error description. +* +* Parameters: +* +* pLastErrorInfo - caller-supplied pointer to an STI_ERROR_INFO structure +* to receive error information +* +* Return Value: +* +* If the operation succeeds, the method must return S_OK. Otherwise, it +* should return one of the STIERR-prefixed error codes defined in stierr.h +* or another standard COM error code. +* +\**************************************************************************/ + +HRESULT CWiaDriver::GetLastErrorInfo( + _Out_ STI_ERROR_INFO *pLastErrorInfo) +{ + HRESULT hr = S_OK; + + if (!pLastErrorInfo) + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X",hr)); + m_hrLastEdviceError = STIERR_INVALID_PARAM; + } + + if (SUCCEEDED(hr)) + { + memset(pLastErrorInfo, 0, sizeof(STI_ERROR_INFO)); + pLastErrorInfo->dwGenericError = WIN32_FROM_HRESULT(m_hrLastEdviceError); + } + + WIAEX_TRACE((g_hInst, "IStiUSD::GetLastErrorInfo 0x%08X (%u, 0x%08X)", hr, m_hrLastEdviceError, m_hrLastEdviceError)); + + // + // If successful reset the recorded error to not report it more than once: + // + if (SUCCEEDED(hr)) + { + m_hrLastEdviceError = STI_ERROR_NO_ERROR; + } + + return hr; +} 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<LONG> &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<LONG> &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; +} diff --git a/wia/ProdScan/WiaUtil.cpp b/wia/ProdScan/WiaUtil.cpp new file mode 100644 index 00000000..7378ae0a --- /dev/null +++ b/wia/ProdScan/WiaUtil.cpp @@ -0,0 +1,406 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: WiaUtil.cpp +* +* Project: Production Scanner Driver Sample +* +* Description: This file contains implementation of helper functions +* declared in wiautil.h +* +***************************************************************************/ + +#include "stdafx.h" + +/**************************************************************************\ +* +* This function creates a full WIA item name from a given WIA item name. +* The new full item name is created by concatenating the WIA item name +* with the parent's full item name. +* +* (e.g. 0000\Root + Flatbed = 0000\Root\Flatbed) +* +* +* Parameters: +* +* pParent - IWiaDrvItem interface of the parent WIA driver item +* bstrItemName - Name of the WIA item +* pbstrFullItemName - Returned full item name. +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT MakeFullItemName( + _In_ IWiaDrvItem* pParent, + _In_ BSTR bstrItemName, + _Out_ BSTR* pbstrFullItemName) +{ + HRESULT hr = S_OK; + + if (pParent && bstrItemName && pbstrFullItemName) + { + BSTR bstrParentFullItemName = NULL; + hr = pParent->GetFullItemName(&bstrParentFullItemName); + if (SUCCEEDED(hr)) + { + WCHAR wFullItemName[MAX_PATH * 2] = {}; + + hr = StringCbPrintf(wFullItemName, sizeof(wFullItemName), TEXT("%ws\\%ws"), bstrParentFullItemName, bstrItemName); + if (SUCCEEDED(hr)) + { + *pbstrFullItemName = SysAllocString(wFullItemName); + if (*pbstrFullItemName) + { + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate memory for BSTR full item name, hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to allocate memory for BSTR full item name, hr = 0x%08X", hr)); + } + + SysFreeString(bstrParentFullItemName); + bstrParentFullItemName = NULL; + } + else + { + WIAEX_ERROR((g_hInst, "Failed to produce the full item name, hr = 0x%08X", hr)); + } + } + else + { + hr = E_INVALIDARG; + WIAEX_ERROR((g_hInst, "Invalid parameter, hr = 0x%08X", hr)); + } + return hr; +} + +/**************************************************************************\ +* +* This function creates a WIA child item +* +* Parameters: +* +* wszItemName - Item name +* pIWiaMiniDrv - WIA minidriver interface +* pParent - Parent's WIA driver item interface +* lItemFlags - Item flags +* guidItemCategory - Item category +* ppChild - Pointer to the newly created child item +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT CreateWIAChildItem( + _In_ LPOLESTR pszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent, + LONG lItemFlags, + GUID guidItemCategory, + _Inout_opt_ IWiaDrvItem **ppChild) +{ + UNREFERENCED_PARAMETER(guidItemCategory); + + HRESULT hr = E_INVALIDARG; + + if (pszItemName && pIWiaMiniDrv && pParent) + { + BSTR bstrItemName = SysAllocString(pszItemName); + BSTR bstrFullItemName = NULL; + IWiaDrvItem *pIWiaDrvItem = NULL; + + if (bstrItemName) + { + hr = MakeFullItemName(pParent, bstrItemName, &bstrFullItemName); + if (SUCCEEDED(hr)) + { + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; + hr = wiasCreateDrvItem(lItemFlags, + bstrItemName, + bstrFullItemName, + pIWiaMiniDrv, + sizeof(WIA_DRIVER_ITEM_CONTEXT), + (BYTE **)&pWiaDriverItemContext, + &pIWiaDrvItem); + + if (SUCCEEDED(hr)) + { + // + // Initialize the item context data: + // + memset(pWiaDriverItemContext, 0, sizeof(WIA_DRIVER_ITEM_CONTEXT)); + pWiaDriverItemContext->m_pUploadedImage = NULL; + + hr = pIWiaDrvItem->AddItemToFolder(pParent); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to add the new WIA item (%ws) to the specified parent item, hr = 0x%08X", + bstrFullItemName, hr)); + pIWiaDrvItem->Release(); + pIWiaDrvItem = NULL; + } + + if (SUCCEEDED(hr)) + { + // + // If a child iterface pointer parameter was specified, then the caller + // expects to have the newly created child interface pointer returned to + // them (do not release the newly created item in this case). + // + + if (ppChild) + { + *ppChild = pIWiaDrvItem; + pIWiaDrvItem = NULL; + } + else if (pIWiaDrvItem) + { + // + // The newly created child has been added to the tree, and is no longer + // needed. Release it. + // + + pIWiaDrvItem->Release(); + pIWiaDrvItem = NULL; + } + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to create the new WIA driver item, hr = 0x%08X", hr)); + } + + SysFreeString(bstrItemName); + bstrItemName = NULL; + SysFreeString(bstrFullItemName); + bstrFullItemName = NULL; + } + else + { + WIAEX_ERROR((g_hInst, "Failed to create the new WIA item's full item name, hr = 0x%08X", hr)); + } + } + else + { + // + // Failed to allocate memory for bstrItemName. + // + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate memory for BSTR storage item name")); + } + + } + else + { + WIAEX_ERROR((g_hInst, "Invalid parameter")); + } + return hr; +} + +/**************************************************************************\ +* +* This function returns the WIA driver item context data stored with the +* driver item. The context is initialized and stored at WIA item creation. +* See CreateWIAChildItem function. +* +* Parameters: +* +* pWiasContext - Pointer to the WIA item context +* ppWiaDriverItemContext - Pointer to the WIA driver item context data +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT wiasGetDriverItemPrivateContext( + _In_ BYTE* pWiasContext, + _Out_ BYTE** ppWiaDriverItemContext) +{ + HRESULT hr = E_INVALIDARG; + + if (pWiasContext && ppWiaDriverItemContext) + { + IWiaDrvItem *pIWiaDrvItem = NULL; + + hr = wiasGetDrvItem(pWiasContext, &pIWiaDrvItem); + + if (SUCCEEDED(hr)) + { + hr = pIWiaDrvItem->GetDeviceSpecContext(ppWiaDriverItemContext); + + // + // The caller will handle the failure case. A failure, may mean that + // the the WIA item does not have a private device specific context + // stored. This is OK, because is is not required. + // + } + else + { + WIAEX_ERROR((g_hInst, "Failed to get the WIA driver item from the application item, hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Invalid parameter")); + } + return hr; +} + + +/**************************************************************************\ +* +* This function allocates a buffer to be used during data transfers. +* FreeTransferBuffer should be called to free the memory allocated by +* this function. +* +* Parameters: +* +* ppBuffer - Pointer to the allocated buffer; the caller must +* call FreeTransferBuffer() when finished with this buffer +* pulBufferSize - Size of the buffer allocated +* +* Return Value: +* +* S_OK or a standard COM error code +* +\**************************************************************************/ + +HRESULT AllocateTransferBuffer( + _Outptr_result_bytebuffer_(*pulBufferSize) BYTE** ppBuffer, + _Out_ ULONG* pulBufferSize) +{ + HRESULT hr = S_OK; + + if (ppBuffer && pulBufferSize) + { + // + // Set the buffer size to DEFAULT_BUFFER_SIZE + // + *pulBufferSize = DEFAULT_BUFFER_SIZE; + + // + // Allocate the memory + // + *ppBuffer = (BYTE*) CoTaskMemAlloc(*pulBufferSize); + if (*ppBuffer) + { + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + WIAEX_ERROR((g_hInst, "Failed to allocate memory for transfer buffer, hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Invalid parameter")); + hr = E_INVALIDARG; + } + + return hr; +} + +/**************************************************************************\ +* +* This function frees any memory allocated using AllocateTransferBuffer() +* +* Parameters: +* +* pBuffer - Pointer to a buffer allocated with an AllocateTransferBuffer +* call. If NULL, this call does nothing. +* +* Return Value: +* +* None +* +\**************************************************************************/ + +void FreeTransferBuffer( + _In_opt_ BYTE* pBuffer) +{ + if (pBuffer) + { + CoTaskMemFree(pBuffer); + } +} + +/**************************************************************************\ +* +* This function queues a WIA event using the passed in WIA item context. +* +* Parameters: +* +* pWiasContext - Pointer to the WIA item context +* guidWIAEvent - WIA event to queue +* +* Return Value: +* +* None +* +\**************************************************************************/ + +void QueueWIAEvent( + _In_ BYTE* pWiasContext, + const GUID& guidWIAEvent) +{ + HRESULT hr = S_OK; + BSTR bstrDeviceID = NULL; + BSTR bstrFullItemName = NULL; + BYTE* pRootItemContext = NULL; + + hr = wiasReadPropStr(pWiasContext, WIA_IPA_FULL_ITEM_NAME, &bstrFullItemName, NULL, TRUE); + + if (SUCCEEDED(hr)) + { + hr = wiasGetRootItem(pWiasContext, &pRootItemContext); + if (SUCCEEDED(hr)) + { + hr = wiasReadPropStr(pRootItemContext, WIA_DIP_DEV_ID, &bstrDeviceID, NULL, TRUE); + if (SUCCEEDED(hr)) + { + hr = wiasQueueEvent(bstrDeviceID, &guidWIAEvent, bstrFullItemName); + if (FAILED(hr)) + { + WIAEX_ERROR((g_hInst, "Failed to queue WIA event, hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to read the WIA_DIP_DEV_ID property, hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to get the Root item from child item, using wiasGetRootItem, hr = 0x%08X", hr)); + } + } + else + { + WIAEX_ERROR((g_hInst, "Failed to read WIA_IPA_FULL_ITEM_NAME property, hr = 0x%08X", hr)); + } + + if (bstrFullItemName) + { + SysFreeString(bstrFullItemName); + } + + if (bstrDeviceID) + { + SysFreeString(bstrDeviceID); + } +} diff --git a/wia/ProdScan/WiaUtil.h b/wia/ProdScan/WiaUtil.h new file mode 100644 index 00000000..d395c86c --- /dev/null +++ b/wia/ProdScan/WiaUtil.h @@ -0,0 +1,59 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: WiaUtil.h +* +* Project: Production Scanning Driver Sample +* +* Description: This file contains various helper functions for the driver. +* +***************************************************************************/ + +#pragma once + +HRESULT +MakeFullItemName( + _In_ IWiaDrvItem* pParent, + _In_ BSTR bstrItemName, + _Out_ BSTR* pbstrFullItemName); + +HRESULT +CreateWIAChildItem( + _In_ LPOLESTR pszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent, + LONG lItemFlags, + GUID guidItemCategory, + _Inout_opt_ IWiaDrvItem **ppChild = NULL); + +HRESULT +wiasGetDriverItemPrivateContext( + _In_ BYTE* pWiasContext, + _Out_ BYTE** ppWiaDriverItemContext); + +HRESULT AllocateTransferBuffer( + _Outptr_result_bytebuffer_(*pulBufferSize) BYTE** ppBuffer, + _Out_ ULONG* pulBufferSize); + +void +FreeTransferBuffer( + _In_opt_ BYTE* pBuffer); + +void +QueueWIAEvent( + _In_ BYTE* pWiasContext, + const GUID& guidWIAEvent); + +inline LONG +BytesPerLine( + LONG lImageWidth, + LONG lBitDepth) +{ + // + // The number of bytes per line include the padding necessary to make each uncompressed + // line (DIB or Raw) DWORD aligned. When the image data is compressed the number of bytes + // per line calculated here describes the original uncompressed image: + // + return (((lImageWidth * lBitDepth) + 31) / 32) * 4; +}; diff --git a/wia/ProdScan/readme.mht b/wia/ProdScan/readme.mht new file mode 100644 index 00000000..7fe6e3bc --- /dev/null +++ b/wia/ProdScan/readme.mht @@ -0,0 +1,956 @@ +MIME-Version: 1.0 +Content-Type: multipart/related; boundary="----=_NextPart_01CB1E95.4412BC30" + +This document is a Single File Web Page, also known as a Web Archive file. If you are seeing this message, your browser or editor doesn't support Web Archive files. Please download a browser that supports Web Archive, such as Windows� Internet Explorer�. + +------=_NextPart_01CB1E95.4412BC30 +Content-Location: file:///C:/2A821E05/readme.htm +Content-Transfer-Encoding: quoted-printable +Content-Type: text/html; charset="windows-1252" + +<html xmlns:v=3D"urn:schemas-microsoft-com:vml" +xmlns:o=3D"urn:schemas-microsoft-com:office:office" +xmlns:w=3D"urn:schemas-microsoft-com:office:word" +xmlns:m=3D"http://schemas.microsoft.com/office/2004/12/omml" +xmlns=3D"http://www.w3.org/TR/REC-html40"> + +<head> +<meta http-equiv=3DContent-Type content=3D"text/html; charset=3Dwindows-125= +2"> +<meta name=3DProgId content=3DWord.Document> +<meta name=3DGenerator content=3D"Microsoft Word 14"> +<meta name=3DOriginator content=3D"Microsoft Word 14"> +<link rel=3DFile-List href=3D"readme_files/filelist.xml"> +<!--[if gte mso 9]><xml> + <o:DocumentProperties> + <o:Author>Marius Niculescu</o:Author> + <o:LastAuthor>Marius Niculescu</o:LastAuthor> + <o:Revision>3</o:Revision> + <o:TotalTime>16</o:TotalTime> + <o:Created>2010-06-30T13:55:00Z</o:Created> + <o:LastSaved>2010-07-08T16:01:00Z</o:LastSaved> + <o:Pages>1</o:Pages> + <o:Words>769</o:Words> + <o:Characters>4388</o:Characters> + <o:Company>Microsoft Corporation</o:Company> + <o:Lines>36</o:Lines> + <o:Paragraphs>10</o:Paragraphs> + <o:CharactersWithSpaces>5147</o:CharactersWithSpaces> + <o:Version>14.00</o:Version> + </o:DocumentProperties> + <o:OfficeDocumentSettings> + <o:AllowPNG/> + </o:OfficeDocumentSettings> +</xml><![endif]--> +<link rel=3DthemeData href=3D"readme_files/themedata.thmx"> +<link rel=3DcolorSchemeMapping href=3D"readme_files/colorschememapping.xml"> +<!--[if gte mso 9]><xml> + <w:WordDocument> + <w:SpellingState>Clean</w:SpellingState> + <w:GrammarState>Clean</w:GrammarState> + <w:TrackMoves>false</w:TrackMoves> + <w:TrackFormatting/> + <w:PunctuationKerning/> + <w:ValidateAgainstSchemas/> + <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> + <w:IgnoreMixedContent>false</w:IgnoreMixedContent> + <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> + <w:DoNotPromoteQF/> + <w:LidThemeOther>EN-US</w:LidThemeOther> + <w:LidThemeAsian>X-NONE</w:LidThemeAsian> + <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> + <w:Compatibility> + <w:BreakWrappedTables/> + <w:SnapToGridInCell/> + <w:WrapTextWithPunct/> + <w:UseAsianBreakRules/> + <w:DontGrowAutofit/> + <w:SplitPgBreakAndParaMark/> + <w:EnableOpenTypeKerning/> + <w:DontFlipMirrorIndents/> + <w:OverrideTableStyleHps/> + </w:Compatibility> + <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> + <m:mathPr> + <m:mathFont m:val=3D"Cambria Math"/> + <m:brkBin m:val=3D"before"/> + <m:brkBinSub m:val=3D"--"/> + <m:smallFrac m:val=3D"off"/> + <m:dispDef/> + <m:lMargin m:val=3D"0"/> + <m:rMargin m:val=3D"0"/> + <m:defJc m:val=3D"centerGroup"/> + <m:wrapIndent m:val=3D"1440"/> + <m:intLim m:val=3D"subSup"/> + <m:naryLim m:val=3D"undOvr"/> + </m:mathPr></w:WordDocument> +</xml><![endif]--><!--[if gte mso 9]><xml> + <w:LatentStyles DefLockedState=3D"false" DefUnhideWhenUsed=3D"true" + DefSemiHidden=3D"true" DefQFormat=3D"false" DefPriority=3D"99" + LatentStyleCount=3D"267"> + <w:LsdException Locked=3D"false" Priority=3D"0" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Normal"/> + <w:LsdException Locked=3D"false" Priority=3D"0" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"heading 1"/> + <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" Name=3D"= +heading 2"/> + <w:LsdException Locked=3D"false" Priority=3D"0" QFormat=3D"true" Name=3D"= +heading 3"/> + <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" Name=3D"= +heading 4"/> + <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" Name=3D"= +heading 5"/> + <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" Name=3D"= +heading 6"/> + <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" Name=3D"= +heading 7"/> + <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" Name=3D"= +heading 8"/> + <w:LsdException Locked=3D"false" Priority=3D"9" QFormat=3D"true" Name=3D"= +heading 9"/> + <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 1"/> + <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 2"/> + <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 3"/> + <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 4"/> + <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 5"/> + <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 6"/> + <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 7"/> + <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 8"/> + <w:LsdException Locked=3D"false" Priority=3D"39" Name=3D"toc 9"/> + <w:LsdException Locked=3D"false" Priority=3D"35" QFormat=3D"true" Name=3D= +"caption"/> + <w:LsdException Locked=3D"false" Priority=3D"10" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Title"/> + <w:LsdException Locked=3D"false" Priority=3D"1" Name=3D"Default Paragraph= + Font"/> + <w:LsdException Locked=3D"false" Priority=3D"11" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Subtitle"/> + <w:LsdException Locked=3D"false" Priority=3D"0" Name=3D"Hyperlink"/> + <w:LsdException Locked=3D"false" Priority=3D"22" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Strong"/> + <w:LsdException Locked=3D"false" Priority=3D"20" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Emphasis"/> + <w:LsdException Locked=3D"false" Priority=3D"0" Name=3D"Normal (Web)"/> + <w:LsdException Locked=3D"false" Priority=3D"59" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Table Grid"/> + <w:LsdException Locked=3D"false" UnhideWhenUsed=3D"false" Name=3D"Placeho= +lder Text"/> + <w:LsdException Locked=3D"false" Priority=3D"1" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"No Spacing"/> + <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Shading"/> + <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light List"/> + <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Grid"/> + <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1"/> + <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2"/> + <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 1"/> + <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 2"/> + <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1"/> + <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2"/> + <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3"/> + <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Dark List"/> + <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Shading"/> + <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful List"/> + <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Grid"/> + <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light List Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 1"/> + <w:LsdException Locked=3D"false" UnhideWhenUsed=3D"false" Name=3D"Revisio= +n"/> + <w:LsdException Locked=3D"false" Priority=3D"34" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"List Paragraph"/> + <w:LsdException Locked=3D"false" Priority=3D"29" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Quote"/> + <w:LsdException Locked=3D"false" Priority=3D"30" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Intense Quote"/> + <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 1"/> + <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light List Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 2"/> + <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light List Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 3"/> + <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light List Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 4"/> + <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light List Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 5"/> + <w:LsdException Locked=3D"false" Priority=3D"60" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Shading Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"61" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light List Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"62" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Light Grid Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"63" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 1 Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"64" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Shading 2 Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"65" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 1 Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"66" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium List 2 Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"67" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 1 Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"68" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 2 Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"69" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Medium Grid 3 Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"70" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Dark List Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"71" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Shading Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"72" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful List Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"73" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" Name=3D"Colorful Grid Accent 6"/> + <w:LsdException Locked=3D"false" Priority=3D"19" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Subtle Emphasis"/> + <w:LsdException Locked=3D"false" Priority=3D"21" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Intense Emphasis"/> + <w:LsdException Locked=3D"false" Priority=3D"31" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Subtle Reference"/> + <w:LsdException Locked=3D"false" Priority=3D"32" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Intense Reference"/> + <w:LsdException Locked=3D"false" Priority=3D"33" SemiHidden=3D"false" + UnhideWhenUsed=3D"false" QFormat=3D"true" Name=3D"Book Title"/> + <w:LsdException Locked=3D"false" Priority=3D"37" Name=3D"Bibliography"/> + <w:LsdException Locked=3D"false" Priority=3D"39" QFormat=3D"true" Name=3D= +"TOC Heading"/> + </w:LatentStyles> +</xml><![endif]--> +<style> +<!-- + /* Font Definitions */ + @font-face + {font-family:Wingdings; + panose-1:5 0 0 0 0 0 0 0 0 0; + mso-font-charset:2; + mso-generic-font-family:auto; + mso-font-pitch:variable; + mso-font-signature:0 268435456 0 0 -2147483648 0;} +@font-face + {font-family:SimSun; + panose-1:2 1 6 0 3 1 1 1 1 1; + mso-font-alt:\5B8B\4F53; + mso-font-charset:134; + mso-generic-font-family:auto; + mso-font-pitch:variable; + mso-font-signature:3 680460288 22 0 262145 0;} +@font-face + {font-family:SimSun; + panose-1:2 1 6 0 3 1 1 1 1 1; + mso-font-alt:\5B8B\4F53; + mso-font-charset:134; + mso-generic-font-family:auto; + mso-font-pitch:variable; + mso-font-signature:3 680460288 22 0 262145 0;} +@font-face + {font-family:"\@SimSun"; + panose-1:2 1 6 0 3 1 1 1 1 1; + mso-font-charset:134; + mso-generic-font-family:auto; + mso-font-pitch:variable; + mso-font-signature:3 680460288 22 0 262145 0;} + /* Style Definitions */ + p.MsoNormal, li.MsoNormal, div.MsoNormal + {mso-style-unhide:no; + mso-style-qformat:yes; + mso-style-parent:""; + margin:0in; + margin-bottom:.0001pt; + mso-pagination:widow-orphan; + font-size:12.0pt; + font-family:"Times New Roman","serif"; + mso-fareast-font-family:"Times New Roman"; + color:black;} +h1 + {mso-style-unhide:no; + mso-style-qformat:yes; + mso-style-link:"Heading 1 Char"; + mso-margin-top-alt:auto; + margin-right:0in; + mso-margin-bottom-alt:auto; + margin-left:0in; + mso-pagination:widow-orphan; + mso-outline-level:1; + font-size:24.0pt; + font-family:"Times New Roman","serif"; + mso-fareast-font-family:SimSun; + color:black; + font-weight:bold;} +h3 + {mso-style-noshow:yes; + mso-style-qformat:yes; + mso-style-link:"Heading 3 Char"; + mso-margin-top-alt:auto; + margin-right:0in; + mso-margin-bottom-alt:auto; + margin-left:0in; + mso-pagination:widow-orphan; + mso-outline-level:3; + font-size:13.5pt; + font-family:"Times New Roman","serif"; + mso-fareast-font-family:SimSun; + color:black; + font-weight:bold;} +a:link, span.MsoHyperlink + {color:blue; + text-decoration:underline; + text-underline:single;} +a:visited, span.MsoHyperlinkFollowed + {mso-style-noshow:yes; + mso-style-priority:99; + color:purple; + mso-themecolor:followedhyperlink; + text-decoration:underline; + text-underline:single;} +p + {mso-style-noshow:yes; + mso-margin-top-alt:auto; + margin-right:0in; + mso-margin-bottom-alt:auto; + margin-left:0in; + mso-pagination:widow-orphan; + font-size:12.0pt; + font-family:"Times New Roman","serif"; + mso-fareast-font-family:"Times New Roman"; + color:black;} +span.Heading1Char + {mso-style-name:"Heading 1 Char"; + mso-style-unhide:no; + mso-style-locked:yes; + mso-style-link:"Heading 1"; + mso-ansi-font-size:24.0pt; + mso-bidi-font-size:24.0pt; + font-family:"Times New Roman","serif"; + mso-ascii-font-family:"Times New Roman"; + mso-fareast-font-family:SimSun; + mso-hansi-font-family:"Times New Roman"; + mso-bidi-font-family:"Times New Roman"; + color:black; + mso-font-kerning:18.0pt; + font-weight:bold;} +span.Heading3Char + {mso-style-name:"Heading 3 Char"; + mso-style-noshow:yes; + mso-style-unhide:no; + mso-style-locked:yes; + mso-style-link:"Heading 3"; + mso-ansi-font-size:13.5pt; + mso-bidi-font-size:13.5pt; + font-family:"Times New Roman","serif"; + mso-ascii-font-family:"Times New Roman"; + mso-fareast-font-family:SimSun; + mso-hansi-font-family:"Times New Roman"; + mso-bidi-font-family:"Times New Roman"; + color:black; + font-weight:bold;} +span.SpellE + {mso-style-name:""; + mso-spl-e:yes;} +span.GramE + {mso-style-name:""; + mso-gram-e:yes;} +.MsoChpDefault + {mso-style-type:export-only; + mso-default-props:yes; + font-size:10.0pt; + mso-ansi-font-size:10.0pt; + mso-bidi-font-size:10.0pt; + font-family:"Calibri","sans-serif"; + mso-ascii-font-family:Calibri; + mso-ascii-theme-font:minor-latin; + mso-fareast-font-family:Calibri; + mso-fareast-theme-font:minor-latin; + mso-hansi-font-family:Calibri; + mso-hansi-theme-font:minor-latin; + mso-bidi-font-family:"Times New Roman"; + mso-bidi-theme-font:minor-bidi;} +@page WordSection1 + {size:8.5in 11.0in; + margin:1.0in 1.0in 1.0in 1.0in; + mso-header-margin:.5in; + mso-footer-margin:.5in; + mso-paper-source:0;} +div.WordSection1 + {page:WordSection1;} + /* List Definitions */ + @list l0 + {mso-list-id:1542011108; + mso-list-type:hybrid; + mso-list-template-ids:-1970876908 67698689 67698691 67698693 67698689 6769= +8691 67698693 67698689 67698691 67698693;} +@list l0:level1 + {mso-level-number-format:bullet; + mso-level-text:\F0B7; + mso-level-tab-stop:none; + mso-level-number-position:left; + text-indent:-.25in; + font-family:Symbol;} +@list l0:level2 + {mso-level-number-format:bullet; + mso-level-text:o; + mso-level-tab-stop:none; + mso-level-number-position:left; + text-indent:-.25in; + font-family:"Courier New";} +@list l0:level3 + {mso-level-number-format:bullet; + mso-level-text:\F0A7; + mso-level-tab-stop:none; + mso-level-number-position:left; + text-indent:-.25in; + font-family:Wingdings;} +@list l0:level4 + {mso-level-number-format:bullet; + mso-level-text:\F0B7; + mso-level-tab-stop:none; + mso-level-number-position:left; + text-indent:-.25in; + font-family:Symbol;} +@list l0:level5 + {mso-level-number-format:bullet; + mso-level-text:o; + mso-level-tab-stop:none; + mso-level-number-position:left; + text-indent:-.25in; + font-family:"Courier New";} +@list l0:level6 + {mso-level-number-format:bullet; + mso-level-text:\F0A7; + mso-level-tab-stop:none; + mso-level-number-position:left; + text-indent:-.25in; + font-family:Wingdings;} +@list l0:level7 + {mso-level-number-format:bullet; + mso-level-text:\F0B7; + mso-level-tab-stop:none; + mso-level-number-position:left; + text-indent:-.25in; + font-family:Symbol;} +@list l0:level8 + {mso-level-number-format:bullet; + mso-level-text:o; + mso-level-tab-stop:none; + mso-level-number-position:left; + text-indent:-.25in; + font-family:"Courier New";} +@list l0:level9 + {mso-level-number-format:bullet; + mso-level-text:\F0A7; + mso-level-tab-stop:none; + mso-level-number-position:left; + text-indent:-.25in; + font-family:Wingdings;} +ol + {margin-bottom:0in;} +ul + {margin-bottom:0in;} +--> +</style> +<!--[if gte mso 10]> +<style> + /* Style Definitions */ + table.MsoNormalTable + {mso-style-name:"Table Normal"; + mso-tstyle-rowband-size:0; + mso-tstyle-colband-size:0; + mso-style-noshow:yes; + mso-style-priority:99; + mso-style-parent:""; + mso-padding-alt:0in 5.4pt 0in 5.4pt; + mso-para-margin:0in; + mso-para-margin-bottom:.0001pt; + mso-pagination:widow-orphan; + font-size:10.0pt; + font-family:"Calibri","sans-serif"; + mso-ascii-font-family:Calibri; + mso-ascii-theme-font:minor-latin; + mso-hansi-font-family:Calibri; + mso-hansi-theme-font:minor-latin; + mso-bidi-font-family:"Times New Roman"; + mso-bidi-theme-font:minor-bidi;} +</style> +<![endif]--><!--[if gte mso 9]><xml> + <o:shapedefaults v:ext=3D"edit" spidmax=3D"1026"/> +</xml><![endif]--><!--[if gte mso 9]><xml> + <o:shapelayout v:ext=3D"edit"> + <o:idmap v:ext=3D"edit" data=3D"1"/> + </o:shapelayout></xml><![endif]--> +</head> + +<body lang=3DEN-US link=3Dblue vlink=3Dpurple style=3D'tab-interval:.5in'> + +<div class=3DWordSection1> + +<h1>Production Scanning WIA 2.0 Driver Sample</h1> + +<p class=3DMsoNormal><b style=3D'mso-bidi-font-weight:normal'><span +style=3D'color:red'>[This is preliminary documentation and subject to chang= +e.]<o:p></o:p></span></b></p> + +<h3>SUMMARY</h3> + +<p>This driver sample shows how to add Production Scanning features to a WIA +2.0 mini-driver. </p> + +<p>The sample driver implements the following programmable data source items +and related functionality: </p> + +<p style=3D'margin-top:0in;margin-right:0in;margin-bottom:0in;margin-left:.= +5in; +margin-bottom:.0001pt;text-indent:-.25in;mso-list:l0 level1 lfo2'><![if !su= +pportLists]><span +style=3D'font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-fa= +mily: +Symbol'><span style=3D'mso-list:Ignore'>�<span style=3D'font:7.0pt "Times N= +ew Roman"'> +</span></span></span><![endif]>Flatbed and Feeder, which both support 8-bpp +grayscale, 24-bpp RGB, Auto-Color, and implement necessary WIA property sup= +port +for Auto-Crop, Over Scan and Color Dropout. </p> + +<p style=3D'margin-top:0in;margin-right:0in;margin-bottom:0in;margin-left:.= +5in; +margin-bottom:.0001pt;text-indent:-.25in;mso-list:l0 level1 lfo2'><![if !su= +pportLists]><span +style=3D'font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-fa= +mily: +Symbol'><span style=3D'mso-list:Ignore'>�<span style=3D'font:7.0pt "Times N= +ew Roman"'> +</span></span></span><![endif]>Auto item, for Auto-Configured Scanning. The +Flatbed, Feeder and Auto items all support the DIB, EXIF and RAW image tran= +sfer +file formats.</p> + +<p style=3D'margin-top:0in;margin-right:0in;margin-bottom:0in;margin-left:.= +5in; +margin-bottom:.0001pt;text-indent:-.25in;mso-list:l0 level1 lfo2'><![if !su= +pportLists]><span +style=3D'font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-fa= +mily: +Symbol'><span style=3D'mso-list:Ignore'>�<span style=3D'font:7.0pt "Times N= +ew Roman"'> +</span></span></span><![endif]>Additionally the Feeder item implements the +necessary properties and commands demonstrating Job Separators, Long Docume= +nt +Scanning, Blank Page Detection, Multi-Feed Detection, Scan Ahead, and Feeder +Motor Control. </p> + +<p style=3D'margin-top:0in;margin-right:0in;margin-bottom:0in;margin-left:.= +5in; +margin-bottom:.0001pt;text-indent:-.25in;mso-list:l0 level1 lfo2'><![if !su= +pportLists]><span +style=3D'font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-fa= +mily: +Symbol'><span style=3D'mso-list:Ignore'>�<span style=3D'font:7.0pt "Times N= +ew Roman"'> +</span></span></span><![endif]>The Job Separators and Multi-feed Detection +functionality is simulated at predetermined scan page numbers.</p> + +<p style=3D'margin-top:0in;margin-right:0in;margin-bottom:0in;margin-left:.= +5in; +margin-bottom:.0001pt;text-indent:-.25in;mso-list:l0 level1 lfo2'><![if !su= +pportLists]><span +style=3D'font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-fa= +mily: +Symbol'><span style=3D'mso-list:Ignore'>�<span style=3D'font:7.0pt "Times N= +ew Roman"'> +</span></span></span><![endif]>Imprinter and Endorser, which both support t= +ext +and graphics bi-directional data transfers. Transfer formats supported are = +DIB +(for graphics), TXT and CSV (for text).</p> + +<p style=3D'margin-top:0in;margin-right:0in;margin-bottom:0in;margin-left:.= +5in; +margin-bottom:.0001pt;text-indent:-.25in;mso-list:l0 level1 lfo2'><![if !su= +pportLists]><span +style=3D'font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-fa= +mily: +Symbol'><span style=3D'mso-list:Ignore'>�<span style=3D'font:7.0pt "Times N= +ew Roman"'> +</span></span></span><![endif]>Barcode Reader, Patch Code Reader and MICR +Reader, which all support XML and RAW metadata download.</p> + +<p style=3D'margin-top:0in;margin-right:0in;margin-bottom:0in;margin-left:.= +5in; +margin-bottom:.0001pt;text-indent:-.25in;mso-list:l0 level1 lfo2'><![if !su= +pportLists]><span +style=3D'font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-fa= +mily: +Symbol;mso-no-proof:yes'><span style=3D'mso-list:Ignore'>�<span style=3D'fo= +nt:7.0pt "Times New Roman"'> +</span></span></span><![endif]>Full configuration for the standard scan eve= +nt +as well as the device status events. <span style=3D'mso-no-proof:yes'><o:p>= +</o:p></span></p> + +<p style=3D'margin-top:0in;margin-right:0in;margin-bottom:0in;margin-left:.= +5in; +margin-bottom:.0001pt;text-indent:-.25in;mso-list:l0 level1 lfo2'><![if !su= +pportLists]><span +style=3D'font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-fa= +mily: +Symbol;mso-no-proof:yes'><span style=3D'mso-list:Ignore'>�<span style=3D'fo= +nt:7.0pt "Times New Roman"'> +</span></span></span><![endif]>WIA <span class=3DGramE>trace</span> +instrumentation, including real-time sample scanning performance (Pages per +Minute, PPM) measurement.<span style=3D'mso-no-proof:yes'><o:p></o:p></span= +></p> + +<p><b>NOTES<o:p></o:p></b></p> + +<p>This sample requires WIA 2.0, thus the sample will work only on Windows +Vista and higher releases. </p> + +<p>The default test images for Flatbed, Feeder and the Auto source are a pa= +ir +of EXIF images loaded from resources, each in size of 2550 x 3300 pixels, +equivalent with a Letter document (8.5� x 11�) scanned at 300 DPI. The samp= +le +uses GDI+ to convert these test images to DIB. The sample RAW images are ob= +tained +from the DIB conversions.</p> + +<p>The default test image for the Imprinter and Endorser is 640 x 480 pixel= +s, 1-bpp +DIB loaded from resources. The WIA application can individually replace the +Imprinter and/or Endorser image for the current driver instance by uploadin= +g at +run time other 640 x 480 pixels, 1-bpp, DIB images.</p> + +<p class=3DMsoNormal>By default the sample reports to support a single stan= +dard +document size (WIA_PAGE_LETTER), which matches the test images that the sam= +ple +by default transfers. The sample also reports to support WIA_PAGE_AUTO and +WIA_PAGE_CUSTOM. The default scan area size can be changed by modifying the= + <span +style=3D'color:windowtext;mso-no-proof:yes'>MIN/MAX_SCAN_AREA_WIDTH/HEIGHT = +values +in Constants.h and rebuilding the sample: the sample will still transfer the +same test images but will report as supported for the Feeder all standard W= +IA document +sizes that fit into the simulated scan area minimum and maximum dimensions.= +</span></p> + +<p class=3DMsoNormal><o:p> </o:p></p> + +<p class=3DMsoNormal>When job separator detection is enabled the sample sim= +ulates +a job separator page every 3 pages. This number can be modified by editing = +the +JOB_SEPARATOR_AT_PAGE value in Constants.h and then rebuilding the sample.<= +/p> + +<p>When multi-feed detection is enabled the sample simulates a multi-feed e= +rror +every 5 pages. This number can be modified by editing the MULTI_FEED_AT_PAGE +value in Constants.h and then rebuilding the sample.</p> + +<p>By default when scanning from the Feeder with WIA_IPS_PAGES is set to +ALL_PAGES and from the Auto item the sample will stop (pretending the feede= +r is +empty) after scanning 200 pages. For Feeder, if the application requests a +WIA_IPS_PAGE value greater than 200 the sample honors this request. The 200 +page limit can be modified by changing the MAX_SCAN_PAGES value in Constant= +s.h +and rebuilding the sample.</p> + +<h3>BUILDING THE SAMPLE</h3> + +<p>To build the sample, complete the following steps:</p> + +<p style=3D'margin-left:.5in;text-indent:-.25in;tab-stops:list .5in'>1.<span +style=3D'font-size:7.0pt'> </span>On the <b +style=3D'mso-bidi-font-weight:normal'>Start</b> menu, under Windows DDK, se= +lect <b +style=3D'mso-bidi-font-weight:normal'>Free Build Environment</b> or <b +style=3D'mso-bidi-font-weight:normal'>Checked Build Environment</b> to open= + a +command window and set basic environment variables needed to build drivers.= + </p> + +<p style=3D'margin-left:.5in;text-indent:-.25in;tab-stops:list .5in'>2.<span +style=3D'font-size:7.0pt'> </span>Navigate to= + the +directory that contains the sample driver source code (that is, the directo= +ry +where this file is located).</p> + +<p style=3D'margin-left:.5in;text-indent:-.25in;tab-stops:list .5in'>3.<span +style=3D'font-size:7.0pt'> </span>Run the bui= +ld command. +After the build completes, the following DLL is built: ProdScan.dll.</p> + +<h3>INSTALLING THE SAMPLE</h3> + +<p>To install the sample, complete the following steps:</p> + +<p style=3D'margin-left:.5in;text-indent:-.25in;tab-stops:list .5in'>1. Ope= +n an +elevated command prompt and then type <b style=3D'mso-bidi-font-weight:norm= +al'>rundll32 +<span class=3DSpellE>sti_ci</span> <span class=3DSpellE>AddDevice</span></b= +>.</p> + +<p style=3D'margin-left:.5in;text-indent:-.25in;tab-stops:list .5in'>2. When +prompted for which scanner or camera you want to install, click <b +style=3D'mso-bidi-font-weight:normal'>Have Disk</b>, and then navigate to t= +he +directory that contains the driver INF file (ProdScan.inf) and the DLL +(ProdScan.dll).</p> + +<h3>USING THE SAMPLE</h3> + +<p>The WiaInfo2 WIA tool can be used to test the sample. WiaInfo2 can displ= +ay +all new programmable data source items, their properties, allow writable +properties to be changed, execute image and metadata download transfers as = +well +as upload data to the device.</p> + +<h3>RESOURCES</h3> + +<p>For information and the latest release of the Microsoft� Windows� Driver= + Kit +(WDK), see <a href=3D"http://msdn.microsoft.com/en-us/library/ff557573.aspx= +">http://msdn.microsoft.com/en-us/library/ff557573.aspx</a>.</p> + +<p>For information about WIA, see <a +href=3D"http://msdn.microsoft.com/en-us/library/ms630368(VS.85).aspx">http:= +//msdn.microsoft.com/en-us/library/ms630368(VS.85).aspx</a>.<o:p></o:p></p> + +<p>For questions about WIA and this sample, send e-mail to <a +href=3D"mailto:[email protected]"><span style=3D'mso-fareast-font-famil= +y:SimSun'>[email protected]</span></a>.</p> + +</div> + +</body> + +</html> + +------=_NextPart_01CB1E95.4412BC30 +Content-Location: file:///C:/2A821E05/readme_files/themedata.thmx +Content-Transfer-Encoding: base64 +Content-Type: application/vnd.ms-officetheme + +UEsDBBQABgAIAAAAIQDp3g+//wAAABwCAAATAAAAW0NvbnRlbnRfVHlwZXNdLnhtbKyRy07DMBBF +90j8g+UtSpyyQAgl6YLHjseifMDImSQWydiyp1X790zSVEKoIBZsLNkz954743K9Hwe1w5icp0qv +8kIrJOsbR12l3zdP2a1WiYEaGDxhpQ+Y9Lq+vCg3h4BJiZpSpXvmcGdMsj2OkHIfkKTS+jgCyzV2 +JoD9gA7NdVHcGOuJkTjjyUPX5QO2sB1YPe7l+Zgk4pC0uj82TqxKQwiDs8CS1Oyo+UbJFkIuyrkn +9S6kK4mhzVnCVPkZsOheZTXRNajeIPILjBLDsAyJX89nIBkt5r87nons29ZZbLzdjrKOfDZezE7B +/xRg9T/oE9PMf1t/AgAA//8DAFBLAwQUAAYACAAAACEApdan58AAAAA2AQAACwAAAF9yZWxzLy5y +ZWxzhI/PasMwDIfvhb2D0X1R0sMYJXYvpZBDL6N9AOEof2giG9sb69tPxwYKuwiEpO/3qT3+rov5 +4ZTnIBaaqgbD4kM/y2jhdj2/f4LJhaSnJQhbeHCGo3vbtV+8UNGjPM0xG6VItjCVEg+I2U+8Uq5C +ZNHJENJKRds0YiR/p5FxX9cfmJ4Z4DZM0/UWUtc3YK6PqMn/s8MwzJ5PwX+vLOVFBG43lExp5GKh +qC/jU72QqGWq1B7Qtbj51v0BAAD//wMAUEsDBBQABgAIAAAAIQBreZYWgwAAAIoAAAAcAAAAdGhl +bWUvdGhlbWUvdGhlbWVNYW5hZ2VyLnhtbAzMTQrDIBBA4X2hd5DZN2O7KEVissuuu/YAQ5waQceg +0p/b1+XjgzfO3xTVm0sNWSycBw2KZc0uiLfwfCynG6jaSBzFLGzhxxXm6XgYybSNE99JyHNRfSPV +kIWttd0g1rUr1SHvLN1euSRqPYtHV+jT9yniResrJgoCOP0BAAD//wMAUEsDBBQABgAIAAAAIQAw +3UMpqAYAAKQbAAAWAAAAdGhlbWUvdGhlbWUvdGhlbWUxLnhtbOxZT2/bNhS/D9h3IHRvYyd2Ggd1 +itixmy1NG8Ruhx5piZbYUKJA0kl9G9rjgAHDumGHFdhth2FbgRbYpfs02TpsHdCvsEdSksVYXpI2 +2IqtPiQS+eP7/x4fqavX7scMHRIhKU/aXv1yzUMk8XlAk7Dt3R72L615SCqcBJjxhLS9KZHetY33 +37uK11VEYoJgfSLXcduLlErXl5akD8NYXuYpSWBuzEWMFbyKcCkQ+AjoxmxpuVZbXYoxTTyU4BjI +3hqPqU/QUJP0NnLiPQaviZJ6wGdioEkTZ4XBBgd1jZBT2WUCHWLW9oBPwI+G5L7yEMNSwUTbq5mf +t7RxdQmvZ4uYWrC2tK5vftm6bEFwsGx4inBUMK33G60rWwV9A2BqHtfr9bq9ekHPALDvg6ZWljLN +Rn+t3slplkD2cZ52t9asNVx8if7KnMytTqfTbGWyWKIGZB8bc/i12mpjc9nBG5DFN+fwjc5mt7vq +4A3I4lfn8P0rrdWGizegiNHkYA6tHdrvZ9QLyJiz7Ur4GsDXahl8hoJoKKJLsxjzRC2KtRjf46IP +AA1kWNEEqWlKxtiHKO7ieCQo1gzwOsGlGTvky7khzQtJX9BUtb0PUwwZMaP36vn3r54/RccPnh0/ ++On44cPjBz9aQs6qbZyE5VUvv/3sz8cfoz+efvPy0RfVeFnG//rDJ7/8/Hk1ENJnJs6LL5/89uzJ +i68+/f27RxXwTYFHZfiQxkSim+QI7fMYFDNWcSUnI3G+FcMI0/KKzSSUOMGaSwX9nooc9M0pZpl3 +HDk6xLXgHQHlowp4fXLPEXgQiYmiFZx3otgB7nLOOlxUWmFH8yqZeThJwmrmYlLG7WN8WMW7ixPH +v71JCnUzD0tH8W5EHDH3GE4UDklCFNJz/ICQCu3uUurYdZf6gks+VuguRR1MK00ypCMnmmaLtmkM +fplW6Qz+dmyzewd1OKvSeoscukjICswqhB8S5pjxOp4oHFeRHOKYlQ1+A6uoSsjBVPhlXE8q8HRI +GEe9gEhZteaWAH1LTt/BULEq3b7LprGLFIoeVNG8gTkvI7f4QTfCcVqFHdAkKmM/kAcQohjtcVUF +3+Vuhuh38ANOFrr7DiWOu0+vBrdp6Ig0CxA9MxEVvrxOuBO/gykbY2JKDRR1p1bHNPm7ws0oVG7L +4eIKN5TKF18/rpD7bS3Zm7B7VeXM9olCvQh3sjx3uQjo21+dt/Ak2SOQEPNb1Lvi/K44e//54rwo +ny++JM+qMBRo3YvYRtu03fHCrntMGRuoKSM3pGm8Jew9QR8G9Tpz4iTFKSyN4FFnMjBwcKHAZg0S +XH1EVTSIcApNe93TREKZkQ4lSrmEw6IZrqSt8dD4K3vUbOpDiK0cEqtdHtjhFT2cnzUKMkaq0Bxo +c0YrmsBZma1cyYiCbq/DrK6FOjO3uhHNFEWHW6GyNrE5lIPJC9VgsLAmNDUIWiGw8iqc+TVrOOxg +RgJtd+uj3C3GCxfpIhnhgGQ+0nrP+6hunJTHypwiWg8bDPrgeIrVStxamuwbcDuLk8rsGgvY5d57 +Ey/lETzzElA7mY4sKScnS9BR22s1l5se8nHa9sZwTobHOAWvS91HYhbCZZOvhA37U5PZZPnMm61c +MTcJ6nD1Ye0+p7BTB1Ih1RaWkQ0NM5WFAEs0Jyv/chPMelEKVFSjs0mxsgbB8K9JAXZ0XUvGY+Kr +srNLI9p29jUrpXyiiBhEwREasYnYx+B+HaqgT0AlXHeYiqBf4G5OW9tMucU5S7ryjZjB2XHM0ghn +5VanaJ7JFm4KUiGDeSuJB7pVym6UO78qJuUvSJVyGP/PVNH7Cdw+rATaAz5cDQuMdKa0PS5UxKEK +pRH1+wIaB1M7IFrgfhemIajggtr8F+RQ/7c5Z2mYtIZDpNqnIRIU9iMVCUL2oCyZ6DuFWD3buyxJ +lhEyEVUSV6ZW7BE5JGyoa+Cq3ts9FEGom2qSlQGDOxl/7nuWQaNQNznlfHMqWbH32hz4pzsfm8yg +lFuHTUOT278QsWgPZruqXW+W53tvWRE9MWuzGnlWALPSVtDK0v41RTjnVmsr1pzGy81cOPDivMYw +WDREKdwhIf0H9j8qfGa/dugNdcj3obYi+HihiUHYQFRfso0H0gXSDo6gcbKDNpg0KWvarHXSVss3 +6wvudAu+J4ytJTuLv89p7KI5c9k5uXiRxs4s7Njaji00NXj2ZIrC0Dg/yBjHmM9k5S9ZfHQPHL0F +3wwmTEkTTPCdSmDooQcmDyD5LUezdOMvAAAA//8DAFBLAwQUAAYACAAAACEADdGQn7YAAAAbAQAA +JwAAAHRoZW1lL3RoZW1lL19yZWxzL3RoZW1lTWFuYWdlci54bWwucmVsc4SPTQrCMBSE94J3CG9v +07oQkSbdiNCt1AOE5DUNNj8kUeztDa4sCC6HYb6ZabuXnckTYzLeMWiqGgg66ZVxmsFtuOyOQFIW +TonZO2SwYIKObzftFWeRSyhNJiRSKC4xmHIOJ0qTnNCKVPmArjijj1bkIqOmQci70Ej3dX2g8ZsB +fMUkvWIQe9UAGZZQmv+z/TgaiWcvHxZd/lFBc9mFBSiixszgI5uqTATKW7q6xN8AAAD//wMAUEsB +Ai0AFAAGAAgAAAAhAOneD7//AAAAHAIAABMAAAAAAAAAAAAAAAAAAAAAAFtDb250ZW50X1R5cGVz +XS54bWxQSwECLQAUAAYACAAAACEApdan58AAAAA2AQAACwAAAAAAAAAAAAAAAAAwAQAAX3JlbHMv +LnJlbHNQSwECLQAUAAYACAAAACEAa3mWFoMAAACKAAAAHAAAAAAAAAAAAAAAAAAZAgAAdGhlbWUv +dGhlbWUvdGhlbWVNYW5hZ2VyLnhtbFBLAQItABQABgAIAAAAIQAw3UMpqAYAAKQbAAAWAAAAAAAA +AAAAAAAAANYCAAB0aGVtZS90aGVtZS90aGVtZTEueG1sUEsBAi0AFAAGAAgAAAAhAA3RkJ+2AAAA +GwEAACcAAAAAAAAAAAAAAAAAsgkAAHRoZW1lL3RoZW1lL19yZWxzL3RoZW1lTWFuYWdlci54bWwu +cmVsc1BLBQYAAAAABQAFAF0BAACtCgAAAAA= + +------=_NextPart_01CB1E95.4412BC30 +Content-Location: file:///C:/2A821E05/readme_files/colorschememapping.xml +Content-Transfer-Encoding: quoted-printable +Content-Type: text/xml + +<?xml version=3D"1.0" encoding=3D"UTF-8" standalone=3D"yes"?> +<a:clrMap xmlns:a=3D"http://schemas.openxmlformats.org/drawingml/2006/main"= + bg1=3D"lt1" tx1=3D"dk1" bg2=3D"lt2" tx2=3D"dk2" accent1=3D"accent1" accent= +2=3D"accent2" accent3=3D"accent3" accent4=3D"accent4" accent5=3D"accent5" a= +ccent6=3D"accent6" hlink=3D"hlink" folHlink=3D"folHlink"/> +------=_NextPart_01CB1E95.4412BC30 +Content-Location: file:///C:/2A821E05/readme_files/filelist.xml +Content-Transfer-Encoding: quoted-printable +Content-Type: text/xml; charset="utf-8" + +<xml xmlns:o=3D"urn:schemas-microsoft-com:office:office"> + <o:MainFile HRef=3D"../readme.htm"/> + <o:File HRef=3D"themedata.thmx"/> + <o:File HRef=3D"colorschememapping.xml"/> + <o:File HRef=3D"filelist.xml"/> +</xml> +------=_NextPart_01CB1E95.4412BC30-- diff --git a/wia/ProdScan/resource.h b/wia/ProdScan/resource.h new file mode 100644 index 00000000..2c1e03cc --- /dev/null +++ b/wia/ProdScan/resource.h @@ -0,0 +1,47 @@ +#pragma once + +#define IDB_TESTIMAGE_GRAY 100 +#define IDB_TESTIMAGE_COLOR 101 +#define IDB_TEST_IMPRINTER_IMAGE 102 +#define IDB_BARCODE_SAMPLE 103 +#define IDB_PATCH_CODE_SAMPLE 104 +#define IDB_MICR_SAMPLE 105 + +#define IDS_EVENT_DEVICE_CONNECTED_NAME 200 +#define IDS_EVENT_DEVICE_DISCONNECTED_NAME 201 +#define IDS_EVENT_DEVICE_CONNECTED_DESCRIPTION 202 +#define IDS_EVENT_DEVICE_DISCONNECTED_DESCRIPTION 203 +#define IDS_CMD_SYNCHRONIZE_NAME 204 +#define IDS_CMD_SYNCHRONIZE_DESCRIPTION 205 +#define IDS_EVENT_SCAN_IMAGE_NAME 206 +#define IDS_EVENT_SCAN_IMAGE_DESCRIPTION 207 +#define IDS_CMD_BUILD_DEVICE_TREE_NAME 208 +#define IDS_CMD_BUILD_DEVICE_TREE_DESCRIPTION 209 +#define IDS_CMD_DELETE_DEVICE_TREE_NAME 210 +#define IDS_CMD_DELETE_DEVICE_TREE_DESCRIPTION 211 +#define IDS_EVENT_POWER_SUSPEND_NAME 212 +#define IDS_EVENT_POWER_RESUME_NAME 213 +#define IDS_EVENT_POWER_SUSPEND_DESCRIPTION 214 +#define IDS_EVENT_POWER_RESUME_DESCRIPTION 215 +#define IDS_EVENT_TREE_UPDATED_NAME 216 +#define IDS_EVENT_TREE_UPDATED_DESCRIPTION 217 +#define IDS_CMD_START_FEEDER_NAME 218 +#define IDS_CMD_START_FEEDER_DESCRIPTION 219 +#define IDS_CMD_STOP_FEEDER_NAME 220 +#define IDS_CMD_STOP_FEEDER_DESCRIPTION 221 +#define IDS_EVENT_DEVICE_NOT_READY_NAME 222 +#define IDS_EVENT_DEVICE_NOT_READY_DESCRIPTION 223 +#define IDS_EVENT_DEVICE_READY_NAME 224 +#define IDS_EVENT_DEVICE_READY_DESCRIPTION 225 +#define IDS_EVENT_FLATBED_LID_OPEN_NAME 226 +#define IDS_EVENT_FLATBED_LID_OPEN_DESCRIPTION 227 +#define IDS_EVENT_FLATBED_LID_CLOSED_NAME 228 +#define IDS_EVENT_FLATBED_LID_CLOSED_DESCRIPTION 229 +#define IDS_EVENT_FEEDER_LOADED_NAME 230 +#define IDS_EVENT_FEEDER_LOADED_DESCRIPTION 231 +#define IDS_EVENT_FEEDER_EMPTIED_NAME 232 +#define IDS_EVENT_FEEDER_EMPTIED_DESCRIPTION 233 +#define IDS_EVENT_COVER_OPEN_NAME 234 +#define IDS_EVENT_COVER_OPEN_DESCRIPTION 235 +#define IDS_EVENT_COVER_CLOSED_NAME 236 +#define IDS_EVENT_COVER_CLOSED_DESCRIPTION 237 diff --git a/wia/ProdScan/stdafx.h b/wia/ProdScan/stdafx.h new file mode 100644 index 00000000..f7f61586 --- /dev/null +++ b/wia/ProdScan/stdafx.h @@ -0,0 +1,87 @@ +/************************************************************************** +* +* Copyright � Microsoft Corporation +* +* File Title: stdafx.h +* +* Project: Production Scanner Driver Sample +* +* Description: precompiled header file +* +***************************************************************************/ + +#pragma once + +// +// This is the size of the buffer the driver uses to write data to the +// WIA image download stream and also to declare for legacy applications +// through WIA_IPA_BUFFER_SIZE. The buffer size chosen is 64KB (65536 bytes): +// +#define DEFAULT_BUFFER_SIZE 65536 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#ifndef _UNICODE +#define _UNICODE +#endif + +// +// WIA_DEBUG is needed in order to enable WIA tracing in free +// builds (see WIAS_TRACE and WIAEX_ERROR in wiamdef.h): +// +#ifndef WIA_DEBUG +#define WIA_DEBUG +#endif + +// +// Windows system headers: +// + +#include <windows.h> // Windows +#include <stdlib.h> // C standard library +#include <stdio.h> // std out +#include <coguid.h> // COM +#include <objbase.h> // COM +#include <shobjidl.h> // Shell UI Extension +#include <shlobj.h> // Shell UI Extension +#include <shlwapi.h> // Shell light weight API +#include <strsafe.h> // Safe character string APIs +#include <gdiplus.h> // GDI+ +#include <limits.h> +#include <initguid.h> + +// +// WIA driver core headers: +// +#include <sti.h> // STI defines +#include <stiusd.h> // IStiUsd interface +#include <wiamindr.h> // IWiaMinidrv interface +#include <wiadevd.h> // IWiaUIExtension interface +#include <wiamdef.h> + +// +// WIA driver headers: +// +#include "constants.h" // Constant declarations +#include "basicarray.h" // CSimpleDynamicArray class +#include "propman.h" // WIA driver property manager class +#include "capman.h" // WIA driver capability manager class +#include "wiautil.h" // WIA driver helper functions +#include "resource.h" // WIA driver resource definitions +#include "minidrv.h" // WIA driver header + +// +// Helpers for image file format translations (using GDI+): +// +using namespace Gdiplus; +#include "fileconv.h" + +// +// WIA tracing macro helpers: +// +#define WIAEX_ERROR(args) { WIAS_ERROR((g_hInst, "Error in %s (%u):", __FUNCTION__, __LINE__)); WIAS_ERROR(args); } +#define WIAEX_TRACE(args) { FAILED(hr) ? WIAS_ERROR(args) : WIAS_TRACE(args); } +#define WIAEX_TRACE_FUNC_HR { FAILED(hr) ? WIAS_ERROR((g_hInst, "%s failed, hr = 0x%08X", __FUNCTION__, hr)) : WIAS_TRACE((g_hInst, "%s succeeded, hr = 0x%08X", __FUNCTION__, hr)); } +#define WIAEX_TRACE_BEGIN { WIAS_TRACE((g_hInst, "%s..", __FUNCTION__)); } diff --git a/wia/README.md b/wia/README.md new file mode 100644 index 00000000..9d74b0d5 --- /dev/null +++ b/wia/README.md @@ -0,0 +1,44 @@ +Windows Image Acquisition (WIA) Driver Samples +============================================== + +The Windows Image Acquisition driver sample set contains samples and test tools for Windows Image Acquisition (WIA), a driver architecture and user interface for acquiring images from still image devices such as scanners. + +### PRODUCTION SCANNING WIA 2.0 DRIVER +The ProdScan directory contains a sample WIA 2.0 mini-driver. This sample shows how to add Production Scanning features to a WIA 2.0 mini-driver. + +### EXTENDED WIA 2.0 MONSTER DRIVER +The Wiadriverex directory contains a sample WIA 2.0 mini-driver. This sample shows how to write a WIA 2.0 mini-driver that uses the stream-based WIA 2.0 transfer model. It also shows an implementation of a very simple segmentation filter, image processing filter, and error handling extension for the WIA 2.0 mini-driver. + +For more information, see [Introduction to WIA](http://msdn.microsoft.com/en-us/library/windows/hardware/ff542835). + + +Build the sample +---------------- + +You can build the sample in two ways: using the Visual Studio Integrated Development Environment (IDE) or from the command line using the Visual Studio Command Prompt window and the Microsoft Build Engine (MSBuild.exe). + +**Building the sample using Visual Studio** + +1.Open Visual Studio. From the **File** menu, select **Open Project/Solution**. Within your WDK installation, navigate to src\\wia and open the wia.sln project file. + +2.Right-click the solution in the **Solution Explorer** and select **Configuration Manager**. + +3.From the **Configuration Manager**, select the **Active Solution Configuration** (for example, Windows 8.1 Debug or Windows 8.1 Release) and the **Active Solution Platform** (for example, Win32) that correspond to the type of build you are interested in. + +4.From the **Build** menu, click **Build Solution** (Ctrl+Shift+B). + +Previous versions of the WDK used the Windows Build utility (Build.exe) and provided separate build environment windows for each of the supported build configurations. You can use the Visual Studio Command Prompt window for all build configurations. + +**Building the sample using the command line (MSBuild)** + +1.Open a Visual Studio Command Prompt window. Click **Start** and search for **Developer Command Prompt**. If your project is under %PROGRAMFILES%, you need to open the command prompt window using elevated permissions (**Run as administrator**). From this window you can use MsBuild.exe to build any Visual Studio project by specifying the project (.VcxProj) or solutions (.Sln) file. + +2.Navigate to the project directory and enter the **MSbuild** command for your target. For example, to perform a clean build of a Visual Studio driver project called extend.vcxproj, navigate to the project directory and enter the following MSBuild command: **msbuild /t:clean /t:build .\\extend.vcxproj**. + +3.If the build succeeds, you will find the driver (extend.dll) in the binary output directory corresponding to the target platform, for example src\\wia\\extend\\Windows 8.1 Debug. + +Run the sample +-------------- + +Run the "copywia.cmd” batch file to gather all of the binaries into a subdirectory named “wiabins”. The WIA driver sample can be installed by using the Add Device icon in the Scanners and Cameras control panel. Use the Have Disk button to point to the wiabins\\drivers or wiabins\\drivers folder. Wiatest.exe (from the WDK Tools\\Wia directory), MS Paint, the Scanner and Camera Wizard, or any TWAIN application (through the WIA TWAIN compatibility layer) can be used to test the samples. + diff --git a/wia/copywia.cmd b/wia/copywia.cmd new file mode 100644 index 00000000..49f6f1cf --- /dev/null +++ b/wia/copywia.cmd @@ -0,0 +1,110 @@ +@echo off +rem Copy all of the WIA WDK binaries to a directory named wiabins. An +rem The first optional parameter is a destination directory to prepend to wiabins. +rem The second optional param is the build directory users select in VS project. +rem For example, if users select "Windows 7 Release" as solution configuration, then +rem the build directory generated by VS project is "Windows7Release". There are several +rem types of build directories, such as Windows7Debug, Windows7Release, WindowsVistaDebug, etc. + +set cpu_samples=NotRazzle +set cpu_tools=NotRazzle +set build_samples=obj%build_alt_dir% +set build_tools=%basedir%\tools\wia +set cpl_suffix=cpl + +if /I "%BUILD_DEFAULT_TARGETS%" EQU "/x86" set cpu_samples=i386 +if /I "%BUILD_DEFAULT_TARGETS%" EQU "/amd64" set cpu_samples=amd64 +if /I "%BUILD_DEFAULT_TARGETS%" EQU "/ia64" set cpu_samples=ia64 + +if /I "%BUILD_DEFAULT_TARGETS%" EQU "/arm" set cpu_samples=arm + + +if /I "%BUILD_DEFAULT_TARGETS%" EQU "/x86" set cpu_tools=x86 +if /I "%BUILD_DEFAULT_TARGETS%" EQU "/amd64" set cpu_tools=amd64 +if /I "%BUILD_DEFAULT_TARGETS%" EQU "/ia64" set cpu_tools=ia64 + +if /I "%BUILD_DEFAULT_TARGETS%" EQU "/arm" set cpu_tools=arm + + +rem If cpu_samples is not the initial string, this is razzle environment and jump to :Common. + +if NOT "%cpu_samples%" EQU "NotRazzle" goto Common + +:VSDeveloper + +rem Set x86 as default cpu type (for developer cmd prompt) +rem Platform is defined when it is a cross-platform cmd prompt (x64 or arm) + +set cpu_samples=x86 +set cpu_tools=x86 + +if defined Platform ( +set cpu_samples=%Platform% +set cpu_tools=%Platform% +) + +rem When selecting non-default configuration, users need to specify the first +rem parameter to rename wiabins and then input the build directory as the second +rem parameter, where the sample project generates output files. + +set build_tools=%WindowsSdkDir%tools +set build_samples=WindowsDeveloperPreviewDebug +if NOT "%2" EQU "" set build_samples=%2 + +rem VS project outputs dll file for sampcpl. Its sources in razzle renames output to cpl file. +rem Copy sampcpl.dll by VS project to sampcpl.cpl. + +set cpl_suffix=dll + +:Common + +md %1wiabins +md %1wiabins\drivers + +if /I "%BUILD_DEFAULT_TARGETS%" EQU "/arm" ( +goto wia20 ) + + +rem +rem WIA 1.0 +rem + +copy microdrv\%build_samples%\%cpu_samples%\testmcro.dll %1wiabins\drivers +copy microdrv\testmcro.inf %1wiabins\drivers +copy "%build_tools%\%cpu_tools%\wiatest.exe" %1wiabins + +if /I "%DDK_TARGET_OS%" EQU "WinXP" ( +copy "%build_tools%\%cpu_tools%\wialogcfg.exe" %1wiabins +goto end ) + +if /I "%DDK_TARGET_OS%" EQU "WinNET" ( +copy "%build_tools%\%cpu_tools%\wiadbgcfg.exe" %1wiabins +goto end ) + +:wia20 + +rem +rem WIA 2.0 +rem + +copy wiadriverex\usd\%build_samples%\%cpu_samples%\wiadriverex.dll %1wiabins\drivers +copy wiadriverex\segfilter\%build_samples%\%cpu_samples%\segfilter.dll %1wiabins\drivers +copy wiadriverex\imgfilter\%build_samples%\%cpu_samples%\imgfilter.dll %1wiabins\drivers +copy wiadriverex\errhandler\%build_samples%\%cpu_samples%\errhandler.dll %1wiabins\drivers +copy wiadriverex\uiext2\%build_samples%\%cpu_samples%\uiext2.dll %1wiabins\drivers +copy wiadriverex\wiadriver.inf %1wiabins\drivers +copy wiadriverex\sample.bmp %1wiabins\drivers + +copy prodscan\%build_samples%\%cpu_samples%\prodscan.dll %1wiabins\drivers +copy prodscan\prodscan.inf %1wiabins\drivers + +copy "%build_tools%\%cpu_tools%\wiainfo2.exe" %1wiabins +copy "%build_tools%\%cpu_tools%\wiatrcvw.exe" %1wiabins +copy "%build_tools%\%cpu_tools%\wiapreview.exe" %1wiabins + +goto end + +:Syntax +Echo %0 Drive\path\ + +:end diff --git a/wia/idl/wiamindr_lh.idl b/wia/idl/wiamindr_lh.idl new file mode 100644 index 00000000..d37a2571 --- /dev/null +++ b/wia/idl/wiamindr_lh.idl @@ -0,0 +1,492 @@ +/**************************************************************************** +* +* (C) COPYRIGHT 1998-2000, MICROSOFT CORP. +* +* FILE: wiamindr_lh.idl +* +* VERSION: 2.0 +* +* DATE: 8/28/1998 +* +* DESCRIPTION: +* IDL source for the WIA mini driver. +* +*****************************************************************************/ + +cpp_quote("#include <winapifamily.h>") + +#pragma region Desktop Family +cpp_quote("#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)") + +interface IWiaMiniDrv; +interface IWiaMiniDrvCallBack; +interface IWiaMiniDrvTransferCallBack; +interface IWiaDrvItem; +interface IWiaItem; +interface IWiaPropertyStorage; + +import "unknwn.idl"; +import "oaidl.idl"; +import "propidl.idl"; +import "wia_lh.idl"; + +midl_pragma warning( disable: 2495 ) + +/**************************************************************************\ +* +* MINIDRV_TRANSFER_CONTEXT - Minidriver data transfer context +* +\**************************************************************************/ + +typedef struct _MINIDRV_TRANSFER_CONTEXT{ + LONG lSize; + LONG lWidthInPixels; + LONG lLines; + LONG lDepth; + LONG lXRes; + LONG lYRes; + LONG lCompression; + GUID guidFormatID; + LONG tymed; + LONG_PTR hFile; + LONG cbOffset; + LONG lBufferSize; + LONG lActiveBuffer; + LONG lNumBuffers; + BYTE *pBaseBuffer; + BYTE *pTransferBuffer; + BOOL bTransferDataCB; + BOOL bClassDrvAllocBuf; + LONG_PTR lClientAddress; + IWiaMiniDrvCallBack *pIWiaMiniDrvCallBack; + LONG lImageSize; + LONG lHeaderSize; + LONG lItemSize; + LONG cbWidthInBytes; + LONG lPage; + LONG lCurIfdOffset; + LONG lPrevIfdOffset; + +} MINIDRV_TRANSFER_CONTEXT, *PMINIDRV_TRANSFER_CONTEXT; + + +/******************************************************************************* +* +* WIA_DEV_CAP_DRV - Device capabilities +* +*******************************************************************************/ + +typedef struct _WIA_DEV_CAP_DRV { + GUID *guid; + ULONG ulFlags; + LPOLESTR wszName; + LPOLESTR wszDescription; + LPOLESTR wszIcon; +} WIA_DEV_CAP_DRV,*PWIA_DEV_CAP_DRV; + + +/******************************************************************************* +* +* IWiaMiniDrvItem interface +* +*******************************************************************************/ + +[ + object, + uuid(d8cdee14-3c6c-11d2-9a35-00c04fa36145), + helpstring("WIA Mini Driver Interface"), + pointer_default(unique) +] + +interface IWiaMiniDrv : IUnknown +{ + [helpstring("Initialize WIA, build item tree, etc")] + HRESULT drvInitializeWia( + [in] BYTE*, + [in] LONG, + [in] BSTR, + [in] BSTR, + [in] IUnknown*, + [in] IUnknown*, + [out] IWiaDrvItem**, + [out] IUnknown**, + [out] LONG*); + + [helpstring("Acquire data from the device item")] + HRESULT drvAcquireItemData( + [in] BYTE*, + [in] LONG, + [in, out] PMINIDRV_TRANSFER_CONTEXT, + [out] LONG*); + + [helpstring("Initialize the device item properties")] + HRESULT drvInitItemProperties( + [in] BYTE*, + [in] LONG, + [out] LONG*); + + [helpstring("Mini driver validatation of the device item properties")] + HRESULT drvValidateItemProperties( + [in] BYTE*, + [in] LONG, + [in] ULONG, + [in] const PROPSPEC*, + [out] LONG*); + + [helpstring("Mini driver write of the device item properties")] + HRESULT drvWriteItemProperties( + [in] BYTE*, + [in] LONG, + [in] PMINIDRV_TRANSFER_CONTEXT, + [out] LONG*); + + [helpstring("Mini driver read of the device item properties")] + HRESULT drvReadItemProperties( + [in] BYTE*, + [in] LONG, + [in] ULONG, + [in] const PROPSPEC*, + [out] LONG*); + + [helpstring("Lock Device")] + HRESULT drvLockWiaDevice( + [in] BYTE*, + [in] LONG, + [out] LONG*); + + [helpstring("UnLock Device")] + HRESULT drvUnLockWiaDevice( + [in] BYTE*, + [in] LONG, + [out] LONG*); + + [helpstring("Look at item and create sub-items if needed")] + HRESULT drvAnalyzeItem( + [in] BYTE*, + [in] LONG, + [in] LONG*); + + [helpstring("Map a device error value to a string")] + HRESULT drvGetDeviceErrorStr( + [in] LONG, + [in] LONG, + [out, string] LPOLESTR*, + [out] LONG*); + + [helpstring("Issue a device command")] + HRESULT drvDeviceCommand( + [in] BYTE*, + [in] LONG, + [in] const GUID*, + [out] IWiaDrvItem**, + [out] LONG*); + + [helpstring("Get the device capabilities")] + HRESULT drvGetCapabilities( + [in] BYTE*, + [in] LONG, + [out] LONG*, + [out] WIA_DEV_CAP_DRV**, + [out] LONG*); + + [helpstring("Delete the item from the device")] + HRESULT drvDeleteItem( + [in] BYTE*, + [in] LONG, + [out] LONG*); + + [helpstring("Free driver item context")] + HRESULT drvFreeDrvItemContext( + [in] LONG, + [in] BYTE*, + [out] LONG*); + + [helpstring("Get the FORMAT and TYMED")] + HRESULT drvGetWiaFormatInfo( + [in] BYTE*, + [in] LONG, + [out] LONG*, + [out] WIA_FORMAT_INFO**, + [out] LONG*); + + [helpstring("Notify Pnp event received by device manager")] + HRESULT drvNotifyPnpEvent( + [in] const GUID *pEventGUID, + [in] BSTR bstrDeviceID, + [in] ULONG ulReserved); + + [helpstring("UnInitialize WIA, remove resources attached to item, etc")] + HRESULT drvUnInitializeWia( + [in] BYTE*); +}; + + +/******************************************************************************* +* +* IWiaMiniDrvCallBack interface +* +*******************************************************************************/ + +[ + object, + uuid(33a57d5a-3de8-11d2-9a36-00c04fa36145), + helpstring("WIA Mini Driver Call Back Interface"), + pointer_default(unique) +] + +interface IWiaMiniDrvCallBack : IUnknown +{ + [id(1), helpstring("Acquire data from the device")] + HRESULT MiniDrvCallback( + [in] LONG lReason, + [in] LONG lStatus, + [in] LONG lPercentComplete, + [in] LONG lOffset, + [in] LONG lLength, + [in] PMINIDRV_TRANSFER_CONTEXT pTranCtx, + [in] LONG lReserved); +}; + +/******************************************************************************* +* +* IWiaMiniDrvTransferCallback interface +* +*******************************************************************************/ + +[ + object, + uuid(a9d2ee89-2ce5-4ff0-8adb-c961d1d774ca), + helpstring("Callback interface for stream-based transfers"), + pointer_default(unique) +] + +interface IWiaMiniDrvTransferCallback : IUnknown +{ + [helpstring("This method is called to get the next stream from the client for upload or download")] + HRESULT GetNextStream( + [in] LONG lFlags, + [in] BSTR bstrItemName, + [in] BSTR bstrFullItemName, + [out, annotation("_Outptr_result_maybenull_ _At_(*ppIStream, _When_(return == S_OK, _Post_notnull_))")] + IStream **ppIStream); + + [helpstring("This sends a messages such as progress to the calling application")] + HRESULT SendMessage( + [in] LONG lFlags, + [in] WiaTransferParams *pWiaTransferParams); +}; + +/**************************************************************************\ +* +* IWiaDrvItem interface +* +\**************************************************************************/ + +[ + object, + uuid(1f02b5c5-b00c-11d2-a094-00c04f72dc3c), + helpstring("WIA Mini Driver DrvItem Interface"), + pointer_default(unique) +] +interface IWiaDrvItem : IUnknown +{ + HRESULT GetItemFlags( + [out] LONG*); + + HRESULT GetDeviceSpecContext( + [out] BYTE**); + + HRESULT GetFullItemName( + [out] BSTR*); + + HRESULT GetItemName( + [out] BSTR*); + + HRESULT AddItemToFolder( + [in] IWiaDrvItem*); + + HRESULT UnlinkItemTree( + [in] LONG); + + HRESULT RemoveItemFromFolder( + [in] LONG); + + HRESULT FindItemByName( + [in] LONG, + [in] BSTR, + [out] IWiaDrvItem**); + + HRESULT FindChildItemByName( + [in] BSTR, + [out] IWiaDrvItem**); + + HRESULT GetParentItem( + [out] IWiaDrvItem**); + + HRESULT GetFirstChildItem( + [out] IWiaDrvItem**); + + HRESULT GetNextSiblingItem( + [out] IWiaDrvItem**); + + HRESULT DumpItemData( + [out] BSTR*); +}; + + +/******************************************************************************* +* +* WIA_PROPERTY_INFO - Stores default access and valid values for item properties +* +*******************************************************************************/ + +typedef struct _WIA_PROPERTY_INFO +{ + ULONG lAccessFlags; + VARTYPE vt; + + union { + + struct { + LONG Min; + LONG Nom; + LONG Max; + LONG Inc; + } Range; + + struct { + DOUBLE Min; + DOUBLE Nom; + DOUBLE Max; + DOUBLE Inc; + } RangeFloat; + + struct { + LONG cNumList; + LONG Nom; + [size_is(cNumList)] BYTE *pList; + } List; + + struct { + LONG cNumList; + DOUBLE Nom; + [size_is(cNumList)] BYTE *pList; + } ListFloat; + + struct { + LONG cNumList; + GUID Nom; + [size_is(cNumList)] GUID *pList; + } ListGuid; + + struct { + LONG cNumList; + BSTR Nom; + [size_is(cNumList)] BSTR *pList; + } ListBStr; + + struct { + LONG Nom; + LONG ValidBits; + } Flag; + + struct { + LONG Dummy; + } None; + + } ValidVal; + +}WIA_PROPERTY_INFO, *PWIA_PROPERTY_INFO; + + +/******************************************************************************* +* +* WIA_PROPERTY_CONTEXT - Stores property id and flag indicating whether the +* application is changing the property +* +*******************************************************************************/ + +typedef struct _WIA_PROPERTY_CONTEXT{ + ULONG cProps; + [size_is(cProps)] PROPID *pProps; + [size_is(cProps)] BOOL *pChanged; +} WIA_PROPERTY_CONTEXT, *PWIA_PROPERTY_CONTEXT; + + +/******************************************************************************* +* +* WIAS_CHANGED_VALUE_INFO - Stores current and previous values for a property +* +*******************************************************************************/ + +typedef struct _WIAS_CHANGED_VALUE_INFO{ + BOOL bChanged; + LONG vt; + + union { + LONG lVal; + FLOAT fltVal; + BSTR bstrVal; + GUID guidVal; + } Old; + + union { + LONG lVal; + FLOAT fltVal; + BSTR bstrVal; + GUID guidVal; + } Current; +} WIAS_CHANGED_VALUE_INFO, *PWIAS_CHANGED_VALUE_INFO; + + +/******************************************************************************* +* +* WIAS_DOWN_SAMPLE_INFO - Used by wiasDownSampleBuffer +* +*******************************************************************************/ + +typedef struct _WIAS_DOWN_SAMPLE_INFO { + ULONG ulOriginalWidth; + ULONG ulOriginalHeight; + ULONG ulBitsPerPixel; + ULONG ulXRes; + ULONG ulYRes; + ULONG ulDownSampledWidth; + ULONG ulDownSampledHeight; + ULONG ulActualSize; + ULONG ulDestBufSize; + ULONG ulSrcBufSize; + [size_is(ulSrcBufSize)] BYTE *pSrcBuffer; + [size_is(ulDestBufSize)] BYTE *pDestBuffer; +} WIAS_DOWN_SAMPLE_INFO, *PWIAS_DOWN_SAMPLE_INFO; + + +/******************************************************************************* +* +* WIAS_ENDORSER_VALUE - Stores endorser strings +* +*******************************************************************************/ +typedef struct _WIAS_ENDORSER_VALUE { + LPWSTR wszTokenName; + LPWSTR wszValue; +} WIAS_ENDORSER_VALUE, *PWIAS_ENDORSER_VALUE; + + +/******************************************************************************* +* +* WIAS_ENDORSER_INFO - Stores token/value pairs for endorser +* +*******************************************************************************/ +typedef struct _WIAS_ENDORSER_INFO { + ULONG ulPageCount; + ULONG ulNumEndorserValues; + [size_is(ulNumEndorserValues)] WIAS_ENDORSER_VALUE *pEndorserValues; +} WIAS_ENDORSER_INFO, *PWIAS_ENDORSER_INFO; + + +cpp_quote("#include \"wiamdef.h\"") + + +cpp_quote("#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */") +#pragma endregion + diff --git a/wia/inc/WiaCI.h b/wia/inc/WiaCI.h new file mode 100644 index 00000000..4f8e117b --- /dev/null +++ b/wia/inc/WiaCI.h @@ -0,0 +1,135 @@ +/******************************************************************************* +* +* (C) COPYRIGHT MICROSOFT CORP., 2000-2003 +* +* +* PUBLISHED TITLE : WiaCI.h +* +* VERSION: 1.0 +* +* AUTHOR: KeisukeT +* +* DATE: 11 Mar, 2003 +* +* DESCRIPTION: +* Header file for class installer exports. +* +*******************************************************************************/ + + + + +#ifndef _DEVMGR_H_ +#define _DEVMGR_H_ + + +// +// Include +// +#include <objbase.h> + +// +// Define +// + +#define WIA_DEVSEARCH_DRVKEY 0x00000001 +#define WIA_DEVSEARCH_DEVICEDATA 0x00000002 + + +#define MAX_FRIENDLYNAME 64 +#define MAX_DEVICE_ID 64 + +// +// Struct +// + +typedef struct _WIADEVICEINSTALL { + IN DWORD dwSize; // Size of the structure. + IN DWORD dwFlags; // Reserved, must be 0. + IN WCHAR szInfPath[MAX_PATH]; // Full path to the INF file. + IN WCHAR szPnPID[MAX_PATH]; // PnP ID string for INF install. + IN WCHAR szIhvID[MAX_PATH]; // IHV unique ID, will be in DeviceData. + IN OUT WCHAR szFriendlyName[MAX_FRIENDLYNAME]; // Specify name, result will be stored too. + OUT WCHAR szWiaDeviceID[MAX_DEVICE_ID]; // WIA Device ID upon successful install. + } WIADEVICEINSTALL, *PWIADEVICEINSTALL; + + +// +// Prototype +// + +DWORD +WINAPI +InstallWiaDevice( + _In_ PWIADEVICEINSTALL pWiaDeviceInstall + ); + +DWORD +WINAPI +UninstallWiaDevice( + _In_ HANDLE hWiaDeviceList, + DWORD dwIndex + ); + +DWORD +WINAPI +CreateWiaDeviceList( + DWORD dwFlags, + _In_opt_ LPCWSTR szQueryEntry, + _In_reads_bytes_(dwQueryParameterSize) PVOID pvQueryParameter, + DWORD dwQueryParameterSize, + _Out_opt_ HANDLE *phWiaDeviceList + ); + +DWORD +WINAPI +DestroyWiaDeviceList( + _In_ HANDLE hWiaDeviceList + ); + +DWORD +WINAPI +GetWiaDeviceProperty( + _In_ HANDLE hWiaDeviceList, + DWORD dwIndex, + DWORD dwFlags, + _In_opt_ LPCWSTR szEntry, + _Out_opt_ LPDWORD pdwType, + _Out_opt_ PVOID pvBuffer, + _Inout_opt_ LPDWORD pdwBufferSize + ); + +DWORD +WINAPI +SetWiaDeviceProperty( + _In_ HANDLE hWiaDeviceList, + DWORD dwIndex, + DWORD dwFlags, + _In_opt_ LPCWSTR szEntry, + DWORD dwType, + _In_reads_bytes_(dwBufferSize) PVOID pvBuffer, + DWORD dwBufferSize + ); + +DWORD +WINAPI +EnableWiaDevice( + _In_ HANDLE hWiaDeviceList, + DWORD dwIndex + ); + + +DWORD +WINAPI +DisableWiaDevice( + _In_ HANDLE hWiaDeviceList, + DWORD dwIndex + ); + + +#endif // _DEVMGR_H_ + + + + + diff --git a/wia/microdrv/resource.h b/wia/microdrv/resource.h new file mode 100644 index 00000000..55300a1a --- /dev/null +++ b/wia/microdrv/resource.h @@ -0,0 +1,20 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by testmcro.rc +// + +#define IDS_SCAN_BUTTON_NAME 700 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 701 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 701 +#endif +#endif + + diff --git a/wia/microdrv/testmcro.cpp b/wia/microdrv/testmcro.cpp new file mode 100644 index 00000000..6514a585 --- /dev/null +++ b/wia/microdrv/testmcro.cpp @@ -0,0 +1,1192 @@ +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_driver_) + +#include "testmcro.h" +#include "wiamicro.h" +#include "resource.h" + +#include <STI.H> +#include <math.h> +#include <winioctl.h> +#include <usbscan.h> + +#ifdef DEBUG +#include <stdio.h> +#endif + +#include <strsafe.h> + +// #define BUTTON_SUPPORT // (uncomment this to allow BUTTON SUPPORT) + // button support is not functional in the test device + +#define MAX_BUTTONS 1 +#define MAX_BUTTON_NAME 255 + +HINSTANCE g_hInst; // instance of this MicroDriver (used for loading from a resource) + + +// note: MEMORYBMP, and BMP file will be added by wiafbdrv host driver. +// do not include them in your extended list. +// + +// #define _USE_EXTENDED_FORMAT_LIST (uncomment this to allow Extented file and memory formats) + +#define NUM_SUPPORTED_FILEFORMATS 1 +GUID g_SupportedFileFormats[NUM_SUPPORTED_FILEFORMATS]; + +#define NUM_SUPPORTED_MEMORYFORMATS 2 +GUID g_SupportedMemoryFormats[NUM_SUPPORTED_MEMORYFORMATS]; + +// +// Button GUID array used in Capability negotiation. +// Set your BUTTON guids here. These must match the GUIDS specified in +// your INF. The Scan Button GUID is public to all scanners with a +// scan button. +// + +GUID g_Buttons[MAX_BUTTONS] ={{0xa6c5a715, 0x8c6e, 0x11d2,{ 0x97, 0x7a, 0x0, 0x0, 0xf8, 0x7a, 0x92, 0x6f}}}; +BOOL g_bButtonNamesCreated = FALSE; +WCHAR* g_ButtonNames[MAX_BUTTONS] = {0}; + +INT g_PalIndex = 0; // simple palette index counter (test driver specific) +BOOL g_bDown = FALSE; // simple band direction bool (test drvier specific) + +BOOL InitializeScanner(PSCANINFO pScanInfo); +VOID InitScannerDefaults(PSCANINFO pScanInfo); +BOOL SetScannerSettings(PSCANINFO pScanInfo); +VOID CheckButtonStatus(PVAL pValue); +VOID GetButtonPress(LONG *pButtonValue); +HRESULT GetInterruptEvent(PVAL pValue); +LONG GetButtonCount(); +HRESULT GetOLESTRResourceString(LONG lResourceID,_Outptr_ LPOLESTR *ppsz,BOOL bLocal); +VOID ReadRegistryInformation(PVAL pValue); + +BOOL APIENTRY DllMain( HANDLE hModule,DWORD dwreason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(lpReserved); + + g_hInst = (HINSTANCE)hModule; + switch(dwreason) { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +/**************************************************************************\ +* MicroEntry (MicroDriver Entry point) +* +* Called by the WIA driver to communicate with the MicroDriver. +* +* Arguments: +* +* lCommand - MicroDriver Command, sent from the WIA driver +* pValue - VAL structure used for settings +* +* +* Return Value: +* +* Status +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +WIAMICRO_API HRESULT MicroEntry(LONG lCommand, _Inout_ PVAL pValue) +{ + HRESULT hr = E_NOTIMPL; + INT index = 0; + +//#define _DEBUG_COMMANDS + +#ifdef _DEBUG_COMMANDS + if(lCommand != CMD_STI_GETSTATUS) + Trace(TEXT("Command Value (%d)"),lCommand); +#endif + + if( !pValue || !(pValue->pScanInfo)) + { + return E_INVALIDARG; + } + + switch(lCommand) + { + case CMD_INITIALIZE: + hr = S_OK; + + // + // create any DeviceIO handles needed, use index (1 - MAX_IO_HANDLES) to store these handles. + // Index '0' is reserved by the WIA flatbed driver. The CreateFile Name is stored in the szVal + // member of the VAL structure. + // + + // pValue->pScanInfo->DeviceIOHandles[1] = CreateFileA( pValue->szVal, + // GENERIC_READ | GENERIC_WRITE, // Access mask + // 0, // Share mode + // NULL, // SA + // OPEN_EXISTING, // Create disposition + // FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, // Attributes + // NULL ); + + // + // if your device supports buttons, create the BUTTON name information here.. + // + + if (!g_bButtonNamesCreated) + { + for(index = 0; index < MAX_BUTTONS; index++) + { + g_ButtonNames[index] = (WCHAR*)CoTaskMemAlloc(MAX_BUTTON_NAME); + if (!g_ButtonNames[index]) + { + hr = E_OUTOFMEMORY; + break; + } + } + + if(SUCCEEDED(hr)) + { + hr = GetOLESTRResourceString(IDS_SCAN_BUTTON_NAME,&g_ButtonNames[0],TRUE); + } + + if(SUCCEEDED(hr)) + { + g_bButtonNamesCreated = TRUE; + } + else + { + for(index = 0; index < MAX_BUTTONS; index++) + { + if (g_ButtonNames[index]) + { + CoTaskMemFree(g_ButtonNames[index]); + g_ButtonNames[index] = NULL; + } + } + } + } + + // + // Initialize the scanner's default settings + // + + InitScannerDefaults(pValue->pScanInfo); + + break; + case CMD_UNINITIALIZE: + + // + // close any open handles created by the Micro driver + // + + if(pValue->pScanInfo->DeviceIOHandles[1] != NULL) + { + CloseHandle(pValue->pScanInfo->DeviceIOHandles[1]); + } + + + // + // if your device supports buttons, free/destroy the BUTTON name information here.. + // + + if(g_bButtonNamesCreated) + { + g_bButtonNamesCreated = FALSE; + + for(index = 0; index < MAX_BUTTONS; index++) + { + if (g_ButtonNames[index]) + { + CoTaskMemFree(g_ButtonNames[index]); + g_ButtonNames[index] = NULL; + } + } + } + + // + // close/unload libraries + // + + hr = S_OK; + break; + case CMD_RESETSCANNER: + + // + // reset scanner + // + + hr = S_OK; + break; + case CMD_STI_DIAGNOSTIC: + case CMD_STI_DEVICERESET: + + // + // reset device + // + + hr = S_OK; + break; + case CMD_STI_GETSTATUS: + + // + // set status flag to ON-LINE + // + + pValue->lVal = MCRO_STATUS_OK; + pValue->pGuid = (GUID*) &GUID_NULL; + + // + // button polling support + // + +#ifdef BUTTON_SUPPORT + CheckButtonStatus(pValue); +#endif + + hr = S_OK; + break; + case CMD_SETXRESOLUTION: + pValue->pScanInfo->Xresolution = pValue->lVal; + hr = S_OK; + break; + case CMD_SETYRESOLUTION: + pValue->pScanInfo->Yresolution = pValue->lVal; + hr = S_OK; + break; + case CMD_SETCONTRAST: + pValue->pScanInfo->Contrast = pValue->lVal; + hr = S_OK; + break; + case CMD_SETINTENSITY: + pValue->pScanInfo->Intensity = pValue->lVal; + hr = S_OK; + break; + case CMD_SETDATATYPE: + pValue->pScanInfo->DataType = pValue->lVal; + hr = S_OK; + break; + case CMD_SETNEGATIVE: + pValue->pScanInfo->Negative = pValue->lVal; + hr = S_OK; + break; + case CMD_GETADFSTATUS: + case CMD_GETADFHASPAPER: + // pValue->lVal = MCRO_ERROR_PAPER_EMPTY; + // hr = S_OK; + break; + case CMD_GET_INTERRUPT_EVENT: + hr = GetInterruptEvent(pValue); + break; + case CMD_GETCAPABILITIES: + pValue->lVal = 0; + pValue->pGuid = NULL; + pValue->ppButtonNames = NULL; + hr = S_OK; + break; + + case CMD_SETSCANMODE: + hr = S_OK; + switch(pValue->lVal) + { + case SCANMODE_FINALSCAN: + Trace(TEXT("Final Scan")); + break; + case SCANMODE_PREVIEWSCAN: + Trace(TEXT("Preview Scan")); + break; + default: + Trace(TEXT("Unknown Scan Mode (%d)"),pValue->lVal); + hr = E_FAIL; + break; + } + break; + case CMD_SETSTIDEVICEHKEY: + ReadRegistryInformation(pValue); + break; + +#ifdef _USE_EXTENDED_FORMAT_LIST + + // note: MEMORYBMP, and BMP file will be added by wiafbdrv host driver. + // do not include them in your extended list. + // + + case CMD_GETSUPPORTEDFILEFORMATS: + g_SupportedFileFormats[0] = WiaImgFmt_JPEG; + pValue->lVal = NUM_SUPPORTED_FILEFORMATS; + pValue->pGuid = g_SupportedFileFormats; + hr = S_OK; + break; + + case CMD_GETSUPPORTEDMEMORYFORMATS: + g_SupportedMemoryFormats[0] = WiaImgFmt_TIFF; + g_SupportedMemoryFormats[1] = WiaImgFmt_MYNEWFORMAT; + pValue->lVal = NUM_SUPPORTED_MEMORYFORMATS; + pValue->pGuid = g_SupportedMemoryFormats; + hr = S_OK; + break; +#endif + + default: + Trace(TEXT("Unknown Command (%d)"),lCommand); + break; + } + + return hr; +} + +/**************************************************************************\ +* Scan (MicroDriver Entry point) +* +* Called by the WIA driver to acquire data from the MicroDriver. +* +* Arguments: +* +* pScanInfo - SCANINFO structure used for settings +* lPhase - Current Scan phase, SCAN_FIRST, SCAN_NEXT, SCAN_FINISH... +* pBuffer - data buffer to be filled with scanned data +* lLength - Maximum length of pBuffer +* plReceived - Number of actual bytes written to pBuffer. +* +* +* Return Value: +* +* Status +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +WIAMICRO_API HRESULT Scan(_Inout_ PSCANINFO pScanInfo, LONG lPhase, _Out_writes_bytes_(lLength) PBYTE pBuffer, LONG lLength, _Out_ LONG *plReceived) +{ + if(pScanInfo == NULL) { + return E_INVALIDARG; + } + + INT i = 0; + *plReceived = 0; // Initialize *plReceived as 0. It has a return value in case of SCAN_FIRST and SCAN_NEXT. + + Trace(TEXT("------ Scan Requesting %d ------"),lLength); + switch (lPhase) { + case SCAN_FIRST: + if (!SetScannerSettings(pScanInfo)) { + return E_FAIL; + } + + Trace(TEXT("SCAN_FIRST")); + + g_PalIndex = 0; + g_bDown = FALSE; + + // + // first phase + // + + Trace(TEXT("Start Scan..")); + + case SCAN_NEXT: // SCAN_FIRST will fall through to SCAN_NEXT (because it is expecting data) + + // + // next phase + // + + if(lPhase == SCAN_NEXT) + Trace(TEXT("SCAN_NEXT")); + + // + // get data from the scanner and set plReceived value + // + + // + // read data + // + + switch(pScanInfo->DataType) { + case WIA_DATA_THRESHOLD: + + // + // make buffer alternate black/White, for sample 1-bit data + // + + memset(pBuffer,0,lLength); + memset(pBuffer,255,lLength/2); + break; + case WIA_DATA_GRAYSCALE: + + // + // make buffer grayscale data, for sample 8-bit data + // + + if(!g_bDown){ + g_PalIndex+=10; + if(g_PalIndex > 255){ + g_PalIndex = 255; + g_bDown = TRUE; + } + } + else { + g_PalIndex-=10; + if(g_PalIndex < 0){ + g_PalIndex = 0; + g_bDown = FALSE; + } + } + memset(pBuffer,g_PalIndex,lLength); + break; + case WIA_DATA_COLOR: + + // + // make buffer red, for sample color data + // + + for (i = 0;i+2<lLength;i+=3) { + memset(pBuffer+i,255,1); + memset(pBuffer+(i+1),0,1); + memset(pBuffer+(i+2),0,1); + } + break; + default: + break; + } + + // + // test device always returns the exact amount of scanned data + // + + *plReceived = lLength; + break; + case SCAN_FINISHED: + default: + Trace(TEXT("SCAN_FINISHED")); + + // + // stop scanner, do not set lRecieved, or write any data to pBuffer. Those values + // will be NULL. This lPhase is only to allow you to stop scanning, and return the + // scan head to the HOME position. SCAN_FINISHED will be called always for regular scans, and + // for cancelled scans. + // + + break; + } + + return S_OK; +} + +/**************************************************************************\ +* SetPixelWindow (MicroDriver Entry point) +* +* Called by the WIA driver to set the scan selection area to the MicroDriver. +* +* Arguments: +* +* pScanInfo - SCANINFO structure used for settings +* pValue - VAL structure used for settings +* x - X Position of scan rect (upper left x coordinate) +* y - Y Position of scan rect (upper left y coordinate) +* xExtent - Width of scan rect (in pixels) +* yExtent - Height of scan rect (in pixels) +* +* +* Return Value: +* +* Status +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +WIAMICRO_API HRESULT SetPixelWindow(_Inout_ PSCANINFO pScanInfo, LONG x, LONG y, LONG xExtent, LONG yExtent) +{ + if(pScanInfo == NULL) { + return E_INVALIDARG; + } + + pScanInfo->Window.xPos = x; + pScanInfo->Window.yPos = y; + pScanInfo->Window.xExtent = xExtent; + pScanInfo->Window.yExtent = yExtent; + return S_OK; +} + + +/**************************************************************************\ +* ReadRegistryInformation (helper) +* +* Called by the MicroDriver to Read registry information from the device's +* installed device section. The HKEY passed in will be closed by the host +* driver after CMD_INITIALIZE is completed. +* +* Arguments: +* +* none +* +* Return Value: +* +* void +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ +VOID ReadRegistryInformation(PVAL pValue) +{ + HKEY hKey = NULL; + if(NULL != pValue->pHandle){ + hKey = (HKEY)*pValue->pHandle; + + // + // Open DeviceData section to read driver specific information + // + + HKEY hOpenKey = NULL; + if (RegOpenKeyEx(hKey, // handle to open key + TEXT("DeviceData"), // address of name of subkey to open + 0, // options (must be NULL) + KEY_QUERY_VALUE|KEY_READ, // just want to QUERY a value + &hOpenKey // address of handle to open key + ) == ERROR_SUCCESS) { + + DWORD dwWritten = sizeof(DWORD); + DWORD dwType = REG_DWORD; + + LONG lSampleEntry = 0; + RegQueryValueEx(hOpenKey, + TEXT("Sample Entry"), + NULL, + &dwType, + (LPBYTE)&lSampleEntry, + &dwWritten); + Trace(TEXT("lSampleEntry Value = %d"),lSampleEntry); + } else { + Trace(TEXT("Could not open DeviceData section")); + } + } +} + +/**************************************************************************\ +* InitScannerDefaults (helper) +* +* Called by the MicroDriver to Initialize the SCANINFO structure +* +* Arguments: +* +* none +* +* Return Value: +* +* void +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +VOID InitScannerDefaults(PSCANINFO pScanInfo) +{ + + pScanInfo->ADF = 0; // set to no ADF in Test device + pScanInfo->RawDataFormat = WIA_PACKED_PIXEL; + pScanInfo->RawPixelOrder = WIA_ORDER_BGR; + pScanInfo->bNeedDataAlignment = TRUE; + + pScanInfo->SupportedCompressionType = 0; + pScanInfo->SupportedDataTypes = SUPPORT_BW|SUPPORT_GRAYSCALE|SUPPORT_COLOR; + + pScanInfo->BedWidth = 8500; // 1000's of an inch (WIA compatible unit) + pScanInfo->BedHeight = 11000; // 1000's of an inch (WIA compatible unit) + + pScanInfo->OpticalXResolution = 300; + pScanInfo->OpticalYResolution = 300; + + pScanInfo->IntensityRange.lMin = -127; + pScanInfo->IntensityRange.lMax = 127; + pScanInfo->IntensityRange.lStep = 1; + + pScanInfo->ContrastRange.lMin = -127; + pScanInfo->ContrastRange.lMax = 127; + pScanInfo->ContrastRange.lStep = 1; + + // Scanner settings + pScanInfo->Intensity = 0; + pScanInfo->Contrast = 0; + + pScanInfo->Xresolution = 150; + pScanInfo->Yresolution = 150; + + pScanInfo->Window.xPos = 0; + pScanInfo->Window.yPos = 0; + pScanInfo->Window.xExtent = (pScanInfo->Xresolution * pScanInfo->BedWidth)/1000; + pScanInfo->Window.yExtent = (pScanInfo->Yresolution * pScanInfo->BedHeight)/1000; + + // Scanner options + pScanInfo->DitherPattern = 0; + pScanInfo->Negative = 0; + pScanInfo->Mirror = 0; + pScanInfo->AutoBack = 0; + pScanInfo->ColorDitherPattern = 0; + pScanInfo->ToneMap = 0; + pScanInfo->Compression = 0; + + // Image Info + pScanInfo->DataType = WIA_DATA_GRAYSCALE; + pScanInfo->WidthPixels = (pScanInfo->Window.xExtent)-(pScanInfo->Window.xPos); + + switch(pScanInfo->DataType) { + case WIA_DATA_THRESHOLD: + pScanInfo->PixelBits = 1; + break; + case WIA_DATA_COLOR: + pScanInfo->PixelBits = 24; + break; + case WIA_DATA_GRAYSCALE: + default: + pScanInfo->PixelBits = 8; + break; + } + + pScanInfo->WidthBytes = pScanInfo->Window.xExtent * (pScanInfo->PixelBits/8); + pScanInfo->Lines = pScanInfo->Window.yExtent; +} + +/**************************************************************************\ +* SetScannerSettings (helper) +* +* Called by the MicroDriver to set the values stored in the SCANINFO structure +* to the actual device. +* +* Arguments: +* +* none +* +* +* Return Value: +* +* TRUE - Success, FALSE - Failure +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +BOOL SetScannerSettings(PSCANINFO pScanInfo) +{ + if(pScanInfo->DataType == WIA_DATA_THRESHOLD) { + pScanInfo->PixelBits = 1; + pScanInfo->WidthBytes = (pScanInfo->Window.xExtent)-(pScanInfo->Window.xPos) * (pScanInfo->PixelBits/7); + + // + // Set data type to device + // + + // if the set fails.. + // return FALSE; + } + else if(pScanInfo->DataType == WIA_DATA_GRAYSCALE) { + pScanInfo->PixelBits = 8; + pScanInfo->WidthBytes = (pScanInfo->Window.xExtent)-(pScanInfo->Window.xPos) * (pScanInfo->PixelBits/8); + + // + // Set data type to device + // + + // if the set fails.. + // return FALSE; + + } + else { + pScanInfo->PixelBits = 24; + pScanInfo->WidthBytes = (pScanInfo->Window.xExtent)-(pScanInfo->Window.xPos) * (pScanInfo->PixelBits/8); + + // + // Set data type to device + // + + // if the set fails.. + // return FALSE; + + } + +#ifdef DEBUG + Trace(TEXT("ScanInfo")); + Trace(TEXT("x res = %d"),pScanInfo->Xresolution); + Trace(TEXT("y res = %d"),pScanInfo->Yresolution); + Trace(TEXT("bpp = %d"),pScanInfo->PixelBits); + Trace(TEXT("xpos = %d"),pScanInfo->Window.xPos); + Trace(TEXT("ypos = %d"),pScanInfo->Window.yPos); + Trace(TEXT("xext = %d"),pScanInfo->Window.xExtent); + Trace(TEXT("yext = %d"),pScanInfo->Window.yExtent); +#endif + + // + // send other values to device, use the values set in pScanInfo to set them to your + // device. + // + + return TRUE; +} + +/**************************************************************************\ +* InitializeScanner (helper) +* +* Called by the MicroDriver to Iniitialize any device specific operations +* +* Arguments: +* +* none +* +* Return Value: +* +* TRUE - Success, FALSE - Failure +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +BOOL InitializeScanner(PSCANINFO pScanInfo) +{ + UNREFERENCED_PARAMETER(pScanInfo); + + HRESULT hr = S_OK; + + // + // Do any device initialization here... + // The test device does not need any. + // + + if (SUCCEEDED(hr)) { + return TRUE; + } + return FALSE; +} + +/**************************************************************************\ +* CheckButtonStatus (helper) +* +* Called by the MicroDriver to Set the current Button pressed value. +* +* Arguments: +* +* pValue - VAL structure used for settings +* +* +* Return Value: +* +* VOID +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + + +VOID CheckButtonStatus(PVAL pValue) +{ + // + // Button Polling is done here... + // + + // + // Check your device for button presses + // + + LONG lButtonValue = 0; + + GetButtonPress(&lButtonValue); + switch (lButtonValue) { + case 1: + pValue->pGuid = (GUID*) &guidScanButton; + Trace(TEXT("Scan Button Pressed!")); + break; + default: + pValue->pGuid = (GUID*) &GUID_NULL; + break; + } +} +/**************************************************************************\ +* GetInterruptEvent (helper) +* +* Called by the MicroDriver to handle USB interrupt events. +* +* Arguments: +* +* pValue - VAL structure used for settings +* +* +* Return Value: +* +* Status +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +HRESULT GetInterruptEvent(PVAL pValue) +{ + // + // Below is a simple example of how DeviceIOControl() can be used to + // determine interrupts with a USB device. + // + // The test device does not support events, + // So this should not be called. + // + + HRESULT hr = S_OK; + BYTE InterruptData; + DWORD dwIndex; + DWORD dwError; + + OVERLAPPED Overlapped; + ZeroMemory( &Overlapped, sizeof( Overlapped )); + Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + + HANDLE hEventArray[2] = {pValue->handle, Overlapped.hEvent}; + BOOL fLooping = TRUE; + BOOL bRet = TRUE; + + // + // use the Handle created in CMD_INITIALIZE. + // + + HANDLE InterruptHandle = pValue->pScanInfo->DeviceIOHandles[1]; + + while (fLooping) { + + // + // Set the wait event, for the interrupt + // + + bRet = DeviceIoControl( InterruptHandle, + (DWORD) IOCTL_WAIT_ON_DEVICE_EVENT, + NULL, + 0, + &InterruptData, + sizeof(InterruptData), + &dwError, + &Overlapped ); + + if ( bRet || ( !bRet && ( ::GetLastError() == ERROR_IO_PENDING ))) { + + // + // Wait for the event to happen + // + + dwIndex = WaitForMultipleObjects( 2, + hEventArray, + FALSE, + INFINITE ); + + // + // Trap the result of the event + // + + switch ( dwIndex ) { + case WAIT_OBJECT_0+1: + DWORD dwBytesRet; + bRet = GetOverlappedResult( InterruptHandle, &Overlapped, &dwBytesRet, FALSE ); + + if ( dwBytesRet ) { + + // + // assign the corresponding button GUID to the *pValue->pGuid + // member., and Set the event. + // + + // Change detected - signal + if (*pValue->pHandle != INVALID_HANDLE_VALUE) { + switch ( InterruptData ) { + case 1: + *pValue->pGuid = guidScanButton; + Trace(TEXT("Scan Button Pressed!")); + break; + default: + *pValue->pGuid = GUID_NULL; + break; + } + Trace(TEXT("Setting This Event by Handle %d"),*pValue->pHandle); + + // + // signal the event, after a button GUID was assigned. + // + + SetEvent(*pValue->pHandle); + } + break; + } + + // + // reset the overlapped event + // + + ResetEvent( Overlapped.hEvent ); + break; + + case WAIT_OBJECT_0: + // Fall through + default: + fLooping = FALSE; + } + } + else { + hr = HRESULT_FROM_WIN32(::GetLastError()); + break; + } + } + return hr; +} + +/**************************************************************************\ +* GetButtonPress (helper) +* +* Called by the MicroDriver to set the actual button value pressed +* +* Arguments: +* +* pButtonValue - actual button pressed +* +* +* Return Value: +* +* Status +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +VOID GetButtonPress(LONG *pButtonValue) +{ + + // + // This where you can set your button value + // + + pButtonValue = 0; +} + +/**************************************************************************\ +* GetButtonCount (helper) +* +* Called by the MicroDriver to get the number of buttons a device supports +* +* Arguments: +* +* none +* +* Return Value: +* +* LONG - number of supported buttons +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +LONG GetButtonCount() +{ + LONG ButtonCount = 0; + + // + // Since the test device does not have a button, + // set this value to 0. For a real device with a button, + // set (LONG ButtonCount = 1;) + // + + // + // determine the button count of your device + // + + return ButtonCount; +} + +/**************************************************************************\ +* GetOLDSTRResourceString (helper) +* +* Called by the MicroDriver to Load a resource string in OLESTR format +* +* Arguments: +* +* lResourceID - String resource ID +* ppsz - Pointer to a OLESTR to be filled with the loaded string +* value +* bLocal - Possible, other source for loading a resource string. +* +* +* Return Value: +* +* Status +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +HRESULT GetOLESTRResourceString(LONG lResourceID,_Outptr_ LPOLESTR *ppsz,BOOL bLocal) +{ + HRESULT hr = S_OK; + TCHAR szStringValue[255]; + if(bLocal) { + + // + // We are looking for a resource in our own private resource file + // + + INT NumTCHARs = LoadString(g_hInst, lResourceID, szStringValue, sizeof(szStringValue)/sizeof(TCHAR)); + + if (NumTCHARs <= 0) + { + +#ifdef UNICODE + DWORD dwError = GetLastError(); + Trace(TEXT("NumTCHARs = %d dwError = %d Resource ID = %d (UNICODE)szString = %ws"), + NumTCHARs, + dwError, + lResourceID, + szStringValue); +#else + DWORD dwError = GetLastError(); + Trace(TEXT("NumTCHARs = %d dwError = %d Resource ID = %d (ANSI)szString = %s"), + NumTCHARs, + dwError, + lResourceID, + szStringValue); +#endif + + return E_FAIL; + } + + // + // NOTE: caller must free this allocated BSTR + // + +#ifdef UNICODE + + *ppsz = NULL; + *ppsz = (LPOLESTR)CoTaskMemAlloc(sizeof(szStringValue)); + if(*ppsz != NULL) + { + + // + // The call to LoadString previously guarantees that szStringValue is null terminated (maybe truncated) + // so a buffer of 'sizeof(szStringValue)/sizeof(TCHAR)' should suffice + // + + hr = StringCchCopy(*ppsz, sizeof(szStringValue)/sizeof(TCHAR), szStringValue); + } + else + { + hr = E_OUTOFMEMORY; + } + +#else + WCHAR wszStringValue[255]; + ZeroMemory(wszStringValue,sizeof(wszStringValue)); + + // + // convert szStringValue from char* to unsigned short* (ANSI only) + // + + MultiByteToWideChar(CP_ACP, + MB_PRECOMPOSED, + szStringValue, + lstrlenA(szStringValue)+1, + wszStringValue, + (sizeof(wszStringValue)/sizeof(WCHAR))); + + *ppsz = NULL; + *ppsz = (LPOLESTR)CoTaskMemAlloc(sizeof(wszStringValue)); + if(*ppsz != NULL) + { + + // + // The call to LoadString & MultiByteToWideChar previously guarantees that wszStringValue is null terminated + // (maybe truncated) so a buffer of 'sizeof(wszStringValue)/sizeof(WCHAR)' should suffice + // + + hr = StringCchCopyW(*ppsz,sizeof(wszStringValue)/sizeof(WCHAR),wszStringValue); + } + else + { + hr = E_OUTOFMEMORY; + } +#endif + + } + else + { + + // + // looking another place for resources?? + // + + hr = E_NOTIMPL; + } + + return hr; +} + +/**************************************************************************\ +* Trace +* +* Called by the MicroDriver to output strings to a debugger +* +* Arguments: +* +* format - formatted string to output +* +* +* Return Value: +* +* VOID +* +* History: +* +* 1/20/2000 Original Version +* +\**************************************************************************/ + +VOID Trace(_In_ LPCTSTR format,...) +{ + +#ifdef DEBUG + + TCHAR Buffer[1024]; + va_list arglist; + va_start(arglist, format); + + // + // StringCchVPrintf API guarantees the buffer to be null terminated (though it maybe truncated) + // + + StringCchVPrintf(Buffer, sizeof(Buffer)/sizeof(TCHAR), format, arglist); + va_end(arglist); + OutputDebugString(Buffer); + OutputDebugString(TEXT("\n")); + +#else + + UNREFERENCED_PARAMETER(format); + +#endif + +} + + diff --git a/wia/microdrv/testmcro.def b/wia/microdrv/testmcro.def new file mode 100644 index 00000000..9fffdbcb --- /dev/null +++ b/wia/microdrv/testmcro.def @@ -0,0 +1,6 @@ +LIBRARY TESTMCRO + +EXPORTS + MicroEntry + Scan + SetPixelWindow diff --git a/wia/microdrv/testmcro.h b/wia/microdrv/testmcro.h new file mode 100644 index 00000000..ac88f1ef --- /dev/null +++ b/wia/microdrv/testmcro.h @@ -0,0 +1,31 @@ +#ifndef TESTMCRO +#define TESTMCRO + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define INITGUID +#include <windows.h> + +// +// Button GUIDS +// + +DEFINE_GUID( guidScanButton, 0xa6c5a715, 0x8c6e, 0x11d2, 0x97, 0x7a, 0x0, 0x0, 0xf8, 0x7a, 0x92, 0x6f); + +// copy any known formats defined in wiadef.h to this location for use in your driver. + +DEFINE_GUID(WiaImgFmt_MEMORYBMP, 0xb96b3caa,0x0728,0x11d3,0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e); +DEFINE_GUID(WiaImgFmt_BMP, 0xb96b3cab,0x0728,0x11d3,0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e); +DEFINE_GUID(WiaImgFmt_JPEG, 0xb96b3cae,0x0728,0x11d3,0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e); +DEFINE_GUID(WiaImgFmt_TIFF, 0xb96b3cb1,0x0728,0x11d3,0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e); + +// define your custom-defined supported formats here +// {3B5DE639-B2C6-4952-98A9-1DC06F3703BD} +DEFINE_GUID(WiaImgFmt_MYNEWFORMAT, 0x3b5de639, 0xb2c6, 0x4952, 0x98, 0xa9, 0x1d, 0xc0, 0x6f, 0x37, 0x3, 0xbd); + +#undef INITGUID + +#endif + diff --git a/wia/microdrv/testmcro.inf b/wia/microdrv/testmcro.inf new file mode 100644 index 00000000..4b59377f --- /dev/null +++ b/wia/microdrv/testmcro.inf @@ -0,0 +1,82 @@ +; TESTMCRO.INF -- WIA sample MicroDriver scanner setup file +; Copyright (c) 2001 Microsoft Corporation +; Manufacturer: Microsoft + +[Version] +Signature="$WINDOWS NT$" +Class=Image +ClassGUID={6bdd1fc6-810f-11d0-bec7-08002be2092f} +Provider=%ProviderString% +DriverVer=11/02/2007,1.0.0.1 +CatalogFile=testmcro.cat + +[SourceDisksFiles.x86] +testmcro.dll=1 +[SourceDisksNames.x86] +1=%Location%,,, + +[SourceDisksFiles.ia64] +testmcro.dll=1 +[SourceDisksNames.ia64] +1=%Location%,,, + +[SourceDisksFiles.amd64] +testmcro.dll=1 +[SourceDisksNames.amd64] +1=%Location%,,, + +[DestinationDirs] +; By default, files will be copied to \windows\system32. +DefaultDestDir=11 + +[Manufacturer] +%ManufacturerName%=Models, NTx86, NTamd64, NTia64 + +; This is the models section for the x86 driver +[Models.NTx86] +%WIASample.DeviceDesc% = WIASample.Scanner, PnPIDInformation + +; This is the models section for the amd64 driver +[Models.NTamd64] +%WIASample.DeviceDesc% = WIASample.Scanner, PnPIDInformation + +; This is the models section for the ia64 driver +[Models.NTia64] +%WIASample.DeviceDesc% = WIASample.Scanner, PnPIDInformation + +[WIASample.Scanner] +Include=sti.inf +Needs=STI.SerialSection, STI.MICRODRIVERSection +SubClass=StillImage +DeviceType=1 +DeviceSubType=0x1 +Capabilities=0x30 +Events=WIASample.Events +DeviceData=WIASample.DeviceData +AddReg=WIASample.AddReg +CopyFiles=WIASample.CopyFiles +ICMProfiles="sRGB Color Space Profile.icm" + +[WIASample.Events] + +[WIASample.Scanner.Services] +Include=sti.inf +Needs=STI.SerialSection.Services + +[WIASample.DeviceData] +Server=local +UI Class ID={4DB1AD10-3391-11D2-9A33-00C04FA36145} +MicroDriver="TESTMCRO.DLL" +Sample Entry=1,1 + +[WIASample.AddReg] +HKR,,HardwareConfig,1,1 + +[WIASample.CopyFiles] +testmcro.dll + +[Strings] +ManufacturerName="TODO-Set-Manufacturer" +ProviderString="TODO-Set-Provider" +Location="Install Source" +WIASample.DeviceDesc="WIA Sample MicroDriver Scanner Device" diff --git a/wia/microdrv/testmcro.rc b/wia/microdrv/testmcro.rc new file mode 100644 index 00000000..2c55a579 --- /dev/null +++ b/wia/microdrv/testmcro.rc @@ -0,0 +1,14 @@ +#include "testmcro.rcv" +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + +IDS_SCAN_BUTTON_NAME "My Scan Button" + +END diff --git a/wia/microdrv/testmcro.rcv b/wia/microdrv/testmcro.rcv new file mode 100644 index 00000000..ff7f25c6 --- /dev/null +++ b/wia/microdrv/testmcro.rcv @@ -0,0 +1,18 @@ +/*****************************************************************/ +/** Microsoft Windows **/ +/** Copyright (C) Microsoft Corp., 1996-2000 **/ +/*****************************************************************/ + +#include <windows.h> +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "TEST Flatbed Scanner Still Image Device Micro Driver DLL" +#define VER_INTERNALNAME_STR "TESTMCRO" +#define VER_ORIGINALFILENAME_STR "TESTMCRO.DLL" + +#include <common.ver> + + + diff --git a/wia/microdrv/testmcro.vcxproj b/wia/microdrv/testmcro.vcxproj new file mode 100644 index 00000000..4fedb7a2 --- /dev/null +++ b/wia/microdrv/testmcro.vcxproj @@ -0,0 +1,199 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{823A3A7D-47CE-46A7-BEC6-87E16E61CCE7}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{72A46237-DB33-46EF-A427-E62F5F6F6664}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>testmcro</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>testmcro</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>testmcro</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>testmcro</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;advapi32.lib;user32.lib;gdi32.lib;ole32.lib;uuid.lib;oleaut32.lib</AdditionalDependencies> + <ModuleDefinitionFile>testmcro.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;advapi32.lib;user32.lib;gdi32.lib;ole32.lib;uuid.lib;oleaut32.lib</AdditionalDependencies> + <ModuleDefinitionFile>testmcro.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;advapi32.lib;user32.lib;gdi32.lib;ole32.lib;uuid.lib;oleaut32.lib</AdditionalDependencies> + <ModuleDefinitionFile>testmcro.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;advapi32.lib;user32.lib;gdi32.lib;ole32.lib;uuid.lib;oleaut32.lib</AdditionalDependencies> + <ModuleDefinitionFile>testmcro.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="testmcro.cpp" /> + <ResourceCompile Include="testmcro.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/wia/microdrv/testmcro.vcxproj.Filters b/wia/microdrv/testmcro.vcxproj.Filters new file mode 100644 index 00000000..77007970 --- /dev/null +++ b/wia/microdrv/testmcro.vcxproj.Filters @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{4B344312-D67F-43C4-ADEA-219822B0DA3C}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{3EB64FCC-F632-49F7-BA8D-65BFC005D073}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{2EAD88AF-FB87-4771-BA31-D241D7C7DD93}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="testmcro.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="testmcro.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="testmcro.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/wia/wia.sln b/wia/wia.sln new file mode 100644 index 00000000..ff7ac18a --- /dev/null +++ b/wia/wia.sln @@ -0,0 +1,118 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microdrv", "Microdrv", "{5F40702E-4251-4896-A0D1-E3B262F566EB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Errhandler", "Errhandler", "{A92C5883-CEAC-40F0-BF6B-339EC471D786}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Wiadriverex", "Wiadriverex", "{B6171A76-0376-4705-883D-A80C2B6002A1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Imgfilter", "Imgfilter", "{0B1D3A1D-779A-47DA-A98D-4B11D2ED824C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Segfilter", "Segfilter", "{6032EC50-C055-4423-ACDE-2580E4AAF3EE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Uiext2", "Uiext2", "{3B11780F-D142-46CE-9097-F1DC616A522E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Usd", "Usd", "{744B6DAE-B21F-4DE5-A865-FACA65CD663A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProdScan", "ProdScan", "{AE4FFB88-463E-4DA3-81DA-2D2143A6097A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testmcro", "microdrv\testmcro.vcxproj", "{823A3A7D-47CE-46A7-BEC6-87E16E61CCE7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "errhandler", "wiadriverex\errhandler\errhandler.vcxproj", "{DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imgfilter", "wiadriverex\imgfilter\imgfilter.vcxproj", "{12455A18-956A-4030-B1C2-4C3EA1A827AD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "segfilter", "wiadriverex\segfilter\segfilter.vcxproj", "{4514674D-F69E-4C3B-902F-23FB5F04DB40}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uiext2", "wiadriverex\uiext2\uiext2.vcxproj", "{D8EF524D-29CB-4721-8EBE-1A049ECE53A2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wiadriverex", "wiadriverex\usd\wiadriverex.vcxproj", "{88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProdScan", "ProdScan\ProdScan.vcxproj", "{041FE80B-1F18-4CF6-90DD-59C690C11A32}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {823A3A7D-47CE-46A7-BEC6-87E16E61CCE7}.Debug|Win32.ActiveCfg = Debug|Win32 + {823A3A7D-47CE-46A7-BEC6-87E16E61CCE7}.Debug|Win32.Build.0 = Debug|Win32 + {823A3A7D-47CE-46A7-BEC6-87E16E61CCE7}.Release|Win32.ActiveCfg = Release|Win32 + {823A3A7D-47CE-46A7-BEC6-87E16E61CCE7}.Release|Win32.Build.0 = Release|Win32 + {823A3A7D-47CE-46A7-BEC6-87E16E61CCE7}.Debug|x64.ActiveCfg = Debug|x64 + {823A3A7D-47CE-46A7-BEC6-87E16E61CCE7}.Debug|x64.Build.0 = Debug|x64 + {823A3A7D-47CE-46A7-BEC6-87E16E61CCE7}.Release|x64.ActiveCfg = Release|x64 + {823A3A7D-47CE-46A7-BEC6-87E16E61CCE7}.Release|x64.Build.0 = Release|x64 + {DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A}.Debug|Win32.ActiveCfg = Debug|Win32 + {DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A}.Debug|Win32.Build.0 = Debug|Win32 + {DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A}.Release|Win32.ActiveCfg = Release|Win32 + {DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A}.Release|Win32.Build.0 = Release|Win32 + {DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A}.Debug|x64.ActiveCfg = Debug|x64 + {DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A}.Debug|x64.Build.0 = Debug|x64 + {DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A}.Release|x64.ActiveCfg = Release|x64 + {DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A}.Release|x64.Build.0 = Release|x64 + {12455A18-956A-4030-B1C2-4C3EA1A827AD}.Debug|Win32.ActiveCfg = Debug|Win32 + {12455A18-956A-4030-B1C2-4C3EA1A827AD}.Debug|Win32.Build.0 = Debug|Win32 + {12455A18-956A-4030-B1C2-4C3EA1A827AD}.Release|Win32.ActiveCfg = Release|Win32 + {12455A18-956A-4030-B1C2-4C3EA1A827AD}.Release|Win32.Build.0 = Release|Win32 + {12455A18-956A-4030-B1C2-4C3EA1A827AD}.Debug|x64.ActiveCfg = Debug|x64 + {12455A18-956A-4030-B1C2-4C3EA1A827AD}.Debug|x64.Build.0 = Debug|x64 + {12455A18-956A-4030-B1C2-4C3EA1A827AD}.Release|x64.ActiveCfg = Release|x64 + {12455A18-956A-4030-B1C2-4C3EA1A827AD}.Release|x64.Build.0 = Release|x64 + {4514674D-F69E-4C3B-902F-23FB5F04DB40}.Debug|Win32.ActiveCfg = Debug|Win32 + {4514674D-F69E-4C3B-902F-23FB5F04DB40}.Debug|Win32.Build.0 = Debug|Win32 + {4514674D-F69E-4C3B-902F-23FB5F04DB40}.Release|Win32.ActiveCfg = Release|Win32 + {4514674D-F69E-4C3B-902F-23FB5F04DB40}.Release|Win32.Build.0 = Release|Win32 + {4514674D-F69E-4C3B-902F-23FB5F04DB40}.Debug|x64.ActiveCfg = Debug|x64 + {4514674D-F69E-4C3B-902F-23FB5F04DB40}.Debug|x64.Build.0 = Debug|x64 + {4514674D-F69E-4C3B-902F-23FB5F04DB40}.Release|x64.ActiveCfg = Release|x64 + {4514674D-F69E-4C3B-902F-23FB5F04DB40}.Release|x64.Build.0 = Release|x64 + {D8EF524D-29CB-4721-8EBE-1A049ECE53A2}.Debug|Win32.ActiveCfg = Debug|Win32 + {D8EF524D-29CB-4721-8EBE-1A049ECE53A2}.Debug|Win32.Build.0 = Debug|Win32 + {D8EF524D-29CB-4721-8EBE-1A049ECE53A2}.Release|Win32.ActiveCfg = Release|Win32 + {D8EF524D-29CB-4721-8EBE-1A049ECE53A2}.Release|Win32.Build.0 = Release|Win32 + {D8EF524D-29CB-4721-8EBE-1A049ECE53A2}.Debug|x64.ActiveCfg = Debug|x64 + {D8EF524D-29CB-4721-8EBE-1A049ECE53A2}.Debug|x64.Build.0 = Debug|x64 + {D8EF524D-29CB-4721-8EBE-1A049ECE53A2}.Release|x64.ActiveCfg = Release|x64 + {D8EF524D-29CB-4721-8EBE-1A049ECE53A2}.Release|x64.Build.0 = Release|x64 + {88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C}.Debug|Win32.ActiveCfg = Debug|Win32 + {88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C}.Debug|Win32.Build.0 = Debug|Win32 + {88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C}.Release|Win32.ActiveCfg = Release|Win32 + {88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C}.Release|Win32.Build.0 = Release|Win32 + {88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C}.Debug|x64.ActiveCfg = Debug|x64 + {88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C}.Debug|x64.Build.0 = Debug|x64 + {88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C}.Release|x64.ActiveCfg = Release|x64 + {88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C}.Release|x64.Build.0 = Release|x64 + {041FE80B-1F18-4CF6-90DD-59C690C11A32}.Debug|Win32.ActiveCfg = Debug|Win32 + {041FE80B-1F18-4CF6-90DD-59C690C11A32}.Debug|Win32.Build.0 = Debug|Win32 + {041FE80B-1F18-4CF6-90DD-59C690C11A32}.Release|Win32.ActiveCfg = Release|Win32 + {041FE80B-1F18-4CF6-90DD-59C690C11A32}.Release|Win32.Build.0 = Release|Win32 + {041FE80B-1F18-4CF6-90DD-59C690C11A32}.Debug|x64.ActiveCfg = Debug|x64 + {041FE80B-1F18-4CF6-90DD-59C690C11A32}.Debug|x64.Build.0 = Debug|x64 + {041FE80B-1F18-4CF6-90DD-59C690C11A32}.Release|x64.ActiveCfg = Release|x64 + {041FE80B-1F18-4CF6-90DD-59C690C11A32}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {823A3A7D-47CE-46A7-BEC6-87E16E61CCE7} = {5F40702E-4251-4896-A0D1-E3B262F566EB} + {DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A} = {A92C5883-CEAC-40F0-BF6B-339EC471D786} + {12455A18-956A-4030-B1C2-4C3EA1A827AD} = {0B1D3A1D-779A-47DA-A98D-4B11D2ED824C} + {4514674D-F69E-4C3B-902F-23FB5F04DB40} = {6032EC50-C055-4423-ACDE-2580E4AAF3EE} + {D8EF524D-29CB-4721-8EBE-1A049ECE53A2} = {3B11780F-D142-46CE-9097-F1DC616A522E} + {88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C} = {744B6DAE-B21F-4DE5-A865-FACA65CD663A} + {041FE80B-1F18-4CF6-90DD-59C690C11A32} = {AE4FFB88-463E-4DA3-81DA-2D2143A6097A} + {A92C5883-CEAC-40F0-BF6B-339EC471D786} = {B6171A76-0376-4705-883D-A80C2B6002A1} + {0B1D3A1D-779A-47DA-A98D-4B11D2ED824C} = {B6171A76-0376-4705-883D-A80C2B6002A1} + {6032EC50-C055-4423-ACDE-2580E4AAF3EE} = {B6171A76-0376-4705-883D-A80C2B6002A1} + {3B11780F-D142-46CE-9097-F1DC616A522E} = {B6171A76-0376-4705-883D-A80C2B6002A1} + {744B6DAE-B21F-4DE5-A865-FACA65CD663A} = {B6171A76-0376-4705-883D-A80C2B6002A1} + EndGlobalSection +EndGlobal diff --git a/wia/wiadriverex/errhandler/DLLExports.def b/wia/wiadriverex/errhandler/DLLExports.def new file mode 100644 index 00000000..34ee1846 --- /dev/null +++ b/wia/wiadriverex/errhandler/DLLExports.def @@ -0,0 +1,31 @@ +; /*++ +; +; Copyright (C) Microsoft Corporation, 1985 - 2002 +; All rights reserved. +; +; Module Name: +; +; DLLExports.def +; +; Abstract: +; +; Declares the module parameters +; +; Author: +; +; Mikael Horal May-5-2003 +; +; Revision History: +; +; Mikael Horal May-5-2003 +; created +; +; --*/ +LIBRARY segfilter + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + diff --git a/wia/wiadriverex/errhandler/errhandler.cpp b/wia/wiadriverex/errhandler/errhandler.cpp new file mode 100644 index 00000000..f205b15b --- /dev/null +++ b/wia/wiadriverex/errhandler/errhandler.cpp @@ -0,0 +1,438 @@ +/***************************************************************************** + * + * errhandler.cpp + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: + * + * CErrHandler is a simple error handler, which works together with + * the wiadriver. + * + *******************************************************************************/ +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_driver_) + +#include "stdafx.h" + +#define MYDESCSTRING TEXT("Special driver device status error (only for testing purposes). Press 'Ok' to continue. Hitting 'Cancel' will abort the transfer.") + +#define HANDLED_PRIVATE_STATUS_ERROR_1 MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 1001) + +// {CFC1A4D4-5F27-4881-81E4-1BE314EB22F7} +static const GUID CLSID_WiaErrorHandler = +{ 0xcfc1a4d4, 0x5f27, 0x4881, { 0x81, 0xe4, 0x1b, 0xe3, 0x14, 0xeb, 0x22, 0xf7 } }; + +static LONG g_cLocks = 0; + +void LockModule(void) { InterlockedIncrement(&g_cLocks); } +void UnlockModule(void) { InterlockedDecrement(&g_cLocks); } + +class CErrHandler : public IWiaErrorHandler +{ +public: + + STDMETHODIMP + QueryInterface(const IID& iid_requested, _COM_Outptr_ void** ppInterfaceOut); + + STDMETHODIMP_(ULONG) + AddRef(void); + + STDMETHODIMP_(ULONG) + Release(void); + + STDMETHODIMP + ReportStatus( + LONG lFlags, + _In_ HWND hwndParent, + _In_ IWiaItem2 *pWiaItem2, + HRESULT hrStatus, + LONG lPercentComplete); + + STDMETHODIMP + GetStatusDescription( + LONG lFlags, + _In_ IWiaItem2 *pWiaItem2, + HRESULT hrStatus, + _Out_ BSTR *pbstrDescription); + + CErrHandler() : m_nRefCount(0) {} +private: + + LONG m_nRefCount; +}; + +/// +/// QueryInterface +/// +STDMETHODIMP +CErrHandler::QueryInterface(const IID& iid_requested, _COM_Outptr_ void** ppInterfaceOut) +{ + HRESULT hr = S_OK; + + hr = ppInterfaceOut ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppInterfaceOut = NULL; + } + + // + // We support IID_IUnknown and IID_IWiaErrorHandler + // + if (SUCCEEDED(hr)) + { + if (IID_IUnknown == iid_requested) + { + *ppInterfaceOut = static_cast<IUnknown*>(this); + } + else if (IID_IWiaErrorHandler == iid_requested) + { + *ppInterfaceOut = static_cast<IWiaErrorHandler*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppInterfaceOut)->AddRef(); + } + + return hr; +} + +/// +/// AddRef +/// +STDMETHODIMP_(ULONG) +CErrHandler::AddRef(void) +{ + if (m_nRefCount == 0) + { + LockModule(); + } + + return InterlockedIncrement(&m_nRefCount); +} + +/// +/// Release +/// +STDMETHODIMP_(ULONG) +CErrHandler::Release(void) +{ + ULONG nRetval = InterlockedDecrement(&m_nRefCount); + + if (0 == nRetval) + { + delete this; + UnlockModule(); + } + + return nRetval; +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CErrHandler::ReportStatus | ReportStatus implementation + * + * @parm LONG | lFlags | + * Flags - currently unused. + * + * @parm HWND | hwndParent | + * Window handle provided by the application + * + * @parm IWiaItem2 | pWiaItem2 | + * The item which is currently being transferred + * + * @parm HRESULT | hrStatus | + * Status code + * + * @parm LONG | lPercentComplete + * Percent of operation completed (e.g. warming up device) + * + * + * @comm + * ReportStatus handles HANDLED_PRIVATE_STATUS_ERROR_1 for which it displays a modal + * dialog box which enables a user to cancel the transfer or to continue. + * For all other messages we return WIA_STATUS_NOT_HANDLED + * + * @rvalue S_OK | + * The function successfully handled the device status message. + * + * @rvalue WIA_STATUS_NOT_HANDLED | + * The function does not handle this device status message + * + * @rvalue E_XXX | + * Error + * + *****************************************************************************/ +STDMETHODIMP +CErrHandler::ReportStatus( + LONG lFlags, + _In_ HWND hwndParent, + _In_ IWiaItem2 *pWiaItem2, + HRESULT hrStatus, + LONG lPercentComplete) +{ + UNREFERENCED_PARAMETER(lFlags); + UNREFERENCED_PARAMETER(lPercentComplete); + + HRESULT hr = pWiaItem2 ? WIA_STATUS_NOT_HANDLED : E_INVALIDARG; + + if ((WIA_STATUS_NOT_HANDLED == hr) && (HANDLED_PRIVATE_STATUS_ERROR_1 == hrStatus)) + { + HINSTANCE hModule = NULL; + TCHAR bufDialog[MAX_PATH] = {0}; + TCHAR bufTitle[MAX_PATH] = {0}; + + hModule = GetModuleHandle(L"errhandler.dll"); + + if (NULL != hModule && + LoadString(hModule, IDS_MESSAGEBOX_ERRORHANDLE_DIALOG, bufDialog, ARRAYSIZE(bufDialog)) && + LoadString(hModule, IDS_MESSAGEBOX_ERRORHANDLE_TITLE, bufTitle, ARRAYSIZE(bufTitle)) && + IDOK == MessageBox(hwndParent, bufDialog, bufTitle, MB_OKCANCEL|MB_TASKMODAL|MB_ICONERROR) + ) + { + hr = S_OK; + } + else + { + hr = HANDLED_PRIVATE_STATUS_ERROR_1; + } + } + + return hr; +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CErrHandler::GetStatusDescription | GetStatusDescription implementation + * + * @parm LONG | lFlags | + * Flags - currently unused. + * + * @parm IWiaItem2 | pWiaItem2 | + * The item which is currently being transferred + * + * @parm HRESULT | hrStatus | + * Status code + * + * @parm BSTR* | pbstrDescription | + * On S_OK this pbstrDescription will point to string with status description + * + * + * @comm + * GetStatusDescription handles HANDLED_PRIVATE_STATUS_ERROR_1 for which it returns + * a description string. It returns WIA_STATUS_NOT_HANDLED for all other messages + * + * @rvalue S_OK | + * The function successfully handled the device status message. + * + * @rvalue WIA_STATUS_NOT_HANDLED | + * The function does not handle this device status message + * + * @rvalue E_XXX | + * Error + * + *****************************************************************************/ +STDMETHODIMP +CErrHandler::GetStatusDescription( + LONG lFlags, + _In_ IWiaItem2 *pWiaItem2, + HRESULT hrStatus, + _Out_ BSTR *pbstrDescription) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = (pbstrDescription && pWiaItem2) ? WIA_STATUS_NOT_HANDLED : E_INVALIDARG; + + if (WIA_STATUS_NOT_HANDLED == hr) + { + BSTR bstrDescription = NULL; + + bstrDescription = SysAllocString((HANDLED_PRIVATE_STATUS_ERROR_1 == hrStatus) ? MYDESCSTRING : L""); + + if (bstrDescription) + { + *pbstrDescription = bstrDescription; + hr = (HANDLED_PRIVATE_STATUS_ERROR_1 == hrStatus) ? S_OK : WIA_STATUS_NOT_HANDLED; + } + else + { + hr = E_OUTOFMEMORY; + } + } + + return hr; +} + + +/***************************************************************************** + * + * Class Object + * + *******************************************************************************/ +class CErrClassObject : public IClassFactory +{ +public: + + STDMETHODIMP + QueryInterface(const IID& iid_requested, void** ppInterfaceOut) + { + HRESULT hr = S_OK; + + hr = ppInterfaceOut ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppInterfaceOut = NULL; + } + + // + // We only support IID_IUnknown and IID_IClassFactory + // + if (SUCCEEDED(hr)) + { + if (IID_IUnknown == iid_requested) + { + *ppInterfaceOut = static_cast<IUnknown*>(this); + } + else if (IID_IClassFactory == iid_requested) + { + *ppInterfaceOut = static_cast<IClassFactory*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppInterfaceOut)->AddRef(); + } + + return hr; + } + + STDMETHODIMP_(ULONG) + AddRef(void) + { + LockModule(); + return 2; + } + + STDMETHODIMP_(ULONG) + Release(void) + { + UnlockModule(); + return 1; + } + + STDMETHODIMP + CreateInstance(_In_opt_ IUnknown *pUnkOuter, + _In_ REFIID riid, + _COM_Outptr_ void **ppv) + { + CErrHandler *pErrHandler = NULL; + HRESULT hr; + + hr = ppv ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppv = 0; + } + + if (SUCCEEDED(hr)) + { + if (pUnkOuter) + { + hr = CLASS_E_NOAGGREGATION; + } + } + + if (SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "pErrHandler is freed on release.") + pErrHandler = new CErrHandler(); + + hr = pErrHandler ? S_OK : E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + pErrHandler->AddRef(); + hr = pErrHandler->QueryInterface(riid, ppv); + pErrHandler->Release(); + } + + return hr; + } + + STDMETHODIMP + LockServer(BOOL bLock) + { + if (bLock) + { + LockModule(); + } + else + { + UnlockModule(); + } + + return S_OK; + } +}; + +STDAPI DllCanUnloadNow(void) +{ + return (g_cLocks == 0) ? S_OK : S_FALSE; +} + +STDAPI DllGetClassObject(_In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ void **ppv) +{ + static CErrClassObject s_FilterClass; + + HRESULT hr; + + hr = ppv ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + if (rclsid == CLSID_WiaErrorHandler) + { + hr = s_FilterClass.QueryInterface(riid, ppv); + } + else + { + *ppv = 0; + hr = CLASS_E_CLASSNOTAVAILABLE; + } + } + + return hr; +} + +STDAPI DllUnregisterServer() +{ + return S_OK; +} + +STDAPI DllRegisterServer() +{ + return S_OK; +} + + diff --git a/wia/wiadriverex/errhandler/errhandler.rc b/wia/wiadriverex/errhandler/errhandler.rc new file mode 100644 index 00000000..523c1041 --- /dev/null +++ b/wia/wiadriverex/errhandler/errhandler.rc @@ -0,0 +1,22 @@ +//(C) COPYRIGHT MICROSOFT CORP., 1998-1999 + +#include <windows.h> +#include <winver.h> +#include <ntverp.h> + +#include "resource.h" + +STRINGTABLE +BEGIN + IDS_MESSAGEBOX_ERRORHANDLE_DIALOG "Special driver device status error (only for testing purposes). Press 'Ok' to continue. Hitting 'Cancel' will abort the transfer." + IDS_MESSAGEBOX_ERRORHANDLE_TITLE "Driver UI Extension - Handling HANDLED_PRIVATE_STATUS_ERROR_1 message" +END + + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WIA ErrHandler DLL" +#define VER_INTERNALNAME_STR "errhandler\0" +#define VER_ORIGINALFILENAME_STR "errhandler.dll" + +#include "common.ver" diff --git a/wia/wiadriverex/errhandler/errhandler.vcxproj b/wia/wiadriverex/errhandler/errhandler.vcxproj new file mode 100644 index 00000000..5d1b8a2f --- /dev/null +++ b/wia/wiadriverex/errhandler/errhandler.vcxproj @@ -0,0 +1,215 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{DD1B17F5-27B3-4EC3-9F49-B8BCA0A07B4A}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{E32E0DF8-F57F-4704-8B63-E200DB908EC8}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>errhandler</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>errhandler</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>errhandler</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>errhandler</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /ignore:4070</AdditionalOptions> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /ignore:4070</AdditionalOptions> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /ignore:4070</AdditionalOptions> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /ignore:4070</AdditionalOptions> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="errhandler.cpp" /> + <ResourceCompile Include="errhandler.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/wia/wiadriverex/errhandler/errhandler.vcxproj.Filters b/wia/wiadriverex/errhandler/errhandler.vcxproj.Filters new file mode 100644 index 00000000..8839da5a --- /dev/null +++ b/wia/wiadriverex/errhandler/errhandler.vcxproj.Filters @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{86F9B487-340F-49D6-B70F-B24D7AB65D53}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{60CED670-3A16-40C5-8501-44CFAD80F505}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{E4E98F4F-AAFA-4F1F-909C-48B1DAFE99BB}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="errhandler.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="DLLExports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="errhandler.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/wia/wiadriverex/errhandler/resource.h b/wia/wiadriverex/errhandler/resource.h new file mode 100644 index 00000000..a1c03d39 --- /dev/null +++ b/wia/wiadriverex/errhandler/resource.h @@ -0,0 +1,4 @@ +//(C) COPYRIGHT MICROSOFT CORP., 1998-1999 + +#define IDS_MESSAGEBOX_ERRORHANDLE_DIALOG 1001 +#define IDS_MESSAGEBOX_ERRORHANDLE_TITLE 1002 diff --git a/wia/wiadriverex/errhandler/stdafx.h b/wia/wiadriverex/errhandler/stdafx.h new file mode 100644 index 00000000..1373e951 --- /dev/null +++ b/wia/wiadriverex/errhandler/stdafx.h @@ -0,0 +1,33 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +// Windows Header Files: +#include <windows.h> +#include <commctrl.h> +#include <commdlg.h> +#include <windowsx.h> +#include <stdio.h> +#include <tchar.h> +#include <shellapi.h> +#include <shlwapi.h> +// C RunTime Header Files +#include <stdlib.h> +#include <malloc.h> +#include <memory.h> +#include <tchar.h> +// WIA headers +#include <wia.h> +// STI headers +#include <sti.h> +#include <strsafe.h> + +#include "resource.h" + + diff --git a/wia/wiadriverex/imgfilter/DLLExports.def b/wia/wiadriverex/imgfilter/DLLExports.def new file mode 100644 index 00000000..eafd2b80 --- /dev/null +++ b/wia/wiadriverex/imgfilter/DLLExports.def @@ -0,0 +1,31 @@ +; /*++ +; +; Copyright (C) Microsoft Corporation, 1985 - 2002 +; All rights reserved. +; +; Module Name: +; +; DLLExports.def +; +; Abstract: +; +; Declares the module parameters +; +; Author: +; +; Mikael Horal May-5-2003 +; +; Revision History: +; +; Mikael Horal May-5-2003 +; created +; +; --*/ +LIBRARY imgfilter + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + diff --git a/wia/wiadriverex/imgfilter/gphelper.h b/wia/wiadriverex/imgfilter/gphelper.h new file mode 100644 index 00000000..6dd570c9 --- /dev/null +++ b/wia/wiadriverex/imgfilter/gphelper.h @@ -0,0 +1,468 @@ +using namespace Gdiplus; + +#define BUFFER_SIZE (128 * 1024) + +/***************************************************************************** + * + * @func Gdiplus::Status | GetEncoderGUIDFromImage | Retrieves the encoder for a Bitmap + * + * @parm Bitmap | pOriginalBitmap | + * The Bitmap for which to get its encoder + * + * @parm CLSID | pFormatEncoder | + * On successful return this contains the GUID of the encoder for + * pOriginalBitmaps image type + * + * @comm + * This function is used to return the GDI+ encoder guid for a Bitmap. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXXXXX | + * Failure to retrieve image format + * + *****************************************************************************/ +static Status GetEncoderGUIDFromImage( + _In_ IN Bitmap *pOriginalBitmap, + _Out_ OUT CLSID *pFormatEncoder) +{ + Status status; + CLSID imageFormat; + UINT num = 0; // number of image encoders + UINT size = 0; // size of the image encoder array in bytes + ImageCodecInfo* pImageCodecInfo = NULL; + BOOL bFound = FALSE; + + status = (pOriginalBitmap && pFormatEncoder) ? Ok : InvalidParameter; + + if (status == Ok) + { + status = pOriginalBitmap->GetRawFormat(&imageFormat); + } + + if (status == Ok) + { + status = GetImageEncodersSize(&num, &size); + + if ((status == Ok) && (size == 0)) + { + status = GenericError; + } + } + + if (status == Ok) + { + pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); + + status = pImageCodecInfo ? Ok : OutOfMemory; + } + + if (status == Ok) + { + status = GetImageEncoders(num, size, pImageCodecInfo); + } + + if (status == Ok) + { + for(UINT j = 0; (j < num) && !bFound ; ++j) + { + _Analysis_assume_(size >= (num * sizeof(ImageCodecInfo))); + if( pImageCodecInfo[j].FormatID == imageFormat ) + { + *pFormatEncoder = pImageCodecInfo[j].Clsid; + bFound = TRUE; + } + } + } + + if (status == Ok) + { + status = bFound ? Ok : UnknownImageFormat; + } + + if (pImageCodecInfo) + { + free(pImageCodecInfo); + } + + return status; +} + + +/***************************************************************************** + * + * @func HRESULT | GetUpperLimitSize | Returns an estimate of the maximum size of a BMP + * image. The result of this function should be used in a subsequent call to + * IStream::SetSize to ensure that the stream does not have to do any reallocations + * of memory, which can be very expensive + * + * @parm ULONG | uWidth | + * Image width in pixels + * + * @parm ULONG | uHeight | + * Image height in pixels + * + * @parm ULONG | uBitsPerPixel | + * Number of bits per pixel + * * + * @rvalue ULONG | + * Estimated upper limit of image size. + * + *****************************************************************************/ +static inline ULONG GetUpperLimitSize( ULONG uWidth, ULONG uHeight, ULONG uBitsPerPixel ) +{ + return ( /*Safety factor of 1.33 = 8/6*/ uWidth * uHeight * uBitsPerPixel / 6 ) + /*Safety amount for overhead*/ 2048; +} + + +static inline HRESULT GDISTATUS_TO_HRESULT(Gdiplus::Status status) +{ + // + // Default to turning GDI+ errors into generic failures + // + HRESULT hr = E_FAIL; + + switch( status ) + { + case Gdiplus::Ok: + hr = S_OK; + break; + + case Gdiplus::InvalidParameter: + hr = E_INVALIDARG; + break; + + case Gdiplus::OutOfMemory: + hr = E_OUTOFMEMORY; + break; + + case Gdiplus::InsufficientBuffer: + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + break; + + case Gdiplus::Aborted: + hr = E_ABORT; + break; + + case Gdiplus::ObjectBusy: + hr = E_PENDING; + break; + + case Gdiplus::FileNotFound: + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + break; + + case Gdiplus::AccessDenied: + hr = E_ACCESSDENIED; + break; + + case Gdiplus::UnknownImageFormat: + hr = HRESULT_FROM_WIN32(ERROR_INVALID_PIXEL_FORMAT); + break; + + case Gdiplus::NotImplemented: + hr = E_NOTIMPL; + break; + + case Gdiplus::Win32Error: + hr = HRESULT_FROM_WIN32(GetLastError()); + break; + + case Gdiplus::ValueOverflow: + case Gdiplus::FontFamilyNotFound: + case Gdiplus::FontStyleNotFound: + case Gdiplus::NotTrueTypeFont: + case Gdiplus::UnsupportedGdiplusVersion: + case Gdiplus::GdiplusNotInitialized: + case Gdiplus::WrongState: + break; + } + return hr; +} + +static inline void CalculateBrightnessAndContrastParams( INT iBrightness, INT iContrast, _Out_ float *scale, _Out_ float *translate ) +{ + // + // force values to be at least 1, to avoid undesired effects + // + if (iBrightness < 1) + { + iBrightness = 1; + } + if (iContrast < 1) + { + iContrast = 1; + } + + // + // get current brightness as a percentage of full scale + // + float fBrightness = (float)( 1000 - iBrightness ) / 1000.0f; + if (fBrightness > 0.95f) + { + fBrightness = 0.95f; /* clamp */ + } + + // + // get current contrast as a percentage of full scale + // + float fContrast = (float) iContrast / 1000.0f; + if (fContrast > 1.0f) + { + fContrast = 1.0; /* limit to 1.0 */ + } + + // + // convert contrast to a scale value + // + if (fContrast <= 0.5f) + { + *scale = fContrast / 0.5f; /* 0 -> 0, .5 -> 1.0 */ + } + else + { + if (fContrast == 1.0f) + { + fContrast = 0.9999f; + } + *scale = 0.5f / (1.0f - fContrast); /* .5 -> 1.0, 1.0 -> inf */ + } + + *translate = 0.5f - *scale * fBrightness; +} + +/***************************************************************************** + * + * @func HRESULT | GetBitmapHeaderFromBitmapData | Fills in BITMAPINFOHEADER from BitmapData object + * + * @parm BitmapData* | pGDIPlusBitmapData | + * Pointer to a GDI+ BitmapData object + * + * + * @parm BITMAPINFOHEADER* | pBitmapInfoHeader | + * Pointer to a BITMAPINFOHEADER structure + * + * @comm + * This function populates a BITMAPINFOHEADER structure + * using data contained in a Gdiplus::BitmapData object. + * This function only works with 24-bit data. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXXXXX | + * The function failed + * + *****************************************************************************/ +HRESULT GetBitmapHeaderFromBitmapData( + _In_ Gdiplus::BitmapData *pGDIPlusBitmapData, + _Out_ BITMAPINFOHEADER *pBitmapInfoHeader) +{ + HRESULT hr = E_INVALIDARG; + if((pGDIPlusBitmapData) && (pBitmapInfoHeader) && (pGDIPlusBitmapData->PixelFormat == PixelFormat24bppRGB)) + { + memset(pBitmapInfoHeader, 0, sizeof(BITMAPINFOHEADER)); + pBitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER); + pBitmapInfoHeader->biPlanes = 1; + pBitmapInfoHeader->biWidth = pGDIPlusBitmapData->Width; + pBitmapInfoHeader->biHeight = pGDIPlusBitmapData->Height; + + // We cannot use the stride to calculate the size, because if there is no + // format conversion, we might get the original bits... + // We need to calculate the size based on the width + pBitmapInfoHeader->biSizeImage = ((((pGDIPlusBitmapData->Width * 3) + 3) & ~3) * pGDIPlusBitmapData->Height); + + pBitmapInfoHeader->biBitCount = 24; + hr = S_OK; + } + + return hr; +} + +/***************************************************************************** + * + * @func HRESULT | WriteBitmapToStream | WriteBitmapToStream writes the data from the Bitmap object pTargetBitmap into the IStream pOutputStream + * + * @parm Bitmap* | pTargetBitmap | + * Pointer to a GDI+ Bitmap object + * + * + * @parm IStream* | pOutputStream | + * Pointer to IStream provided by application. We write the data from pTargetBitmap + * into this stream + * + * @comm + * We use this function since the GDI+ method Bitmap::Save method does not work + * very well for images that an application displays band by band since it results + * in a large number of small Write calls. Instead we do a LockBits to read the bits + * from the bitmap and then write them to the application's stream. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXXXXX | + * The function failed + * + *****************************************************************************/ +HRESULT +WriteBitmapToStream( + _In_ Gdiplus::Bitmap *pTargetBitmap, + _In_ IStream *pOutputStream, + _Inout_ ULONG64 *pulBytesWrittenToOutputStream) + +{ + HRESULT hr = S_OK; + + Gdiplus::Rect rFrame(0, 0, pTargetBitmap->GetWidth(), pTargetBitmap->GetHeight()); + BitmapData bitmapData = {0}; + BITMAPINFOHEADER bmih = {0}; + BITMAPFILEHEADER bmfh = {0}; + BOOL bBitsLocked = FALSE; + DWORD dwTotalBytes = 0; + DWORD dwTotalBytesRead = 0; + DWORD dwLinesRead = 0; + BYTE *pBitmapBits = NULL; + ULONG cbWritten = 0; + INT iScanline = 0; + DWORD dwNumLineBytesInBuffer = 0; + DWORD dwNumBytesLeftToRead = 0; + BYTE *pBuffer = NULL; + + if (!pTargetBitmap || !pOutputStream || !pulBytesWrittenToOutputStream) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr)) + { + pBuffer = (BYTE*) LocalAlloc(LPTR, BUFFER_SIZE); + + hr = pBuffer ? S_OK : E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + hr = GDISTATUS_TO_HRESULT(pTargetBitmap->LockBits(&rFrame, ImageLockModeRead, PixelFormat24bppRGB, &bitmapData)); + } + + if (SUCCEEDED(hr)) + { + bBitsLocked = TRUE; + hr = GetBitmapHeaderFromBitmapData(&bitmapData,&bmih); + } + + if (SUCCEEDED(hr)) + { + pBitmapBits = (BYTE*)bitmapData.Scan0; + bmfh.bfType = ((WORD) ('M' << 8) | 'B'); + bmfh.bfOffBits = sizeof(bmfh) + sizeof(bmih); + bmfh.bfSize = bmfh.bfOffBits + bmih.biSizeImage; + + dwTotalBytes = bmfh.bfSize; + dwTotalBytesRead = 0; + dwLinesRead = 0; + // + // iScanline contains the number of bytes to copy from each scanline + // + iScanline = ((bitmapData.Width * 3) + 3) & ~3; + + if (iScanline > BUFFER_SIZE) + { + // + // We don't have enough space in our temporary scanline buffer + // + hr = E_OUTOFMEMORY; + } + else + { + // + // Calculate number of bytes in whole scan lines. + // + dwNumLineBytesInBuffer = (BUFFER_SIZE - (BUFFER_SIZE % iScanline)); + } + } + + if (SUCCEEDED(hr)) + { + LARGE_INTEGER li = {0}; + hr = pOutputStream->Seek(li, STREAM_SEEK_END, NULL); + } + + // + // First write bitmap headers + // + if (SUCCEEDED(hr)) + { + hr = pOutputStream->Write(&bmfh, sizeof(bmfh), &cbWritten); + dwTotalBytesRead += sizeof(bmfh); + } + + if (SUCCEEDED(hr)) + { + hr = pOutputStream->Write(&bmih, sizeof(bmih), &cbWritten); + dwTotalBytesRead += sizeof(bmih); + } + + while (SUCCEEDED(hr) && (dwTotalBytesRead < dwTotalBytes)) + { + dwNumBytesLeftToRead = (dwTotalBytes - dwTotalBytesRead); + + // + // Set how many bytes we are going to read. This is either the maxiumun + // nunmber of scan lines that will fit into the buffer, or it's the number + // of bytes left in the last chunk. + // + if(dwNumBytesLeftToRead < dwNumLineBytesInBuffer) + { + dwNumLineBytesInBuffer = dwNumBytesLeftToRead; + } + + // + // Position buffer pointer to correct data location for this band. We are copying + // in reverse scanline order so that the bitmap becomes topdown (it is currently + // upside-down in the source buffer). + // + BYTE *pBits = pBitmapBits + (bitmapData.Height * bitmapData.Stride); + pBits -= (bitmapData.Stride * (1 + dwLinesRead)); + + DWORD dwDestOffset = 0; + for (BYTE *pCurLine = pBits; dwDestOffset < dwNumLineBytesInBuffer; pCurLine -= bitmapData.Stride, dwLinesRead++) + { + _Analysis_assume_(dwDestOffset + iScanline <= BUFFER_SIZE); + memcpy(pBuffer + dwDestOffset, pCurLine, iScanline); + dwDestOffset += iScanline; + } + + hr = pOutputStream->Write(pBuffer, dwNumLineBytesInBuffer, &cbWritten); + + // + // We should check cbWritten here! + // + + dwTotalBytesRead+= dwNumLineBytesInBuffer; + + } + + // + // Update the pulBytesWrittenToOutputStream even in failure case + // + if (pulBytesWrittenToOutputStream) + { + *pulBytesWrittenToOutputStream = (ULONG64)dwTotalBytesRead; + } + + if (bBitsLocked) + { + // + // Although we do not save the results we should log any errors + // during UnlockBits + // + pTargetBitmap->UnlockBits(&bitmapData); + } + + if (pBuffer) + { + LocalFree(pBuffer); + } + + return hr; +} + diff --git a/wia/wiadriverex/imgfilter/imagefilter.cpp b/wia/wiadriverex/imgfilter/imagefilter.cpp new file mode 100644 index 00000000..6c727577 --- /dev/null +++ b/wia/wiadriverex/imgfilter/imagefilter.cpp @@ -0,0 +1,2242 @@ +/***************************************************************************** + * + * imagefilter.cpp + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: + * + * Contains implementation of Image Processing Filer with "filtering stream". + * The implementation uses GDI+ for cutting out images, for deskewing as well + * as for implementing brightness and contrast. + * + *******************************************************************************/ +#include "stdafx.h" +#include <gdiplus.h> +#include <math.h> +#include <objidl.h> + +#include "imagefilter.h" +#include "wiaitem.h" +#include "gphelper.h" + +using namespace Gdiplus; + +/***************************************************************************** + * + * @func STDMETHODIMP | DoFiltering | Reads unfiltered data from input stream, cuts, deskews, rotates and filters the image data + * and then writes fitlered data to output stream. + * + * @parm LONG | lBrightness | + * The brightness set into the region we are filtering. Should be between -1000 and 1000 + * + * @parm LONG | lContrast | + * The contrast set into the region we are filtering. Should be between -1000 and 1000 + * + * @parm LONG | regionRotate | + * How much we should rotate the reion (note rotate happens after deskew!) + * + * @parm LONG | regionDeskewX | + * WIA_IPS_DESKEW_X for region to deskew (note 0 means no deskew) + * + * @parm LONG | regionDeskewY | + * WIA_IPS_DESKEW_Y for region to deskew (note 0 means no deskew) + * + * @parm IStream* | pInputStream | + * Unfiltered image data, either directly from driver of from WIA Preview Component + * + * + * @parm IStream* | pOutputStream | + * Application stream where we write image data + * + * @parm LONG | inputXPOS | + * X-position of upper left corner of region to "cut-out" from image in pInputStream. + * Note that this parameter is relative to image in pInputStream which is not necessarily + * its X-position on the flatbed. + * + * @parm LONG | inputYPOS | + * Y-position of upper left corner of region to "cut-out" from image in pInputStream. + * Note that this parameter is relative to image in pInputStream which is not necessarily + * its Y-position on the flatbed. + * + * @parm LONG | boundingRegionWidth | + * Width of bounding area to "cut-out" from pInputStream. A value of 0 means that we should not perform + * any cutting, but instead filter the whole image. + * boundingRegionWidth will be set to 0 when we receive the image data from the driver since the driver + * will only send us the bounding rectangle of the selected region and not the entire flatbed. + * Note: if there is not deskewing being performed this is the "actual" width of the region. + * + * @parm LONG | boundingRegionHeight | + * Height of bounding area to "cut-out" from pInputStream. A value of 0 means that we should not perform + * any cutting, but instead filter the whole image. + * boundingRegionHeight will be set to 0 when we receive the image data from the driver since the driver + * will only send us the bounding rectangle of the selected region and not the entire flatbed. + * Note: if there is not deskewing being performed this is the "actual" height of the region. + * + * @comm + * Note, our simple implementation of DoFiltering always write all the data + * in one chunk to the application. An actual image processing filter should + * be able to work on bands of data in the case where there is no rotation + * or deskewing being performed. + * This implementation also does not send callbacks (TransferCallback) messages + * to the application indicating progress. A "real" implementation should do that! + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ + +static HRESULT DoFiltering( + LONG lBrightness, + LONG lContrast, + LONG regionRotate, + LONG regionDeskewX, + LONG regionDeskewY, + _In_ IStream *pInputStream, + _In_ IStream *pOutputStream, + _Inout_ ULONG64 *pulBytesWrittenToOutputStream, + LONG inputXPOS = 0, + LONG inputYPOS = 0, + LONG boundingRegionWidth = 0, + LONG boundingRegionHeight = 0 + ) +{ + HRESULT hr = S_OK; + + Bitmap *pOriginalBitmap = NULL; + Bitmap *pTargetBitmap = NULL; + CLSID formatEncoder = {0}; + GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR ulImageLibraryToken = 0; + + if (SUCCEEDED(hr)) + { + hr = GDISTATUS_TO_HRESULT(GdiplusStartup(&ulImageLibraryToken, &gdiplusStartupInput, NULL)); + } + + // + // Create a Bitmap object on the unfiltered input stream + // + if (SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK_EXCEPTION, "Sample code only. Production code should handle exceptions.") + pOriginalBitmap = new Bitmap(pInputStream, TRUE); + + if (pOriginalBitmap) + { + hr = GDISTATUS_TO_HRESULT(pOriginalBitmap->GetLastStatus()); + } + else + { + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + hr = GDISTATUS_TO_HRESULT(GetEncoderGUIDFromImage(pOriginalBitmap, &formatEncoder)); + } + } + + // + // If boundingRegionWidth or boundingRegionHeight is 0, this means that we should not perform any + // "cutting" but instead just filter the whole input image. + // + if (SUCCEEDED(hr)) + { + if ((0 == boundingRegionWidth) || (0 == boundingRegionHeight)) + { + inputXPOS = 0; + inputYPOS = 0; + boundingRegionWidth = pOriginalBitmap->GetWidth(); + boundingRegionHeight = pOriginalBitmap->GetHeight(); + } + } + + // + // Perform filtering. This is done in 3 steps: + // 1. Create a new bitmap with the dimensions of the final, filtered image. + // 2. "Cut-out" and deskew final image from full image. This is done by a translate + // followed by a rotate transformtation. + // 3. Apply color matrix to to perform brightness and contrast modifications. + // + if (SUCCEEDED(hr)) + { + PixelFormat originalPixelFormat = pOriginalBitmap->GetPixelFormat(); + + double dblDeskewAngle = 0.0; + LONG lXdelta = 0; + LONG lYdelta = 0; + LONG lActualRegionWidth = 0; + LONG lActualRegionHeight = 0; + + // + // No deskew, just cut out a rectangular area! + // + if ((regionDeskewX) == 0 || (regionDeskewY == 0)) + { + lActualRegionWidth = boundingRegionWidth; + lActualRegionHeight = boundingRegionHeight; + dblDeskewAngle = 0.0; + } + else + { + if (regionDeskewX > regionDeskewY) + { + lYdelta = regionDeskewY; + + dblDeskewAngle = atan2((double)regionDeskewY, (double)regionDeskewX); + + lActualRegionWidth = (LONG) sqrt((double) (regionDeskewX * regionDeskewX + regionDeskewY * regionDeskewY)); + lActualRegionHeight = (LONG) (((double) (boundingRegionHeight - regionDeskewY)) / cos(dblDeskewAngle)); + } + else + { + lXdelta = regionDeskewX; + + dblDeskewAngle = atan2((double)regionDeskewX, (double)regionDeskewY); + + lActualRegionWidth = (LONG) (((double) (boundingRegionWidth - regionDeskewX)) / cos(dblDeskewAngle)); + lActualRegionHeight = (LONG) sqrt((double) (regionDeskewX * regionDeskewX + regionDeskewY * regionDeskewY)); + + dblDeskewAngle = -dblDeskewAngle; + } + } + + pTargetBitmap = new Bitmap(lActualRegionWidth, lActualRegionHeight, originalPixelFormat); + + if (pTargetBitmap) + { + hr = GDISTATUS_TO_HRESULT(pTargetBitmap->GetLastStatus()); + } + else + { + hr = E_OUTOFMEMORY; + } + + + + if (SUCCEEDED(hr)) + { + Graphics graphics(pTargetBitmap); + ImageAttributes imageAttributes; + + hr = GDISTATUS_TO_HRESULT(graphics.GetLastStatus()); + + if (SUCCEEDED(hr)) + { + graphics.TranslateTransform((REAL)-(inputXPOS + lXdelta), (REAL)-(inputYPOS + lYdelta)); + hr = GDISTATUS_TO_HRESULT(graphics.GetLastStatus()); + } + + + if (dblDeskewAngle != 0.0) + { + if (SUCCEEDED(hr)) + { + graphics.RotateTransform((REAL)(dblDeskewAngle * 180.0 / PI), MatrixOrderAppend); + hr = GDISTATUS_TO_HRESULT(graphics.GetLastStatus()); + } + } + + if (SUCCEEDED(hr)) + { + // + // Calculate the values needed for the matrix + // + REAL scale = 0.0; + REAL trans = 0.0; + + // + // Normalize brightness and contrast to 0 to 1000. + // This assumes valid settings are - 1000 to 1000. + // + CalculateBrightnessAndContrastParams( (lBrightness + 1000) /2, (lContrast + 1000) / 2, &scale, &trans ); + + // + // Prepare the matrix for brightness and contrast transforms + // + ColorMatrix brightnessAndContrast = {scale, 0, 0, 0, 0, + 0, scale, 0, 0, 0, + 0, 0, scale, 0, 0, + 0, 0, 0, 1, 0, + trans, trans, trans, 0, 1}; + + hr = imageAttributes.SetColorMatrix(&brightnessAndContrast); + } + + if (SUCCEEDED(hr)) + { + UINT uWidth = pOriginalBitmap->GetWidth(); + UINT uHeight = pOriginalBitmap->GetHeight(); + + Rect rect( 0, 0, uWidth, uHeight ); + + hr = GDISTATUS_TO_HRESULT(graphics.DrawImage(pOriginalBitmap,rect,0,0,uWidth, uHeight,UnitPixel,&imageAttributes)); + } + } + + + } + + // + // The last step for us to perform is rotating the region + // + if (SUCCEEDED(hr) && (regionRotate != PORTRAIT)) + { + RotateFlipType rotateFlipType; + + switch (regionRotate) + { + case LANSCAPE: + rotateFlipType = Rotate270FlipNone; + break; + case ROT180: + rotateFlipType = Rotate180FlipNone; + break; + case ROT270: + rotateFlipType = Rotate90FlipNone; + break; + default: + // + // We should never get here! + // + rotateFlipType = RotateNoneFlipNone; + } + + hr = GDISTATUS_TO_HRESULT(pTargetBitmap->RotateFlip(rotateFlipType)); + } + + // + // The GDI+ Bitmap::Save method does not work very well for images that + // an application displays band by band since it results in a large number + // of small Write calls. Instead we do a LockBits to read the bits from + // the bitmap and then write them to the application's stream. + // + if (SUCCEEDED(hr)) + { + hr = WriteBitmapToStream(pTargetBitmap, pOutputStream, pulBytesWrittenToOutputStream); + } + + if (pOriginalBitmap) + { + delete pOriginalBitmap; + } + + if (pTargetBitmap) + { + delete pTargetBitmap; + } + + if(ulImageLibraryToken) + { + GdiplusShutdown(ulImageLibraryToken); + ulImageLibraryToken = 0; + } + + return hr; +} + + +/******************************************************************************* + +Routine Name: ConvertBMPImageToRaw + +Routine Description: Converts an uncompressed 24-bpp RGB BMP image Stream to a RAW Stream + +Arguments: input Stream + +Return Value: Output Stream if conversion successful + HRESULT (S_OK in case the operation succeeds) + +*******************************************************************************/ + +HRESULT ConvertBMPImageToRaw(IStream * pStreamIn, IStream *pStreamOut, ULONG64 * pcbWritten = NULL) +{ + HRESULT hr = S_OK; + ULONG ulRead = 0, ulWrite = 0; + + WIA_RAW_HEADER RawHeader = {0}; + + BITMAPFILEHEADER bmfh = {0}; + BITMAPINFOHEADER bmih = {0}; + + if (!pStreamIn || !pStreamOut) + { + hr = E_POINTER; + } + + // + // Seek to the beginning of Input Stream + // + if (SUCCEEDED(hr)) + { + if (pcbWritten) + { + *pcbWritten = (ULONG64)0; + } + + LARGE_INTEGER li = {0}; + hr = pStreamIn->Seek(li, STREAM_SEEK_SET, NULL); + } + + // + // Attempt to read the Bitmap File Header + // + if (SUCCEEDED(hr)) + { + hr = pStreamIn->Read(&bmfh, sizeof(bmfh), &ulRead); + + if (SUCCEEDED(hr)) + { + if (ulRead != sizeof(bmfh)) + { + hr = E_FAIL; + } + } + } + + // + // Attempt to read the Bitmap File Header + // + if (SUCCEEDED(hr)) + { + hr = pStreamIn->Read(&bmih, sizeof(bmih), &ulRead); + + if (SUCCEEDED(hr)) + { + if (ulRead != sizeof(bmih)) + { + hr = E_FAIL; + } + } + } + + // + // todo: check the bitmap info header and bitmap file header for validity + // + if (SUCCEEDED(hr)) + { + // + // The 'WRAW' 4 ASCII character signature is required at the begining of all WIA Raw transfers: + // + const char szSignature[] = "WRAW"; + memcpy(&RawHeader.Tag, szSignature, sizeof(DWORD)); + + // + // Fill in the fields describing version identity for this header: + // + RawHeader.Version = 0x00010000; + RawHeader.HeaderSize = sizeof(WIA_RAW_HEADER); + + // + // Fill in all the fields that we can retrieve directly from the current MINIDRV_TRANSFER_CONTEXT: + // + + // + // Resolution values must be converted to DPI (pixels per inch) from pixels per meter: + // + // (1" = 25.4 mm, 1 m ~ 39.37") + // + RawHeader.XRes = (LONG)((float)bmih.biXPelsPerMeter / 39.37f); + RawHeader.YRes = (LONG)((float)bmih.biYPelsPerMeter / 39.37f); + + RawHeader.XExtent = bmih.biWidth; + RawHeader.YExtent = bmih.biHeight; + + RawHeader.BytesPerLine = bmih.biWidth * 3; + + RawHeader.BitsPerPixel = bmih.biBitCount; + RawHeader.ChannelsPerPixel = 3; + RawHeader.DataType = WIA_DATA_RAW_RGB; + + ZeroMemory(RawHeader.BitsPerChannel, sizeof(RawHeader.BitsPerChannel)); + RawHeader.BitsPerChannel[0] = 8; + RawHeader.BitsPerChannel[1] = 8; + RawHeader.BitsPerChannel[2] = 8; + + RawHeader.Compression = WIA_COMPRESSION_NONE; + + RawHeader.PhotometricInterp = bmih.biSizeImage; + + RawHeader.LineOrder = WIA_LINE_ORDER_BOTTOM_TO_TOP; + + // + // Raw data: the offset is the size of the header (we don't have a color palette in this case): + // + RawHeader.RawDataOffset = RawHeader.HeaderSize; + RawHeader.RawDataSize = bmih.biSizeImage; + + RawHeader.PaletteSize = 0; + RawHeader.PaletteOffset = 0; + } + + // + // Save the RawHeader: Dont Seek + // + if (SUCCEEDED(hr)) + { + hr = pStreamOut->Write(&RawHeader, sizeof(RawHeader), &ulWrite); + + if (SUCCEEDED(hr)) + { + if (pcbWritten) + { + (*pcbWritten)+= (ULONG64)ulWrite; + } + + if (ulWrite != sizeof(RawHeader)) + { + hr = E_FAIL; + } + } + } + + // + // Save the DIB data: Read from in stream and write to out stream + // + ULONG ulBufferSize = 100000; // approx 100 KB + BYTE *pbImageData = NULL; + if (SUCCEEDED(hr)) + { + pbImageData = (BYTE *)malloc(ulBufferSize); + if (!pbImageData) + { + hr = E_OUTOFMEMORY; + } + + // + // memory allocated. now copy + // + while(S_OK == hr) + { + hr = pStreamIn->Read(pbImageData, ulBufferSize, &ulRead); + if (SUCCEEDED(hr)) + { + hr = pStreamOut->Write(pbImageData, ulRead, &ulWrite); + if (SUCCEEDED(hr)) + { + if (pcbWritten) + { + (*pcbWritten)+= (ULONG64)ulWrite; + } + + if (ulRead != ulWrite) + { + hr = E_FAIL; + } + } + } + if (ulRead != ulBufferSize) + { + break; + } + } + } + + // + // Clean-up: + // + if (pbImageData) + { + free(pbImageData); + pbImageData = NULL; + } + + return hr; +} + + +/******************************************************************************* + +Routine Name: ConvertRawImageToBMP + +Routine Description: Converts an uncompressed 24-bpp RGB raw image Stream to a DIB Stream + +Arguments: input Stream + +Return Value: Output Stream if conversion successful + HRESULT (S_OK in case the operation succeeds) + +*******************************************************************************/ + +HRESULT ConvertRawImageToBMP(IStream * pStreamIn, IStream **ppStreamOut, ULONG64 * pcbWritten = NULL) +{ + HRESULT hr = S_OK; + ULONG ulRead = 0, ulWrite = 0; + IStream *pStreamOut = NULL; + + WIA_RAW_HEADER RawHeader = {0}; + + BITMAPFILEHEADER bmfh = {0}; + BITMAPINFOHEADER bmih = {0}; + + if (!pStreamIn || !ppStreamOut) + { + hr = E_POINTER; + } + + if (SUCCEEDED(hr)) + { + if(pcbWritten) + { + *pcbWritten = (ULONG64)0; + } + + (*ppStreamOut) = NULL; + + // + // Seek to the beginning of Input Stream + // + LARGE_INTEGER li = {0}; + hr = pStreamIn->Seek(li, STREAM_SEEK_SET, NULL); + } + + // + // Attempt to read the WIA_RAW_HEADER: + // + if (SUCCEEDED(hr)) + { + hr = pStreamIn->Read(&RawHeader, sizeof(WIA_RAW_HEADER), &ulRead); + + if (SUCCEEDED(hr)) + { + if (ulRead != sizeof(WIA_RAW_HEADER)) + { + hr = E_FAIL; + } + } + } + + // + // Verify the WIA raw header signature: + // + if (SUCCEEDED(hr)) + { + const char szSignature[] = "WRAW"; + if (memcmp(&RawHeader.Tag, szSignature, sizeof(DWORD))) + { + hr = E_FAIL; + } + } + + // + // Verify the WIA raw header reported size and version number: + // + if (SUCCEEDED(hr)) + { + if ((0x00010000 != RawHeader.Version) || (sizeof(WIA_RAW_HEADER) != RawHeader.HeaderSize)) + { + hr = E_FAIL; + } + } + + // + // Verify if the raw image format - this sample supports only uncompressed 24-bpp RGB data: + // + if (SUCCEEDED(hr)) + { + if ((WIA_COMPRESSION_NONE != RawHeader.Compression) || (24 != RawHeader.BitsPerPixel) || + (3 != RawHeader.ChannelsPerPixel) || (RawHeader.PaletteSize) || + (8 != RawHeader.BitsPerChannel[0]) || (8 != RawHeader.BitsPerChannel[1]) || + (8 != RawHeader.BitsPerChannel[2])) + { + hr = E_FAIL; + } + } + + // + // Build the BITMAPFILEHEADER and the BITMAPINFOHEADER structures needed + // to convert the raw uncompressed 24-bpp RGB image to a DIB: + // + if (SUCCEEDED(hr)) + { + // + // BITMAPFILEHEADER: + // + const char szBM[] = "BM"; + memcpy(&bmfh.bfType, szBM, sizeof(WORD)); + bmfh.bfSize = sizeof(BITMAPFILEHEADER); + bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + + // + // BITMAPINFOHEADER: + // + bmih.biSize = sizeof(BITMAPINFOHEADER); + bmih.biWidth = RawHeader.XExtent; + bmih.biHeight = (WIA_LINE_ORDER_BOTTOM_TO_TOP == RawHeader.LineOrder) ? ((LONG)RawHeader.YExtent) : (-(LONG)RawHeader.YExtent); + bmih.biPlanes = 1; + bmih.biBitCount = (WORD)RawHeader.BitsPerPixel; + bmih.biCompression = BI_RGB; + bmih.biSizeImage = RawHeader.RawDataSize; + bmih.biClrUsed = 0; + bmih.biClrImportant = 0; + + // + // Resolution values must be converted from DPI (pixels per inch) to pixels per meter: + // + // (1" = 25.4 mm, 1 m ~ 39.37") + // + bmih.biXPelsPerMeter = (LONG)((float)RawHeader.XRes * 39.37f); + bmih.biYPelsPerMeter = (LONG)((float)RawHeader.YRes * 39.37f); + } + + if (SUCCEEDED(hr)) + { + hr = CreateStreamOnHGlobal(0, TRUE, &pStreamOut); + } + + // + // Save the BITMAPFILEHEADER: + // + if (SUCCEEDED(hr)) + { + hr = pStreamOut->Write(&bmfh, bmfh.bfSize, &ulWrite); + + if (SUCCEEDED(hr)) + { + if (pcbWritten) + { + (*pcbWritten)+= (ULONG64)ulWrite; + } + if (ulWrite != bmfh.bfSize) + { + hr = E_FAIL; + } + } + } + + // + // Save the BITMAPINFOHEADER: + // + if (SUCCEEDED(hr)) + { + hr = pStreamOut->Write(&bmih, bmih.biSize, &ulWrite); + + if (SUCCEEDED(hr)) + { + if (pcbWritten) + { + (*pcbWritten)+= (ULONG64)ulWrite; + } + if (ulWrite != bmih.biSize) + { + hr = E_FAIL; + } + } + } + + // + // Save the DIB data: Read from in stream and write to out stream + // + ULONG ulBufferSize = 100000; // approx 100 KB + BYTE *pbImageData = NULL; + if (SUCCEEDED(hr)) + { + + pbImageData = (BYTE *)malloc(ulBufferSize); + if (!pbImageData) + { + hr = E_OUTOFMEMORY; + } + + // + // memory allocated. now copy + // + while(S_OK == hr) + { + hr = pStreamIn->Read(pbImageData, ulBufferSize, &ulRead); + if (SUCCEEDED(hr)) + { + hr = pStreamOut->Write(pbImageData, ulRead, &ulWrite); + if (SUCCEEDED(hr)) + { + if (pcbWritten) + { + (*pcbWritten)+= (ULONG64)ulWrite; + } + if (ulRead != ulWrite) + { + hr = E_FAIL; + } + } + } + if (ulRead != ulBufferSize) + { + break; + } + } + } + + // + // Clean-up: + // + if (pbImageData) + { + free(pbImageData); + pbImageData = NULL; + } + + if (SUCCEEDED(hr)) + { + // + // Seek to the beginning of Output Stream (We can do this since we created the stream) + // + LARGE_INTEGER li = {0}; + hr = pStreamOut->Seek(li, STREAM_SEEK_SET, NULL); + } + + if (pStreamOut) + { + if (SUCCEEDED(hr)) + { + *ppStreamOut = pStreamOut; + } + else + { + pStreamOut->Release(); + } + } + + return hr; +} + + +/***************************************************************************** + * + * CMyFilterStream is our implemetation of the filtering stream. + * The only IStream method that it implements is Write(). + * + * The stream keeps a reference to the applications stream into which it writes + * the filtered data (the header is not modified however). + * + *******************************************************************************/ + +/// +/// Constructor - note sets reference count to 1 +/// +CMyFilterStream::CMyFilterStream( + VOID) : m_pAppStream(NULL) , m_pCachingStream(NULL), m_nRefCount(0), m_cBytesWritten(0), + m_lBrightness(0), m_lContrast(0), m_lRotation(0), m_lDeskewX(0), m_lDeskewY(0) +{ + // + // Note: Do not initialize refcount to 1 as it will break module locking, instead call AddRef() + // + AddRef(); +} + +/// +/// Destructor: +/// +CMyFilterStream::~CMyFilterStream( + VOID) +{ + if (m_pAppStream) + { + m_pAppStream->Release(); + m_pAppStream = NULL; + } + + if (m_pCachingStream) + { + m_pCachingStream->Release(); + m_pCachingStream = NULL; + } +} + +/// +/// Initilize stores a reference to the application's stream. It also creates +/// its own stream with CreateStreamOnHGlobal into which it stores all the +/// unfiltered image data before it performs its filtering (in Flush). +/// +HRESULT +CMyFilterStream::Initialize( + _In_ IStream *pAppStream, + LONG lBrightness, + LONG lContrast, + LONG lRotation, + LONG lDeskewX, + LONG lDeskewY, + LONG lXExtent, + LONG lYExtent, + LONG lBitDepth, + GUID guidFormat) +{ + UNREFERENCED_PARAMETER(lXExtent); + UNREFERENCED_PARAMETER(lYExtent); + UNREFERENCED_PARAMETER(lBitDepth); + + HRESULT hr = S_OK; + + hr = pAppStream ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + m_pAppStream = pAppStream; + m_pAppStream->AddRef(); + } + + if (SUCCEEDED(hr)) + { + hr = CreateStreamOnHGlobal(0, TRUE, &m_pCachingStream); + } + + if (SUCCEEDED(hr)) + { + m_lBrightness = lBrightness; + m_lContrast = lContrast; + m_lRotation = lRotation; + m_lDeskewX = lDeskewX; + m_lDeskewY = lDeskewY; + m_guidFormat = guidFormat; + } + + return hr; +} + +/***************************************************************************** + * + * @func STDMETHODIMP | CMyFilterStream::Flush | Reads unfiltered data, performs filtering and writes + * data to application stream + * + * @comm + * + * Flush is called when the image processing filter receives a WIA_TRANSFER_MSG_END_OF_STREAM message. + * Flush calls DoFiltering where the actual filtering is done. + * + * Note that this simple implementation performs all its filtering only after it has received all + * unfiltered image data and stored it in m_pCachingStream. A "real" implementation should be able + * to work on bands of data (at least if no deskew and rotation has to be performed). + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +HRESULT +CMyFilterStream::Flush( + VOID) +{ + HRESULT hr = S_OK; + IStream * tempStream = NULL; + IStream * tempOutStream = NULL; + + if(IsEqualGUID(m_guidFormat, WiaImgFmt_RAW)) + { + if (SUCCEEDED(hr)) + { + hr = ConvertRawImageToBMP(m_pCachingStream, &tempStream); + + if (SUCCEEDED(hr) && tempStream) + { + hr = CreateStreamOnHGlobal(0, TRUE, &tempOutStream); + + if (SUCCEEDED(hr) && tempOutStream) + { + ULONG64 ulDummy = 0; + hr = DoFiltering(m_lBrightness, + m_lContrast, + m_lRotation, + m_lDeskewX, + m_lDeskewY, + tempStream, + tempOutStream, + &ulDummy); + + if (SUCCEEDED(hr)) + { + hr = ConvertBMPImageToRaw(tempOutStream, m_pAppStream, &m_cBytesWritten); + } + + tempOutStream->Release(); + } + tempStream->Release(); + } + } + } + else + { + hr = DoFiltering( + m_lBrightness, + m_lContrast, + m_lRotation, + m_lDeskewX, + m_lDeskewY, + m_pCachingStream, + m_pAppStream, + &m_cBytesWritten); + } + + // + // Note: m_pAppStream and m_pCachingStream are released by ReleaseStreams which must be always called after Flush + // + + return hr; +} + +/// +/// Query Interface +/// +STDMETHODIMP +CMyFilterStream::QueryInterface(_In_ const IID& iid_requested, _Out_ void** ppInterfaceOut) +{ + HRESULT hr = S_OK; + + hr = ppInterfaceOut ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppInterfaceOut = NULL; + } + + // + // We support IID_IUnknown and IID_IStream + // + if (SUCCEEDED(hr)) + { + if (IID_IUnknown == iid_requested) + { + *ppInterfaceOut = static_cast<IUnknown*>(this); + } + else if (IID_IStream == iid_requested) + { + *ppInterfaceOut = static_cast<IStream*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppInterfaceOut)->AddRef(); + } + + return hr; +} + +/// +/// AddRef +/// +STDMETHODIMP_(ULONG) +CMyFilterStream::AddRef(void) +{ + if (m_nRefCount == 0) + { + LockModule(); + } + + return InterlockedIncrement(&m_nRefCount); +} + +/// +/// Release +/// +STDMETHODIMP_(ULONG) +CMyFilterStream::Release(void) +{ + ULONG nRetval = InterlockedDecrement(&m_nRefCount); + + if (0 == nRetval) + { + delete this; + UnlockModule(); + } + + return nRetval; +} + +STDMETHODIMP +CMyFilterStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, _Out_ ULARGE_INTEGER *plibNewPosition) +{ + return m_pCachingStream->Seek(dlibMove,dwOrigin,plibNewPosition); +} + +STDMETHODIMP +CMyFilterStream::SetSize(ULARGE_INTEGER libNewSize) +{ + return m_pCachingStream->SetSize(libNewSize); +} + +STDMETHODIMP +CMyFilterStream::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) +{ + return m_pCachingStream->LockRegion(libOffset,cb,dwLockType); +} + +STDMETHODIMP +CMyFilterStream::CopyTo(_In_ IStream *pstm, ULARGE_INTEGER cb, _Out_ ULARGE_INTEGER *pcbRead, _Out_ ULARGE_INTEGER *pcbWritten) +{ + return m_pCachingStream->CopyTo(pstm,cb,pcbRead,pcbWritten); +} + +STDMETHODIMP +CMyFilterStream::Commit(DWORD grfCommitFlags) +{ + return m_pCachingStream->Commit(grfCommitFlags); +} + +STDMETHODIMP +CMyFilterStream::Revert(void) +{ + return m_pCachingStream->Revert(); +} + +STDMETHODIMP +CMyFilterStream::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) +{ + return m_pCachingStream->UnlockRegion(libOffset,cb,dwLockType); +} + +STDMETHODIMP +CMyFilterStream::Stat(_Out_ STATSTG *pstatstg, DWORD grfStatFlag) +{ + return m_pCachingStream->Stat(pstatstg, grfStatFlag); +} + +STDMETHODIMP +CMyFilterStream::Clone(_Out_ IStream **ppstm) +{ + return m_pCachingStream->Clone(ppstm); +} + +STDMETHODIMP +CMyFilterStream::Read(_Out_ void *pv, ULONG cb, _Out_ ULONG *pcbRead) +{ + return m_pCachingStream->Read(pv,cb,pcbRead); +} + +STDMETHODIMP +CMyFilterStream::ReleaseStreams() +{ + if (m_pAppStream) + { + m_pAppStream->Release(); + m_pAppStream = NULL; + } + + if (m_pCachingStream) + { + m_pCachingStream->Release(); + m_pCachingStream = NULL; + } + + return S_OK; +} + +/***************************************************************************** + * + * @func STDMETHODIMP | CMyFilterStream::Write | Filtering streams implementation of Write + * + * @parm const void * | pv | + * Pointer to the memory buffer. + * + * @parm ULONG | cb | + * Specifies the number of bytes of data to write from the stream object. + * + * @parm ULONG | pcbWritten | + * Pointer to a ULONG variable that receives the actual number of bytes written from the stream object. + * + * @comm + * Write simply writes unfiltered data from the driver into its internal caching stream. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +STDMETHODIMP +CMyFilterStream::Write(_In_ const void *pv, ULONG cb, _Out_ ULONG *pcbWritten) +{ + return m_pCachingStream->Write(pv, cb, pcbWritten); +} + +/// +/// Constructor +/// +CImageFilter::CImageFilter( + VOID) : m_pWiaItem(NULL), m_pAppWiaTransferCallback(NULL), m_nRefCount(0), m_pCurrentStream(NULL) +{ + // + // Nothing + // +} + +/// +/// Destructor +/// +CImageFilter::~CImageFilter( + VOID) +{ + if (m_pWiaItem) + { + m_pWiaItem->Release(); + m_pWiaItem = NULL; + } + + if (m_pAppWiaTransferCallback) + { + m_pAppWiaTransferCallback->Release(); + m_pAppWiaTransferCallback = NULL; + } +} + +/// +/// QueryInterface +/// +STDMETHODIMP +CImageFilter::QueryInterface(_In_ const IID& iid_requested, _Out_ void** ppInterfaceOut) +{ + HRESULT hr = S_OK; + + hr = ppInterfaceOut ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppInterfaceOut = NULL; + } + + // + // We support IID_IUnknown, IID_IWiaImageFilter and IID_IWiaTransferCallback + // + if (SUCCEEDED(hr)) + { + if (IID_IUnknown == iid_requested) + { + *ppInterfaceOut = static_cast<IWiaImageFilter*>(this); + } + else if (IID_IWiaImageFilter == iid_requested) + { + *ppInterfaceOut = static_cast<IWiaImageFilter*>(this); + } + else if (IID_IWiaTransferCallback == iid_requested) + { + *ppInterfaceOut = static_cast<IWiaTransferCallback*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppInterfaceOut)->AddRef(); + } + + return hr; +} + +/// +/// AddRef +/// +STDMETHODIMP_(ULONG) +CImageFilter::AddRef(void) +{ + if (m_nRefCount == 0) + { + LockModule(); + } + + return InterlockedIncrement(&m_nRefCount); +} + +/// +/// Release +/// +STDMETHODIMP_(ULONG) +CImageFilter::Release(void) +{ + ULONG nRetval = InterlockedDecrement(&m_nRefCount); + + if (0 == nRetval) + { + delete this; + UnlockModule(); + } + + return nRetval; +} + +/***************************************************************************** + * + * @func STDMETHODIMP | CImageFilter::InitializeFilter | Initializes image processing filter + * + * @parm IWiaItem2 | pWiaItem | + * The WIA item we are doing the download for. This will actually be the parent item + * for some of the item we acquire the image for. See implementation of GetNextStream + * for more details. + * + * @parm IWiaTransferCallback | pWiaTransferCallback | + * Application's callback function + * + * @comm + * Initializes image processing filter. Stores references to applications callback interface + * and IWiaItem2 + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +STDMETHODIMP +CImageFilter::InitializeFilter( + _In_ IN IWiaItem2 *pWiaItem, + __callback IN IWiaTransferCallback *pWiaTransferCallback) +{ + HRESULT hr = S_OK; + + m_bTransferCancelled = FALSE; + + hr = (pWiaItem && pWiaTransferCallback) ? S_OK : E_INVALIDARG; + + // + // Image processing filters supplied with WIA drivers do not + // support storage items. + // + + if (SUCCEEDED(hr)) + { + GUID guidItemCategory = {0}; + hr = pWiaItem->GetItemCategory(&guidItemCategory); + if (SUCCEEDED(hr)) + { + if ((WIA_CATEGORY_FINISHED_FILE == guidItemCategory) || + (WIA_CATEGORY_FOLDER == guidItemCategory) || + (WIA_CATEGORY_ROOT == guidItemCategory)) + { + hr = E_NOTIMPL; + } + } + } + + // + // InitializeFilter should only be called once ... but we still Release + // any resources we might reference + // + if (SUCCEEDED(hr)) + { + if (m_pWiaItem) + { + m_pWiaItem->Release(); + m_pWiaItem = NULL; + } + + if (m_pAppWiaTransferCallback) + { + m_pAppWiaTransferCallback->Release(); + m_pAppWiaTransferCallback = NULL; + } + } + + if (SUCCEEDED(hr)) + { + m_pWiaItem = pWiaItem; + m_pWiaItem->AddRef(); + + m_pAppWiaTransferCallback = pWiaTransferCallback; + m_pAppWiaTransferCallback->AddRef(); + } + + return hr; +} + +/***************************************************************************** + * + * @func STDMETHODIMP | CImageFilter::SetNewCallback | Sets new callback for image processing filter to use + * + * @parm IWiaTransferCallback | pWiaTransferCallback | + * The new application callback which the filter should use. + * + * @comm + * Since an application can change the callback to use in the IWiaPreview::UpdatePreview call the image + * processing filter must "get notified" of this. + * Note, the image processing filter is always required to release its current callback even if it is + * passed NULL for the callback. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +STDMETHODIMP +CImageFilter::SetNewCallback( + _In_opt_ __callback IN IWiaTransferCallback *pWiaTransferCallback) +{ + if (m_pAppWiaTransferCallback) + { + m_pAppWiaTransferCallback->Release(); + m_pAppWiaTransferCallback = NULL; + } + + if (pWiaTransferCallback) + { + m_pAppWiaTransferCallback = pWiaTransferCallback; + m_pAppWiaTransferCallback->AddRef(); + } + + return S_OK; +} + + + +/***************************************************************************** + * + * @func STDMETHODIMP | CImageFilter::FilterPreviewImage | FilterPreviewImage implementation + * + + * @parm IWiaItem2 | pWiaChildItem | + * pWiaChildItem2 is the item which the image process is to process. + * This item must be a child item of the item, m_pWiaItem, that was passed into InitializeFilter. + * + * @parm RECT | InputImageExtents | + * The coordinates (on the flatbed scanner) of the image that the preview component caches internally, + * which is also the image that is passed into the pInputStream parameter. + * We need this parameter since it is possible that the cached image (pInputStream) was not captured + * with XPOS=YPOS=0. + * + * @parm IStream | pInputStream | + * Unfiltered image that is stored by WIA Preview Component. + * + * @comm + * FilterPreviewImage is called by the preview component, when an application calls UpdatePreview. + * We simply read all the properties from pWiaChildItem that are required for us to do the filtering + * and then retrieve the application stream. The actual filtering is then performed in DoFiltering. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +STDMETHODIMP +CImageFilter::FilterPreviewImage( + IN LONG lFlags, + _In_ IN IWiaItem2 *pWiaChildItem, + IN RECT InputImageExtents, + _In_ IN IStream *pInputStream) +{ + UNREFERENCED_PARAMETER(lFlags); + + IStream *pAppStream = NULL; + + BSTR bstrItemName = NULL; + BSTR bstrFullItemName = NULL; + GUID guidItemCategory = {0}; + LONG xpos = 0, ypos = 0, width = 0, height = 0; + LONG lBrightness = 0; + LONG lContrast = 0; + LONG lDeskewX = 0; + LONG lDeskewY = 0; + LONG lRotation = PORTRAIT; + + HRESULT hr = S_OK; + + IStream * tempStream = NULL; + IStream * tempOutStream = NULL; + BOOL bConvertedRawImage = FALSE; + + ULONG64 ulBytesWrittenToOutputStream = 0; + + // + // Parameter validation + // + + hr = (pWiaChildItem && pInputStream) ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + // + // Check whether the image extents are correct. + // Error if the right or bottom coordinate is zero. + // Or Left >= Right or Top >= Bottom. + // + + if ((0 == InputImageExtents.right) || + (0 == InputImageExtents.bottom) || + (InputImageExtents.left >= InputImageExtents.right) || + (InputImageExtents.top >= InputImageExtents.bottom)) + { + hr = E_INVALIDARG; + } + } + + if (SUCCEEDED(hr)) + { + hr = m_pAppWiaTransferCallback ? S_OK : E_UNEXPECTED; + } + + // + // Read all properties we need + // + if (SUCCEEDED(hr)) + { + CWiaItem *pWiaItemWrapper = new CWiaItem(); + + hr = pWiaItemWrapper ? S_OK : E_OUTOFMEMORY; + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->SetIWiaItem(pWiaChildItem); + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyGUID(WIA_IPA_ITEM_CATEGORY, &guidItemCategory); + + if (SUCCEEDED(hr) && ((guidItemCategory == WIA_CATEGORY_ROOT) || (guidItemCategory == WIA_CATEGORY_FINISHED_FILE) || (WIA_CATEGORY_FOLDER == guidItemCategory))) + { + // + // We should never get here for storage items! + // + hr = E_INVALIDARG; + } + } + + // + // Error if the following is not satisfied: + // WIA_IPS_MIN_HORIZONTAL_SIZE <= right - left <= WIA_IPS_MAX_HORIZONTAL_SIZE + // WIA_IPS_MIN_VERTICAL_SIZE <= bottom - top <= WIA_IPS_MAX_VERTICAL_SIZE + // + + if (SUCCEEDED(hr)) + { + LONG lHorMin = 0, lHorMax = 0, lHorExtent = InputImageExtents.right - InputImageExtents.left; + LONG lVerMin = 0, lVerMax = 0, lVerExtent = InputImageExtents.bottom - InputImageExtents.top; + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_MIN_HORIZONTAL_SIZE, &lHorMin); + } + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_MAX_HORIZONTAL_SIZE, &lHorMax); + } + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_MIN_VERTICAL_SIZE, &lVerMin); + } + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_MAX_VERTICAL_SIZE, &lVerMax); + + } + if (SUCCEEDED(hr)) + { + if ((lHorExtent < lHorMin) || (lHorExtent > lHorMax) || + (lVerExtent < lVerMin) || (lVerExtent > lVerMax)) + { + hr = E_INVALIDARG; + } + } + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_XPOS, &xpos); + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_YPOS, &ypos); + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_XEXTENT, &width); + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_YEXTENT, &height); + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyBSTR(WIA_IPA_ITEM_NAME, &bstrItemName); + if (SUCCEEDED(hr) && !bstrItemName) + { + hr = E_UNEXPECTED; + } + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyBSTR(WIA_IPA_FULL_ITEM_NAME, &bstrFullItemName); + if (SUCCEEDED(hr) && !bstrFullItemName) + { + hr = E_UNEXPECTED; + } + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_BRIGHTNESS, &lBrightness); + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_CONTRAST, &lContrast); + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_ROTATION, &lRotation); + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_DESKEW_X, &lDeskewX); + } + + if (SUCCEEDED(hr)) + { + hr = pWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_DESKEW_Y, &lDeskewY); + } + + if(SUCCEEDED(hr)) + { + GUID guidItemFormat = {0}; + + hr = pWiaItemWrapper->ReadRequiredPropertyGUID(WIA_IPA_FORMAT, &guidItemFormat); + if((SUCCEEDED(hr)) && (IsEqualGUID(guidItemFormat, WiaImgFmt_RAW))) + { + hr = ConvertRawImageToBMP(pInputStream, &tempStream); + + if (SUCCEEDED(hr) && tempStream) + { + bConvertedRawImage = TRUE; + pInputStream = tempStream; + } + } + } + + if (pWiaItemWrapper) + { + delete pWiaItemWrapper; + } + } + + // + // If the upper left corner of the passed image does not correspond to (0,0) + // on the flatbed we have to adjust xpos and ypos accordingly in order for us + // to "cut out" the correct region represented by pWiaChildItem + // + if (SUCCEEDED(hr)) + { + xpos = xpos - InputImageExtents.left; + ypos = ypos - InputImageExtents.top; + } + + // + // Now get the application stream and write to it + // + if (SUCCEEDED(hr)) + { + hr = m_pAppWiaTransferCallback->GetNextStream(0, bstrItemName, bstrFullItemName, &pAppStream); + if (SUCCEEDED(hr) && !pAppStream) + { + hr = E_UNEXPECTED; + } + } + + + if (SUCCEEDED(hr)) + { + if (bConvertedRawImage) + { + + hr = CreateStreamOnHGlobal(0, TRUE, &tempOutStream); + if (SUCCEEDED(hr)) + { + ULONG64 ulDummy = 0; + + hr = DoFiltering(lBrightness, + lContrast, + lRotation, + lDeskewX, + lDeskewY, + pInputStream, + tempOutStream, + &ulDummy, + xpos, + ypos, + width, + height + ); + } + + if (SUCCEEDED(hr)) + { + hr = ConvertBMPImageToRaw(tempOutStream, pAppStream,&ulBytesWrittenToOutputStream); + } + + } + else + { + hr = DoFiltering(lBrightness, + lContrast, + lRotation, + lDeskewX, + lDeskewY, + pInputStream, + pAppStream, + &ulBytesWrittenToOutputStream, + xpos, + ypos, + width, + height + ); + } + } + + if (pAppStream) + { + pAppStream->Release(); + } + + if (tempStream) + { + tempStream->Release(); + } + + if (tempOutStream) + { + tempOutStream->Release(); + } + + return hr; +} + + +/***************************************************************************** + * + * @func STDMETHODIMP | CImageFilter::ApplyProperties | Apply properties after filtering. + * + * @parm IWiaPropertyStorage | pWiaPropertyStorage | + * Pointer to property storage that the image processing filter can write properties to. + * + * @comm + * ApplyProperties is called by the WIA service after the image processing filter has processed + * the raw data. This method allows the image processing filter to write data back to the driver and device. + * This may be necessary for filters that implement things such as auto-exposure. + * Note, an image processing filter should only use the WriteMultiple method to write properties into + * the provided storage. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +STDMETHODIMP +CImageFilter::ApplyProperties( + _Inout_ IN IWiaPropertyStorage *pWiaPropertyStorage) +{ + HRESULT hr = S_OK; + + hr = pWiaPropertyStorage ? S_OK : E_INVALIDARG; + + // + // This filter only writes the MY_TEST_FILTER_PROP property for + // illustrational purposes. + // In general if a filter does not need to write any properties it + // should just return S_OK. + // + if (SUCCEEDED(hr)) + { + PROPSPEC PropSpec[1] = {0}; + PROPVARIANT PropVariant[1] = {0}; + + PropVariantInit(PropVariant); + + PropSpec[0].ulKind = PRSPEC_PROPID; + PropSpec[0].propid = MY_TEST_FILTER_PROP; + PropVariant[0].vt = VT_I4; + PropVariant[0].lVal = 1; + + // + // Set the properties + // + hr = pWiaPropertyStorage->WriteMultiple( 1, PropSpec, PropVariant, WIA_IPA_FIRST ); + } + + return hr; +} + + +/***************************************************************************** + * + * @func STDMETHODIMP | CImageFilter::TransferCallback | TransferCallback implementation + * + + * @parm LONG | lFlags | + * Flags + * + * @parm WiaTransferParams | pWiaTransferParams | + * Contains transfer status + * + * @comm + * TransferCallback delegates to the application's callback. It changes the + * number of bytes written since we always cache all the data before writing to + * the application's stream. We do however not change the percentage since this + * represents percentage of total transfer time (a "real" implementation probably + * would take the filtering into account here). + * We do not write the data to the application's stream until when we receive + * a WIA_TRANSFER_MSG_END_OF_STREAM message. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +STDMETHODIMP +CImageFilter::TransferCallback( + IN LONG lFlags, + _In_ IN WiaTransferParams *pWiaTransferParams) +{ + HRESULT hr = S_OK; + + if (!m_pAppWiaTransferCallback) + { + hr = E_UNEXPECTED; + } + + if ((SUCCEEDED(hr)) && (!pWiaTransferParams)) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr)) + { + if (m_pCurrentStream) + { + pWiaTransferParams->ulTransferredBytes = m_pCurrentStream->m_cBytesWritten; + } + + // + // Note the percent reflects the amount of scanning the driver reports + // whereas the "BytesWritten" member is the actual number of bytes + // that we have sent to the application stream. + // + if (m_pCurrentStream && (pWiaTransferParams->lMessage == WIA_TRANSFER_MSG_END_OF_STREAM)) + { + if (!m_bTransferCancelled) + { + hr = m_pCurrentStream->Flush(); + pWiaTransferParams->ulTransferredBytes = m_pCurrentStream->m_cBytesWritten; + } + m_pCurrentStream -> ReleaseStreams(); + } + + // + // Call this regardless of hr because applications need termination messages + // + HRESULT hrInner = m_pAppWiaTransferCallback->TransferCallback(lFlags, pWiaTransferParams); + + // + // Don't overwrite the original error if there was one + // + if (SUCCEEDED(hr)) + { + hr = hrInner; + } + + + if (m_pCurrentStream && (pWiaTransferParams->lMessage == WIA_TRANSFER_MSG_END_OF_STREAM)) + { + m_pCurrentStream->Release(); + m_pCurrentStream = NULL; + } + + // + // To indicate not to write to the stream later + // + if ( S_OK != hr) + { + m_bTransferCancelled = TRUE; + } + } + + return hr; +} + +/***************************************************************************** + * + * @func STDMETHODIMP | CImageFilter::GetNextStream | Implementation of GetNextStream + * + * @parm LONG | lFlags | + * Flags + * + * @parm BSTR | bstrItemName | + * Name of item + * + * @parm BSTR | bstrFullItemName | + * Full name of item + * + * @parm IStream | ppDestination | + * Upon successful return this will contain the filtering stream + * + * @comm + * GetNextStream creates a filtering stream. Since the item represented by + * bstrFullItemName may be a child item of the item passed into InitializeFilter + * we have to call FindItemByName to retrieve the actual item. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXXXXX | + * Failure + * + *****************************************************************************/ +STDMETHODIMP +#pragma warning(suppress: 6101) +CImageFilter::GetNextStream( + LONG lFlags, + _In_z_ BSTR bstrItemName, + _In_z_ BSTR bstrFullItemName, + _Outptr_result_maybenull_ _At_(*ppDestination, _When_(return == S_OK, _Post_notnull_)) + IStream **ppDestination) +{ + HRESULT hr; + IStream *pAppStream = NULL; + IWiaItem2 *pCurrentWiaItem = NULL; + BOOL bStorageItem = FALSE; + LONG lBrightness = 0; + LONG lContrast = 0; + LONG lDeskewX = 0; + LONG lDeskewY = 0; + LONG lRotation = PORTRAIT; + LONG lXExtent = 0; + LONG lYExtent = 0; + LONG lBitDepth = 0; + GUID guidItemFormat = {0}; + + hr = (bstrItemName && bstrFullItemName && ppDestination) ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + *ppDestination = NULL; + + hr = m_pAppWiaTransferCallback ? S_OK : E_UNEXPECTED; + } + + if (m_pCurrentStream) + { + m_pCurrentStream->Release(); + m_pCurrentStream = NULL; + } + + if (SUCCEEDED(hr)) + { + hr = m_pAppWiaTransferCallback->GetNextStream(lFlags, bstrItemName, bstrFullItemName, &pAppStream); + if (SUCCEEDED(hr) && !pAppStream) + { + hr = E_UNEXPECTED; + } + } + + // + // Return immediately following cancellations or skips + // + if ((S_FALSE == hr) || (WIA_STATUS_SKIP_ITEM == hr)) + { + return hr; + } + + if (SUCCEEDED(hr)) + { + hr = m_pWiaItem->FindItemByName(0, bstrFullItemName, &pCurrentWiaItem); + } + + // + // Here we read all properties from pCurrentWiaItem that we need in order to + // do the the filtering - in this specific case only brightness. + // + if (SUCCEEDED(hr)) + { + CWiaItem *pIWiaItemWrapper = NULL; + + pIWiaItemWrapper = new CWiaItem(); + + hr = pIWiaItemWrapper ? S_OK : E_OUTOFMEMORY; + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->SetIWiaItem(pCurrentWiaItem); + } + + if (SUCCEEDED(hr)) + { + GUID guidItemCategory = {0}; + + hr = pIWiaItemWrapper->ReadRequiredPropertyGUID(WIA_IPA_ITEM_CATEGORY,&guidItemCategory); + + bStorageItem = ((guidItemCategory == WIA_CATEGORY_FINISHED_FILE) || (WIA_CATEGORY_FOLDER == guidItemCategory)); + } + + if(SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadRequiredPropertyGUID(WIA_IPA_FORMAT, &guidItemFormat); + } + + if (!bStorageItem) + { + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_BRIGHTNESS,&lBrightness); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_CONTRAST,&lContrast); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_ROTATION, &lRotation); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_DESKEW_X, &lDeskewX); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_DESKEW_Y, &lDeskewY); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_XEXTENT, &lXExtent); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPS_YEXTENT, &lYExtent); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadRequiredPropertyLong(WIA_IPA_DEPTH, &lBitDepth); + } + } + + if (pIWiaItemWrapper) + { + delete pIWiaItemWrapper; + } + } + + if (SUCCEEDED(hr)) + { + if (!bStorageItem) + { + // + // We could easily improve the performace by creating a separate filtering stream + // which simply delegates all calls directly to the application's stream in case + // Rotation, DeskewX, DeskewY, Brightness and Contrast are all set to 0. + // + m_pCurrentStream = new CMyFilterStream(); + + if (m_pCurrentStream) + { + hr = m_pCurrentStream->Initialize(pAppStream, + lBrightness, + lContrast, + lRotation, + lDeskewX, + lDeskewY, + lXExtent, + lYExtent, + lBitDepth, + guidItemFormat); + } + else + { + hr = E_OUTOFMEMORY; + } + } + else + { + (*ppDestination) = pAppStream; + (*ppDestination)->AddRef(); + } + } + + if (SUCCEEDED(hr) && m_pCurrentStream) + { + hr = m_pCurrentStream->QueryInterface(IID_IStream, (void**)ppDestination); + } + + if (pAppStream) + { + pAppStream->Release(); + } + + if (pCurrentWiaItem) + { + pCurrentWiaItem->Release(); + } + + return hr; +} + +/***************************************************************************** + * + * Class Object + * + *******************************************************************************/ +class CFilterClass : public IClassFactory +{ +public: + + STDMETHODIMP + QueryInterface(_In_ const IID& iid_requested, _Out_ void** ppInterfaceOut) + { + HRESULT hr = S_OK; + + hr = ppInterfaceOut ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppInterfaceOut = NULL; + } + + // + // We support IID_IUnknown and IID_IClassFactory + // + if (SUCCEEDED(hr)) + { + if (IID_IUnknown == iid_requested) + { + *ppInterfaceOut = static_cast<IUnknown*>(this); + } + else if (IID_IClassFactory == iid_requested) + { + *ppInterfaceOut = static_cast<IClassFactory*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppInterfaceOut)->AddRef(); + } + + return hr; + } + + STDMETHODIMP_(ULONG) + AddRef(void) + { + LockModule(); + return 2; + } + + STDMETHODIMP_(ULONG) + Release(void) + { + UnlockModule(); + return 1; + } + + STDMETHODIMP + CreateInstance(_In_ IUnknown *pUnkOuter, + _In_ REFIID riid, + _Out_ void **ppv) + { + CImageFilter *pImageFilter = NULL; + HRESULT hr; + + hr = ppv ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppv = 0; + } + + if (SUCCEEDED(hr)) + { + if (pUnkOuter) + { + hr = CLASS_E_NOAGGREGATION; + } + } + + if (SUCCEEDED(hr)) + { + pImageFilter = new CImageFilter(); + + hr = pImageFilter ? S_OK : E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + pImageFilter->AddRef(); + hr = pImageFilter->QueryInterface(riid, ppv); + pImageFilter->Release(); + } + + return hr; + } + + STDMETHODIMP + LockServer(BOOL bLock) + { + if (bLock) + { + LockModule(); + } + else + { + UnlockModule(); + } + + return S_OK; + } +}; + +STDAPI DllCanUnloadNow(void) +{ + return (g_cLocks == 0) ? S_OK : S_FALSE; +} + +STDAPI DllGetClassObject(_In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ void **ppv) +{ + static CFilterClass s_FilterClass; + + if (rclsid == CLSID_WiaImageFilter) + { + return s_FilterClass.QueryInterface(riid, ppv); + } + + *ppv = 0; + + return CLASS_E_CLASSNOTAVAILABLE; +} + +// +// Registered in driver INF file - what about un-regestering? +// +STDAPI DllUnregisterServer() +{ + return S_OK; +} + +STDAPI DllRegisterServer() +{ + return S_OK; +} diff --git a/wia/wiadriverex/imgfilter/imagefilter.h b/wia/wiadriverex/imgfilter/imagefilter.h new file mode 100644 index 00000000..c92f3743 --- /dev/null +++ b/wia/wiadriverex/imgfilter/imagefilter.h @@ -0,0 +1,212 @@ +/***************************************************************************** + * + * imagefilter.h + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: + * + * Contains class declarations for CMyFilterStream and CImageFilter + * + *******************************************************************************/ + +#define COUNTOF(x) (sizeof(x)/sizeof(x[0])) +#define HEADER_SIZE 54 + +#ifndef PI +#define PI 3.1415926538 +#endif + +#define MY_TEST_FILTER_PROP WIA_PRIVATE_ITEMPROP+1 +#define MY_TEST_FILTER_PROP_STR L"My test filter property" + +// {AA9198F3-3B91-47d3-A371-EBE7D243F606} +static const GUID CLSID_WiaImageFilter = +{ 0xaa9198f3, 0x3b91, 0x47d3, { 0xa3, 0x71, 0xeb, 0xe7, 0xd2, 0x43, 0xf6, 0x6 } }; + +static LONG g_cLocks = 0; + +void LockModule(void) { InterlockedIncrement(&g_cLocks); } +void UnlockModule(void) { InterlockedDecrement(&g_cLocks); } + +/***************************************************************************** + * + * CMyFilterStream is our implemetation of the filtering stream. + * The only IStream method that it implements is Write(). + * + * The stream keeps a reference to the applications stream into which it writes + * the filtered data (the header is not modified however). + * + *******************************************************************************/ + +class CMyFilterStream : public IStream +{ +public: + + + CMyFilterStream( + VOID); + + ~CMyFilterStream( + VOID); + + STDMETHODIMP + Initialize( + _In_ IStream *pAppStream, + LONG lBrightness, + LONG lContrast, + LONG lRotation, + LONG lDeskewX, + LONG lDeskewY, + LONG lXExtent, + LONG lYExtent, + LONG lBitDepth, + GUID guidFormat + ); + + STDMETHODIMP + Flush(void); + + STDMETHODIMP + QueryInterface(_In_ const IID& iid_requested, _Out_ void** ppInterfaceOut); + + STDMETHODIMP_(ULONG) + AddRef(void); + + STDMETHODIMP_(ULONG) + Release(void); + + STDMETHODIMP + Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, _Out_ ULARGE_INTEGER *plibNewPosition); + + STDMETHODIMP + SetSize(ULARGE_INTEGER libNewSize); + + STDMETHODIMP + LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); + + STDMETHODIMP + CopyTo(_In_ IStream *pstm, ULARGE_INTEGER cb, _Out_ ULARGE_INTEGER *pcbRead, _Out_ ULARGE_INTEGER *pcbWritten); + + STDMETHODIMP + Commit(DWORD grfCommitFlags); + + STDMETHODIMP + Revert(void); + + STDMETHODIMP + UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); + + STDMETHODIMP + Stat(_Out_ STATSTG *pstatstg, DWORD grfStatFlag); + + STDMETHODIMP + Clone(_Out_ IStream **ppstm); + + STDMETHODIMP + Read(_Out_ void *pv, ULONG cb, _Out_ ULONG *pcbRead); + + STDMETHODIMP + Write(_In_ const void *pv, ULONG cb, _Out_ ULONG *pcbWritten); + + STDMETHODIMP + ReleaseStreams(); + + ULONG64 m_cBytesWritten; + +private: + + IStream *m_pAppStream; + IStream *m_pCachingStream; + + LONG m_lBrightness; + LONG m_lContrast; + LONG m_lRotation; + LONG m_lDeskewX; + LONG m_lDeskewY; + GUID m_guidFormat; + + LONG m_nRefCount; +}; + + +/***************************************************************************** + * + * CImageFilter is the main image processing filter class. It implements IWiaImageFilter + * as well as the callback interface IWiaTransferCallback. + * + * Internally it creates the filtering stream CMyFilterStream in its GetNextStream + * implementation. Its implementation of TransferCallback simply delegates to the + * applications callback, since it does not alter the size or the flow of the data + * that the driver writes to it. + * + *******************************************************************************/ +class CImageFilter : public IWiaImageFilter, public IWiaTransferCallback +{ +public: + + CImageFilter( + VOID); + + ~CImageFilter( + VOID); + + STDMETHODIMP + QueryInterface(_In_ const IID& iid_requested, _Out_ void** ppInterfaceOut); + + STDMETHODIMP_(ULONG) + AddRef(void); + + STDMETHODIMP_(ULONG) + Release(void); + + STDMETHODIMP + InitializeFilter( + _In_ IN IWiaItem2 *pWiaItem, + __callback IN IWiaTransferCallback *pWiaTransferCallback); + + STDMETHODIMP + SetNewCallback( + _In_opt_ __callback IN IWiaTransferCallback *pWiaTransferCallback); + + + STDMETHODIMP + FilterPreviewImage( + IN LONG lFlags, + _In_ IN IWiaItem2 *pWiaChildItem, + IN RECT InputImageExtents, + _In_ IN IStream *pInputStream); + + STDMETHODIMP + TransferCallback( + IN LONG lFlags, + _In_ IN WiaTransferParams *pWiaTransferParams); + + STDMETHODIMP + GetNextStream( + LONG lFlags, + _In_z_ BSTR bstrItemName, + _In_z_ BSTR bstrFullItemName, + _Outptr_result_maybenull_ _At_(*ppDestination, _When_(return == S_OK, _Post_notnull_)) + IStream **ppDestination); + + STDMETHODIMP + ApplyProperties( + _Inout_ IN IWiaPropertyStorage *pWiaPropertyStorage); + + LONG lPercentComplete; + ULONG64 m_ulTransferredBytes; + +private: + + CMyFilterStream *m_pCurrentStream; + + IWiaItem2 *m_pWiaItem; + IWiaTransferCallback *m_pAppWiaTransferCallback; + + BOOL m_bTransferCancelled; + + LONG m_nRefCount; +}; + + diff --git a/wia/wiadriverex/imgfilter/imgfilter.vcxproj b/wia/wiadriverex/imgfilter/imgfilter.vcxproj new file mode 100644 index 00000000..19b9ae28 --- /dev/null +++ b/wia/wiadriverex/imgfilter/imgfilter.vcxproj @@ -0,0 +1,215 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{12455A18-956A-4030-B1C2-4C3EA1A827AD}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{8098E18F-D029-45ED-BFA5-C3532B6903B9}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>imgfilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>imgfilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>imgfilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>imgfilter</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;gdiplus.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;gdiplus.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;gdiplus.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;gdiplus.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="imagefilter.cpp" /> + <ClCompile Include="wiaitem.cpp" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/wia/wiadriverex/imgfilter/imgfilter.vcxproj.Filters b/wia/wiadriverex/imgfilter/imgfilter.vcxproj.Filters new file mode 100644 index 00000000..ac3f02b8 --- /dev/null +++ b/wia/wiadriverex/imgfilter/imgfilter.vcxproj.Filters @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{BF4ABCAE-135C-427E-9394-A7FC61A186EA}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{D5367D42-F868-4EE4-87E7-926E435BC29B}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{D73FCF55-1995-4351-A5F2-A5383DB851A3}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="imagefilter.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="wiaitem.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="DLLExports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/wia/wiadriverex/imgfilter/stdafx.h b/wia/wiadriverex/imgfilter/stdafx.h new file mode 100644 index 00000000..bca637ae --- /dev/null +++ b/wia/wiadriverex/imgfilter/stdafx.h @@ -0,0 +1,35 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_driver_) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +// Windows Header Files: +#include <windows.h> +#include <commctrl.h> +#include <commdlg.h> +#include <windowsx.h> +#include <stdio.h> +#include <tchar.h> +#include <shellapi.h> +#include <shlwapi.h> +// C RunTime Header Files +#include <stdlib.h> +#include <malloc.h> +#include <memory.h> +#include <tchar.h> +// WIA headers +#include <wia.h> +// STI headers +#include <sti.h> +#include <strsafe.h> + +VOID TRC(LPCTSTR format,...); + diff --git a/wia/wiadriverex/imgfilter/wiaitem.cpp b/wia/wiadriverex/imgfilter/wiaitem.cpp new file mode 100644 index 00000000..5d0e3e50 --- /dev/null +++ b/wia/wiadriverex/imgfilter/wiaitem.cpp @@ -0,0 +1,219 @@ +/***************************************************************************** + * + * wiaitem.cpp + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: + * + * wiaitem is a simply wrapper class used to read properties from an item + * of interface IWiaItem2 + * + *******************************************************************************/ +#include "stdafx.h" +#include "wiaitem.h" + +/// +/// Constructor - sets m_pIWiaPropStg to NULL +/// +CWiaItem::CWiaItem() +{ + m_pIWiaPropStg = NULL; +} + +/// +/// Destructor +/// +CWiaItem::~CWiaItem() +{ + Release(); +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CWiaItem::SetIWiaItem | Specifies the item to read from + * + * @parm IWiaItem2 | pIWiaItem | + * The item we want to read properties from + * + * @comm + * SetIWiaItem simply QIs the passed in item for its IWiaPropertyStorage interface. + * This interface is later used in all calls to Read[Required]PropertyXXX + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +HRESULT CWiaItem::SetIWiaItem(IWiaItem2 *pIWiaItem) +{ + HRESULT hr = S_OK; + Release(); + + if (!pIWiaItem) + { + return E_INVALIDARG; + } + + hr = pIWiaItem->QueryInterface(IID_IWiaPropertyStorage,(VOID**)&m_pIWiaPropStg); + + return hr; +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CWiaItem::ReadPropertyLong | Reads a LONG value from the + * currently set item. + * + * @parm PROPID | PropertyID | + * Id of property to read + * + * @parm LONG* | plPropertyValue | + * Pointer where we store the result from the read operation. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +HRESULT CWiaItem::ReadRequiredPropertyLong(PROPID PropertyID, _Out_ LONG *plPropertyValue) +{ + if (!plPropertyValue) + { + return E_INVALIDARG; + } + + if (!m_pIWiaPropStg) + { + return E_POINTER; + } + + PROPSPEC PropSpec[1]; + PROPVARIANT PropVar[1]; + + memset(PropVar, 0, sizeof(PropVar)); + PropVariantInit(PropVar); + + PropSpec[0].ulKind = PRSPEC_PROPID; + PropSpec[0].propid = PropertyID; + + HRESULT hr = S_OK; + hr = m_pIWiaPropStg->ReadMultiple(1, PropSpec, PropVar); + + // + // This is a required property + // + if (S_FALSE == hr) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr)) + { + *plPropertyValue = PropVar[0].lVal; + PropVariantClear(PropVar); + } + + return hr; +} + +HRESULT CWiaItem::ReadRequiredPropertyBSTR(PROPID PropertyID, _Outptr_ BSTR *pbstrPropertyValue) +{ + if (!pbstrPropertyValue) + { + return E_INVALIDARG; + } + + if (!m_pIWiaPropStg) + { + return E_POINTER; + } + + PROPSPEC PropSpec[1]; + PROPVARIANT PropVar[1]; + + memset(PropVar, 0, sizeof(PropVar)); + PropVariantInit(PropVar); + + PropSpec[0].ulKind = PRSPEC_PROPID; + PropSpec[0].propid = PropertyID; + + HRESULT hr = S_OK; + hr = m_pIWiaPropStg->ReadMultiple(1, PropSpec, PropVar); + + // + // This is a required property + // + if (S_FALSE == hr) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr)) + { + *pbstrPropertyValue = SysAllocString(PropVar[0].bstrVal); + if (!*pbstrPropertyValue ) + { + hr = E_OUTOFMEMORY; + } + PropVariantClear(PropVar); + } + + return hr; +} + +HRESULT CWiaItem::ReadRequiredPropertyGUID(PROPID PropertyID, _Out_ GUID *pguidPropertyValue) +{ + if (!pguidPropertyValue) + { + return E_INVALIDARG; + } + + if (!m_pIWiaPropStg) + { + return E_POINTER; + } + + PROPSPEC PropSpec[1]; + PROPVARIANT PropVar[1]; + + memset(PropVar, 0, sizeof(PropVar)); + PropVariantInit(PropVar); + + PropSpec[0].ulKind = PRSPEC_PROPID; + PropSpec[0].propid = PropertyID; + + HRESULT hr = S_OK; + hr = m_pIWiaPropStg->ReadMultiple(1, PropSpec, PropVar); + + if (S_FALSE == hr) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr)) + { + memcpy(pguidPropertyValue,PropVar[0].puuid,sizeof(GUID)); + PropVariantClear(PropVar); + } + + return hr; +} + +/// +/// Release releases the IPropertyStorage member variable +/// +void CWiaItem::Release() +{ + if (m_pIWiaPropStg) + { + m_pIWiaPropStg->Release(); + m_pIWiaPropStg = NULL; + } +} diff --git a/wia/wiadriverex/imgfilter/wiaitem.h b/wia/wiadriverex/imgfilter/wiaitem.h new file mode 100644 index 00000000..362f618e --- /dev/null +++ b/wia/wiadriverex/imgfilter/wiaitem.h @@ -0,0 +1,19 @@ +#pragma once + +#define MIN_PROPID 2 + +class CWiaItem { +public: + CWiaItem(); + ~CWiaItem(); + HRESULT SetIWiaItem(IWiaItem2 *pIWiaItem); + void Release(); + + HRESULT ReadRequiredPropertyLong(PROPID PropertyID, _Out_ LONG *plPropertyValue); + HRESULT ReadRequiredPropertyBSTR(PROPID PropertyID, _Outptr_ BSTR *pbstrPropertyValue); + HRESULT ReadRequiredPropertyGUID(PROPID PropertyID, _Out_ GUID *pguidPropertyValue); + +private: + IWiaPropertyStorage *m_pIWiaPropStg; +protected: +}; diff --git a/wia/wiadriverex/sample.bmp b/wia/wiadriverex/sample.bmp Binary files differnew file mode 100644 index 00000000..6e99c92a --- /dev/null +++ b/wia/wiadriverex/sample.bmp diff --git a/wia/wiadriverex/segfilter/DLLExports.def b/wia/wiadriverex/segfilter/DLLExports.def new file mode 100644 index 00000000..34ee1846 --- /dev/null +++ b/wia/wiadriverex/segfilter/DLLExports.def @@ -0,0 +1,31 @@ +; /*++ +; +; Copyright (C) Microsoft Corporation, 1985 - 2002 +; All rights reserved. +; +; Module Name: +; +; DLLExports.def +; +; Abstract: +; +; Declares the module parameters +; +; Author: +; +; Mikael Horal May-5-2003 +; +; Revision History: +; +; Mikael Horal May-5-2003 +; created +; +; --*/ +LIBRARY segfilter + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + diff --git a/wia/wiadriverex/segfilter/segfilter.vcxproj b/wia/wiadriverex/segfilter/segfilter.vcxproj new file mode 100644 index 00000000..32c9db8c --- /dev/null +++ b/wia/wiadriverex/segfilter/segfilter.vcxproj @@ -0,0 +1,211 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{4514674D-F69E-4C3B-902F-23FB5F04DB40}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{11F8CCAC-6F9C-48DC-BD97-C789BBFB807D}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>segfilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>segfilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>segfilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>segfilter</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="segmentation.cpp" /> + <ClCompile Include="wiaitem.cpp" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/wia/wiadriverex/segfilter/segfilter.vcxproj.Filters b/wia/wiadriverex/segfilter/segfilter.vcxproj.Filters new file mode 100644 index 00000000..5a2d6a15 --- /dev/null +++ b/wia/wiadriverex/segfilter/segfilter.vcxproj.Filters @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{E9DDA5CD-671B-48D4-9C93-46112EE184FC}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{9ED4691B-A5E4-4753-9002-8531A416D522}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{715ACF19-CAFA-4F78-851E-7B9096DDDABA}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="segmentation.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="wiaitem.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="DLLExports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/wia/wiadriverex/segfilter/segmentation.cpp b/wia/wiadriverex/segfilter/segmentation.cpp new file mode 100644 index 00000000..1e201432 --- /dev/null +++ b/wia/wiadriverex/segfilter/segmentation.cpp @@ -0,0 +1,499 @@ +/***************************************************************************** + * + * segmentation.cpp + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: + * + * CSegFilter is a simple sample segmentation filter, which works together with + * the wiadriver. It supports only three hardcoded regions. + * + *******************************************************************************/ + +#include "stdafx.h" + +#include "wiaitem.h" + +#define COUNTOF(x) (sizeof(x)/sizeof(x[0])) + +typedef struct _FILTER_IMAGE { + double XPOS; + double YPOS; + double XEXTENT; + double YEXTENT; + double DESKEWX; + double DESKEWY; +} FILTER_IMAGE; + +static FILTER_IMAGE g_FilterImages[] = { { 0.25, 0.5625, 3.3125, 2.75, 0.0, 0.0 }, + { 4.0625, 0.5625, 4.1875, 3.625, 0.0, 0.0 }, + { 0.547, 4.66, 7.360, 6.173, 6.347, 1.35 } }; + +static WCHAR *gszChildNameBase = L"Sub Region #"; + +// {7B6D704B-A4F2-4ecf-8B86-8E0CF1A707F5} +static const GUID CLSID_WiaSegmentationFilter = +{ 0x7b6d704b, 0xa4f2, 0x4ecf, { 0x8b, 0x86, 0x8e, 0xc, 0xf1, 0xa7, 0x7, 0xf5 } }; + +static LONG g_cLocks = 0; + +void LockModule(void) { InterlockedIncrement(&g_cLocks); } +void UnlockModule(void) { InterlockedDecrement(&g_cLocks); } + +class CSegFilter : public IWiaSegmentationFilter +{ +public: + + STDMETHODIMP + QueryInterface(_In_ const IID& iid_requested, _Out_ void** ppInterfaceOut); + + STDMETHODIMP_(ULONG) + AddRef(void); + + STDMETHODIMP_(ULONG) + Release(void); + + STDMETHODIMP + DetectRegions( + IN LONG lFlags, + _In_ IN IStream *pInputStream, + _In_ IN IWiaItem2 *pWiaItem); + + CSegFilter() : m_nRefCount(0) {} + +private: + + HRESULT + GenerateChildNames( + IN DWORD cChildNum, + _Out_ OUT BSTR *pbstrChildName); + + LONG m_nRefCount; +}; + +/// +/// QueryInterface +/// +STDMETHODIMP +CSegFilter::QueryInterface(_In_ const IID& iid_requested, _Out_ void** ppInterfaceOut) +{ + HRESULT hr = S_OK; + + hr = ppInterfaceOut ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppInterfaceOut = NULL; + } + + // + // We support IID_IUnknown and IID_IWiaSegmentationFilter + // + if (SUCCEEDED(hr)) + { + if (IID_IUnknown == iid_requested) + { + *ppInterfaceOut = static_cast<IUnknown*>(this); + } + else if (IID_IWiaSegmentationFilter == iid_requested) + { + *ppInterfaceOut = static_cast<IWiaSegmentationFilter*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppInterfaceOut)->AddRef(); + } + + return hr; +} + +/// +/// AddRef +/// +STDMETHODIMP_(ULONG) +CSegFilter::AddRef(void) +{ + if (m_nRefCount == 0) + { + LockModule(); + } + + return InterlockedIncrement(&m_nRefCount); +} + +/// +/// Release +/// +STDMETHODIMP_(ULONG) +CSegFilter::Release(void) +{ + ULONG nRetval = InterlockedDecrement(&m_nRefCount); + + if (0 == nRetval) + { + delete this; + UnlockModule(); + } + + return nRetval; +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CSegFilter::DetectRegions | Creates three child items with hardcoded coordinates + * + * @parm LONG | lFlags | + * Currently unused. + * + * @parm IStream | pInputStream | + * The (preview) image on which to perform segmentation. In this example the regions + * are hard-coded so we do not read pInputStream + * + * @parm IWiaItem2 | pWiaItem | + * The item under which to create the new child items. + * + * @comm + * Creates three child items with hardcoded coordinates. Notes that it sets deskew + * properties for one of the child items. This is only for demostration purposes since + * the driver cannot perform deskew. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +STDMETHODIMP +CSegFilter::DetectRegions( + IN LONG lFlags, + _In_ IN IStream *pInputStream, + _In_ IN IWiaItem2 *pWiaItem) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr; + CWiaItem *pIWiaItemWrapper = NULL; + IWiaItem2 *pChildIWiaItem = NULL; + LONG xres_dpi = 0; + LONG yres_dpi = 0; + LONG lItemFlags = WiaItemTypeGenerated | + WiaItemTypeTransfer | + WiaItemTypeImage | + WiaItemTypeFile | + WiaItemTypeProgrammableDataSource; + + hr = pWiaItem ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + hr = pInputStream ? S_OK : E_INVALIDARG; + } + + if (SUCCEEDED(hr)) + { + pIWiaItemWrapper = new CWiaItem(); + + hr = pIWiaItemWrapper ? S_OK : E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->SetIWiaItem(pWiaItem); + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadPropertyLong(WIA_IPS_XRES,&xres_dpi); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->ReadPropertyLong(WIA_IPS_YRES,&yres_dpi); + } + } + + if (SUCCEEDED(hr)) + { + BSTR bstrChildName = NULL; + + for (DWORD i = 0 ; i < COUNTOF(g_FilterImages) ; i++) + { + hr = GenerateChildNames(i, &bstrChildName); + + if (SUCCEEDED(hr)) + { + hr = pWiaItem->CreateChildItem(lItemFlags, COPY_PARENT_PROPERTY_VALUES, bstrChildName, &pChildIWiaItem); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->SetIWiaItem(pChildIWiaItem); + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->WritePropertyLong(WIA_IPS_XPOS, (LONG) (g_FilterImages[i].XPOS * xres_dpi)); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->WritePropertyLong(WIA_IPS_YPOS, (LONG) (g_FilterImages[i].YPOS * yres_dpi)); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->WritePropertyLong(WIA_IPS_XEXTENT, (LONG) (g_FilterImages[i].XEXTENT * xres_dpi)); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->WritePropertyLong(WIA_IPS_YEXTENT, (LONG) (g_FilterImages[i].YEXTENT * yres_dpi)); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->WritePropertyLong(WIA_IPS_DESKEW_X, (LONG) ((g_FilterImages[i].DESKEWX) * xres_dpi)); + } + + if (SUCCEEDED(hr)) + { + hr = pIWiaItemWrapper->WritePropertyLong(WIA_IPS_DESKEW_Y, (LONG) ((g_FilterImages[i].DESKEWY) * yres_dpi)); + } + } + + if(pChildIWiaItem) + { + pChildIWiaItem->Release(); + pChildIWiaItem = NULL; + } + + SysFreeString(bstrChildName); + bstrChildName = NULL; + } + } + + if (pIWiaItemWrapper) + { + delete pIWiaItemWrapper; + } + + return hr; +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CSegFilter::GenerateChildNames | Generates names for a new child item + * + * @parm DWORD | cChildNum | + * The childs number + * + * @parm BSTR | pbstrChildName | + * On successful return contains the name of the child to be created + * + * @comm + * Helper function that generates names for a child item # cChildNum + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +HRESULT +CSegFilter::GenerateChildNames( + IN DWORD cChildNum, + _Out_ OUT BSTR *pbstrChildName) +{ + HRESULT hr; + WCHAR szChildName[20]; + + hr = pbstrChildName ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + hr = StringCchPrintf(szChildName, + COUNTOF(szChildName), + L"%ws%u", + gszChildNameBase, + cChildNum); + } + + if (SUCCEEDED(hr)) + { + *pbstrChildName = SysAllocString(szChildName); + + hr = (*pbstrChildName) ? S_OK : E_OUTOFMEMORY; + } + + return hr; +} + +/***************************************************************************** + * + * Class Object + * + *******************************************************************************/ +class CFilterClass : public IClassFactory +{ +public: + + STDMETHODIMP + QueryInterface(_In_ const IID& iid_requested, _Out_ void** ppInterfaceOut) + { + HRESULT hr = S_OK; + + hr = ppInterfaceOut ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppInterfaceOut = NULL; + } + + // + // We only support IID_IUnknown and IID_IClassFactory + // + if (SUCCEEDED(hr)) + { + if (IID_IUnknown == iid_requested) + { + *ppInterfaceOut = static_cast<IUnknown*>(this); + } + else if (IID_IClassFactory == iid_requested) + { + *ppInterfaceOut = static_cast<IClassFactory*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppInterfaceOut)->AddRef(); + } + + return hr; + } + + STDMETHODIMP_(ULONG) + AddRef(void) + { + LockModule(); + return 2; + } + + STDMETHODIMP_(ULONG) + Release(void) + { + UnlockModule(); + return 1; + } + + STDMETHODIMP + CreateInstance(_In_ IUnknown *pUnkOuter, + _In_ REFIID riid, + _Out_ void **ppv) + { + CSegFilter *pSegFilter = NULL; + HRESULT hr; + + hr = ppv ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppv = 0; + } + + if (SUCCEEDED(hr)) + { + if (pUnkOuter) + { + hr = CLASS_E_NOAGGREGATION; + } + } + + if (SUCCEEDED(hr)) + { + pSegFilter = new CSegFilter(); + + hr = pSegFilter ? S_OK : E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + pSegFilter->AddRef(); + hr = pSegFilter->QueryInterface(riid, ppv); + pSegFilter->Release(); + } + + return hr; + } + + STDMETHODIMP + LockServer(BOOL bLock) + { + if (bLock) + { + LockModule(); + } + else + { + UnlockModule(); + } + + return S_OK; + } +}; + +STDAPI DllCanUnloadNow(void) +{ + return (g_cLocks == 0) ? S_OK : S_FALSE; +} + +STDAPI DllGetClassObject(_In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ void **ppv) +{ + static CFilterClass s_FilterClass; + + HRESULT hr; + + hr = ppv ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + if (rclsid == CLSID_WiaSegmentationFilter) + { + hr = s_FilterClass.QueryInterface(riid, ppv); + } + else + { + *ppv = 0; + hr = CLASS_E_CLASSNOTAVAILABLE; + } + } + + return hr; +} + +STDAPI DllUnregisterServer() +{ + return S_OK; +} + +STDAPI DllRegisterServer() +{ + return S_OK; +} + + diff --git a/wia/wiadriverex/segfilter/stdafx.h b/wia/wiadriverex/segfilter/stdafx.h new file mode 100644 index 00000000..48df9bb4 --- /dev/null +++ b/wia/wiadriverex/segfilter/stdafx.h @@ -0,0 +1,35 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_driver_) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +// Windows Header Files: +#include <windows.h> +#include <commctrl.h> +#include <commdlg.h> +#include <windowsx.h> +#include <stdio.h> +#include <tchar.h> +#include <shellapi.h> +#include <shlwapi.h> +// C RunTime Header Files +#include <stdlib.h> +#include <malloc.h> +#include <memory.h> +#include <tchar.h> +// WIA headers +#include <wia.h> +// STI headers +#include <sti.h> +#include <strsafe.h> + +VOID TRC(_In_ LPCTSTR format,...); + diff --git a/wia/wiadriverex/segfilter/wiaitem.cpp b/wia/wiadriverex/segfilter/wiaitem.cpp new file mode 100644 index 00000000..bb1b7ba4 --- /dev/null +++ b/wia/wiadriverex/segfilter/wiaitem.cpp @@ -0,0 +1,325 @@ +/***************************************************************************** + * + * wiaitem.cpp + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: + * + * wiaitem is a simply wrapper class used to read properties from an item + * of interface IWiaItem2 + * + *******************************************************************************/ +#include "stdafx.h" +#include "wiaitem.h" + +/// +/// Constructor - sets m_pIWiaPropStg to NULL +/// +CWiaItem::CWiaItem() +{ + m_pIWiaPropStg = NULL; +} + +/// +/// Destructor +/// +CWiaItem::~CWiaItem() +{ + Release(); +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CWiaItem::SetIWiaItem | Specifies the item to read from + * + * @parm IWiaItem2 | pIWiaItem | + * The item we want to read properties from + * + * @comm + * SetIWiaItem QIs the passed in IWiaItem2 object for its IWiaPropertyStorage interface + * which it stores internally and uses in the read and write functions. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +HRESULT CWiaItem::SetIWiaItem(_In_ IWiaItem2 *pIWiaItem) +{ + if (!pIWiaItem) + { + return E_INVALIDARG; + } + + HRESULT hr = S_OK; + Release(); + + // + // Get WIA property storage interface and store into member variable + // + hr = pIWiaItem->QueryInterface(IID_IWiaPropertyStorage,(VOID**)&m_pIWiaPropStg); + + return hr; +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CWiaItem::ReadPropertyLong | Reads a LONG value from the + * currently set item. + * + * @parm PROPID | PropertyID | + * Id of property to read + * + * @parm LONG* | plPropertyValue | + * Pointer where we store the result from the read operation. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +HRESULT CWiaItem::ReadPropertyLong(PROPID PropertyID, _Out_ LONG *plPropertyValue) +{ + if (!plPropertyValue) + { + return E_INVALIDARG; + } + + if (!m_pIWiaPropStg) + { + return E_POINTER; + } + + *plPropertyValue = 0; + + PROPSPEC PropSpec[1]; + PROPVARIANT PropVar[1]; + + memset(PropVar, 0, sizeof(PropVar)); + PropVariantInit(PropVar); + + PropSpec[0].ulKind = PRSPEC_PROPID; + PropSpec[0].propid = PropertyID; + + HRESULT hr = S_OK; + hr = m_pIWiaPropStg->ReadMultiple(1, PropSpec, PropVar); + if (S_OK == hr) + { + *plPropertyValue = PropVar[0].lVal; + PropVariantClear(PropVar); + } + return hr; +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CWiaItem::ReadPropertyGUID | Reads a GUID value from the + * currently set item. + * + * @parm PROPID | PropertyID | + * Id of property to read + * + * @parm GUID* | pguidPropertyValue | + * Pointer where we store the result from the read operation. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +HRESULT CWiaItem::ReadPropertyGUID(PROPID PropertyID, _Out_ GUID *pguidPropertyValue) +{ + if (!pguidPropertyValue) + { + return E_INVALIDARG; + } + + if (!m_pIWiaPropStg) + { + return E_POINTER; + } + + memset(pguidPropertyValue, 0, sizeof(GUID)); + + PROPSPEC PropSpec[1]; + PROPVARIANT PropVar[1]; + + memset(PropVar, 0, sizeof(PropVar)); + PropVariantInit(PropVar); + + PropSpec[0].ulKind = PRSPEC_PROPID; + PropSpec[0].propid = PropertyID; + + HRESULT hr = S_OK; + hr = m_pIWiaPropStg->ReadMultiple(1, PropSpec, PropVar); + if (hr == S_OK) + { + memcpy(pguidPropertyValue,PropVar[0].puuid,sizeof(GUID)); + PropVariantClear(PropVar); + } + return hr; +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CWiaItem::ReadPropertyBSTR | Reads a BSTR value from the + * currently set item. + * + * @parm PROPID | PropertyID | + * Id of property to read + * + * @parm BSTR* | pbstrPropertyValue | + * Pointer where we store the result from the read operation. + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +HRESULT CWiaItem::ReadPropertyBSTR(PROPID PropertyID, _Out_ BSTR *pbstrPropertyValue) +{ + if (!pbstrPropertyValue) + { + return E_INVALIDARG; + } + + if (!m_pIWiaPropStg) + { + return E_POINTER; + } + + *pbstrPropertyValue = NULL; + + PROPSPEC PropSpec[1]; + PROPVARIANT PropVar[1]; + + memset(PropVar, 0, sizeof(PropVar)); + PropVariantInit(PropVar); + + PropSpec[0].ulKind = PRSPEC_PROPID; + PropSpec[0].propid = PropertyID; + + HRESULT hr = S_OK; + hr = m_pIWiaPropStg->ReadMultiple(1, PropSpec, PropVar); + if (hr == S_OK) + { + *pbstrPropertyValue = SysAllocString(PropVar[0].bstrVal); + if (!*pbstrPropertyValue) + { + hr = E_OUTOFMEMORY; + } + PropVariantClear(PropVar); + } + return hr; +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CWiaItem::WritePropertyLong | Writes a LONG value to the + * currently set item. + * + * @parm PROPID | PropertyID | + * Id of property to read + * + * @parm LONG | lPropertyValue | + * Value to write + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +HRESULT CWiaItem::WritePropertyLong(PROPID PropertyID, LONG lPropertyValue) +{ + if (!m_pIWiaPropStg) + { + return E_POINTER; + } + + PROPSPEC PropSpec[1]; + PROPVARIANT PropVar[1]; + + memset(PropVar, 0, sizeof(PropVar)); + PropVariantInit(PropVar); + + PropSpec[0].ulKind = PRSPEC_PROPID; + PropSpec[0].propid = PropertyID; + PropVar[0].vt = VT_I4; + PropVar[0].lVal = lPropertyValue; + + HRESULT hr = S_OK; + hr = m_pIWiaPropStg->WriteMultiple(1, PropSpec, PropVar, MIN_PROPID); + + return hr; +} + +/***************************************************************************** + * + * @doc INTERNAL + * + * @func STDMETHODIMP | CWiaItem::WritePropertyGUID | Writes a GUID value to the + * currently set item. + * + * @parm PROPID | PropertyID | + * Id of property to read + * + * @parm GUID | guidPropertyValue | + * Value to write + * + * @rvalue S_OK | + * The function succeeded. + * @rvalue E_XXX | + * The function failed + * + *****************************************************************************/ +HRESULT CWiaItem::WritePropertyGUID(PROPID PropertyID, GUID guidPropertyValue) +{ + if (!m_pIWiaPropStg) + { + return E_POINTER; + } + + PROPSPEC PropSpec[1]; + PROPVARIANT PropVar[1]; + + memset(PropVar, 0, sizeof(PropVar)); + PropVariantInit(PropVar); + + PropSpec[0].ulKind = PRSPEC_PROPID; + PropSpec[0].propid = PropertyID; + PropVar[0].vt = VT_CLSID; + PropVar[0].puuid = &guidPropertyValue; + + HRESULT hr = S_OK; + hr = m_pIWiaPropStg->WriteMultiple(1, PropSpec, PropVar, MIN_PROPID); + + return hr; +} + +/// +/// Release releases the IWiaPropertyStorage member variable +/// +void CWiaItem::Release() +{ + if (m_pIWiaPropStg) + { + m_pIWiaPropStg->Release(); + m_pIWiaPropStg = NULL; + } +} diff --git a/wia/wiadriverex/segfilter/wiaitem.h b/wia/wiadriverex/segfilter/wiaitem.h new file mode 100644 index 00000000..3eae8639 --- /dev/null +++ b/wia/wiadriverex/segfilter/wiaitem.h @@ -0,0 +1,23 @@ +#pragma once + +#define MIN_PROPID 2 + +class CWiaItem { +public: + CWiaItem(); + ~CWiaItem(); + HRESULT SetIWiaItem(_In_ IWiaItem2 *pIWiaItem); + + void Release(); + + HRESULT ReadPropertyLong(PROPID PropertyID, _Out_ LONG *plPropertyValue); + HRESULT ReadPropertyGUID(PROPID PropertyID, _Out_ GUID *pguidPropertyValue); + HRESULT ReadPropertyBSTR(PROPID PropertyID, _Out_ BSTR *pbstrPropertyValue); + + HRESULT WritePropertyLong(PROPID PropertyID, LONG lPropertyValue); + HRESULT WritePropertyGUID(PROPID PropertyID, GUID guidPropertyValue); + +private: + IWiaPropertyStorage *m_pIWiaPropStg; +protected: +}; diff --git a/wia/wiadriverex/uiext2/DLLExports.def b/wia/wiadriverex/uiext2/DLLExports.def new file mode 100644 index 00000000..eebbf61c --- /dev/null +++ b/wia/wiadriverex/uiext2/DLLExports.def @@ -0,0 +1,22 @@ +; /*++ +; +; Copyright (C) Microsoft Corporation, 1985 - 2002 +; All rights reserved. +; +; Module Name: +; +; DLLExports.def +; +; Abstract: +; +; Declares the module parameters +; + +LIBRARY uiext2 + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + diff --git a/wia/wiadriverex/uiext2/resource.h b/wia/wiadriverex/uiext2/resource.h new file mode 100644 index 00000000..208aba2e --- /dev/null +++ b/wia/wiadriverex/uiext2/resource.h @@ -0,0 +1,6 @@ +//(C) COPYRIGHT MICROSOFT CORP., 1998-1999 +#define IDI_TESTDEVICE 2005 + +#define IDS_MESSAGEBOX_WIAUIEXTENSION_DIALOG 3001 +#define IDS_MESSAGEBOX_WIAUIEXTENSION_TITLE 3002 +#define IDS_MESSAGEBOX_TRANSFERMESSAGE_DIALOG 3003 diff --git a/wia/wiadriverex/uiext2/stdafx.h b/wia/wiadriverex/uiext2/stdafx.h new file mode 100644 index 00000000..ce12f0e3 --- /dev/null +++ b/wia/wiadriverex/uiext2/stdafx.h @@ -0,0 +1,33 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +// Windows Header Files: +#include <windows.h> +#include <commctrl.h> +#include <commdlg.h> +#include <windowsx.h> +#include <stdio.h> +#include <tchar.h> +#include <shellapi.h> +#include <shlobj.h> +#include <shlwapi.h> +// C RunTime Header Files +#include <stdlib.h> +#include <malloc.h> +#include <memory.h> +#include <tchar.h> +// WIA headers +#include <wia.h> +// STI headers +#include <sti.h> +#include <strsafe.h> + +#include "wiadevd.h" +#include "resource.h"
\ No newline at end of file diff --git a/wia/wiadriverex/uiext2/testdev.ico b/wia/wiadriverex/uiext2/testdev.ico Binary files differnew file mode 100644 index 00000000..26cbef1b --- /dev/null +++ b/wia/wiadriverex/uiext2/testdev.ico diff --git a/wia/wiadriverex/uiext2/uiext2.cpp b/wia/wiadriverex/uiext2/uiext2.cpp new file mode 100644 index 00000000..1cb19ede --- /dev/null +++ b/wia/wiadriverex/uiext2/uiext2.cpp @@ -0,0 +1,655 @@ +/***************************************************************************** + * + * errhandler.cpp + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: + * + * CErrHandler is a simple error handler, which works together with + * the wiadriver. + * + *******************************************************************************/ +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_driver_) + +#include "stdafx.h" + +// {61364062-0593-4eda-84d2-f5531d8c3259} +static const GUID CLSID_WiaUIExt2 = +{ 0x61364062, 0x0593, 0x4eda, { 0x84, 0xd2, 0xf5, 0x53, 0x1d, 0x8c, 0x32, 0x59 } }; + +static LONG g_cLocks = 0; +static HINSTANCE g_hInst = 0; + + +void LockModule(void) { InterlockedIncrement(&g_cLocks); } +void UnlockModule(void) { InterlockedDecrement(&g_cLocks); } + +HRESULT TransferFromWiaItem( PDEVICEDIALOGDATA2 pDeviceDialogData, IWiaItem2 *pWiaFlatbed); + +class CWiaUIExtension2 : public IWiaUIExtension2 +{ +public: + + STDMETHODIMP + QueryInterface(const IID& iid_requested, _COM_Outptr_ void** ppInterfaceOut); + + STDMETHODIMP_(ULONG) + AddRef(void); + + STDMETHODIMP_(ULONG) + Release(void); + + STDMETHODIMP + DeviceDialog(_In_ PDEVICEDIALOGDATA2 pDeviceDialogData ); + + STDMETHODIMP + GetDeviceIcon(_In_ BSTR bstrDeviceId, _Out_ HICON *phIcon, ULONG nSize ); + + CWiaUIExtension2() : m_nRefCount(0) {} + +private: + + LONG m_nRefCount; +}; + +STDMETHODIMP +CWiaUIExtension2::QueryInterface(const IID& iid_requested, _COM_Outptr_ void** ppInterfaceOut) +{ + HRESULT hr = S_OK; + + hr = ppInterfaceOut ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppInterfaceOut = NULL; + } + + // + // We support IID_IUnknown and IWiaUIExtension2 + // + if (SUCCEEDED(hr)) + { + if (IID_IUnknown == iid_requested) + { + *ppInterfaceOut = static_cast<IUnknown*>(this); + } + else if (IID_IWiaUIExtension2 == iid_requested) + { + *ppInterfaceOut = static_cast<IWiaUIExtension2*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppInterfaceOut)->AddRef(); + } + + return hr; +} + +/// +/// AddRef +/// +STDMETHODIMP_(ULONG) +CWiaUIExtension2::AddRef(void) +{ + if (m_nRefCount == 0) + { + LockModule(); + } + + return InterlockedIncrement(&m_nRefCount); +} + +/// +/// Release +/// +STDMETHODIMP_(ULONG) +CWiaUIExtension2::Release(void) +{ + ULONG nRetval = InterlockedDecrement(&m_nRefCount); + + if (0 == nRetval) + { + delete this; + UnlockModule(); + } + + return nRetval; +} + +// +// IWiaUIExtension2 +// +STDMETHODIMP +CWiaUIExtension2::DeviceDialog(_In_ PDEVICEDIALOGDATA2 pDeviceDialogData) +{ + HRESULT hr = S_OK; + IEnumWiaItem2* pEnumItem = NULL; + IWiaItem2* pWiaFlatbed = NULL; + GUID guidCategory = WIA_CATEGORY_FLATBED; + TCHAR bufDialog[MAX_PATH] = {0}; + TCHAR bufTitle[MAX_PATH] = {0}; + + if (LoadString(g_hInst, IDS_MESSAGEBOX_WIAUIEXTENSION_DIALOG, bufDialog, ARRAYSIZE(bufDialog)) && + LoadString(g_hInst, IDS_MESSAGEBOX_WIAUIEXTENSION_TITLE, bufTitle, ARRAYSIZE(bufTitle)) + ) + { + MessageBox( NULL, bufDialog, bufTitle, 0 ); + } + + hr = pDeviceDialogData->pIWiaItemRoot->EnumChildItems(&guidCategory, &pEnumItem); + + if (SUCCEEDED(hr)) + { + ULONG ulFetched = 0; + hr = pEnumItem->Next(1, &pWiaFlatbed, &ulFetched); + + if (SUCCEEDED(hr) && (1 == ulFetched)) + { + hr = TransferFromWiaItem(pDeviceDialogData, pWiaFlatbed); + + pWiaFlatbed->Release(); + } + + pEnumItem->Release(); + } + + return hr; +} + +STDMETHODIMP +CWiaUIExtension2::GetDeviceIcon(_In_ BSTR bstrDeviceId, _Out_ HICON *phIcon, ULONG nSize ) +{ + UNREFERENCED_PARAMETER(bstrDeviceId); + + // + // Load an icon, and copy it, using CopyIcon, so it will still be valid if our interface is freed + // + HICON hIcon = reinterpret_cast<HICON>(LoadImage( g_hInst, MAKEINTRESOURCE(IDI_TESTDEVICE), IMAGE_ICON, nSize, nSize, LR_DEFAULTCOLOR )); + if (hIcon) + { + *phIcon = CopyIcon(hIcon); + DestroyIcon(hIcon); + return S_OK; + } + return E_FAIL; +} + + +/***************************************************************************** + * + * Class Object + * + *******************************************************************************/ +class CUIExt2ClassObject : public IClassFactory +{ +public: + + STDMETHODIMP + QueryInterface(const IID& iid_requested, _COM_Outptr_ void** ppInterfaceOut) + { + HRESULT hr = S_OK; + + hr = ppInterfaceOut ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppInterfaceOut = NULL; + } + + // + // We only support IID_IUnknown and IID_IClassFactory + // + if (SUCCEEDED(hr)) + { + if (IID_IUnknown == iid_requested) + { + *ppInterfaceOut = static_cast<IUnknown*>(this); + } + else if (IID_IClassFactory == iid_requested) + { + *ppInterfaceOut = static_cast<IClassFactory*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppInterfaceOut)->AddRef(); + } + + return hr; + } + + STDMETHODIMP_(ULONG) + AddRef(void) + { + LockModule(); + return 2; + } + + STDMETHODIMP_(ULONG) + Release(void) + { + UnlockModule(); + return 1; + } + + STDMETHODIMP + CreateInstance(_In_opt_ IUnknown *pUnkOuter, + _In_ REFIID riid, + _COM_Outptr_ void **ppv) + { + CWiaUIExtension2 *pExt = NULL; + HRESULT hr; + + hr = ppv ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppv = 0; + } + + if (SUCCEEDED(hr)) + { + if (pUnkOuter) + { + hr = CLASS_E_NOAGGREGATION; + } + } + + if (SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "pExt is freed on release.") + pExt = new CWiaUIExtension2(); + + hr = pExt ? S_OK : E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + pExt->AddRef(); + hr = pExt->QueryInterface(riid, ppv); + pExt->Release(); + } + + return hr; + } + + STDMETHODIMP + LockServer(BOOL bLock) + { + if (bLock) + { + LockModule(); + } + else + { + UnlockModule(); + } + + return S_OK; + } +}; + +STDAPI DllCanUnloadNow(void) +{ + return (g_cLocks == 0) ? S_OK : S_FALSE; +} + +STDAPI DllGetClassObject(_In_ REFCLSID rclsid, + _In_ REFIID riid, + _Outptr_ void **ppv) +{ + static CUIExt2ClassObject s_FilterClass; + + HRESULT hr; + + hr = ppv ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + if (rclsid == CLSID_WiaUIExt2) + { + hr = s_FilterClass.QueryInterface(riid, ppv); + } + else + { + *ppv = 0; + hr = CLASS_E_CLASSNOTAVAILABLE; + } + } + + return hr; +} + +STDAPI DllUnregisterServer() +{ + return S_OK; +} + +STDAPI DllRegisterServer() +{ + return S_OK; +} + +BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(lpReserved); + + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + g_hInst = hinst; + break; + } + return TRUE; +} + +class CSimpleWIACallback : public IWiaTransferCallback +{ +private: + volatile LONG m_cRef; + +public: + STDMETHODIMP CSimpleWIACallback::QueryInterface(const IID &iid_requested, _COM_Outptr_ void** ppInterfaceOut) + { + HRESULT hr = S_OK; + + hr = ppInterfaceOut ? S_OK : E_POINTER; + + if (SUCCEEDED(hr)) + { + *ppInterfaceOut = NULL; + } + + // + // We support IID_IUnknown and IID_IWiaTransferCallback + // + if (SUCCEEDED(hr)) + { + if (IID_IUnknown == iid_requested) + { + *ppInterfaceOut = static_cast<IWiaTransferCallback*>(this); + } + else if (IID_IWiaTransferCallback == iid_requested) + { + *ppInterfaceOut = static_cast<IWiaTransferCallback*>(this); + } + else + { + hr = E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr)) + { + reinterpret_cast<IUnknown*>(*ppInterfaceOut)->AddRef(); + } + + return hr; + } + + STDMETHODIMP_(ULONG) + CSimpleWIACallback::AddRef() + { + return InterlockedIncrement(&m_cRef); + } + + STDMETHODIMP_(ULONG) + CSimpleWIACallback::Release() + { + ULONG ulRefCount = InterlockedDecrement(&m_cRef); + + if (0 == ulRefCount) + { + delete this; + } + + return ulRefCount; + } + +private: + IStream * m_pStream; + +public: + CSimpleWIACallback(IStream * pStream): m_cRef(1) + { + m_pStream = pStream; + } + + STDMETHODIMP GetNextStream( + LONG lFlags, + _In_z_ BSTR bstrItemName, + _In_z_ BSTR bstrFullItemName, + _Outptr_result_maybenull_ _At_(*ppDestination, _When_(return == S_OK, _Post_notnull_)) + IStream **ppDestination) + { + UNREFERENCED_PARAMETER(lFlags); + UNREFERENCED_PARAMETER(bstrItemName); + UNREFERENCED_PARAMETER(bstrFullItemName); + + HRESULT hr = S_OK; + + if (ppDestination) + { + *ppDestination = NULL; + } + + if (m_pStream) + { + *ppDestination = m_pStream; + } + else + { + hr = E_FAIL; + } + return hr; + } + + STDMETHODIMP TransferCallback(LONG lFlags, _In_ WiaTransferParams *pWiaTransferParams) + { + UNREFERENCED_PARAMETER(lFlags); + UNREFERENCED_PARAMETER(pWiaTransferParams); + + return S_OK; + } + +}; + + +/*****************************************************************************\ + + TransferFromWiaItem + + Transfers the file from the given wia item to the file name specified in the + pDeviceDialogData + +*****************************************************************************/ +HRESULT TransferFromWiaItem( PDEVICEDIALOGDATA2 pDeviceDialogData, IWiaItem2 *pWiaFlatbed) +{ + + HRESULT hr = S_OK; + IStream * pStream = NULL; + IWiaTransfer * pWiaTransfer = NULL; + IWiaPropertyStorage * pPropertyStorage = NULL; + + if (!pDeviceDialogData || !pWiaFlatbed) + { + hr = E_INVALIDARG; + } + + WCHAR *pFileName = (WCHAR*) LocalAlloc(LPTR, sizeof(WCHAR)*MAX_PATH); + WCHAR *pUniqueFileName = (WCHAR*) LocalAlloc(LPTR, sizeof(WCHAR)*MAX_PATH); + + if(!pFileName || !pUniqueFileName) + { + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + hr = pWiaFlatbed->QueryInterface(IID_IWiaPropertyStorage, (LPVOID *)&pPropertyStorage); + + if (SUCCEEDED(hr)) + { + PROPSPEC pSpec[1] = {0}; + PROPVARIANT pVar[1] = {0}; + GUID guidFormat = WiaImgFmt_BMP; + + pSpec[0].ulKind = PRSPEC_PROPID; + pSpec[0].propid = WIA_IPA_FORMAT; + + pVar[0].vt = VT_CLSID; + pVar[0].puuid = &guidFormat; + + hr = pPropertyStorage->WriteMultiple(1, pSpec, pVar, WIA_IPS_FIRST); + + pPropertyStorage->Release(); + } + } + + if (SUCCEEDED(hr)) + { + hr = pWiaFlatbed->QueryInterface(IID_IWiaTransfer, (LPVOID *)&pWiaTransfer); + } + + if (SUCCEEDED(hr)) + { + hr = StringCchCopyW(pFileName, MAX_PATH, pDeviceDialogData->bstrFolderName); + } + + if (SUCCEEDED(hr)) + { + size_t cchFileNameLength = 0; + + hr = StringCchLengthW(pFileName, MAX_PATH, &cchFileNameLength); + + if (SUCCEEDED(hr) && (pFileName[cchFileNameLength - 1] != L'\\')) + { + hr = StringCchCatW(pFileName, MAX_PATH, L"\\"); + } + } + + if (SUCCEEDED(hr)) + { + hr = StringCchCatW(pFileName, MAX_PATH, pDeviceDialogData->bstrFilename); + } + + if (SUCCEEDED(hr)) + { + // + // Add the extension. This will help if the application forgot the extension. + // + hr = StringCchCatW(pFileName, MAX_PATH, L".BMP"); + + if (SUCCEEDED(hr)) + { + if( !PathYetAnotherMakeUniqueName(pUniqueFileName, pFileName, NULL, NULL) ) + { + hr = E_FAIL; + } + } + } + + if (SUCCEEDED(hr)) + { + // + // We dont have to release the stream. WIA service will release the stream after transfer. + // + hr = SHCreateStreamOnFileEx(pUniqueFileName, STGM_READWRITE, FILE_ATTRIBUTE_NORMAL, TRUE, 0, &pStream); + } + + if (SUCCEEDED(hr)) + { + CSimpleWIACallback * pCallback = NULL; + +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "pTransferCallback is freed on release.") + pCallback = new CSimpleWIACallback(pStream); + + if (pCallback) + { + IWiaTransferCallback * pTransferCallback = NULL; + + hr = pCallback->QueryInterface(IID_IWiaTransferCallback, (LPVOID*)&pTransferCallback); + + if (SUCCEEDED(hr)) + { + hr = pWiaTransfer->Download(0, pTransferCallback); + + pTransferCallback ->Release(); + } + + pCallback->Release(); + } + } + + // + // Fill the Out Parameters + // + if (SUCCEEDED(hr)) + { + pDeviceDialogData->lNumFiles = 1; + + pWiaFlatbed->AddRef(); + pDeviceDialogData->pWiaItem = pWiaFlatbed; + + pDeviceDialogData->pbstrFilePaths = (BSTR *)CoTaskMemAlloc(sizeof(BSTR *)); + + if (pDeviceDialogData->pbstrFilePaths) + { + *(pDeviceDialogData->pbstrFilePaths) = SysAllocString(pUniqueFileName); + } + else + { + hr = E_FAIL; + } + } + + + if (SUCCEEDED(hr)) + { + WCHAR bufDialog[MAX_PATH] = {0}; + WCHAR bufTitle[MAX_PATH] = {0}; + + if (LoadString(g_hInst, IDS_MESSAGEBOX_TRANSFERMESSAGE_DIALOG, bufDialog, ARRAYSIZE(bufDialog)) && + LoadString(g_hInst, IDS_MESSAGEBOX_WIAUIEXTENSION_TITLE, bufTitle, ARRAYSIZE(bufTitle)) && + SUCCEEDED(StringCchCatW(bufDialog, MAX_PATH, pUniqueFileName)) + ) + { +#pragma prefast(suppress:__WARNING_CONCATENATED_RESOURCE_STRING, "The concatenated string that does not come from localizable resources is a file name constructed at run time." + MessageBoxW (NULL, bufDialog, bufTitle, 0 ); + } + } + + if (pWiaTransfer) + { + pWiaTransfer->Release(); + pWiaTransfer = NULL; + } + + if (pFileName) + { + LocalFree(pFileName); + pFileName = NULL; + } + + if (pUniqueFileName) + { + LocalFree(pUniqueFileName); + pUniqueFileName = NULL; + } + + return hr; +} + diff --git a/wia/wiadriverex/uiext2/uiext2.rc b/wia/wiadriverex/uiext2/uiext2.rc new file mode 100644 index 00000000..b12722e7 --- /dev/null +++ b/wia/wiadriverex/uiext2/uiext2.rc @@ -0,0 +1,30 @@ +//(C) COPYRIGHT MICROSOFT CORP., 1998-1999 + + +#include "resource.h" +#include "windows.h" + +IDI_TESTDEVICE ICON "testdev.ico" + +#include <winver.h> +#include <ntverp.h> + + +STRINGTABLE +BEGIN + IDS_MESSAGEBOX_WIAUIEXTENSION_DIALOG "CWiaUIExtension::DeviceDialog is being called" + IDS_MESSAGEBOX_WIAUIEXTENSION_TITLE "IWiaUIExtension" + IDS_MESSAGEBOX_TRANSFERMESSAGE_DIALOG "Transferred From Flatbed to File: " +END + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WIA TestCam UI DLL" +#define VER_INTERNALNAME_STR "extend\0" +#define VER_ORIGINALFILENAME_STR "extend.dll" + +#include "common.ver" + + + + diff --git a/wia/wiadriverex/uiext2/uiext2.vcxproj b/wia/wiadriverex/uiext2/uiext2.vcxproj new file mode 100644 index 00000000..e38167ab --- /dev/null +++ b/wia/wiadriverex/uiext2/uiext2.vcxproj @@ -0,0 +1,211 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{D8EF524D-29CB-4721-8EBE-1A049ECE53A2}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{BC7810D3-ADBE-4971-AB62-385AA0C02DEE}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>uiext2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>uiext2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>uiext2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>uiext2</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shell32.lib;shlwapi.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shell32.lib;shlwapi.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shell32.lib;shlwapi.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;ADVAPI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shell32.lib;shlwapi.lib</AdditionalDependencies> + <ModuleDefinitionFile>DLLExports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="uiext2.cpp" /> + <ResourceCompile Include="uiext2.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/wia/wiadriverex/uiext2/uiext2.vcxproj.Filters b/wia/wiadriverex/uiext2/uiext2.vcxproj.Filters new file mode 100644 index 00000000..6d931dac --- /dev/null +++ b/wia/wiadriverex/uiext2/uiext2.vcxproj.Filters @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{56B00973-0E3A-44A0-BFC9-087EF86F61FF}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{5391BEF6-E8E9-4AA2-AB04-1F7B36168EB5}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{711636B0-15B5-4312-B71A-6A073350FBCE}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="uiext2.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="DLLExports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="uiext2.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/wia/wiadriverex/usd/WiaDevice.h b/wia/wiadriverex/usd/WiaDevice.h new file mode 100644 index 00000000..ec83ecaf --- /dev/null +++ b/wia/wiadriverex/usd/WiaDevice.h @@ -0,0 +1,433 @@ +/***************************************************************************** + * + * WiaDevice.h + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: + * + * This class simulates a "real" device from which we can acquire image data and upload + * image data. It uses GDI+ internally to create the image. + * + *******************************************************************************/ + +#pragma once + +using namespace Gdiplus; + +extern HINSTANCE g_hInst; + +class WiaDevice +{ +public: + WiaDevice() : + m_dwTotalBytesToRead(0), + m_dwTotalBytesRead(0), + m_dwLinesRead(0), + m_pBitmap(NULL), + m_pBitmapData(NULL), + m_pBitmapBits(NULL), + m_ulHeaderSize(NULL), + m_ulBytesPerLineBMP(0), + m_ulBytesPerLineRAW(0) + { + memset(&m_bmfh, 0, sizeof(m_bmfh)); + memset(&m_bmih, 0, sizeof(m_bmih)); + }; + + virtual ~WiaDevice() + { + UninitializeForDownload(); + }; + + HRESULT InitializeForDownload( + _In_ BYTE *pWiasContext, + _In_ HINSTANCE hInstance, + UINT uiBitmapResourceID, + const GUID &guidFormatID) + { + HRESULT hr = E_INVALIDARG; + + memset(&m_RawHeader, 0, sizeof(m_RawHeader)); + + if((pWiasContext)&&(hInstance)) + { + HBITMAP hBitmap = static_cast<HBITMAP>(LoadImage(hInstance, MAKEINTRESOURCE(uiBitmapResourceID), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION)); + + if (hBitmap) + { + m_pBitmap = Bitmap::FromHBITMAP(hBitmap, NULL); + + if(m_pBitmap) + { + m_pBitmapData = new BitmapData; + + if(m_pBitmapData) + { + hr = LockSelectionAreaOnBitmap(pWiasContext, m_pBitmap, m_pBitmapData, &m_bmih, &m_pBitmapBits); + if(SUCCEEDED(hr)) + { + if(IsEqualGUID(guidFormatID, WiaImgFmt_RAW)) + { + // + // Raw format (no color palette is used, just the header): + // + m_ulHeaderSize = sizeof(WIA_RAW_HEADER); + } + else + { + // + // Device Independent Bitmap (DIB): + // + m_ulHeaderSize = sizeof(m_bmfh) + sizeof(m_bmih); + } + + // + // Initialize the remaining BITMAPINFOHEADER fields (use for both BMP and RAW transfers): + // + m_bmfh.bfType = ((WORD) ('M' << 8) | 'B'); + m_bmfh.bfOffBits = sizeof(m_bmfh) + sizeof(m_bmih); //m_ulHeaderSize; + m_bmfh.bfSize = m_bmfh.bfOffBits + m_bmih.biSizeImage; + + // + // We assume the sample source data is 24-bit RGB only: + // + m_ulBytesPerLineBMP = m_bmih.biWidth * 3; + + // + // The WIA raw format requires image lines to be DWORD aligned, + // in this case however the DIB data that we are using as the + // source is already DWORD aligned: + // + // m_ulBytesPerLineRAW = (m_ulBytesPerLineBMP + 3) & ~3; + // + m_ulBytesPerLineRAW = m_ulBytesPerLineBMP; + + // + // m_dwTotalBytesToRead is used to measure the total number of bytes to read from the source DIB + // (in a real case for RAW this may be different than the actual number of bytes to be transferred, + // however in this particular case the two match because we accept in this sample only DIBs at input + // - with the exception of the DIB file header, see below..) + // + if(IsEqualGUID(guidFormatID, WiaImgFmt_RAW)) + { + // + // For Raw this is just the size of the DIB data (no file header) + // + m_dwTotalBytesToRead = m_bmih.biSizeImage; + + // + // The number of bytes in the raw data is described in this case by the number of bytes + // to be read from the DIB source (the data comes already DWORD aligned so the two numbers + // match in this particular case): + // + m_RawHeader.RawDataSize = m_dwTotalBytesToRead; + m_RawHeader.BytesPerLine = m_ulBytesPerLineRAW; + } + else + { + // + // For bitmap transfers the DIB file header is transferred too.. + // + m_dwTotalBytesToRead = m_bmfh.bfSize; + m_RawHeader.RawDataSize = 0; + } + + m_dwTotalBytesRead = 0; + m_dwLinesRead = 0; + } + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for GDI+ bitmap data object, hr = 0x%lx",hr)); + } + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for GDI+ bitmap object, hr = 0x%lx",hr)); + } + + DeleteObject(hBitmap); + } + else + { + DWORD dwError = GetLastError(); + + hr = HRESULT_FROM_WIN32(dwError); + WIAS_ERROR((g_hInst, "Failed to get HBITMAP for bitmap object, hr = 0x%lx", hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; + } + + void UninitializeForDownload() + { + if (m_pBitmap && m_pBitmapData) + { + UnlockSelectionAreaOnBitmap(m_pBitmap, m_pBitmapData); + } + m_pBitmapBits = NULL; + SAFE_DELETE(m_pBitmapData); + SAFE_DELETE(m_pBitmap); + } + + BOOL InitializedForDownload() + { + return (BOOL)(m_pBitmap && m_pBitmapData); + } + + BitmapData* GetBitmapData() + { + return m_pBitmapData; + } + + HRESULT GetNextBand(_Out_writes_bytes_to_(ulBufferSize, *pulBytesRead) BYTE *pBuffer, + ULONG ulBufferSize, + _Out_ ULONG *pulBytesRead, + _Out_ LONG *plPercentComplete, + const GUID &guidFormatID) + { + HRESULT hr = S_OK; + + if (pBuffer && pulBytesRead && plPercentComplete && (ulBufferSize > m_ulHeaderSize)) + { + // + // iScanline contains the number of bytes to copy from each scanline + // + // Note: this logic works well considering that we are using only + // 24-bit RGB color sample images. For a real solution different + // pixel formats and bit depths may have to be considered. + // + INT iScanline = ((m_pBitmapData->Width * 3) + 3) & ~3; + + *pulBytesRead = 0; + *plPercentComplete = 0; + + if(m_dwTotalBytesRead < m_dwTotalBytesToRead) + { + // + // Check whether we should send the bitmap header or the data. + // The header is always sent first, unless this is a Raw transfer + // (when the raw header is individually sent before calling GetNextBand) + // + if((m_dwTotalBytesRead == 0) && (!IsEqualGUID(guidFormatID, WiaImgFmt_RAW))) + { + if (ulBufferSize >= sizeof(m_bmfh) + sizeof(m_bmih)) + { + // + // Read the header. + // + memcpy(pBuffer,&m_bmfh, sizeof(m_bmfh)); + memcpy(pBuffer + sizeof(m_bmfh),&m_bmih, sizeof(m_bmih)); + *pulBytesRead = m_ulHeaderSize; + } + else + { + // + // Insufficient Buffer + // + hr = E_FAIL; + } + } + else + { + // + // For WIA raw transfers we do not have much to do in this case other than + // just copy the DIB data which already had DWORD line alignment, in the + // current line order the DIB provides (bottom to top usually) considering + // the raw header describes the current order (the WIA raw format supports + // both possible configurations). So we'll use the same code for both + // formats, WiaImgFmt_BMP and WiaImgFmt_RAW. + // + + // Read a data band + // First calculate number of bytes in whole scan lines. + DWORD dwNumLineBytesInBuffer = (ulBufferSize - (ulBufferSize % iScanline)); + DWORD dwNumBytesLeftToRead = (m_dwTotalBytesToRead - m_dwTotalBytesRead); + // Set how many bytes we are going to read. This is either the maxiumun + // nunmber of scan lines that will fit into the buffer, or it's the number + // of bytes left in the last chunk. + if(dwNumBytesLeftToRead < dwNumLineBytesInBuffer) + { + dwNumLineBytesInBuffer = dwNumBytesLeftToRead; + } + // Position buffer pointer to correct data location for this band. We are copying + // in reverse scanline order so that the bitmap becomes topdown (it is currently + // upside-down in the source buffer). + BYTE *pBits = m_pBitmapBits + (m_pBitmapData->Height * m_pBitmapData->Stride); + pBits -= (m_pBitmapData->Stride * (1 + m_dwLinesRead)); + + DWORD dwDestOffset = 0; + for (BYTE *pCurLine = pBits; dwDestOffset < dwNumLineBytesInBuffer; pCurLine -= m_pBitmapData->Stride, m_dwLinesRead++) + { + if (ulBufferSize - dwDestOffset >= (ULONG) iScanline) + { + memcpy(pBuffer + dwDestOffset, pCurLine, iScanline); + dwDestOffset += iScanline; + } + else + { + hr = E_FAIL; + break; + } + } + + *pulBytesRead = dwNumLineBytesInBuffer; + } + m_dwTotalBytesRead += *pulBytesRead; + + if(IsEqualGUID(guidFormatID, WiaImgFmt_RAW)) + { + *plPercentComplete = (LONG)((((float)(m_RawHeader.HeaderSize + m_dwTotalBytesRead) / + (float)(m_RawHeader.RawDataSize + m_RawHeader.HeaderSize + m_RawHeader.PaletteSize))) * 100.0f); + } + else + { + *plPercentComplete = (LONG)((((float)m_dwTotalBytesRead/(float)m_dwTotalBytesToRead)) * 100.0f); + } + } + else + { + // We have no more data + hr = WIA_STATUS_END_OF_MEDIA; + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters")); + hr = E_INVALIDARG; + } + return hr; + } + + HRESULT Upload(_In_ BSTR bstrItemName, + ULONG ulTotalBytes, + _In_ IStream *pSourceStream, + __callback IWiaMiniDrvTransferCallback *pTransferCallback, + _Inout_ WiaTransferParams *pParams, + const CBasicStringWide &cswStoragePath) + { + // TBD: don't write to C:\TEMP\DATATRANSFERTEST, use actual storage item. + HRESULT hr = S_OK; + IStream *pDestination = NULL; + CBasicStringWide cswFileName = cswStoragePath; + cswFileName += L"\\"; + cswFileName += bstrItemName; + + // create stream on a file in the temporary directory (filename is bstrItemName) + hr = SHCreateStreamOnFile(cswFileName.String(),STGM_WRITE|STGM_CREATE,&pDestination); + if(SUCCEEDED(hr)) + { + // loop while reading data is availble from source stream + BYTE *pBuffer = (BYTE*)CoTaskMemAlloc(DEFAULT_BUFFER_SIZE); + if(pBuffer) + { + ULONG ulNumBytesRead = 0; + ULONG ulNumBytesWritten = 0; + ULONG ulTotalBytesWritten = 0; + + // + // Seek to the beginning of the stream before reading: + // + LARGE_INTEGER li = {0}; + hr = pSourceStream->Seek(li, STREAM_SEEK_SET, NULL); + if (FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Could not seek to stream start before during upload, hr = 0x%lx", hr)); + } + + while (SUCCEEDED(hr) && SUCCEEDED(pSourceStream->Read(pBuffer,DEFAULT_BUFFER_SIZE,&ulNumBytesRead)) && ulNumBytesRead) + { + // write the chunk + hr = pDestination->Write(pBuffer,ulNumBytesRead,&ulNumBytesWritten); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to write upload data to destination stream, hr = 0x%lx",hr)); + break; + } + + ulTotalBytesWritten += ulNumBytesWritten; + + LONG lPercentComplete = -1; + if(ulTotalBytes > 0) + { + lPercentComplete = (LONG)((((float)ulTotalBytesWritten/(float)ulTotalBytes)) * 100.0f); + } + // make callback + + pParams->lMessage = WIA_TRANSFER_MSG_STATUS; + pParams->lPercentComplete = lPercentComplete; + pParams->ulTransferredBytes = ulTotalBytesWritten; + + hr = pTransferCallback->SendMessage(0,pParams); + if(SUCCEEDED(hr)) + { + if(S_FALSE == hr) + { + WIAS_TRACE((g_hInst,"Application cancelled upload")); + break; + } + else if (S_OK != hr) + { + WIAS_ERROR((g_hInst, "SendMessage returned unknown Success value, hr = 0x%lx",hr)); + hr = E_UNEXPECTED; + break; + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to send status message to application. Upload aborted, hr = 0x%lx",hr)); + break; + } + } + + if(ulTotalBytesWritten == 0) + { + hr = E_FAIL; + WIAS_ERROR((g_hInst, "No data was written during upload, hr = 0x%lx",hr)); + } + + CoTaskMemFree(pBuffer); + pBuffer = NULL; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate buffer for upload, hr = 0x%lx",hr)); + } + + // TBD: decide on exact behavior for notifying clients. + + pDestination->Release(); + pDestination = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Failed to create destination stream on file %ws, hr = 0x%lx",cswFileName.String(),hr)); + } + return hr; + } + +public: + DWORD m_dwTotalBytesToRead; + WIA_RAW_HEADER m_RawHeader; + +private: + ULONG m_ulHeaderSize; + BITMAPFILEHEADER m_bmfh; + BITMAPINFOHEADER m_bmih; + DWORD m_dwTotalBytesRead; + DWORD m_dwLinesRead; + ULONG m_ulBytesPerLineBMP; + ULONG m_ulBytesPerLineRAW; + Bitmap *m_pBitmap; + BitmapData *m_pBitmapData; + BYTE *m_pBitmapBits; +}; + diff --git a/wia/wiadriverex/usd/basicarray.h b/wia/wiadriverex/usd/basicarray.h new file mode 100644 index 00000000..2c3f8a03 --- /dev/null +++ b/wia/wiadriverex/usd/basicarray.h @@ -0,0 +1,265 @@ +/******************************************************************************* + * + * (C) COPYRIGHT MICROSOFT CORPORATION, 1998 + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: Dynamic array template class + * + *******************************************************************************/ +#ifndef __SIMARRAY_H_INCLUDED +#define __SIMARRAY_H_INCLUDED + +template<class T> +class CBasicDynamicArray +{ +private: + int m_nSize; + int m_nMaxSize; + int m_nGrowSize; + T *m_pArray; + enum + { + eGrowSize = 10 // The number of items to add each time the array grows. + }; +public: + CBasicDynamicArray(void) + : m_nSize(0), + m_nMaxSize(0), + m_nGrowSize(eGrowSize), + m_pArray(NULL) + { + } + CBasicDynamicArray( int nInitialSize, int nGrowSize=0 ) + : m_nSize(0), + m_nMaxSize(0), + m_nGrowSize(nGrowSize ? nGrowSize : eGrowSize), + m_pArray(NULL) + { + GrowTo(nInitialSize); + } + CBasicDynamicArray( const CBasicDynamicArray<T> &other ) + : m_nSize(0), + m_nMaxSize(0), + m_nGrowSize(eGrowSize), + m_pArray(NULL) + { + Append(other); + } + virtual ~CBasicDynamicArray(void) + { + Destroy(); + } + CBasicDynamicArray &operator=( const CBasicDynamicArray &other ) + { + if (this != &other) + { + Destroy(); + Append(other); + } + return *this; + } + void Destroy(void) + { + if (m_pArray) + { + delete[] m_pArray; + m_pArray = NULL; + } + m_nSize = m_nMaxSize = 0; + } + void Append( const CBasicDynamicArray &other ) + { + if (GrowTo( m_nSize + other.Size() )) + { + for (int i=0;i<other.Size();i++) + { + Append(other[i]); + } + } + } + int Append( const T &element ) + { + if (GrowTo( m_nSize + 1 )) + { + m_pArray[m_nSize] = element; + int nResult = m_nSize; + m_nSize++; + return nResult; + } + else return -1; + } + int Insert( const T &element, int nIndex ) + { + // + // Make sure we can accomodate this new item + // + if (GrowTo( m_nSize + 1 )) + { + // + // Make sure the item is within the range we've allocated + // + if (nIndex >= 0 && nIndex <= m_nSize) + { + // + // Make room for the new item by moving all items above up by one slot + // + for (int i=Size();i>nIndex;i--) + { + m_pArray[i] = m_pArray[i-1]; + } + + // + // Save the new item + // + m_pArray[nIndex] = element; + + // + // We're now one larger + // + m_nSize++; + + // + // Return the index of the slot we used + // + return nIndex; + } + } + + // + // Return an error + // + return -1; + } + void Delete( int nItem ) + { + if (nItem >= 0 && nItem < m_nSize && m_pArray) + { + T *pTmpArray = new T[m_nMaxSize]; + if (pTmpArray) + { + T *pSrc, *pTgt; + pSrc = m_pArray; + pTgt = pTmpArray; + for (int i=0;i<m_nSize;i++) + { + if (i != nItem) + { + *pTgt = *pSrc; + pTgt++; + } + pSrc++; + } + delete[] m_pArray; + m_pArray = pTmpArray; + m_nSize--; + } + } + } + bool GrowTo( int nSize ) + { + // + // If the array is already large enough, just return true + // + if (nSize < m_nMaxSize) + { + return true; + } + + // + // Save old size, in case we can't allocate a new array + // + int nOldMaxSize = m_nMaxSize; + + // + // Find the correct size to grow to + // + while (m_nMaxSize < nSize) + { + m_nMaxSize += m_nGrowSize; + } + + // + // Allocate the array + // + T *pTmpArray = new T[m_nMaxSize]; + if (pTmpArray) + { + // + // Copy the old array over + // + for (int i=0;i<m_nSize;i++) + { + pTmpArray[i] = m_pArray[i]; + } + + // + // Delete the old array + // + if (m_pArray) + { + delete[] m_pArray; + } + + // + // Assign the new array to the old one and return true + // + m_pArray = pTmpArray; + return true; + } + else + { + // + // If we couldn't allocate the new array, restore the maximum size + // and return false + // + m_nMaxSize = nOldMaxSize; + return false; + } + } + + // + // Simple swap + // + void Swap( T &a, T &b ) + { + T t = a; + a = b; + b = t; + } + + int Find( const T& element ) const + { + for (int i=0;i<m_nSize;i++) + { + if (m_pArray[i] == element) + { + return i; + } + } + return -1; + } + bool operator==( const CBasicDynamicArray &other ) + { + if (Size() != other.Size()) + return false; + for (int i=0;i<Size();i++) + if (!(m_pArray[i] == other[i])) + return false; + return true; + } + bool Contains( const T& element ) { return(Find(element) >= 0);} + void Size( int nSize ) { m_nSize = nSize;} + void MaxSize( int nMaxSize ) { m_nMaxSize = nMaxSize;} + void GrowSize( int nGrowSize ) { m_nGrowSize = nGrowSize;} + int Size(void) const { return m_nSize;} + int MaxSize(void) const { return m_nMaxSize;} + int GrowSize(void) const { return m_nGrowSize;} + T *GetBuffer( int nSize ) { return GrowTo(nSize) ? m_pArray : NULL;} + const T *Array(void) const { return m_pArray;} + const T &operator[](int nIndex) const { return m_pArray[nIndex];} + T &operator[](int nIndex) { return m_pArray[nIndex];} +}; + +#endif + diff --git a/wia/wiadriverex/usd/basicstr.h b/wia/wiadriverex/usd/basicstr.h new file mode 100644 index 00000000..64e7c25c --- /dev/null +++ b/wia/wiadriverex/usd/basicstr.h @@ -0,0 +1,1378 @@ +/******************************************************************************* +* +* (C) COPYRIGHT MICROSOFT CORPORATION, 1998 +* +* Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. +* +* DESCRIPTION: Simple string classes +* +*******************************************************************************/ +#ifndef _SIMSTR_H_INCLUDED +#define _SIMSTR_H_INCLUDED + +/* +* Simple string class. +* +* Template class: +* CBasicStringBase<CharType> +* Implementations: +* CBasicStringBase<wchar_t> CBasicStringWide +* CBasicStringBase<char> CBasicStringAnsi +* CBasicString = CBasicString[Ansi|Wide] depending on UNICODE macro +* Inline functions: +* CBasicStringAnsi CBasicStringConvert::AnsiString(CharType n) +* CBasicStringWide CBasicStringConvert::WideString(CharType n) +* Macros: +* IS_CHAR(CharType) +* IS_WCHAR(CharType) +*/ + +#include <windows.h> +#include <stdarg.h> +#include <stdio.h> +#include <tchar.h> +#include <strsafe.h> + +// +// Disable the "conditional expression is constant" warning that is caused by +// the IS_CHAR and IS_WCHAR macros +// +#pragma warning( push ) +#pragma warning( disable : 4127 ) + +#define IS_CHAR(x) (sizeof(x) & sizeof(char)) +#define IS_WCHAR(x) (sizeof(x) & sizeof(wchar_t)) + +#ifndef ARRAYSIZE + #define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +template <class CharType> +class CBasicStringBase +{ +private: + enum + { + c_nDefaultGranularity = 16, // Default number of extra characters to allocate when we have to grow + c_nInitialLoadStringBuffer = 1024, // Initial length of .RC string + c_nMaxAutoDataLength = 128 // Length of non-dynamically allocated string + }; + +private: + // + // If the string is less than c_nMaxAutoDataLength characters, it will be + // stored here, instead of in a dynamically allocated buffer + // + CharType m_pstrAutoData[c_nMaxAutoDataLength]; + + // + // If we have to allocate data, it will be stored here + // + CharType *m_pstrData; + + // + // Current maximum buffer size + // + size_t m_nMaxSize; + + // + // Amount of extra space we allocate when we have to grow the buffer + // + size_t m_nGranularity; + + // + // Error flag. This is set if an allocation fails. + // + bool m_bError; + +private: + + // + // Min, in case it isn't already defined + // + template <class NumberType> + static NumberType Min( const NumberType &a, const NumberType &b ) + { + return (a < b) ? a : b; + } + +private: + + // + // Replacements (in some cases just wrappers) for strlen, strcpy, ... + // + static inline CharType *GenericCopyLength( CharType *pstrTarget, const CharType *pstrSource, size_t nSize ); + static inline size_t GenericLength( const CharType *pstrStr ); + static inline CharType *GenericConcatenate( CharType *pstrTarget, const CharType *pstrSource ); + static inline int GenericCompare( const CharType *pstrTarget, const CharType *pstrSource ); + static inline int GenericCompareNoCase( const CharType *pstrStrA, const CharType *pstrStrB ); + static inline int GenericCompareLength( const CharType *pstrTarget, const CharType *pstrSource, size_t cchLength ); + static inline LPSTR GenericCharNext( LPCSTR ); + static inline LPWSTR GenericCharNext( LPCWSTR ); + +private: + // + // Internal only helpers + // + bool EnsureLength( size_t nMaxSize ); + void DeleteStorage(); + CharType *CreateStorage( size_t nCount, size_t &nAllocated ); + void Destroy(); + +public: + // + // Constructors and destructor + // + CBasicStringBase(); + CBasicStringBase( const CBasicStringBase & ); + CBasicStringBase( const CharType *szStr ); + CBasicStringBase( CharType ch ); + CBasicStringBase( UINT nResId, HMODULE hModule ); + virtual ~CBasicStringBase(); + + // + // String state + // + bool OK() const + { + return (!Error() && String()); + } + bool IsValid() const + { + return (String() != NULL); + } + bool Error() const + { + return m_bError; + } + HRESULT Status() const + { + return OK() ? S_OK : E_OUTOFMEMORY; + } + void ClearError() + { + m_bError = false; + } + +private: + void PropagateError( const CBasicStringBase &other ) + { + if (!Error() && other.Error()) + { + m_bError = true; + } + } + +public: +#if defined(SIMSTR_UNIT_TEST) + bool m_bForceError; + void ForceError( bool bForceError ) { m_bForceError = bForceError; } +#endif + + // + // Various helpers + // + size_t Length() const; + void Concat( const CBasicStringBase &other ); + bool Assign( const CharType *szStr ); + bool Assign( const CBasicStringBase & ); + void SetAt( size_t nIndex, CharType chValue ); + CharType GetAt( size_t nIndex ) const; + CharType &operator[](int index); + const CharType &operator[](int index) const; + + // + // Handy Win32 wrappers + // + CBasicStringBase &Format( const CharType *strFmt, ... ); + CBasicStringBase &Format( int nResId, HINSTANCE hInst, ... ); + bool LoadString( UINT nResId, HMODULE hModule ); + + // + // Operators + // + CBasicStringBase &operator=( const CBasicStringBase &other ); + CBasicStringBase &operator=( const CharType *other ); + CBasicStringBase &operator+=( const CBasicStringBase &other ); + + + // + // Convert this string and return the converted string + // + CBasicStringBase ToUpper() const; + CBasicStringBase ToLower() const; + + // + // Convert in place + // + CBasicStringBase &MakeUpper(); + CBasicStringBase &MakeLower(); + + // + // Remove leading and trailing spaces + // + CBasicStringBase &TrimRight(); + CBasicStringBase &TrimLeft(); + CBasicStringBase &Trim(); + + // + // Searching + // + int Find( CharType cChar ) const; + int Find( const CBasicStringBase &other, size_t nStart=0 ) const; + int ReverseFind( CharType cChar ) const; + int ReverseFind( const CBasicStringBase &other ) const; + + // + // Substring copies + // + CBasicStringBase SubStr( size_t nStart, size_t nCount ) const; + CBasicStringBase SubStr( size_t nStart ) const; + + CBasicStringBase Left( size_t nCount ) const + { + return SubStr( 0, (int)nCount ); + } + CBasicStringBase Right( size_t nCount ) const + { + return SubStr( Length()-nCount ); + } + + // + // Comparison functions + // + int CompareNoCase( const CBasicStringBase &other, int cchLength=-1 ) const; + int Compare( const CBasicStringBase &other, int cchLength=-1 ) const; + + // + // Direct manipulation + // + CharType *GetBuffer( size_t cchLength ) + { + // + // If we are able to allocate a string of the + // requested length, return a pointer to the actual data. + // + return EnsureLength(cchLength+1) ? m_pstrData : NULL; + } + + // + // Useful inlines + // + const CharType *String() const + { + return m_pstrData; + } + size_t MaxSize() const + { + return m_nMaxSize; + } + size_t Granularity( size_t nGranularity ) + { + if (nGranularity>0) + { + m_nGranularity = nGranularity; + } + return m_nGranularity; + } + size_t Granularity() const + { + return m_nGranularity; + } + + // + // Implicit cast operator + // + operator const CharType *() const + { + return String(); + } + + friend class CBasicStringBase; +}; + +template <> +inline LPSTR CBasicStringBase<CHAR>::GenericCharNext( LPCSTR pszStr ) +{ + if (!pszStr) + { + return NULL; + } + return CharNextA(pszStr); +} + +template <> +inline LPWSTR CBasicStringBase<WCHAR>::GenericCharNext( LPCWSTR pszStr ) +{ + if (!pszStr) + { + return NULL; + } + return CharNextW(pszStr); +} + +template <class CharType> +inline CharType *CBasicStringBase<CharType>::GenericCopyLength( CharType *pszTarget, const CharType *pszSource, size_t nCount ) +{ + if (!pszTarget || !pszSource) + { + return NULL; + } + + size_t nCopyLen = min( nCount, GenericLength(pszSource) + 1 ); + if (0 == nCopyLen) + { + return pszTarget; + } + + CopyMemory( pszTarget, pszSource, nCopyLen * sizeof(CharType) ); + pszTarget[nCopyLen-1] = 0; + return pszTarget; +} + +template <> +inline size_t CBasicStringBase<CHAR>::GenericLength( LPCSTR pszString ) +{ + if (!pszString) + { + return 0; + } + + size_t nSize = 0; + if (S_OK != StringCchLengthA( pszString, STRSAFE_MAX_CCH, &nSize )) + { + return 0; + } + + return nSize; +} + +template <> +inline size_t CBasicStringBase<WCHAR>::GenericLength( LPCWSTR pszString ) +{ + if (!pszString) + { + return 0; + } + + size_t nSize = 0; + if (S_OK != StringCchLengthW( pszString, STRSAFE_MAX_CCH, &nSize )) + { + return 0; + } + + return nSize; +} + +template <class CharType> +inline CharType*CBasicStringBase<CharType>::GenericConcatenate( CharType *pszTarget, const CharType *pszSource ) +{ + if (!pszTarget || !pszSource) + { + return NULL; + } + + CharType *pszCurr = pszTarget; + + while (*pszCurr) + { + pszCurr++; + } + + CopyMemory( pszCurr, pszSource, sizeof(CharType) * (GenericLength(pszSource) + 1) ); + + return pszTarget; +} + + +template <class CharType> +inline int CBasicStringBase<CharType>::GenericCompare( const CharType *pszSource, const CharType *pszTarget ) +{ +#if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE) + if (sizeof(CharType) == sizeof(wchar_t)) + { + OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!")); + } +#endif + int nRes = IS_CHAR(*pszSource) ? + CompareStringA( LOCALE_USER_DEFAULT, 0, (LPCSTR)pszSource, -1, (LPCSTR)pszTarget, -1 ) : + CompareStringW( LOCALE_USER_DEFAULT, 0, (LPCWSTR)pszSource, -1, (LPCWSTR)pszTarget, -1 ); + switch (nRes) + { + case CSTR_LESS_THAN: + return -1; + case CSTR_GREATER_THAN: + return 1; + default: + return 0; + } +} + + + +template <class CharType> +inline int CBasicStringBase<CharType>::GenericCompareNoCase( const CharType *pszSource, const CharType *pszTarget ) +{ +#if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE) + if (sizeof(CharType) == sizeof(wchar_t)) + { + OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!")); + } +#endif + int nRes = IS_CHAR(*pszSource) ? + CompareStringA( LOCALE_USER_DEFAULT, NORM_IGNORECASE, (LPCSTR)pszSource, -1, (LPCSTR)pszTarget, -1 ) : + CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE, (LPCWSTR)pszSource, -1, (LPCWSTR)pszTarget, -1 ); + switch (nRes) + { + case CSTR_LESS_THAN: + return -1; + case CSTR_GREATER_THAN: + return 1; + default: + return 0; + } +} + +template <class CharType> +inline int CBasicStringBase<CharType>::GenericCompareLength( const CharType *pszStringA, const CharType *pszStringB, size_t cchLength ) +{ +#if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE) + if (sizeof(CharType) == sizeof(wchar_t)) + { + OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!")); + } +#endif + if (!cchLength) + return(0); + int nRes = IS_CHAR(*pszStringA) ? + CompareStringA( LOCALE_USER_DEFAULT, 0, (LPCSTR)pszStringA, (int)Min(cchLength,CBasicStringBase<CHAR>::GenericLength((LPCSTR)pszStringA)), (LPCSTR)pszStringB, (int)Min(cchLength,CBasicStringBase<CHAR>::GenericLength((LPCSTR)pszStringB)) ) : + CompareStringW( LOCALE_USER_DEFAULT, 0, (LPWSTR)pszStringA, (int)Min(cchLength,CBasicStringBase<WCHAR>::GenericLength((LPCWSTR)pszStringA)), (LPCWSTR)pszStringB, (int)Min(cchLength,CBasicStringBase<WCHAR>::GenericLength((LPCWSTR)pszStringB)) ); + switch (nRes) + { + case CSTR_LESS_THAN: + return -1; + case CSTR_GREATER_THAN: + return 1; + default: + return 0; + } +} + +template <class CharType> +bool CBasicStringBase<CharType>::EnsureLength( size_t nMaxSize ) +{ + // + // If the string is already long enough, just return true + // + if (m_nMaxSize >= nMaxSize) + { + return true; + } + + // Get the new size + // + size_t nNewMaxSize = nMaxSize + m_nGranularity; + + // + // Allocate the new buffer + // + size_t nAllocated = 0; + CharType *pszTmp = CreateStorage(nNewMaxSize,nAllocated); + + // + // Make sure the allocation succeeded + // + if (pszTmp) + { + // + // If we have an existing string, copy it and delete it + // + if (m_pstrData) + { + GenericCopyLength( pszTmp, m_pstrData, Length()+1 ); + DeleteStorage(); + } + + // + // Save the new max size + // + m_nMaxSize = nAllocated; + + // + // Save this new string + // + m_pstrData = pszTmp; + + // + // Return success + // + return true; + } + + // + // Couldn't allocate memory + // + return false; +} + +template <class CharType> +CBasicStringBase<CharType>::CBasicStringBase() + : m_pstrData(m_pstrAutoData), + m_nMaxSize(ARRAYSIZE(m_pstrAutoData)), + m_nGranularity(c_nDefaultGranularity), + m_bError(false) +{ +#if defined(SIMSTR_UNIT_TEST) + m_bForceError = false; +#endif + m_pstrAutoData[0] = 0; +} + +template <class CharType> +CBasicStringBase<CharType>::CBasicStringBase( const CBasicStringBase &other ) + : m_pstrData(m_pstrAutoData), + m_nMaxSize(ARRAYSIZE(m_pstrAutoData)), + m_nGranularity(c_nDefaultGranularity), + m_bError(false) +{ +#if defined(SIMSTR_UNIT_TEST) + m_bForceError = false; +#endif + m_pstrAutoData[0] = 0; + Assign(other); +} + +template <class CharType> +CBasicStringBase<CharType>::CBasicStringBase( const CharType *szStr ) + : m_pstrData(m_pstrAutoData), + m_nMaxSize(ARRAYSIZE(m_pstrAutoData)), + m_nGranularity(c_nDefaultGranularity), + m_bError(false) +{ +#if defined(SIMSTR_UNIT_TEST) + m_bForceError = false; +#endif + m_pstrAutoData[0] = 0; + Assign(szStr); +} + +template <class CharType> +CBasicStringBase<CharType>::CBasicStringBase( CharType ch ) + : m_pstrData(m_pstrAutoData), + m_nMaxSize(ARRAYSIZE(m_pstrAutoData)), + m_nGranularity(c_nDefaultGranularity), + m_bError(false) +{ +#if defined(SIMSTR_UNIT_TEST) + m_bForceError = false; +#endif + m_pstrAutoData[0] = 0; + CharType szTmp[2]; + szTmp[0] = ch; + szTmp[1] = 0; + Assign(szTmp); +} + + +template <class CharType> +CBasicStringBase<CharType>::CBasicStringBase( UINT nResId, HMODULE hModule ) + : m_pstrData(m_pstrAutoData), + m_nMaxSize(ARRAYSIZE(m_pstrAutoData)), + m_nGranularity(c_nDefaultGranularity), + m_bError(false) +{ +#if defined(SIMSTR_UNIT_TEST) + m_bForceError = false; +#endif + m_pstrAutoData[0] = 0; + LoadString( nResId, hModule ); +} + +template <> +inline CBasicStringBase<WCHAR> &CBasicStringBase<WCHAR>::Format( const WCHAR *strFmt, ... ) +{ + // + // Initialize the string + // + Assign(NULL); + + // + // Prepare the argument list + // + va_list ArgList; + va_start( ArgList, strFmt ); + + // + // How many characters do we need? + // + int cchLength = _vscwprintf( strFmt, ArgList ); + + // + // Make sure we have a valid length + // + if (cchLength >= 0) + { + // + // Get a pointer to the buffer + // + LPWSTR pszBuffer = GetBuffer(cchLength + 1); + if (pszBuffer) + { + // + // Print the string + // + StringCchVPrintfW( pszBuffer, cchLength + 1, strFmt, ArgList ); + } + } + + // + // Done with the argument list + // + va_end( ArgList ); + return *this; +} + +template <> +inline CBasicStringBase<CHAR> &CBasicStringBase<CHAR>::Format( const CHAR *strFmt, ... ) +{ + // + // Initialize the string + // + Assign(NULL); + + // + // Prepare the argument list + // + va_list ArgList; + va_start( ArgList, strFmt ); + + // + // How many characters do we need? + // + int cchLength = _vscprintf( strFmt, ArgList ); + + // + // Make sure we have a valid length + // + if (cchLength >= 0) + { + // + // Get a pointer to the buffer + // + LPSTR pszBuffer = GetBuffer(cchLength + 1); + if (pszBuffer) + { + // + // Print the string + // + StringCchVPrintfA( pszBuffer, cchLength + 1, strFmt, ArgList ); + } + } + + // + // Done with the argument list + // + va_end( ArgList ); + return *this; +} + +template <> +inline CBasicStringBase<WCHAR> &CBasicStringBase<WCHAR>::Format( int nResId, HINSTANCE hInst, ... ) +{ + // + // Initialize the string + // + Assign(NULL); + + // + // Load the format string + // + CBasicStringBase<WCHAR> strFmt; + if (strFmt.LoadString( nResId, hInst )) + { + // + // Prepare the argument list + // + va_list ArgList; + va_start( ArgList, hInst ); + + // + // How many characters do we need? + // + int cchLength = _vscwprintf( strFmt, ArgList ); + + // + // Make sure we have a valid length + // + if (cchLength >= 0) + { + // + // Get a pointer to the buffer + // + LPWSTR pszBuffer = GetBuffer(cchLength + 1); + if (pszBuffer) + { + // + // Print the string + // + StringCchVPrintfW( pszBuffer, cchLength + 1, strFmt, ArgList ); + } + } + + // + // Done with the argument list + // + va_end( ArgList ); + } + return *this; +} + +template <> +inline CBasicStringBase<CHAR> &CBasicStringBase<CHAR>::Format( int nResId, HINSTANCE hInst, ... ) +{ + // + // Initialize the string + // + Assign(NULL); + + // + // Load the format string + // + CBasicStringBase<CHAR> strFmt; + if (strFmt.LoadString(nResId,hInst)) + { + // + // Prepare the argument list + // + va_list ArgList; + va_start( ArgList, hInst ); + + // + // How many characters do we need? + // + int cchLength = _vscprintf( strFmt, ArgList ); + + // + // Make sure we have a valid length + // + if (cchLength >= 0) + { + // + // Get a pointer to the buffer + // + LPSTR pszBuffer = GetBuffer(cchLength + 1); + if (pszBuffer) + { + // + // Print the string + // + StringCchVPrintfA( pszBuffer, cchLength + 1, strFmt, ArgList ); + } + } + + // + // Done with the argument list + // + va_end(ArgList); + } + return *this; +} + + +template <> +inline bool CBasicStringBase<CHAR>::LoadString( UINT nResId, HMODULE hModule ) +{ + // + // Assume failure + // + bool bResult = false; + + // + // Initialize the current string + // + Assign(NULL); + + // + // If no hmodule was provided, use the current EXE's + // + if (!hModule) + { + hModule = GetModuleHandle(NULL); + } + + // + // Loop through, doubling the size of the string, until we get to 64K + // + for (int nSize = c_nInitialLoadStringBuffer;nSize < 0x0000FFFF; nSize <<= 1 ) + { + // + // Get a buffer to hold the string + // + LPSTR pszBuffer = GetBuffer(nSize); + + // + // If we can't get a buffer, exit the loop + // + if (!pszBuffer) + { + break; + } + + // + // Make sure the string is NULL terminated. + // + *pszBuffer = '\0'; + + // + // Attempt to load the string + // + #pragma prefast(suppress:__WARNING_ANSI_APICALL, "Replace with LoadStringW if using for WCHAR; this instance is for CHAR; see CBasicStringBase<WCHAR>::LoadString below" + int nResult = ::LoadStringA( hModule, nResId, pszBuffer, nSize ); + + // + // If the buffer was long enough, exit the loop, and set the success flag + // + if (nResult < (nSize - 1)) + { + bResult = true; + break; + } + + // + // If it was unsuccessful, exit the loop + // + if (!nResult) + { + break; + } + } + return bResult; +} + +template <> +inline bool CBasicStringBase<WCHAR>::LoadString( UINT nResId, HMODULE hModule ) +{ + // + // Assume failure + // + bool bResult = false; + + // + // Initialize the current string + // + Assign(NULL); + + // + // If no hmodule was provided, use the current EXE's + // + if (!hModule) + { + hModule = GetModuleHandle(NULL); + } + + // + // Loop through, doubling the size of the string, until we get to 64K + // + for (int nSize = c_nInitialLoadStringBuffer;nSize < 0x0000FFFF; nSize <<= 1 ) + { + // + // Get a buffer to hold the string + // + LPWSTR pszBuffer = GetBuffer(nSize); + + // + // If we can't get a buffer, exit the loop + // + if (!pszBuffer) + { + break; + } + + // + // Make sure the string is NULL terminated. + // + *pszBuffer = L'\0'; + + // + // Attempt to load the string + // + int nResult = ::LoadStringW( hModule, nResId, pszBuffer, nSize ); + + // + // If the buffer was long enough, exit the loop, and set the success flag + // + if (nResult < (nSize - 1)) + { + bResult = true; + break; + } + + // + // If it was unsuccessful, exit the loop + // + if (!nResult) + { + break; + } + } + return bResult; +} + + +template <class CharType> +CBasicStringBase<CharType>::~CBasicStringBase() +{ + Destroy(); +} + +template <class CharType> +void CBasicStringBase<CharType>::DeleteStorage() +{ + // + // Only delete the string if it is non-NULL and not pointing to our non-dynamically allocated buffer + // + if (m_pstrData && m_pstrData != m_pstrAutoData) + { + delete[] m_pstrData; + } + m_pstrData = NULL; +} + +template <class CharType> +CharType *CBasicStringBase<CharType>::CreateStorage( size_t nCount, size_t &nAllocated ) +{ +#if defined(SIMSTR_UNIT_TEST) + if (m_bForceError) + { + m_bError = true; + return NULL; + } +#endif + + CharType *pResult = NULL; + nAllocated = 0; + + // + // If we are currently pointing to our fixed buffer, or the requested + // size is greater than our fixed-length buffer, allocate using new. + // Otherwise, return the address of our fixed-length buffer. + // + if (m_pstrData == m_pstrAutoData || nCount > ARRAYSIZE(m_pstrAutoData)) + { + pResult = new CharType[nCount]; + if (pResult) + { + nAllocated = nCount; + } + } + else + { + pResult = m_pstrAutoData; + nAllocated = ARRAYSIZE(m_pstrAutoData); + } + if (!pResult) + { + m_bError = true; + } + + return pResult; +} + +template <class CharType> +void CBasicStringBase<CharType>::Destroy() +{ + DeleteStorage(); + m_nMaxSize = 0; +} + +template <class CharType> +size_t CBasicStringBase<CharType>::Length() const +{ + return(m_pstrData ? GenericLength(m_pstrData) : 0); +} + +template <class CharType> +CBasicStringBase<CharType> &CBasicStringBase<CharType>::operator=( const CBasicStringBase &other ) +{ + if (&other != this) + { + Assign(other); + } + return *this; +} + +template <class CharType> +CBasicStringBase<CharType> &CBasicStringBase<CharType>::operator=( const CharType *other ) +{ + if (other != String()) + { + Assign(other); + } + return *this; +} + +template <class CharType> +CBasicStringBase<CharType> &CBasicStringBase<CharType>::operator+=( const CBasicStringBase &other ) +{ + Concat(other.String()); + + return *this; +} + +template <class CharType> +bool CBasicStringBase<CharType>::Assign( const CharType *szStr ) +{ + if (szStr && EnsureLength(GenericLength(szStr)+1)) + { + GenericCopyLength(m_pstrData,szStr,GenericLength(szStr)+1); + } + else if (EnsureLength(1)) + { + *m_pstrData = 0; + } + else Destroy(); + return OK(); +} + +template <class CharType> +bool CBasicStringBase<CharType>::Assign( const CBasicStringBase &other ) +{ + Assign( other.String() ); + + PropagateError( other ); + + return OK(); +} + +template <class CharType> +void CBasicStringBase<CharType>::SetAt( size_t nIndex, CharType chValue ) +{ + // + // Make sure we don't go off the end of the string or overwrite the '\0' + // + if (Length() > nIndex) + { + m_pstrData[nIndex] = chValue; + } +} + + +template <class CharType> +CharType CBasicStringBase<CharType>::GetAt( size_t nIndex ) const +{ + return m_pstrData[nIndex]; +} + + +template <class CharType> +void CBasicStringBase<CharType>::Concat( const CBasicStringBase &other ) +{ + if (EnsureLength( Length() + other.Length() + 1 )) + { + GenericConcatenate( m_pstrData, other.String() ); + + PropagateError( other ); + } +} + +template <class CharType> +CBasicStringBase<CharType> &CBasicStringBase<CharType>::MakeUpper() +{ + // + // Make sure the string is not NULL + // + if (m_pstrData) + { + IS_CHAR(*m_pstrData) ? CharUpperBuffA( (LPSTR)m_pstrData, (DWORD)Length() ) : CharUpperBuffW( (LPWSTR)m_pstrData, (DWORD)Length() ); + } + return *this; +} + +template <class CharType> +CBasicStringBase<CharType> &CBasicStringBase<CharType>::MakeLower() +{ + // + // Make sure the string is not NULL + // + if (m_pstrData) + { + IS_CHAR(*m_pstrData) ? CharLowerBuffA( (LPSTR)m_pstrData, (DWORD)Length() ) : CharLowerBuffW( (LPWSTR)m_pstrData, (DWORD)Length() ); + } + return *this; +} + +template <class CharType> +CBasicStringBase<CharType> CBasicStringBase<CharType>::ToUpper() const +{ + CBasicStringBase str(*this); + str.MakeUpper(); + return str; +} + +template <class CharType> +CBasicStringBase<CharType> CBasicStringBase<CharType>::ToLower() const +{ + CBasicStringBase str(*this); + str.MakeLower(); + return str; +} + +template <class CharType> +CharType &CBasicStringBase<CharType>::operator[](int nIndex) +{ + return m_pstrData[nIndex]; +} + +template <class CharType> +const CharType &CBasicStringBase<CharType>::operator[](int index) const +{ + return m_pstrData[index]; +} + +template <class CharType> +int CBasicStringBase<CharType>::Find( CharType cChar ) const +{ + CharType strTemp[2] = { cChar, 0}; + return Find(strTemp); +} + + +template <class CharType> +int CBasicStringBase<CharType>::Find( const CBasicStringBase &other, size_t nStart ) const +{ + if (!m_pstrData) + return -1; + if (nStart > Length()) + return -1; + CharType *pstrCurr = m_pstrData+nStart, *pstrSrc, *pstrSubStr; + while (*pstrCurr) + { + pstrSrc = pstrCurr; + pstrSubStr = (CharType *)other.String(); + while (*pstrSrc && *pstrSubStr && *pstrSrc == *pstrSubStr) + { + pstrSrc = GenericCharNext(pstrSrc); + pstrSubStr = GenericCharNext(pstrSubStr); + } + if (!*pstrSubStr) + return static_cast<int>(pstrCurr-m_pstrData); + pstrCurr = GenericCharNext(pstrCurr); + } + return -1; +} + +template <class CharType> +int CBasicStringBase<CharType>::ReverseFind( CharType cChar ) const +{ + CharType strTemp[2] = { cChar, 0}; + return ReverseFind(strTemp); +} + +template <class CharType> +int CBasicStringBase<CharType>::ReverseFind( const CBasicStringBase &srcStr ) const +{ + int nLastFind = -1, nFind=0; + while ((nFind = Find( srcStr, nFind )) >= 0) + { + nLastFind = nFind; + ++nFind; + } + return nLastFind; +} + +template <class CharType> +CBasicStringBase<CharType> CBasicStringBase<CharType>::SubStr( size_t nStart, size_t nCount ) const +{ + if (nStart >= Length()) + { + return CBasicStringBase<CharType>(); + } + + nCount = min( Length(), nCount ); + + CBasicStringBase<CharType> strResult; + CharType *pszBuffer = strResult.GetBuffer(nCount); + if (pszBuffer) + { + GenericCopyLength( pszBuffer, m_pstrData+nStart, nCount+1 ); + } + return strResult; +} + +template <class CharType> +CBasicStringBase<CharType> CBasicStringBase<CharType>::SubStr( size_t nStart ) const +{ + return SubStr( nStart, Length() - nStart ); +} + + +template <class CharType> +int CBasicStringBase<CharType>::CompareNoCase( const CBasicStringBase &other, int cchLength ) const +{ + if (cchLength < 0) + { + // + // Make sure both strings are non-NULL + // + if (!String() && !other.String()) + { + return 0; + } + else if (!String()) + { + return -1; + } + else if (!other.String()) + { + return 1; + } + else return GenericCompareNoCase(m_pstrData,other.String()); + } + CBasicStringBase<CharType> strSrc(*this); + CBasicStringBase<CharType> strTgt(other); + strSrc.MakeUpper(); + strTgt.MakeUpper(); + // + // Make sure both strings are non-NULL + // + if (!strSrc.String() && !strTgt.String()) + { + return 0; + } + else if (!strSrc.String()) + { + return -1; + } + else if (!strTgt.String()) + { + return 1; + } + else return GenericCompareLength(strSrc.String(),strTgt.String(),cchLength); +} + + +template <class CharType> +int CBasicStringBase<CharType>::Compare( const CBasicStringBase &other, int cchLength ) const +{ + // + // Make sure both strings are non-NULL + // + if (!String() && !other.String()) + { + return 0; + } + else if (!String()) + { + return -1; + } + else if (!other.String()) + { + return 1; + } + + if (cchLength < 0) + { + return GenericCompare(String(),other.String()); + } + return GenericCompareLength(String(),other.String(),cchLength); +} + +// +// Two main typedefs +// +typedef CBasicStringBase<char> CBasicStringAnsi; +typedef CBasicStringBase<wchar_t> CBasicStringWide; + +// +// LPCTSTR equivalents +// +#if defined(UNICODE) || defined(_UNICODE) +typedef CBasicStringWide CBasicString; +#else +typedef CBasicStringAnsi CBasicString; +#endif + +// +// Operators +// +inline bool operator<( const CBasicStringAnsi &a, const CBasicStringAnsi &b ) +{ + return a.Compare(b) < 0; +} + +inline bool operator<( const CBasicStringWide &a, const CBasicStringWide &b ) +{ + return a.Compare(b) < 0; +} + +inline bool operator<=( const CBasicStringAnsi &a, const CBasicStringAnsi &b ) +{ + return a.Compare(b) <= 0; +} + +inline bool operator<=( const CBasicStringWide &a, const CBasicStringWide &b ) +{ + return a.Compare(b) <= 0; +} + +inline bool operator==( const CBasicStringAnsi &a, const CBasicStringAnsi &b ) +{ + return a.Compare(b) == 0; +} + +inline bool operator==( const CBasicStringWide &a, const CBasicStringWide &b ) +{ + return a.Compare(b) == 0; +} + +inline bool operator!=( const CBasicStringAnsi &a, const CBasicStringAnsi &b ) +{ + return a.Compare(b) != 0; +} + +inline bool operator!=( const CBasicStringWide &a, const CBasicStringWide &b ) +{ + return a.Compare(b) != 0; +} + +inline bool operator>=( const CBasicStringAnsi &a, const CBasicStringAnsi &b ) +{ + return a.Compare(b) >= 0; +} + +inline bool operator>=( const CBasicStringWide &a, const CBasicStringWide &b ) +{ + return a.Compare(b) >= 0; +} + +inline bool operator>( const CBasicStringAnsi &a, const CBasicStringAnsi &b ) +{ + return a.Compare(b) > 0; +} + +inline bool operator>( const CBasicStringWide &a, const CBasicStringWide &b ) +{ + return a.Compare(b) > 0; +} + +inline CBasicStringWide operator+( const CBasicStringWide &a, const CBasicStringWide &b ) +{ + CBasicStringWide strResult(a); + strResult.Concat(b); + return strResult; +} + +inline CBasicStringAnsi operator+( const CBasicStringAnsi &a, const CBasicStringAnsi &b ) +{ + CBasicStringAnsi strResult(a); + strResult.Concat(b); + return strResult; +} + +// +// Restore the warning state +// +#pragma warning( pop ) + +#endif // ifndef _SIMSTR_H_INCLUDED + diff --git a/wia/wiadriverex/usd/feeder.bmp b/wia/wiadriverex/usd/feeder.bmp Binary files differnew file mode 100644 index 00000000..37b4d9a9 --- /dev/null +++ b/wia/wiadriverex/usd/feeder.bmp diff --git a/wia/wiadriverex/usd/film.bmp b/wia/wiadriverex/usd/film.bmp Binary files differnew file mode 100644 index 00000000..0cee26ce --- /dev/null +++ b/wia/wiadriverex/usd/film.bmp diff --git a/wia/wiadriverex/usd/flatbed.bmp b/wia/wiadriverex/usd/flatbed.bmp Binary files differnew file mode 100644 index 00000000..1d3c4db6 --- /dev/null +++ b/wia/wiadriverex/usd/flatbed.bmp diff --git a/wia/wiadriverex/usd/resource.h b/wia/wiadriverex/usd/resource.h new file mode 100644 index 00000000..82f0e6e6 --- /dev/null +++ b/wia/wiadriverex/usd/resource.h @@ -0,0 +1,16 @@ +#pragma once + +#define IDB_FLATBED 100 +#define IDB_FEEDER 101 +#define IDB_FILM 102 +#define IDS_EVENT_DEVICE_CONNECTED_NAME 200 +#define IDS_EVENT_DEVICE_DISCONNECTED_NAME 201 +#define IDS_EVENT_DEVICE_CONNECTED_DESCRIPTION 202 +#define IDS_EVENT_DEVICE_DISCONNECTED_DESCRIPTION 203 +#define IDS_EVENT_TREE_UPDATED_NAME 204 +#define IDS_EVENT_TREE_UPDATED_DESCRIPTION 205 +#define IDS_CMD_SYNCHRONIZE_NAME 206 +#define IDS_CMD_SYNCHRONIZE_DESCRIPTION 207 + + + diff --git a/wia/wiadriverex/usd/stdafx.h b/wia/wiadriverex/usd/stdafx.h new file mode 100644 index 00000000..6b307db2 --- /dev/null +++ b/wia/wiadriverex/usd/stdafx.h @@ -0,0 +1,59 @@ +#pragma once + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_driver_) + +#define SAFE_DELETE(p) \ +{ \ + if(p) \ + { \ + delete p; \ + p = NULL; \ + } \ +} + +/////////////////////////////////////////////////////////////////////////////// +// Windows system headers +// + +#include <windows.h> // Windows defines +#include <stdio.h> // std out defines +#include <coguid.h> // COM defines +#include <objbase.h> // COM defines +#include <shobjidl.h> // Shell UI Extension +#include <shlobj.h> // Shell UI Extension +#include <gdiplus.h> // GDI+ +#include <shlwapi.h> // Shell light weight API + + +/////////////////////////////////////////////////////////////////////////////// +// WIA common library headers +// + +#include "basicstr.h" +#include "basicarray.h" // CSimpleDynamicArray + +/////////////////////////////////////////////////////////////////////////////// +// WIA driver core headers +// + +#include <sti.h> // STI defines +#include <stiusd.h> // IStiUsd interface +#include <wiamindr.h> // IWiaMinidrv interface +#include <wiadevd.h> // IWiaUIExtension interface +#include <wiamdef.h> + + +/////////////////////////////////////////////////////////////////////////////// +// WIA driver common headers + +#define DEFAULT_BUFFER_SIZE (128 * 1024) + +#include "wiapropertymanager.h" // WIA driver property manager class +#include "wiacapabilitymanager.h" // WIA driver capability manager class +#include "wiahelpers.h" // WIA driver helper functions + +#include "resource.h" // WIA driver resource defines +#include "WiaDevice.h" // WIA simulated device class +#include "wiadriver.h" // WIA driver header + diff --git a/wia/wiadriverex/usd/wiacapabilitymanager.cpp b/wia/wiadriverex/usd/wiacapabilitymanager.cpp new file mode 100644 index 00000000..ed094808 --- /dev/null +++ b/wia/wiadriverex/usd/wiacapabilitymanager.cpp @@ -0,0 +1,366 @@ +/***************************************************************************** + * + * wiacapabilitymanager.cpp + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: + * + * Helper class for WIA capabilities + * + *******************************************************************************/ + +#include "stdafx.h" +#include <strsafe.h> + +CWIACapabilityManager::CWIACapabilityManager() +{ + +} + +CWIACapabilityManager::~CWIACapabilityManager() +{ + Destroy(); +} + +HRESULT CWIACapabilityManager::Initialize(_In_ HINSTANCE hInstance) +{ + HRESULT hr = E_INVALIDARG; + if(hInstance) + { + m_hInstance = hInstance; + hr = S_OK; + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +void CWIACapabilityManager::Destroy() +{ + WIAS_TRACE((g_hInst,"Array contents")); + for(INT i = 0; i < m_CapabilityArray.Size(); i++) + { + FreeCapability(&m_CapabilityArray[i],TRUE); + } + m_CapabilityArray.Destroy(); +} + +HRESULT CWIACapabilityManager::AddCapability(const GUID guidCapability, + UINT uiNameResourceID, + UINT uiDescriptionResourceID, + ULONG ulFlags, + _In_ LPWSTR wszIcon) +{ + HRESULT hr = S_OK; + + WIA_DEV_CAP_DRV *pWIADeviceCapability = NULL; + hr = AllocateCapability(&pWIADeviceCapability); + if((SUCCEEDED(hr)&& (pWIADeviceCapability))) + { + pWIADeviceCapability->ulFlags = ulFlags; + *pWIADeviceCapability->guid = guidCapability; + + CBasicStringWide cswCapabilityString; + + // + // Load capability name from resource + // + + if(cswCapabilityString.LoadString(uiNameResourceID,m_hInstance)) + { + hr = StringCbCopyW(pWIADeviceCapability->wszName, + MAX_CAPABILITY_STRING_SIZE_BYTES, + cswCapabilityString.String()); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to copy source string (%ws) to destination string, hr = 0x%lx",cswCapabilityString.String(),hr)); + } + } + else + { + hr = E_FAIL; + WIAS_ERROR((g_hInst, "Failed to load the device capability name string from DLL resource, hr = 0x%lx",hr)); + } + + // + // Load capability description from resource + // + + if(cswCapabilityString.LoadString(uiDescriptionResourceID,m_hInstance)) + { + hr = StringCbCopyW(pWIADeviceCapability->wszDescription, + MAX_CAPABILITY_STRING_SIZE_BYTES, + cswCapabilityString.String()); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to copy source string (%ws) to destination string, hr = 0x%lx",cswCapabilityString.String(),hr)); + } + } + else + { + hr = E_FAIL; + WIAS_ERROR((g_hInst, "Failed to load the device capability description string from DLL resource, hr = 0x%lx",hr)); + } + + // + // Copy icon location string + // + + cswCapabilityString = wszIcon; + + if(cswCapabilityString.Length()) + { + hr = StringCbCopyW(pWIADeviceCapability->wszIcon, + MAX_CAPABILITY_STRING_SIZE_BYTES, + cswCapabilityString.String()); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to copy source string (%ws) to destination string, hr = 0x%lx",cswCapabilityString.String(),hr)); + } + } + else + { + hr = E_FAIL; + WIAS_ERROR((g_hInst, "Failed to load the device capability icon location string from DLL resource, hr = 0x%lx",hr)); + } + + if(SUCCEEDED(hr)) + { + if((pWIADeviceCapability->ulFlags == WIA_NOTIFICATION_EVENT) || + (pWIADeviceCapability->ulFlags == WIA_ACTION_EVENT)) + { + // + // The capability being added is an event, so always add it to the beginning of the array + // + + m_CapabilityArray.Insert(*pWIADeviceCapability,0); + } + else + { + // + // The capability being added is a command, so always add it to the end of the array + // + + m_CapabilityArray.Append(*pWIADeviceCapability); + } + } + + if(pWIADeviceCapability) + { + CoTaskMemFree(pWIADeviceCapability); + pWIADeviceCapability = NULL; + } + } + return hr; +} + +HRESULT CWIACapabilityManager::AllocateCapability(_Out_ WIA_DEV_CAP_DRV **ppWIADeviceCapability) +{ + HRESULT hr = E_INVALIDARG; + if(ppWIADeviceCapability) + { + *ppWIADeviceCapability = NULL; + WIA_DEV_CAP_DRV *pWIADeviceCapability = NULL; + +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed when calling FreeCapability(*ppWIADeviceCapability).") + pWIADeviceCapability = (WIA_DEV_CAP_DRV*)CoTaskMemAlloc(sizeof(WIA_DEV_CAP_DRV)); + if(pWIADeviceCapability) + { + memset(pWIADeviceCapability,0,sizeof(WIA_DEV_CAP_DRV)); + // + // attempt to allocate the GUID member of the structure + // + +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed when calling FreeCapability(*ppWIADeviceCapability).") + pWIADeviceCapability->guid = (GUID*)CoTaskMemAlloc(sizeof(GUID)); + if(pWIADeviceCapability->guid) + { + *pWIADeviceCapability->guid = GUID_NULL; + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for GUID member of WIA_DEV_CAP_DRV structure, hr = 0x%lx",hr)); + } + + // + // attempt to allocate the LPOLESTR name member of the structure + // + + if(SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed when calling FreeCapability(*ppWIADeviceCapability).") + pWIADeviceCapability->wszName = (LPOLESTR)CoTaskMemAlloc(MAX_CAPABILITY_STRING_SIZE_BYTES); + if(pWIADeviceCapability->wszName) + { + memset(pWIADeviceCapability->wszName,0,MAX_CAPABILITY_STRING_SIZE_BYTES); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for LPOLESTR (wszName) member of WIA_DEV_CAP_DRV structure, hr = 0x%lx",hr)); + } + } + + // + // attempt to allocate the LPOLESTR description member of the structure + // + + if(SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed when calling FreeCapability(*ppWIADeviceCapability).") + pWIADeviceCapability->wszDescription = (LPOLESTR)CoTaskMemAlloc(MAX_CAPABILITY_STRING_SIZE_BYTES); + if(pWIADeviceCapability->wszDescription) + { + memset(pWIADeviceCapability->wszDescription,0,MAX_CAPABILITY_STRING_SIZE_BYTES); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for LPOLESTR (wszDescription) member of WIA_DEV_CAP_DRV structure, hr = 0x%lx",hr)); + } + } + + // + // attempt to allocate the LPOLESTR icon member of the structure + // + + if(SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_MEMORY_LEAK, "Freed when calling FreeCapability(*ppWIADeviceCapability).") + pWIADeviceCapability->wszIcon = (LPOLESTR)CoTaskMemAlloc(MAX_CAPABILITY_STRING_SIZE_BYTES); + if(pWIADeviceCapability->wszIcon) + { + memset(pWIADeviceCapability->wszIcon,0,MAX_CAPABILITY_STRING_SIZE_BYTES); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for LPOLESTR (wszIcon) member of WIA_DEV_CAP_DRV structure, hr = 0x%lx",hr)); + } + } + + if(SUCCEEDED(hr)) + { + *ppWIADeviceCapability = pWIADeviceCapability; + } + else + { + FreeCapability(pWIADeviceCapability); + pWIADeviceCapability = NULL; + } + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for WIA_DEV_CAP_DRV structure, hr = 0x%lx",hr)); + } + } + return hr; +} + +void CWIACapabilityManager::FreeCapability(_In_ WIA_DEV_CAP_DRV *pWIADeviceCapability, + BOOL bFreeCapabilityContentOnly) +{ + if(pWIADeviceCapability) + { + if(pWIADeviceCapability->guid) + { + CoTaskMemFree(pWIADeviceCapability->guid); + pWIADeviceCapability->guid = NULL; + } + + if(pWIADeviceCapability->wszName) + { + CoTaskMemFree(pWIADeviceCapability->wszName); + pWIADeviceCapability->wszName = NULL; + } + + if(pWIADeviceCapability->wszDescription) + { + CoTaskMemFree(pWIADeviceCapability->wszDescription); + pWIADeviceCapability->wszDescription = NULL; + } + + if(pWIADeviceCapability->wszIcon) + { + CoTaskMemFree(pWIADeviceCapability->wszIcon); + pWIADeviceCapability->wszIcon = NULL; + } + + if(bFreeCapabilityContentOnly == FALSE) + { + CoTaskMemFree(pWIADeviceCapability); + pWIADeviceCapability = NULL; + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed, caller attempted to free a NULL WIA_DEV_CAP_DRV structure")); + } +} + +HRESULT CWIACapabilityManager::DeleteCapability(const GUID guidCapability, + ULONG ulFlags) +{ + UNREFERENCED_PARAMETER(guidCapability); + UNREFERENCED_PARAMETER(ulFlags); + + return E_NOTIMPL; +} + +LONG CWIACapabilityManager::GetNumCapabilities() +{ + return (LONG)m_CapabilityArray.Size(); +} + +LONG CWIACapabilityManager::GetNumCommands() +{ + LONG lNumCommands = 0; + for(INT i = 0; i < m_CapabilityArray.Size(); i++) + { + if((m_CapabilityArray[i].ulFlags != WIA_NOTIFICATION_EVENT) && + (m_CapabilityArray[i].ulFlags != WIA_ACTION_EVENT)) + { + lNumCommands++; + } + } + return lNumCommands; +} + +LONG CWIACapabilityManager::GetNumEvents() +{ + LONG lNumEvents = 0; + for(INT i = 0; i < m_CapabilityArray.Size(); i++) + { + if((m_CapabilityArray[i].ulFlags == WIA_NOTIFICATION_EVENT) || + (m_CapabilityArray[i].ulFlags == WIA_ACTION_EVENT)) + { + lNumEvents++; + } + } + return lNumEvents; +} + +WIA_DEV_CAP_DRV* CWIACapabilityManager::GetCapabilities() +{ + return &m_CapabilityArray[0]; +} + +WIA_DEV_CAP_DRV* CWIACapabilityManager::GetCommands() +{ + return &m_CapabilityArray[GetNumEvents()]; +} + +WIA_DEV_CAP_DRV* CWIACapabilityManager::GetEvents() +{ + return &m_CapabilityArray[0]; +} + diff --git a/wia/wiadriverex/usd/wiacapabilitymanager.h b/wia/wiadriverex/usd/wiacapabilitymanager.h new file mode 100644 index 00000000..ed199ff8 --- /dev/null +++ b/wia/wiadriverex/usd/wiacapabilitymanager.h @@ -0,0 +1,42 @@ +/***************************************************************************** + * + * wiacapabilitymanager.h + * + * Copyright (c) 2003 Microsoft Corporation. All Rights Reserved. + * + * DESCRIPTION: + * + * Contains class declaration for CWIACapabilityManager + * + *******************************************************************************/ + +#pragma once + +#define MAX_CAPABILITY_STRING_SIZE_BYTES (sizeof(WCHAR) * MAX_PATH) + +class CWIACapabilityManager { +public: + CWIACapabilityManager(); + ~CWIACapabilityManager(); +public: + HRESULT Initialize(_In_ HINSTANCE hInstance); + void Destroy(); + HRESULT AddCapability(const GUID guidCapability, + UINT uiNameResourceID, + UINT uiDescriptionResourceID, + ULONG ulFlags, + _In_ LPWSTR wszIcon); + HRESULT DeleteCapability(const GUID guidCapability,ULONG ulFlags); + HRESULT AllocateCapability(_Out_ WIA_DEV_CAP_DRV **ppWIADeviceCapability); + void FreeCapability(_In_ WIA_DEV_CAP_DRV *pWIADeviceCapability, BOOL bFreeCapabilityContentOnly = FALSE); + LONG GetNumCapabilities(); + LONG GetNumCommands(); + LONG GetNumEvents(); + + WIA_DEV_CAP_DRV* GetCapabilities(); + WIA_DEV_CAP_DRV* GetCommands(); + WIA_DEV_CAP_DRV* GetEvents(); +private: + HINSTANCE m_hInstance; + CBasicDynamicArray<WIA_DEV_CAP_DRV> m_CapabilityArray; +}; diff --git a/wia/wiadriverex/usd/wiadriver.cpp b/wia/wiadriverex/usd/wiadriver.cpp new file mode 100644 index 00000000..49b7cff0 --- /dev/null +++ b/wia/wiadriverex/usd/wiadriver.cpp @@ -0,0 +1,2695 @@ +/************************************************************************** +* +* Copyright (c) 2003 Microsoft Corporation +* +* Title: wiadriver.cpp +* +* Description: This file contains the implementation of IStiUSD and IWiaMiniDrv +* in the class CWIADriver. +* The file also contains all COM DLL entry point functions and an +* implementation of IClassFactory, CWIADriverClassFactory. +* +***************************************************************************/ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include <initguid.h> +#include "stdafx.h" +#include <strsafe.h> +#include <limits.h> + +HINSTANCE g_hInst = NULL; + +/////////////////////////////////////////////////////////////////////////////// +// WIA driver GUID +/////////////////////////////////////////////////////////////////////////////// + +// {EEA1E6F7-A59C-487a-BFFA-BD8AA99FE501} +DEFINE_GUID(CLSID_WIADriver, 0xeea1e6f7, 0xa59c, 0x487a, 0xbf, 0xfa, 0xbd, 0x8a, 0xa9, 0x9f, 0xe5, 0x3); + +#define HANDLED_PRIVATE_STATUS_ERROR_1 MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 1001) +#define UNHANDLED_PRIVATE_STATUS_ERROR_1 MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 1002) +#define UNHANDLED_PRIVATE_STATUS_MESSAGE_1 MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_ITF, 1001) + + +/////////////////////////////////////////////////////////////////////////// +// Construction/Destruction Section +/////////////////////////////////////////////////////////////////////////// + +CWIADriver::CWIADriver(_In_opt_ LPUNKNOWN punkOuter) : m_cRef(1), + m_punkOuter(NULL), + m_pIDrvItemRoot(NULL), + m_lClientsConnected(0), + m_pFormats(NULL), + m_ulNumFormats(0), + m_bstrDeviceID(NULL), + m_bstrRootFullItemName(NULL), + m_ulImageLibraryToken(0), + m_pIStiDevice(NULL) +{ + if(punkOuter) + { + m_punkOuter = punkOuter; + } + else + { + m_punkOuter = reinterpret_cast<IUnknown*>(static_cast<INonDelegatingUnknown*>(this)); + } + + memset(m_wszStoragePath,0,sizeof(m_wszStoragePath)); + + // + // Intialize GDI+ image library for image manipulation + // + + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + if(GdiplusStartup(&m_ulImageLibraryToken, &gdiplusStartupInput, NULL) != Gdiplus::Ok) + { + WIAS_ERROR((g_hInst, "GDI+ image library could not be initialized")); + } +} + +CWIADriver::~CWIADriver() +{ + if(m_bstrDeviceID) + { + SysFreeString(m_bstrDeviceID); + m_bstrDeviceID = NULL; + } + + if(m_bstrRootFullItemName) + { + SysFreeString(m_bstrRootFullItemName); + m_bstrRootFullItemName = NULL; + } + + // + // Free cached driver capability array + // + + m_CapabilityManager.Destroy(); + + // + // Free cached driver format array + // + + if(m_pFormats) + { + WIAS_TRACE((g_hInst,"Deleting WIA format array memory")); + delete [] m_pFormats; + m_pFormats = NULL; + m_ulNumFormats = 0; + } + + // + // Unlink and release the cached IWiaDrvItem root item interface. + // + + DestroyDriverItemTree(); + + // + // Unintialize/shutdown GDI+ image library + // + + if(m_ulImageLibraryToken) + { + Gdiplus::GdiplusShutdown(m_ulImageLibraryToken); + m_ulImageLibraryToken = 0; + } +} + +/////////////////////////////////////////////////////////////////////////// +// Standard COM Section +/////////////////////////////////////////////////////////////////////////// + +HRESULT CWIADriver::QueryInterface(REFIID riid, _COM_Outptr_ LPVOID * ppvObj) +{ + if (ppvObj == NULL) + { + return E_INVALIDARG; + } + *ppvObj = NULL; + + if(!m_punkOuter) + { + return E_NOINTERFACE; + } + return m_punkOuter->QueryInterface(riid,ppvObj); +} +ULONG CWIADriver::AddRef() +{ + if(!m_punkOuter) + { + return 0; + } + return m_punkOuter->AddRef(); +} +ULONG CWIADriver::Release() +{ + if(!m_punkOuter) + { + return 0; + } + return m_punkOuter->Release(); +} + +/////////////////////////////////////////////////////////////////////////// +// IStiUSD Interface Section (for all WIA drivers) +/////////////////////////////////////////////////////////////////////////// + +HRESULT CWIADriver::Initialize(_In_ PSTIDEVICECONTROL pHelDcb, + DWORD dwStiVersion, + _In_ HKEY hParametersKey) +{ + UNREFERENCED_PARAMETER(dwStiVersion); + + HRESULT hr = E_INVALIDARG; + if((pHelDcb)&&(hParametersKey)) + { + // + // Open DeviceData section in the registry + // + + HKEY hDeviceDataKey = NULL; + if(RegOpenKeyEx(hParametersKey,REG_ENTRY_DEVICEDATA,0,KEY_QUERY_VALUE|KEY_READ,&hDeviceDataKey) == ERROR_SUCCESS) + { + DWORD dwSize = sizeof(m_wszStoragePath); + DWORD dwType = REG_SZ; + if(RegQueryValueEx(hDeviceDataKey,REG_ENTRY_STORAGEPATH,NULL,&dwType,(BYTE*)m_wszStoragePath,&dwSize) == ERROR_SUCCESS) + { + WIAS_TRACE((g_hInst,"WIA storage path = %ws",m_wszStoragePath)); + hr = S_OK; + } + else + { + WIAS_ERROR((g_hInst, "Failed to read (%ws) entry under %ws section of device registry",REG_ENTRY_STORAGEPATH,REG_ENTRY_DEVICEDATA)); + } + + hr = S_OK; + + // + // close open DeviceData registry key + // + + RegCloseKey(hDeviceDataKey); + hDeviceDataKey = NULL; + } + + hr = m_CapabilityManager.Initialize(g_hInst); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to initialize the WIA driver capability manager object, hr = 0x%lx",hr)); + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +HRESULT CWIADriver::GetCapabilities(_Out_ PSTI_USD_CAPS pDevCaps) +{ + HRESULT hr = E_INVALIDARG; + if(pDevCaps) + { + memset(pDevCaps, 0, sizeof(STI_USD_CAPS)); + pDevCaps->dwVersion = STI_VERSION_3; + pDevCaps->dwGenericCaps = STI_GENCAP_WIA | + STI_USD_GENCAP_NATIVE_PUSHSUPPORT | + STI_GENCAP_NOTIFICATIONS | + STI_GENCAP_POLLING_NEEDED; + + WIAS_TRACE((g_hInst,"========================================================")); + WIAS_TRACE((g_hInst,"STI Capabilities information reported to the WIA Service")); + WIAS_TRACE((g_hInst,"Version: 0x%lx",pDevCaps->dwVersion)); + WIAS_TRACE((g_hInst,"GenericCaps: 0x%lx", pDevCaps->dwGenericCaps)); + WIAS_TRACE((g_hInst,"========================================================")); + + hr = S_OK; + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +HRESULT CWIADriver::GetStatus(_Inout_ PSTI_DEVICE_STATUS pDevStatus) +{ + HRESULT hr = E_INVALIDARG; + if(pDevStatus) + { + // + // assume successful status checks + // + + hr = S_OK; + + if(pDevStatus->StatusMask & STI_DEVSTATUS_ONLINE_STATE) + { + // + // check if the device is ON-LINE + // + + WIAS_TRACE((g_hInst,"Checking device online status...")); + pDevStatus->dwOnlineState = 0L; + + if(SUCCEEDED(hr)) + { + pDevStatus->dwOnlineState |= STI_ONLINESTATE_OPERATIONAL; + WIAS_TRACE((g_hInst,"The device is online")); + } + else + { + WIAS_TRACE((g_hInst,"The device is offline")); + } + } + + if(pDevStatus->StatusMask & STI_DEVSTATUS_EVENTS_STATE) + { + // + // check for polled events + // + + pDevStatus->dwEventHandlingState &= ~STI_EVENTHANDLING_PENDING; + + hr = S_FALSE; // no are events detected + + if(hr == S_OK) + { + pDevStatus->dwEventHandlingState |= STI_EVENTHANDLING_PENDING; + WIAS_TRACE((g_hInst,"The device reported a polled event")); + } + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} +HRESULT CWIADriver::DeviceReset() +{ + return S_OK; +} +HRESULT CWIADriver::Diagnostic(_Out_ LPDIAG pBuffer) +{ + HRESULT hr = E_INVALIDARG; + if(pBuffer) + { + memset(pBuffer,0,sizeof(DIAG)); + hr = S_OK; + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} +HRESULT CWIADriver::Escape( STI_RAW_CONTROL_CODE EscapeFunction, + _In_reads_bytes_(cbInDataSize) LPVOID lpInData, + DWORD cbInDataSize, + _Out_writes_bytes_(dwOutDataSize) LPVOID pOutData, + DWORD dwOutDataSize, + _Out_ LPDWORD pdwActualData) +{ + UNREFERENCED_PARAMETER(EscapeFunction); + UNREFERENCED_PARAMETER(lpInData); + UNREFERENCED_PARAMETER(cbInDataSize); + UNREFERENCED_PARAMETER(pOutData); + UNREFERENCED_PARAMETER(dwOutDataSize); + UNREFERENCED_PARAMETER(pdwActualData); + + WIAS_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + return E_NOTIMPL; +} +HRESULT CWIADriver::GetLastError(_Out_ LPDWORD pdwLastDeviceError) +{ + HRESULT hr = E_INVALIDARG; + if(pdwLastDeviceError) + { + *pdwLastDeviceError = 0; + hr = S_OK; + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} +HRESULT CWIADriver::LockDevice() +{ + return S_OK; +} +HRESULT CWIADriver::UnLockDevice() +{ + return S_OK; +} +HRESULT CWIADriver::RawReadData(_Out_writes_bytes_(*lpdwNumberOfBytes) LPVOID lpBuffer, + _Out_ LPDWORD lpdwNumberOfBytes, + _Out_ LPOVERLAPPED lpOverlapped) +{ + UNREFERENCED_PARAMETER(lpBuffer); + UNREFERENCED_PARAMETER(lpdwNumberOfBytes); + UNREFERENCED_PARAMETER(lpOverlapped); + + WIAS_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + return E_NOTIMPL; +} +HRESULT CWIADriver::RawWriteData(_In_reads_bytes_(dwNumberOfBytes) LPVOID lpBuffer, + DWORD dwNumberOfBytes, + _Out_ LPOVERLAPPED lpOverlapped) +{ + UNREFERENCED_PARAMETER(lpBuffer); + UNREFERENCED_PARAMETER(dwNumberOfBytes); + UNREFERENCED_PARAMETER(lpOverlapped); + + WIAS_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + return E_NOTIMPL; +} +HRESULT CWIADriver::RawReadCommand(_Out_writes_bytes_(*lpdwNumberOfBytes) LPVOID lpBuffer, + _Out_ LPDWORD lpdwNumberOfBytes, + _Out_ LPOVERLAPPED lpOverlapped) +{ + UNREFERENCED_PARAMETER(lpBuffer); + UNREFERENCED_PARAMETER(lpdwNumberOfBytes); + UNREFERENCED_PARAMETER(lpOverlapped); + + WIAS_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + return E_NOTIMPL; +} +HRESULT CWIADriver::RawWriteCommand(_In_reads_bytes_(dwNumberOfBytes) LPVOID lpBuffer, + DWORD dwNumberOfBytes, + _Out_ LPOVERLAPPED lpOverlapped) +{ + UNREFERENCED_PARAMETER(lpBuffer); + UNREFERENCED_PARAMETER(dwNumberOfBytes); + UNREFERENCED_PARAMETER(lpOverlapped); + + WIAS_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + return E_NOTIMPL; +} + +HRESULT CWIADriver::SetNotificationHandle(_In_ HANDLE hEvent) +{ + UNREFERENCED_PARAMETER(hEvent); + + WIAS_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + return E_NOTIMPL; +} +HRESULT CWIADriver::GetNotificationData(_In_ LPSTINOTIFY lpNotify) +{ + UNREFERENCED_PARAMETER(lpNotify); + + WIAS_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + return E_NOTIMPL; +} +HRESULT CWIADriver::GetLastErrorInfo(_Out_ STI_ERROR_INFO *pLastErrorInfo) +{ + HRESULT hr = E_INVALIDARG; + if(pLastErrorInfo) + { + memset(pLastErrorInfo,0,sizeof(STI_ERROR_INFO)); + hr = S_OK; + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +///////////////////////////////////////////////////////////////////////// +// IWiaMiniDrv Interface Section (for all WIA drivers) // +///////////////////////////////////////////////////////////////////////// + +HRESULT CWIADriver::drvInitializeWia(_Inout_ BYTE *pWiasContext, + LONG lFlags, + _In_ BSTR bstrDeviceID, + _In_ BSTR bstrRootFullItemName, + _In_ IUnknown *pStiDevice, + _In_ IUnknown *pIUnknownOuter, + _Out_ IWiaDrvItem **ppIDrvItemRoot, + _Out_ IUnknown **ppIUnknownInner, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + UNREFERENCED_PARAMETER(pIUnknownOuter); + + HRESULT hr = S_OK; + if((pWiasContext)&&(plDevErrVal)&&(ppIDrvItemRoot)) + { + *plDevErrVal = 0; + *ppIDrvItemRoot = NULL; + *ppIUnknownInner = NULL; + + if(!m_bstrDeviceID) + { + m_bstrDeviceID = SysAllocString(bstrDeviceID); + if(!m_bstrDeviceID) + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate BSTR DeviceID string, hr = 0x%lx",hr)); + } + } + + if(!m_pIStiDevice) + { + m_pIStiDevice = reinterpret_cast<IStiDevice*>(pStiDevice); + } + + if(!m_bstrRootFullItemName) + { + m_bstrRootFullItemName = SysAllocString(bstrRootFullItemName); + if(!m_bstrRootFullItemName) + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate BSTR Root full item name string, hr = 0x%lx",hr)); + } + } + + if(SUCCEEDED(hr)) + { + if(!m_pIDrvItemRoot) + { + hr = BuildDriverItemTree(); + } + else + { + + // + // A WIA item tree already exists. The root item of this item tree + // should be returned to the WIA service. + // + + hr = S_OK; + } + } + + // + // Make PREfast happy by inspecting m_pIDrvItemRoot. + // PREfast doesn't seem to figure out that m_pIDrvItemRoot is set by + // BuildDriverTree()'s call to waisCreateDrvItem() only on success. + // + + if(SUCCEEDED(hr) && !m_pIDrvItemRoot) + { + hr = E_UNEXPECTED; + WIAS_ERROR((g_hInst, "Missing driver item tree root unexpected, hr = 0x%lx",hr)); + } + + // + // Only increment the client connection count, when the driver + // has successfully created all the necessary WIA items for + // a client to use. + // + + if(SUCCEEDED(hr)) + { + *ppIDrvItemRoot = m_pIDrvItemRoot; + InterlockedIncrement(&m_lClientsConnected); + WIAS_TRACE((g_hInst,"%d client(s) are currently connected to this driver.",m_lClientsConnected)); + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +UINT CWIADriver::GetBitmapResourceIDFromCategory(const GUID &guidItemCategory) +{ + UINT uiBitmapResourceID = 0; + + if (guidItemCategory == WIA_CATEGORY_FLATBED) + { + uiBitmapResourceID = IDB_FLATBED; + } + else if (guidItemCategory == WIA_CATEGORY_FEEDER) + { + uiBitmapResourceID = IDB_FEEDER; + } + else if (guidItemCategory == WIA_CATEGORY_FILM) + { + uiBitmapResourceID = IDB_FILM; + } + else + { + uiBitmapResourceID = IDB_FLATBED; + } + + return uiBitmapResourceID; +} + + +/*++ + +Routine Name: CWIADriver::DownloadRawHeader + +Routine Description: Builds and downloads to the specified ouput stream the WIA Raw Format header. + It should be called only from within CWIADriver::DownloadToStream + after WiaDevice::InitializeForDownload was executed +Arguments: + pDestination - the output stream (same as used in DownloadToStream) + pWiasContext - WIA service context, passed by caller (DownloadToStream) + pmdtc - the stream WIA mini-driver context (see DownloadToStream) + +Return Value: + HRESULT (S_OK in case the operation succeeds) +Last Error: + - +++*/ +HRESULT +CWIADriver::DownloadRawHeader( + _In_ IStream *pDestination, + _Inout_ BYTE *pWiasContext, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc + ) +{ + HRESULT hr = S_OK; + LONG lValue = 0; + WIA_RAW_HEADER& RawHeader = m_WiaDevice.m_RawHeader; + + // + // Verify input parameters: + // + if((!pDestination) || (!pmdtc)) + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameter(s) for DownloadRawHeader, hr: 0x%X", hr)); + } + + if(S_OK == hr) + { + // + // The 'WRAW' 4 ASCII character signature is required at the begining of all WIA Raw transfers: + // + const char szSignature[] = "WRAW"; + memcpy(&RawHeader.Tag, szSignature, sizeof(DWORD)); + + // + // Fill in the fields describing version identity for this header: + // + RawHeader.Version = 0x00010000; + RawHeader.HeaderSize = sizeof(WIA_RAW_HEADER); + + // + // Fill in all the fields that we can retrieve directly from the current MINIDRV_TRANSFER_CONTEXT: + // + RawHeader.XRes = pmdtc->lXRes; + RawHeader.YRes = pmdtc->lYRes; + RawHeader.XExtent = pmdtc->lWidthInPixels; + RawHeader.YExtent = pmdtc->lLines; + RawHeader.BitsPerPixel = pmdtc->lDepth; + RawHeader.Compression = pmdtc->lCompression; + + // + // Raw data: the offset is the size of the header (we don't have a color palette in this case): + // + RawHeader.RawDataOffset = RawHeader.HeaderSize; + + // + // Notes: + // + // RawHeader.RawDataSize is filled in already by CWiaDevice::InitializeForDownload + // Same for RawHeader.BytesPerLine. + // + } + + // + // The remaining fields have to be filled in reading the rescctive current property values: + // + + // + // The pixel/data type is described by WIA_IPA_FORMAT: + // + if(S_OK == hr) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPA_FORMAT, &lValue, NULL, true); + if(S_OK == hr) + { + RawHeader.DataType = lValue; + } + else + { + WIAS_ERROR((g_hInst, "wiasReadPropLong(WIA_IPA_FORMAT) failed, hr: 0x%X", hr)); + } + } + + // + // The number of channels per pixel is described by WIA_IPA_CHANNELS_PER_PIXEL: + // + if(S_OK == hr) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPA_CHANNELS_PER_PIXEL, &lValue, NULL, true); + if(S_OK == hr) + { + RawHeader.ChannelsPerPixel = lValue; + } + else + { + WIAS_ERROR((g_hInst, "wiasReadPropLong(WIA_IPA_CHANNELS_PER_PIXEL) failed, hr: 0x%X", hr)); + } + } + + // + // The photometric interpretation is described by WIA_IPS_PHOTOMETRIC_INTERP: + // + if(S_OK == hr) + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_PHOTOMETRIC_INTERP, &lValue, NULL, true); + if(S_OK == hr) + { + RawHeader.PhotometricInterp = lValue; + } + else + { + WIAS_ERROR((g_hInst, "wiasReadPropLong(WIA_IPS_PHOTOMETRIC_INTERP) failed, hr: 0x%X", hr)); + } + } + + // + // The discrete bits per channel table is described by the new WIA_IPA_RAW_BITS_PER_CHANNEL: + // + if(S_OK == hr) + { + memset(&RawHeader.BitsPerChannel[0], 0, sizeof(RawHeader.BitsPerChannel)); + + PROPSPEC ps; + ps.ulKind = PRSPEC_PROPID; + ps.propid = WIA_IPA_RAW_BITS_PER_CHANNEL; + PROPVARIANT pv = {0}; + + hr = wiasReadMultiple(pWiasContext, 1, &ps, &pv, NULL); + if(S_OK == hr) + { + ULONG ulItemCount = (pv.caub.cElems > 8) ? 8 : pv.caub.cElems; + for(ULONG i = 0; i < ulItemCount; i++) + { + RawHeader.BitsPerChannel[i] = *(BYTE *)((BYTE *)pv.caub.pElems + i * sizeof(BYTE)); + } + } + } + + // + // In the case of this sample the image data is retrieved from a resource bitmap. + // + // Important: this bitmap must be initialized by the WiaDevice::InitializeForDownload + // before calling this function. + // + if(S_OK == hr) + { + if(!m_WiaDevice.InitializedForDownload()) + { + // + // S_FALSE returned from this function would be interpreted as a cancel request: + // + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Bitmap not initialized correctly, hr: 0x%X", hr)); + } + } + + if(S_OK == hr) + { + // + // For the line order use the BitmapData object initialized for the sample bitmap that + // we are using: the "Stride" field value sign indicates the line order: + // + RawHeader.LineOrder = ((m_WiaDevice.GetBitmapData())->Stride < 0) ? + WIA_LINE_ORDER_BOTTOM_TO_TOP : WIA_LINE_ORDER_TOP_TO_BOTTOM; + + // + // We won't be using a color palette here but it would be possible to try to retrieve + // the color palette, if any, from the DIB header describing the sample bitmap: + // + RawHeader.PaletteSize = 0; + RawHeader.PaletteOffset = 0; + } + + // + // Write the header to the stream provided to us: + // + ULONG ulBytesWritten = 0; + if(S_OK == hr) + { + hr = pDestination->Write(&RawHeader, RawHeader.HeaderSize, &ulBytesWritten); + } + + return hr; +} + + + +HRESULT CWIADriver::DownloadToStream( LONG lFlags, + _In_ BYTE *pWiasContext, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + const GUID &guidItemCategory, + const GUID &guidFormatID, + __callback IWiaMiniDrvTransferCallback *pTransferCallback, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = S_OK; + BSTR bstrItemName = NULL; + BSTR bstrFullItemName = NULL; + UINT uiBitmapResourceID = GetBitmapResourceIDFromCategory(guidItemCategory); + + if (plDevErrVal) + { + *plDevErrVal = 0; + } + + // + // A maximum of 10 image transfers (including final and preview scans) can be requested + // from the Feeder item before the driver will return WIA_ERROR_PAPER_EMPTY. In order to + // reset the counter (used only for the Feeder item) the application must change a Feeder + // item property current value or reload the driver. + // + // IMPORTANT: + // + // Legacy WIA applications such as Scan Wizard requires WIA_ERROR_PAPER_EMPTY + // (as the return code for IWiaMiniDrv::drvAcquireItemData) in order to stop + // normally a Feeder acquisition sequence. + // + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; + hr = wiasGetDriverItemPrivateContext(pWiasContext, (BYTE**)&pWiaDriverItemContext); + if ((!pWiaDriverItemContext) && (SUCCEEDED(hr))) + { + hr = E_POINTER; + } + if (FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to get private driver item context data, hr = 0x%lx", hr)); + } + + const ULONG ulMaxTransfers = 10; + if ((SUCCEEDED(hr)) && (IsEqualGUID(WIA_CATEGORY_FEEDER, guidItemCategory))) + { + // + // Limit the number of "continuous" transfers from the Feeder item - + // without this Scan Wizard would not stop requesting transfers: + // + if (pWiaDriverItemContext->ulFeederTransferCount >= ulMaxTransfers) + { + hr = WIA_ERROR_PAPER_EMPTY; + } + } + + if (S_OK == hr) + { + // Get the item name + hr = wiasReadPropStr(pWiasContext, WIA_IPA_ITEM_NAME, &bstrItemName, NULL, TRUE); + if (SUCCEEDED(hr)) + { + // Get the full item name + hr = wiasReadPropStr(pWiasContext, WIA_IPA_FULL_ITEM_NAME, &bstrFullItemName, NULL, TRUE); + if (SUCCEEDED(hr)) + { + // Get the destination stream + IStream *pDestination = NULL; + _Analysis_assume_nullterminated_(bstrItemName); + hr = pTransferCallback->GetNextStream(0, bstrItemName, bstrFullItemName, &pDestination); + if (hr == S_OK) + { + WiaTransferParams *pParams = (WiaTransferParams*)CoTaskMemAlloc(sizeof(WiaTransferParams)); + if (pParams) + { + memset(pParams, 0, sizeof(WiaTransferParams)); + BYTE *pBuffer = NULL; + ULONG ulBufferSize = 0; + hr = AllocateTransferBuffer(pWiasContext, &pBuffer, &ulBufferSize); + if (SUCCEEDED(hr)) + { + if ((S_OK == hr) && (guidItemCategory != WIA_CATEGORY_FINISHED_FILE) && (WIA_CATEGORY_FOLDER != guidItemCategory)) + { + LONG lErrorHandling = ERROR_HANDLING_NONE; + + hr = wiasReadPropLong(pWiasContext, MY_WIA_ERROR_HANDLING_PROP, &lErrorHandling, NULL, TRUE); + + BOOL bSendWarmingUpMsg = lErrorHandling & ERROR_HANDLING_WARMING_UP; + BOOL bSendCoverOpenMsg = lErrorHandling & ERROR_HANDLING_COVER_OPEN; + BOOL bSendPrivateErrorMsg = lErrorHandling & ERROR_HANDLING_PRIVATE_ERROR; + BOOL bSendUnhandledStatusMsg = lErrorHandling & ERROR_HANDLING_UNHANDLED_STATUS; + BOOL bSendUnhandledErrorMsg = lErrorHandling & ERROR_HANDLING_UNHANDLED_ERROR; + + // We need to initialize our device object for each item we transfer. + // Each item may have it's own selection area, data type and so on. + hr = m_WiaDevice.InitializeForDownload(pWiasContext, + g_hInst, + uiBitmapResourceID, + guidFormatID); + + if ((S_OK == hr) && bSendWarmingUpMsg) + { + // + // Send non-modal warming up message. To be catched by default UI + // unless application handles it (WiaPreview does not handle this + // message). + // + // Sending "update messages" makes it possible for a user to cancel transfer + // and also for an error handler to provide progress dialog. + // + for (int i = 0; i < 10 ; i++) + { + pParams->lMessage = WIA_TRANSFER_MSG_DEVICE_STATUS; + pParams->hrErrorStatus = WIA_STATUS_WARMING_UP; + pParams->lPercentComplete = i * 10; + pParams->ulTransferredBytes = 0; + + hr = pTransferCallback->SendMessage(0, pParams); + + if (S_OK != hr) + { + break; + } + + Sleep(500); + } + } + + if (S_OK == hr) + { + BOOL bProblemFixed = FALSE; + + // Data transfer loop + // Read from device + ULONG ulBytesRead = 0; + LONG lPercentComplete = 0; + + if (bSendUnhandledStatusMsg) + { + // + // Send "special" unhandled status message + // + pParams->lMessage = WIA_TRANSFER_MSG_DEVICE_STATUS; + pParams->hrErrorStatus = UNHANDLED_PRIVATE_STATUS_MESSAGE_1; + pParams->lPercentComplete = 0; + pParams->ulTransferredBytes = 0; + + hr = pTransferCallback->SendMessage(0, pParams); + } + + if ((S_OK == hr) && bSendUnhandledErrorMsg) + { + + // + // Since none handles this device error it will cause our transfer to be + // be aborted. + // + pParams->lMessage = WIA_TRANSFER_MSG_DEVICE_STATUS; + pParams->hrErrorStatus = UNHANDLED_PRIVATE_STATUS_ERROR_1; + pParams->lPercentComplete = 0; + pParams->ulTransferredBytes = 0; + + hr = pTransferCallback->SendMessage(0, pParams); + } + + if ((S_OK == hr) && bSendCoverOpenMsg) + { + pParams->lMessage = WIA_TRANSFER_MSG_DEVICE_STATUS; + pParams->hrErrorStatus = WIA_ERROR_COVER_OPEN; + pParams->lPercentComplete = 0; + pParams->ulTransferredBytes = 0; + + hr = pTransferCallback->SendMessage(0, pParams); + } + + // + // If this is a Raw format transfer we should transfer the raw header first. + // WiaDevice::InitializeForDownload suceedeed and it is safe to execute + // now DownloadRawHeader: + // + if((S_OK == hr) && (IsEqualGUID(guidFormatID, WiaImgFmt_RAW))) + { + hr = DownloadRawHeader(pDestination, pWiasContext, pmdtc); + + if(S_OK == hr) + { + WIA_RAW_HEADER& RawHeader = m_WiaDevice.m_RawHeader; + lPercentComplete = (LONG)((((float)RawHeader.HeaderSize / + (float)(RawHeader.RawDataSize + RawHeader.HeaderSize + RawHeader.PaletteSize))) * 100.0f); + + pParams->lMessage = WIA_TRANSFER_MSG_STATUS; + pParams->lPercentComplete = lPercentComplete; + pParams->ulTransferredBytes += RawHeader.HeaderSize; + + hr = pTransferCallback->SendMessage(0, pParams); + } + } + + while((S_OK == hr) && + ((hr = m_WiaDevice.GetNextBand(pBuffer, ulBufferSize, &ulBytesRead, &lPercentComplete, guidFormatID)) == S_OK)) + { + ULONG ulBytesWritten = 0; + LARGE_INTEGER li = {0}; + + // + // Write to stream after seeking to end of stream as it could + // be randomized intially or during the callback + // + hr = pDestination->Seek(li, STREAM_SEEK_END, NULL); + + if (S_OK == hr) + { + hr = pDestination->Write(pBuffer, ulBytesRead, &ulBytesWritten); + } + + if (S_OK == hr) + { + // + // Make progress callback + // + pParams->lMessage = WIA_TRANSFER_MSG_STATUS; + pParams->lPercentComplete = lPercentComplete; + pParams->ulTransferredBytes += ulBytesWritten; + + hr = pTransferCallback->SendMessage(0, pParams); + if (FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to send progress notification during download, hr = 0x%lx",hr)); + break; + } + else if (S_FALSE == hr) + { + // + // Transfer cancelled + // + break; + } + else if (S_OK != hr) + { + WIAS_ERROR((g_hInst, "SendMessage returned unknown Success value, hr = 0x%lx",hr)); + hr = E_UNEXPECTED; + break; + } + + if ((lPercentComplete > 50) && !bProblemFixed) + { + + if (bSendPrivateErrorMsg) + { + // + // Send "special" driver status message that only our error handling extension knows about + // + pParams->lMessage = WIA_TRANSFER_MSG_DEVICE_STATUS; + pParams->hrErrorStatus = HANDLED_PRIVATE_STATUS_ERROR_1; + + hr = pTransferCallback->SendMessage(0, pParams); + } + + if (S_OK == hr) + { + bProblemFixed = TRUE; + } + } + } + } + + if ((pWiaDriverItemContext) && (IsEqualGUID(WIA_CATEGORY_FEEDER, guidItemCategory))) + { + // + // Increment the feeder transfer counter for both preview and final scans: + // + if (pWiaDriverItemContext->ulFeederTransferCount < ulMaxTransfers) + { + pWiaDriverItemContext->ulFeederTransferCount += 1; + } + } + + if (WIA_STATUS_END_OF_MEDIA == hr) + { + hr = S_OK; + } + + m_WiaDevice.UninitializeForDownload(); + } + else + { + WIAS_ERROR((g_hInst, "Failed to initialize device for download, hr = 0x%lx",hr)); + } + } + else + { + IStream *pStorageDataStream = NULL; + + hr = SHCreateStreamOnFile(pWiaDriverItemContext->bstrStorageDataPath,STGM_READ,&pStorageDataStream); + + if(SUCCEEDED(hr)) + { + STATSTG statstg = {0}; + ULONG ulTotalBytesToWrite = 0; + + hr = pStorageDataStream->Stat(&statstg, STATFLAG_NONAME); + + if (SUCCEEDED(hr)) + { + ulTotalBytesToWrite = statstg.cbSize.LowPart; + + if (!ulTotalBytesToWrite) + { + hr = E_UNEXPECTED; + WIAS_ERROR((g_hInst, "Storage item has zero size, hr = %#x", hr)); + } + } + + if (SUCCEEDED(hr)) + { + ULONG ulBytesRead = 0; + ULONG ulTotalBytesWritten = 0; + LONG lPercentComplete = -1; + + while((SUCCEEDED(pStorageDataStream->Read(pBuffer, ulBufferSize, &ulBytesRead)) && ulBytesRead)) + { + // + // Write to stream + // + ULONG ulBytesWritten = 0; + hr = pDestination->Write(pBuffer, ulBytesRead, &ulBytesWritten); + + if (SUCCEEDED(hr)) + { + ulTotalBytesWritten += ulBytesWritten; + lPercentComplete = (LONG)((((float)ulTotalBytesWritten/(float)ulTotalBytesToWrite)) * 100.0f); + + // + // Make progress callback + // + pParams->lMessage = WIA_TRANSFER_MSG_STATUS; + pParams->lPercentComplete = lPercentComplete; + pParams->ulTransferredBytes += ulBytesWritten; + + hr = pTransferCallback->SendMessage(0, pParams); + if (hr != S_OK) + { + if (FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to send progress notification during download, hr = 0x%lx",hr)); + } + else if (S_FALSE == hr) + { + WIAS_TRACE((g_hInst, "Download was cancelled")); + } + else + { + WIAS_ERROR((g_hInst, "SendMessage returned unknown Success value, hr = 0x%lx",hr)); + hr = E_UNEXPECTED; + } + break; + } + } + } + } + + pStorageDataStream->Release(); + pStorageDataStream = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Failed to create a source stream on storage item data content file (%ws), hr = 0x%lx",pWiaDriverItemContext->bstrStorageDataPath,hr)); + } + } + FreeTransferBuffer(pBuffer); + } + else + { + WIAS_ERROR((g_hInst, "Failed to allocate memory for transfer buffer, hr = 0x%lx",hr)); + } + CoTaskMemFree(pParams); + pParams = NULL; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for WiaTransferParams structure, hr = 0x%lx",hr)); + } + pDestination->Release(); + pDestination = NULL; + } + else if(!((S_FALSE == hr) || (WIA_STATUS_SKIP_ITEM == hr))) + { + WIAS_ERROR((g_hInst, "GetNextStream returned unknown Success value, hr = 0x%lx",hr)); + hr = E_UNEXPECTED; + } + else + { + WIAS_ERROR((g_hInst, "Failed to get the destination stream for download, hr = 0x%lx",hr)); + } + + SysFreeString(bstrFullItemName); + bstrFullItemName = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_IPA_FULL_ITEM_NAME property, hr = 0x%lx",hr)); + } + SysFreeString(bstrItemName); + bstrItemName = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_IPA_ITEM_NAME property, hr = 0x%lx",hr)); + } + } + return hr; +} + +HRESULT CWIADriver::UploadFromStream( LONG lFlags, + _In_ BYTE *pWiasContext, + const GUID &guidItemCategory, + __callback IWiaMiniDrvTransferCallback *pTransferCallback, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(guidItemCategory); + + HRESULT hr = S_OK; + BSTR bstrItemName = NULL; + BSTR bstrFullItemName = NULL; + + if (plDevErrVal) + { + *plDevErrVal = 0; + } + + // Get the item name + hr = wiasReadPropStr(pWiasContext, WIA_IPA_ITEM_NAME, &bstrItemName, NULL, TRUE); + if (SUCCEEDED(hr)) + { + // Get the full item name + hr = wiasReadPropStr(pWiasContext, WIA_IPA_FULL_ITEM_NAME, &bstrFullItemName, NULL, TRUE); + if (SUCCEEDED(hr)) + { + // Get the source stream + IStream *pSourceStream = NULL; + _Analysis_assume_nullterminated_(bstrItemName); + hr = pTransferCallback->GetNextStream(lFlags, bstrItemName, bstrFullItemName, &pSourceStream); + if (S_OK == hr) + { + hr = wiasReadPropStr(pWiasContext,WIA_IPA_ITEM_NAME,&bstrItemName,NULL,TRUE); + if(SUCCEEDED(hr)) + { + STATSTG statstg = {0}; + + hr = pSourceStream->Stat(&statstg, STATFLAG_NONAME); + if(SUCCEEDED(hr)) + { + WiaTransferParams *pParams = (WiaTransferParams*)CoTaskMemAlloc(sizeof(WiaTransferParams)); + if (pParams) + { + memset(pParams, 0, sizeof(WiaTransferParams)); + + hr = m_WiaDevice.Upload(bstrItemName, statstg.cbSize.LowPart, pSourceStream,pTransferCallback, pParams,m_wszStoragePath); + if(SUCCEEDED(hr)) + { + // Succeeded with upload. We expect the App to do a synchronize to get the new items, + // so there's nothing further we need to do. + + // + // TBD: Ideal case would be to create a WIA driver item, and link it to the existing + // application item. This will also be the place that a item created/added event + // would be sent to the other clients, allowing them to reenumerate and pick up the + // freshly uploaded item. + // + } + else + { + WIAS_ERROR((g_hInst, "Failed to upload data to the device, hr = 0x%lx",hr)); + } + + CoTaskMemFree(pParams); + pParams = NULL; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for WiaTransferParams structure, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to call IStream::Stat on application provided stream, hr = 0x%lx",hr)); + } + SysFreeString(bstrItemName); + bstrItemName = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Failed to read WIA_IPA_ITEM_NAME property, hr = 0x%lx",hr)); + } + + pSourceStream->Release(); + pSourceStream = NULL; + } + else if(!((S_FALSE == hr) ||(WIA_STATUS_SKIP_ITEM == hr))) + { + WIAS_ERROR((g_hInst, "GetNextStream returned unknown Success value, hr = 0x%lx",hr)); + hr = E_UNEXPECTED; + } + else + { + WIAS_ERROR((g_hInst, "Failed to get the source stream for upload, hr = 0x%lx",hr)); + } + + SysFreeString(bstrFullItemName); + bstrFullItemName = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_IPA_FULL_ITEM_NAME property, hr = 0x%lx",hr)); + } + SysFreeString(bstrItemName); + bstrItemName = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_IPA_ITEM_NAME property, hr = 0x%lx",hr)); + } + + return hr; +} + +HRESULT CWIADriver::drvAcquireItemData(_In_ BYTE *pWiasContext, + LONG lFlags, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + _Out_ LONG *plDevErrVal) +{ + HRESULT hr = E_INVALIDARG; + GUID guidItemCategory = GUID_NULL; + GUID guidFormatID = GUID_NULL; + + if((pWiasContext)&&(pmdtc)&&(plDevErrVal)) + { + *plDevErrVal = 0; + + // + // Read the current transfer format that we are requested to use: + // + guidFormatID = pmdtc->guidFormatID; + + // + // Read the WIA item category, to decide which data transfer handler should + // be used. + // + hr = wiasReadPropGuid(pWiasContext,WIA_IPA_ITEM_CATEGORY,&guidItemCategory,NULL,TRUE); + if (SUCCEEDED(hr)) + { + // + // Check what kind of data transfer is requested. This driver + // supports 2 transfer modes: + // 1. Stream-based download + // 2. Stream-based upload + // + + if (lFlags & WIA_MINIDRV_TRANSFER_DOWNLOAD) + { + // This is stream-based download + IWiaMiniDrvTransferCallback *pTransferCallback = NULL; + hr = GetTransferCallback(pmdtc, &pTransferCallback); + if (SUCCEEDED(hr)) + { + LONG lStreamsToDownload = 0; + LONG lStreamCount = 0; + + if (!IsEqualGUID(guidItemCategory, WIA_CATEGORY_FEEDER)) + { + lStreamsToDownload = 1; + } + else + { + hr = wiasReadPropLong(pWiasContext, WIA_IPS_PAGES, &lStreamsToDownload, NULL, TRUE); + if (FAILED(hr)) + { + WIAS_ERROR((g_hInst, "drvAcquireItemData: failure reading WIA_IPS_PAGES property for Feeder item, hr = 0x%lx", hr)); + } + else if (ALL_PAGES == lStreamsToDownload) + { + // + // When WIA_IPS_PAGES is set to 0 (ALL_PAGES) meaning "scan as many documents + // as there may be loaded into the feeder" + // We assume 5 pages are in feeder + // + lStreamsToDownload = 5; + } + } + + // + // We support only TYMED_FILE for WIA_IPA_TYMED so we should call DownloadToStream + // for each individual image transfer. If WIA_IPA_TYMED would support and would be + // set to TYMED_MULTIPAGE_FILE then all images acquired in a continous sequence should + // be transferred to the same strem (GetNextStream called just once): + // + while ((SUCCEEDED(hr)) && (lStreamCount < lStreamsToDownload)) + { + // + // DownloadToStream writes its own trace message in case of failure: + // + hr = DownloadToStream(lFlags, pWiasContext, pmdtc, guidItemCategory, guidFormatID, pTransferCallback, plDevErrVal); + lStreamCount++; + } + + pTransferCallback->Release(); + pTransferCallback = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Could not get our IWiaMiniDrvTransferCallback for download")); + } + } + else if (lFlags & WIA_MINIDRV_TRANSFER_UPLOAD) + { + // + // We only want to do "Upload" if category of the item is WIA_CATEGORY_FINISHED_FILE and it is not the root storage item: + // + LONG lItemType = 0; + + hr = wiasGetItemType(pWiasContext,&lItemType); + if (SUCCEEDED(hr)) + { + if ((guidItemCategory == WIA_CATEGORY_FINISHED_FILE) && !(lItemType & WiaItemTypeStorage)) + { + // This is stream-based upload + IWiaMiniDrvTransferCallback *pTransferCallback = NULL; + hr = GetTransferCallback(pmdtc, &pTransferCallback); + if (SUCCEEDED(hr)) + { + hr = UploadFromStream(lFlags, pWiasContext, guidItemCategory, pTransferCallback, plDevErrVal); + pTransferCallback->Release(); + pTransferCallback = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Could not get our IWiaMiniDrvTransferCallback for upload")); + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Cannot do Upload to selected item, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to get the WIA item type, hr = 0x%lx",hr)); + } + } + else + { + // This should not happen! + hr = E_INVALIDARG; + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_IPA_ITEM_CATEGORY property, hr = 0x%lx",hr)); + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} +HRESULT CWIADriver::drvInitItemProperties(_Inout_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = E_INVALIDARG; + LONG lItemFlags = 0; + if((pWiasContext)&&(plDevErrVal)) + { + *plDevErrVal = 0; + + // + // Initialize individual storage item properties using the CWIAStorage object + // + hr = wiasReadPropLong(pWiasContext,WIA_IPA_ITEM_FLAGS,&lItemFlags,NULL,TRUE); + if(SUCCEEDED(hr)) + { + if((lItemFlags & WiaItemTypeRoot)) + { + // + // Add any root item properties needed. + // + hr = InitializeRootItemProperties(pWiasContext); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to initialize generic WIA root item properties, hr = 0x%lx",hr)); + } + } + else + { + // + // Add any non-root item properties needed. + // + GUID guidItemCategory = GUID_NULL; + + // + // Use the WIA category setting to determine what type of property + // set should be created for this WIA item. + // + if((lItemFlags & WiaItemTypeGenerated) == FALSE) + { + // + // Item is not a generated item, assume that this was created by this WIA driver + // and the WIA_ITEM_CATEGORY setting can be read from the WIA_DRIVER_ITEM_CONTEXT + // structure stored with the WIA driver item. + // + + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; + hr = wiasGetDriverItemPrivateContext(pWiasContext,(BYTE**)&pWiaDriverItemContext); + if(SUCCEEDED(hr) && (pWiaDriverItemContext)) + { + guidItemCategory = pWiaDriverItemContext->guidItemCategory; + } + else + { + // + // This WIA item has no item context and will receive default item + // property initialization. This allows applications to create child items + // for storing private data. + // NOTE: Data transfers on these types of items will probably not succeed since + // the driver does not have a category to help classify the behavior of the + // item. + // + hr = S_OK; + } + } + else + { + // + // Read the parents WIA_ITEM_CATEGORY property setting to determine this new + // child item's category setting. + // + + BYTE *pWiasParentContext = NULL; + hr = wiasGetAppItemParent(pWiasContext,&pWiasParentContext); + if(SUCCEEDED(hr)) + { + hr = wiasReadPropGuid(pWiasParentContext,WIA_IPA_ITEM_CATEGORY,&guidItemCategory,NULL,TRUE); + if(FAILED(hr)) + { + WIAS_TRACE((g_hInst,"The item does not have a category property setting. Assuming that it is unknown.")); + // + // This WIA item has no item category property setting and will receive default item + // property initialization. This allows applications to create child items + // for storing private data. + // NOTE: Data transfers on these types of items will probably not succeed since + // the driver does not have a category to help classify the behavior of the + // item. + // + hr = S_OK; + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to obtain the WIA application item's parent, hr = 0x%lx",hr)); + } + } + + if(SUCCEEDED(hr)) + { + // + // Initialize the WIA item property set according to the category specified + // + + if(guidItemCategory == WIA_CATEGORY_FLATBED) + { + // + // We do not support folder items to be created under the flatbed item: + // + if ((lItemFlags & WiaItemTypeFolder) && (lItemFlags & WiaItemTypeGenerated)) + { + // + // This is a folder item to be created under the base flatbed item, deny the request: + // + hr = E_INVALIDARG; + } + + if(SUCCEEDED(hr)) + { + hr = InitializeWIAItemProperties(pWiasContext,g_hInst,IDB_FLATBED); + } + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to initialize the flatbed item's property set. hr = 0x%lx",hr)); + } + } + else if(guidItemCategory == WIA_CATEGORY_FEEDER) + { + hr = InitializeWIAItemProperties(pWiasContext,g_hInst,IDB_FEEDER); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to initialize the feeder item's property set. hr = 0x%lx",hr)); + } + } + else if(guidItemCategory == WIA_CATEGORY_FILM) + { + hr = InitializeWIAItemProperties(pWiasContext,g_hInst,IDB_FILM); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to initialize the film item's property set. hr = 0x%lx",hr)); + } + } + else if((guidItemCategory == WIA_CATEGORY_FINISHED_FILE) || (WIA_CATEGORY_FOLDER == guidItemCategory)) + { + hr = InitializeWIAStorageItemProperties(pWiasContext, FALSE, + (BOOL)((WIA_CATEGORY_FOLDER == guidItemCategory) && (lItemFlags & WiaItemTypeFolder))); + + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to initialize the storage item's property set. hr = 0x%lx",hr)); + } + } + else + { + hr = S_OK; + } + } + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to read WIA_IPA_ITEM_FLAGS property, hr = 0x%lx",hr)); + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + + if ((FAILED(hr)) && (plDevErrVal)) + { + *plDevErrVal = (E_INVALIDARG == hr) ? WIA_ERROR_INVALID_COMMAND : WIA_ERROR_GENERAL_ERROR; + } + + return hr; +} +HRESULT CWIADriver::drvValidateItemProperties(_Inout_ BYTE *pWiasContext, + LONG lFlags, + ULONG nPropSpec, + _In_ const PROPSPEC *pPropSpec, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = E_INVALIDARG; + if((pWiasContext)&&(pPropSpec)&&(plDevErrVal)&&(nPropSpec)) + { + *plDevErrVal = 0; + + LONG lItemType = 0; + hr = wiasGetItemType(pWiasContext,&lItemType); + if(SUCCEEDED(hr)) + { + if(lItemType & WiaItemTypeRoot) + { + // + // Validate root item property settings, if needed. + // + + hr = S_OK; + } + else + { + // + // Validate child item property settings, if needed. + // + LONG lScanningSurfaceWidth = 0; + LONG lScanningSurfaceHeight = 0; + GUID guidItemCategory = GUID_NULL; + GUID guidFormat = GUID_NULL; + WIA_PROPERTY_CONTEXT PropertyContext = {0}; + BOOL bUpdateFileExt = FALSE; + + // + // Use the WIA item category to help classify and gather WIA item information + // needed to validate the property set. + // + hr = wiasReadPropGuid(pWiasContext,WIA_IPA_ITEM_CATEGORY,&guidItemCategory,NULL,TRUE); + if(SUCCEEDED(hr)) + { + BOOL bValidCategory = FALSE; + // + // Validate the selection area against the entire scanning surface of the device. + // The scanning surface may be different sizes depending on the type of WIA item. + // (ie. Flatbed glass platen sizes may be different to film scanning surfaces, and + // feeder sizes.) + // + if((guidItemCategory == WIA_CATEGORY_FLATBED)||(guidItemCategory == WIA_CATEGORY_FILM)) + { + bValidCategory = TRUE; + + // + // Flatbed items and Film items use the same WIA properties to describe their scanning + // surface. + // + hr = wiasReadPropLong(pWiasContext,WIA_IPS_MAX_HORIZONTAL_SIZE,&lScanningSurfaceWidth,NULL,TRUE); + if(SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext,WIA_IPS_MAX_VERTICAL_SIZE,&lScanningSurfaceHeight,NULL,TRUE); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to read WIA_IPS_MAX_VERTICAL_SIZE property, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to read WIA_IPS_MAX_HORIZONTAL_SIZE property, hr = 0x%lx",hr)); + } + } + else if(guidItemCategory == WIA_CATEGORY_FEEDER) + { + bValidCategory = TRUE; + + // + // Feeder items use a different set of properties to describe the scanning surface. + // + hr = wiasReadPropLong(pWiasContext,WIA_IPS_MAX_HORIZONTAL_SIZE,&lScanningSurfaceWidth,NULL,TRUE); + if(SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext,WIA_IPS_MAX_VERTICAL_SIZE,&lScanningSurfaceHeight,NULL,TRUE); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to read WIA_IPS_MAX_VERTICAL_SIZE property, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to read WIA_IPS_MAX_HORIZONTAL_SIZE property, hr = 0x%lx",hr)); + } + } + else if((guidItemCategory == WIA_CATEGORY_FINISHED_FILE) || (WIA_CATEGORY_FOLDER == guidItemCategory)) + { + bValidCategory = TRUE; + hr = S_OK; + } + else + { + hr = S_OK; + WIAS_TRACE((g_hInst,"Unknown WIA category read from WIA item, hr = 0x%lx",hr)); + } + + if((SUCCEEDED(hr))&&(bValidCategory)) + { + hr = wiasCreatePropContext(nPropSpec,(PROPSPEC*)pPropSpec,0,NULL,&PropertyContext); + if(SUCCEEDED(hr)) + { + // + // Only perform extent validation for items that contain extent properties. + // + + if((guidItemCategory != WIA_CATEGORY_FINISHED_FILE) && (WIA_CATEGORY_FOLDER != guidItemCategory)) + { + if(SUCCEEDED(hr)) + { + hr = wiasUpdateValidFormat(pWiasContext,&PropertyContext,(IWiaMiniDrv*)this); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to validate supported formats, hr = %lx",hr)); + } + } + + + if(SUCCEEDED(hr)) + { + hr = wiasUpdateScanRect(pWiasContext,&PropertyContext,lScanningSurfaceWidth, lScanningSurfaceHeight); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to validate extent settings. (current selection area), hr = %lx",hr)); + } + } + } + + HRESULT FreePropContextHR = wiasFreePropContext(&PropertyContext); + if(FAILED(FreePropContextHR)) + { + WIAS_ERROR((g_hInst, "wiasFreePropContext failed, hr = 0x%lx",FreePropContextHR)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to create WIA property context for validation, hr = 0x%lx",hr)); + } + } + } + + if (SUCCEEDED(hr) && (guidItemCategory != WIA_CATEGORY_FINISHED_FILE) && (WIA_CATEGORY_FOLDER != guidItemCategory)) + { + // + // We have several properties dependent on the current image transfer format + // (currently this sample supports WiaImgFmt_BMP and WiaImgFmt_RAW): + // + BOOL bRawFormat = FALSE; + hr = wiasReadPropGuid(pWiasContext, WIA_IPA_FORMAT, &guidFormat, NULL, TRUE); + if (SUCCEEDED(hr)) + { + bRawFormat = (BOOL)IsEqualGUID(guidFormat, WiaImgFmt_RAW); + } + + // + // Update format dependent properties according with the current WIA_IPA_FORMAT value: + // + BSTR bstrFileExtension = NULL; + if(SUCCEEDED(hr)) + { + // + // Read the current WIA_IPA_FILENAME_EXTENSION and see if a change is needed: + // + hr = wiasReadPropStr(pWiasContext, WIA_IPA_FILENAME_EXTENSION, &bstrFileExtension, NULL, TRUE); + if(SUCCEEDED(hr)) + { + bUpdateFileExt = (BOOL)(((IsEqualGUID(guidFormat, WiaImgFmt_RAW)) && (wcscmp(bstrFileExtension, TEXT("RAW")))) || + ((IsEqualGUID(guidFormat, WiaImgFmt_BMP)) && (wcscmp(bstrFileExtension, TEXT("BMP"))))); + SysFreeString(bstrFileExtension); + bstrFileExtension = NULL; + + if(bUpdateFileExt) + { + if(SUCCEEDED(hr)) + { + if(bRawFormat) + { + bstrFileExtension = SysAllocString(L"RAW"); + } + else + { + bstrFileExtension = SysAllocString(L"BMP"); + } + + if(bstrFileExtension) + { + hr = wiasWritePropStr(pWiasContext, WIA_IPA_FILENAME_EXTENSION, bstrFileExtension); + + SysFreeString(bstrFileExtension); + bstrFileExtension = NULL; + + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Could not update the file name extension property value, hr = 0x%lx.", hr)); + } + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Could not allocate the file name extension property value, hr = 0x%lx.", hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Cannot remove current file name extension property, hr = 0x%lx.", hr)); + } + } + } + } + else + { + WIAS_ERROR((g_hInst, "Cannot read current format property, hr = 0x%lx.", hr)); + } + } + } + + // + // Only call wiasValidateItemProperties if the validation above + // succeeded. + // + if(SUCCEEDED(hr)) + { + hr = wiasValidateItemProperties(pWiasContext,nPropSpec,pPropSpec); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to validate remaining properties using wiasValidateItemProperties, hr = 0x%lx",hr)); + } + } + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +HRESULT CWIADriver::drvWriteItemProperties(_Inout_ BYTE *pWiasContext, + LONG lFlags, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = E_INVALIDARG; + if ((pWiasContext) && (pmdtc) && (plDevErrVal)) + { + *plDevErrVal = 0; + + // + // We have to reset the counter from time to time to allow other + // acquisitions from the feeder item without to reload the Monster + // driver and open a new session - we can do this when a property + // is changed on the Feeder item. + // + // (in the case of a driver deserving a real scanner device such a counter + // would have to be replaced with feeder status checking). + // + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; + hr = wiasGetDriverItemPrivateContext(pWiasContext, (BYTE**)&pWiaDriverItemContext); + if ((SUCCEEDED(hr)) && (pWiaDriverItemContext)) + { + pWiaDriverItemContext->ulFeederTransferCount = 0; + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} +HRESULT CWIADriver::drvReadItemProperties(_In_ BYTE *pWiasContext, + LONG lFlags, + ULONG nPropSpec, + _In_ const PROPSPEC *pPropSpec, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + UNREFERENCED_PARAMETER(nPropSpec); + + HRESULT hr = E_INVALIDARG; + if((pWiasContext)&&(pPropSpec)&&(plDevErrVal)) + { + *plDevErrVal = 0; + hr = S_OK; + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} +HRESULT CWIADriver::drvLockWiaDevice(_In_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = E_INVALIDARG; + if((pWiasContext)&&(plDevErrVal)) + { + *plDevErrVal = 0; + + if(m_pIStiDevice) + { + hr = m_pIStiDevice->LockDevice(DEFAULT_LOCK_TIMEOUT); + } + else + { + hr = S_OK; + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +HRESULT CWIADriver::drvUnLockWiaDevice(_In_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = E_INVALIDARG; + if((pWiasContext)&&(plDevErrVal)) + { + *plDevErrVal = 0; + + if(m_pIStiDevice) + { + hr = m_pIStiDevice->UnLockDevice(); + } + else + { + hr = S_OK; + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +HRESULT CWIADriver::drvAnalyzeItem(_In_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(pWiasContext); + UNREFERENCED_PARAMETER(lFlags); + UNREFERENCED_PARAMETER(plDevErrVal); + + WIAS_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + return E_NOTIMPL; +} +HRESULT CWIADriver::drvGetDeviceErrorStr( LONG lFlags, + LONG lDevErrVal, + _Out_ LPOLESTR *ppszDevErrStr, + _Out_ LONG *plDevErr) +{ + UNREFERENCED_PARAMETER(lFlags); + UNREFERENCED_PARAMETER(lDevErrVal); + UNREFERENCED_PARAMETER(ppszDevErrStr); + UNREFERENCED_PARAMETER(plDevErr); + + WIAS_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + return E_NOTIMPL; +} +HRESULT CWIADriver::DestroyDriverItemTree() +{ + HRESULT hr = S_OK; + + if(m_pIDrvItemRoot) + { + WIAS_TRACE((g_hInst,"Unlinking WIA item tree")); + hr = m_pIDrvItemRoot->UnlinkItemTree(WiaItemTypeDisconnected); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to unlink WIA item tree before being released, hr = 0x%lx",hr)); + } + + WIAS_TRACE((g_hInst,"Releasing IDrvItemRoot interface")); + m_pIDrvItemRoot->Release(); + m_pIDrvItemRoot = NULL; + } + + return hr; +} + +HRESULT CWIADriver::BuildDriverItemTree() +{ + HRESULT hr = S_OK; + if(!m_pIDrvItemRoot) + { + LONG lItemFlags = WiaItemTypeFolder | WiaItemTypeDevice | WiaItemTypeRoot; + BSTR bstrRootItemName = SysAllocString(WIA_DRIVER_ROOT_NAME); + if(bstrRootItemName) + { + // + // Create a default WIA root item + // + hr = wiasCreateDrvItem(lItemFlags, + bstrRootItemName, + m_bstrRootFullItemName, + (IWiaMiniDrv*)this, + 0, + NULL, + &m_pIDrvItemRoot); + // + // Create child items that represent the data or programmable data sources. + // + if(SUCCEEDED(hr)) + { + hr = CreateWIAFlatbedItem(WIA_DRIVER_FLATBED_NAME,(IWiaMiniDrv*)this,m_pIDrvItemRoot); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to create WIA flatbed item, hr = 0x%lx",hr)); + } + } + + if(SUCCEEDED(hr)) + { + hr = CreateWIAFeederItem(WIA_DRIVER_FEEDER_NAME,(IWiaMiniDrv*)this,m_pIDrvItemRoot); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to create WIA feeder item, hr = 0x%lx",hr)); + } + } + + if(SUCCEEDED(hr)) + { + hr = CreateWIAFilmItem(WIA_DRIVER_FILM_NAME,(IWiaMiniDrv*)this,m_pIDrvItemRoot); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to create WIA film item, hr = 0x%lx",hr)); + } + } + + if(SUCCEEDED(hr)) + { + hr = CreateWIAStorageItem(WIA_DRIVER_STORAGE_NAME,(IWiaMiniDrv*)this,m_pIDrvItemRoot,m_wszStoragePath); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to create WIA storage item, hr = 0x%lx",hr)); + } + } + + SysFreeString(bstrRootItemName); + bstrRootItemName = NULL; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for the root item name, hr = 0x%lx",hr)); + } + } + + return hr; +} + + +HRESULT CWIADriver::DoSynchronizeCommand( + _Inout_ BYTE *pWiasContext) +{ + HRESULT hr = S_OK; + + hr = DestroyDriverItemTree(); + if (SUCCEEDED(hr)) + { + hr = BuildDriverItemTree(); + + // + // Queue tree updated event, regardless ofwhether it + // succeeded, since we can't guarantee that the tree + // was left in the same condition. + // + QueueWIAEvent(pWiasContext, WIA_EVENT_TREE_UPDATED); + } + else + { + WIAS_ERROR((g_hInst, " failed, hr = 0x%lx", hr)); + } + + return hr; +} + +HRESULT CWIADriver::drvDeviceCommand(_Inout_ BYTE *pWiasContext, + LONG lFlags, + _In_ const GUID *pguidCommand, + _Out_ IWiaDrvItem **ppWiaDrvItem, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = E_NOTIMPL; + + if (ppWiaDrvItem) + { + *ppWiaDrvItem = NULL; + } + + if (plDevErrVal) + { + *plDevErrVal = 0; + } + + if (pguidCommand) + { + if (*pguidCommand == WIA_CMD_SYNCHRONIZE) + { + hr = DoSynchronizeCommand(pWiasContext); + } + } + else + { + hr = E_NOTIMPL; + WIAS_ERROR((g_hInst, "This method is not implemented or supported for this driver")); + } + + return hr; +} + +HRESULT CWIADriver::drvGetCapabilities(_In_ BYTE *pWiasContext, + LONG ulFlags, + _Out_ LONG *pcelt, + _Out_ WIA_DEV_CAP_DRV **ppCapabilities, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(pWiasContext); + + HRESULT hr = E_INVALIDARG; + if((pcelt)&&(ppCapabilities)&&(plDevErrVal)) + { + hr = S_OK; + + *pcelt = 0; + *ppCapabilities = NULL; + *plDevErrVal = 0; + + if(m_CapabilityManager.GetNumCapabilities() == 0) + { + hr = m_CapabilityManager.AddCapability(WIA_EVENT_DEVICE_CONNECTED, + IDS_EVENT_DEVICE_CONNECTED_NAME, + IDS_EVENT_DEVICE_CONNECTED_DESCRIPTION, + WIA_NOTIFICATION_EVENT, + WIA_ICON_DEVICE_CONNECTED); + if(SUCCEEDED(hr)) + { + hr = m_CapabilityManager.AddCapability(WIA_EVENT_TREE_UPDATED, + IDS_EVENT_TREE_UPDATED_NAME, + IDS_EVENT_TREE_UPDATED_DESCRIPTION, + WIA_NOTIFICATION_EVENT, + WIA_ICON_TREE_UPDATED); + if(SUCCEEDED(hr)) + { + hr = m_CapabilityManager.AddCapability(WIA_EVENT_DEVICE_DISCONNECTED, + IDS_EVENT_DEVICE_DISCONNECTED_NAME, + IDS_EVENT_DEVICE_DISCONNECTED_DESCRIPTION, + WIA_NOTIFICATION_EVENT, + WIA_ICON_DEVICE_DISCONNECTED); + if(SUCCEEDED(hr)) + { + hr = m_CapabilityManager.AddCapability(WIA_CMD_SYNCHRONIZE, + IDS_CMD_SYNCHRONIZE_NAME, + IDS_CMD_SYNCHRONIZE_DESCRIPTION, + 0, + WIA_ICON_SYNCHRONIZE); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_CMD_SYNCHRONIZE to capability manager, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to add WIA_EVENT_DEVICE_DISCONNECTED to capability manager, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to add WIA_EVENT_TREE_UPDATED to capability manager, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to add WIA_EVENT_DEVICE_CONNECTED to capability manager, hr = 0x%lx",hr)); + } + } + + if(SUCCEEDED(hr)) + { + if(((ulFlags & WIA_DEVICE_COMMANDS) == WIA_DEVICE_COMMANDS)&&(ulFlags & WIA_DEVICE_EVENTS) == WIA_DEVICE_EVENTS) + { + *ppCapabilities = m_CapabilityManager.GetCapabilities(); + *pcelt = m_CapabilityManager.GetNumCapabilities(); + WIAS_TRACE((g_hInst,"Application is asking for Commands and Events, and we have %d total capabilities",*pcelt)); + } + else if((ulFlags & WIA_DEVICE_COMMANDS) == WIA_DEVICE_COMMANDS) + { + *ppCapabilities = m_CapabilityManager.GetCommands(); + *pcelt = m_CapabilityManager.GetNumCommands(); + WIAS_TRACE((g_hInst,"Application is asking for Commands, and we have %d",*pcelt)); + } + else if((ulFlags & WIA_DEVICE_EVENTS) == WIA_DEVICE_EVENTS) + { + *ppCapabilities = m_CapabilityManager.GetEvents(); + *pcelt = m_CapabilityManager.GetNumEvents(); + WIAS_TRACE((g_hInst,"Application is asking for Events, and we have %d",*pcelt)); + } + + WIAS_TRACE((g_hInst,"========================================================")); + WIAS_TRACE((g_hInst,"WIA driver capability information")); + WIAS_TRACE((g_hInst,"========================================================")); + + WIA_DEV_CAP_DRV *pCapabilities = m_CapabilityManager.GetCapabilities(); + LONG lNumCapabilities = m_CapabilityManager.GetNumCapabilities(); + + for(LONG i = 0; i < lNumCapabilities; i++) + { + if(pCapabilities[i].ulFlags & WIA_NOTIFICATION_EVENT) + { + WIAS_TRACE((g_hInst,"Event Name: %ws",pCapabilities[i].wszName)); + WIAS_TRACE((g_hInst,"Event Description: %ws",pCapabilities[i].wszDescription)); + } + else + { + WIAS_TRACE((g_hInst,"Command Name: %ws",pCapabilities[i].wszName)); + WIAS_TRACE((g_hInst,"Command Description: %ws",pCapabilities[i].wszDescription)); + } + } + WIAS_TRACE((g_hInst,"========================================================")); + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +HRESULT CWIADriver::drvDeleteItem(_Inout_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = E_INVALIDARG; + if((pWiasContext)&&(plDevErrVal)) + { + *plDevErrVal = 0; + + GUID guidWiaItemCategory = GUID_NULL; + hr = wiasReadPropGuid(pWiasContext,WIA_IPA_ITEM_CATEGORY,&guidWiaItemCategory,NULL,TRUE); + if(SUCCEEDED(hr)) + { + if(guidWiaItemCategory == WIA_CATEGORY_FINISHED_FILE) + { + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; + hr = wiasGetDriverItemPrivateContext(pWiasContext,(BYTE**)&pWiaDriverItemContext); + if(SUCCEEDED(hr)) + { + DeleteFile(pWiaDriverItemContext->bstrStorageDataPath); + } + else + { + // + // If the WIA item does not have a driver item context, then + // assume that there is no associated storage data with it. + // + + hr = S_OK; + } + } + else + { + // + // If the WIA item is not of finished file category, then + // assume that there is no associated storage data with it. + // + + hr = S_OK; + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_IPA_ITEM_CATEGORY property, hr = 0x%lx",hr)); + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + + // + // Only queue the deleted event, if the deletion was a success + // + + if(SUCCEEDED(hr)) + { + QueueWIAEvent(pWiasContext,WIA_EVENT_ITEM_DELETED); + } + + return hr; +} +HRESULT CWIADriver::drvFreeDrvItemContext( + LONG lFlags, + _Inout_updates_bytes_(sizeof(WIA_DRIVER_ITEM_CONTEXT)) BYTE *pSpecContext, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + if (plDevErrVal) + { + *plDevErrVal = NULL; + } + + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = (WIA_DRIVER_ITEM_CONTEXT*)pSpecContext; + if(pWiaDriverItemContext) + { + // Free allocated BSTR if it exists. + if(pWiaDriverItemContext->bstrStorageDataPath) + { + SysFreeString(pWiaDriverItemContext->bstrStorageDataPath); + pWiaDriverItemContext->bstrStorageDataPath = NULL; + } + } + + return S_OK; +} + +HRESULT CWIADriver::drvGetWiaFormatInfo(_In_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *pcelt, + _Out_ WIA_FORMAT_INFO **ppwfi, + _Out_ LONG *plDevErrVal) +{ + UNREFERENCED_PARAMETER(lFlags); + + HRESULT hr = S_OK; + + if ((!plDevErrVal) || (!pcelt) || (!ppwfi)) + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + + if (SUCCEEDED(hr)) + { + *plDevErrVal = 0; + + if (m_pFormats) + { + delete [] m_pFormats; + m_pFormats = NULL; + } + + m_ulNumFormats = DEFAULT_NUM_DRIVER_FORMATS; + + CBasicDynamicArray<GUID> FileFormats; + + // + // add the default formats to the corresponding arrays + // + if (pWiasContext) + { + // + // Create a format list that is specific to the WIA item. + // + LONG lItemType = 0; + hr = wiasGetItemType(pWiasContext, &lItemType); + if (SUCCEEDED(hr)) + { + if (lItemType & WiaItemTypeImage) + { + FileFormats.Append(WiaImgFmt_BMP); + FileFormats.Append(WiaImgFmt_RAW); + } + else + { + FileFormats.Append(WiaImgFmt_UNDEFINED); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to get WIA item type, hr = 0x%lx",hr)); + } + } + else + { + // + // Create a default format list + // + // For this sample driver we are assuming that the majority of data + // transferred will be image data, so when a query for formats fails, + // it is safe to default to DIB and Raw as the formats. + // + FileFormats.Append(WiaImgFmt_BMP); + FileFormats.Append(WiaImgFmt_RAW); + } + + *pcelt = 0; + *ppwfi = NULL; + + if (SUCCEEDED(hr)) + { + m_ulNumFormats = FileFormats.Size(); + m_pFormats = new WIA_FORMAT_INFO[m_ulNumFormats]; + if (m_pFormats) + { + // + // add file (TYMED_FILE) formats to format array + // + for (ULONG iIndex = 0; iIndex < m_ulNumFormats; iIndex++) + { + m_pFormats[iIndex].guidFormatID = FileFormats[iIndex]; + m_pFormats[iIndex].lTymed = TYMED_FILE; + } + + *pcelt = m_ulNumFormats; + *ppwfi = &m_pFormats[0]; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for WIA_FORMAT_INFO structure array, hr = 0x%lx",hr)); + + m_ulNumFormats = 0; + } + } + } + + return hr; +} + +HRESULT CWIADriver::drvNotifyPnpEvent(_In_ const GUID *pEventGUID, + _In_ BSTR bstrDeviceID, + ULONG ulReserved) +{ + UNREFERENCED_PARAMETER(bstrDeviceID); + UNREFERENCED_PARAMETER(ulReserved); + + HRESULT hr = E_INVALIDARG; + if(pEventGUID) + { + // TBD: Add any special event handling here. + // Power management, canceling pending I/O etc. + hr = S_OK; + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +HRESULT CWIADriver::drvUnInitializeWia(_Inout_ BYTE *pWiasContext) +{ + HRESULT hr = E_INVALIDARG; + if(pWiasContext) + { + if(InterlockedDecrement(&m_lClientsConnected) < 0) + { + WIAS_TRACE((g_hInst, "The client connection counter decremented below zero. Assuming no clients are currently connected and automatically setting to 0")); + m_lClientsConnected = 0; + } + + WIAS_TRACE((g_hInst,"%d client(s) are currently connected to this driver.",m_lClientsConnected)); + + if(m_lClientsConnected == 0) + { + + // + // When the last client disconnects, destroy the WIA item tree. + // This should reduce the idle memory foot print of this driver + // + + DestroyDriverItemTree(); + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +///////////////////////////////////////////////////////////////////////// +// INonDelegating Interface Section (for all WIA drivers) // +///////////////////////////////////////////////////////////////////////// + +HRESULT CWIADriver::NonDelegatingQueryInterface(REFIID riid,LPVOID *ppvObj) +{ + if(!ppvObj) + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + return E_INVALIDARG; + } + + *ppvObj = NULL; + + if(IsEqualIID( riid, IID_IUnknown )) + { + *ppvObj = static_cast<INonDelegatingUnknown*>(this); + } + else if(IsEqualIID( riid, IID_IStiUSD )) + { + *ppvObj = static_cast<IStiUSD*>(this); + } + else if(IsEqualIID( riid, IID_IWiaMiniDrv )) + { + *ppvObj = static_cast<IWiaMiniDrv*>(this); + } + else + { + return E_NOINTERFACE; + } + + reinterpret_cast<IUnknown*>(*ppvObj)->AddRef(); + return S_OK; +} + +ULONG CWIADriver::NonDelegatingAddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +ULONG CWIADriver::NonDelegatingRelease() +{ + ULONG ulRef = InterlockedDecrement(&m_cRef); + if(ulRef == 0) + { + delete this; + return 0; + } + return ulRef; +} + +///////////////////////////////////////////////////////////////////////// +// IClassFactory Interface Section (for all COM objects) // +///////////////////////////////////////////////////////////////////////// + +class CWIADriverClassFactory : public IClassFactory +{ +public: + CWIADriverClassFactory() : m_cRef(1) {} + ~CWIADriverClassFactory(){} + HRESULT __stdcall QueryInterface(REFIID riid, _COM_Outptr_ LPVOID *ppv) + { + if(!ppv) + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + return E_INVALIDARG; + } + + *ppv = NULL; + HRESULT hr = E_NOINTERFACE; + if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) + { + *ppv = static_cast<IClassFactory*>(this); + reinterpret_cast<IUnknown*>(*ppv)->AddRef(); + hr = S_OK; + } + return hr; + } + ULONG __stdcall AddRef() + { + return InterlockedIncrement(&m_cRef); + } + ULONG __stdcall Release() + { + ULONG ulRef = InterlockedDecrement(&m_cRef); + if(ulRef == 0) + { + delete this; + return 0; + } + return ulRef; + } +#pragma prefast(suppress:__WARNING_INVALID_PARAM_VALUE_2, "Set ppvObject to NULL if failed.") + HRESULT __stdcall CreateInstance(_In_opt_ IUnknown* pUnkOuter, _In_ REFIID riid, _COM_Outptr_ void** ppvObject) + { + if (ppvObject == NULL) + { + return E_INVALIDARG; + } + *ppvObject = NULL; + + if((pUnkOuter)&&(!IsEqualIID(riid,IID_IUnknown))) + { + return CLASS_E_NOAGGREGATION; + } + + HRESULT hr = E_NOINTERFACE; +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "pDev is freed on release.") + CWIADriver *pDev = new CWIADriver(pUnkOuter); + if(pDev) + { + hr = pDev->NonDelegatingQueryInterface(riid,ppvObject); + pDev->NonDelegatingRelease(); + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate WIA driver class object, hr = 0x%lx",hr)); + } + + return hr; + } + HRESULT __stdcall LockServer(BOOL fLock) + { + UNREFERENCED_PARAMETER(fLock); + + return S_OK; + } +private: + LONG m_cRef; +}; + +///////////////////////////////////////////////////////////////////////// +// DLL Entry Point Section (for all COM objects, in a DLL) // +///////////////////////////////////////////////////////////////////////// + +extern "C" __declspec(dllexport) BOOL APIENTRY DllMain(HINSTANCE hinst,DWORD dwReason, _Reserved_ LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(lpReserved); + + g_hInst = hinst; + switch(dwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinst); + break; + } + return TRUE; +} + +extern "C" HRESULT __stdcall DllCanUnloadNow(void) +{ + return S_OK; +} +extern "C" HRESULT __stdcall DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID *ppv) +{ + if(!ppv) + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + return E_INVALIDARG; + } + HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; + *ppv = NULL; + if(IsEqualCLSID(rclsid, CLSID_WIADriver)) + { +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "pcf is freed on release.") + CWIADriverClassFactory *pcf = new CWIADriverClassFactory; + if(pcf) + { + hr = pcf->QueryInterface(riid,ppv); + pcf->Release(); + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate WIA driver class factory object, hr = 0x%lx",hr)); + } + } + return hr; +} + +extern "C" HRESULT __stdcall DllRegisterServer() +{ + return S_OK; +} + +extern "C" HRESULT __stdcall DllUnregisterServer() +{ + return S_OK; +} diff --git a/wia/wiadriverex/usd/wiadriver.h b/wia/wiadriverex/usd/wiadriver.h new file mode 100644 index 00000000..61ed7b82 --- /dev/null +++ b/wia/wiadriverex/usd/wiadriver.h @@ -0,0 +1,316 @@ +/************************************************************************** +* +* Copyright (c) 2003 Microsoft Corporation +* +* Title: wiadriver.h +* +* Description: This contains the WIA driver class definition and needed +* defines. +* +***************************************************************************/ + +#pragma once + +#define MY_WIA_ERROR_HANDLING_PROP WIA_PRIVATE_ITEMPROP +#define MY_WIA_ERROR_HANDLING_PROP_STR L"My error handling property" + +#define ERROR_HANDLING_NONE 0x00000000 +#define ERROR_HANDLING_WARMING_UP 0x00000001 +#define ERROR_HANDLING_COVER_OPEN 0x00000002 +#define ERROR_HANDLING_PRIVATE_ERROR 0x00000004 +#define ERROR_HANDLING_UNHANDLED_STATUS 0x00000008 +#define ERROR_HANDLING_UNHANDLED_ERROR 0x00000010 + +// +// The only purpose of the MY_TEST_FILTER_PROP property is to illustrate +// the IWiaImageFilter::ApplyProperties method. It is never used by the +// driver itself. +// +#define MY_TEST_FILTER_PROP WIA_PRIVATE_ITEMPROP+1 +#define MY_TEST_FILTER_PROP_STR L"My test filter property" + +#define REG_ENTRY_DEVICEDATA TEXT("DeviceData") +#define REG_ENTRY_STORAGEPATH TEXT("StoragePath") + +#define WIA_DRIVER_ROOT_NAME L"Root" // THIS SHOULD NOT BE LOCALIZED +#define WIA_DRIVER_FLATBED_NAME L"Flatbed" // THIS SHOULD NOT BE LOCALIZED +#define WIA_DRIVER_FEEDER_NAME L"Feeder" // THIS SHOULD NOT BE LOCALIZED +#define WIA_DRIVER_FILM_NAME L"Film" // THIS SHOULD NOT BE LOCALIZED +#define WIA_DRIVER_STORAGE_NAME L"Storage" // THIS SHOULD NOT BE LOCALIZED + +#define DEFAULT_LOCK_TIMEOUT 1000 +#define DEFAULT_NUM_DRIVER_EVENTS 2 +#define DEFAULT_NUM_DRIVER_COMMANDS 0 +#define DEFAULT_NUM_DRIVER_FORMATS 2 + +typedef struct _WIA_DRIVER_ITEM_CONTEXT +{ + GUID guidItemCategory; + LONG lNumItemsStored; + BSTR bstrStorageDataPath; + ULONG ulFeederTransferCount; +}WIA_DRIVER_ITEM_CONTEXT,*PWIA_DRIVER_ITEM_CONTEXT; + +class INonDelegatingUnknown { +public: + virtual STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,LPVOID *ppvObj) = 0; + virtual STDMETHODIMP_(ULONG) NonDelegatingAddRef() = 0; + virtual STDMETHODIMP_(ULONG) NonDelegatingRelease() = 0; +}; + +class CWIADriver : public INonDelegatingUnknown, // NonDelegatingUnknown + public IStiUSD, // STI USD interface + public IWiaMiniDrv // WIA Minidriver interface +{ +public: + + /////////////////////////////////////////////////////////////////////////// + // Construction/Destruction Section + /////////////////////////////////////////////////////////////////////////// + + CWIADriver(_In_opt_ LPUNKNOWN punkOuter); + ~CWIADriver(); + +private: + + /////////////////////////////////////////////////////////////////////////// + // WIA driver internals + /////////////////////////////////////////////////////////////////////////// + + LONG m_cRef; // Device object reference count. + LPUNKNOWN m_punkOuter; // Pointer to outer unknown. + IStiDevice *m_pIStiDevice; // STI device interface for locking + IWiaDrvItem *m_pIDrvItemRoot; // WIA root item + LONG m_lClientsConnected; // number of applications connected + CWIACapabilityManager m_CapabilityManager; // WIA driver capabilities + WIA_FORMAT_INFO *m_pFormats; // WIA format information + ULONG m_ulNumFormats; // number of data formats + BSTR m_bstrDeviceID; // WIA device ID; + ULONG_PTR m_ulImageLibraryToken; // GDI plus token + WiaDevice m_WiaDevice; // Simulated device object + WCHAR m_wszStoragePath[MAX_PATH]; // WIA storage path + BSTR m_bstrRootFullItemName; // WIA root item (full item name) + +public: + + /////////////////////////////////////////////////////////////////////////// + // Standard COM Section + /////////////////////////////////////////////////////////////////////////// + + STDMETHODIMP QueryInterface(REFIID riid, _COM_Outptr_ LPVOID * ppvObj); + + STDMETHODIMP_(ULONG) AddRef(); + + STDMETHODIMP_(ULONG) Release(); + + /////////////////////////////////////////////////////////////////////////// + // IStiUSD Interface Section (for all WIA drivers) + /////////////////////////////////////////////////////////////////////////// + + STDMETHOD(Initialize)(THIS_ + _In_ PSTIDEVICECONTROL pHelDcb, + DWORD dwStiVersion, + _In_ HKEY hParametersKey); + + STDMETHOD(GetCapabilities)(THIS_ _Out_ PSTI_USD_CAPS pDevCaps); + + STDMETHOD(GetStatus)(THIS_ _Inout_ PSTI_DEVICE_STATUS pDevStatus); + + STDMETHOD(DeviceReset)(THIS); + + STDMETHOD(Diagnostic)(THIS_ _Out_ LPDIAG pBuffer); + + STDMETHOD(Escape)(THIS_ + STI_RAW_CONTROL_CODE EscapeFunction, + _In_reads_bytes_(cbInDataSize) LPVOID lpInData, + DWORD cbInDataSize, + _Out_writes_bytes_(dwOutDataSize) LPVOID pOutData, + DWORD dwOutDataSize, + _Out_ LPDWORD pdwActualData); + + STDMETHOD(GetLastError)(THIS_ _Out_ LPDWORD pdwLastDeviceError); + + STDMETHOD(LockDevice)(); + + STDMETHOD(UnLockDevice)(); + + STDMETHOD(RawReadData)(THIS_ + _Out_writes_bytes_(*lpdwNumberOfBytes) LPVOID lpBuffer, + _Out_ LPDWORD lpdwNumberOfBytes, + _Out_ LPOVERLAPPED lpOverlapped); + + STDMETHOD(RawWriteData)(THIS_ + _In_reads_bytes_(dwNumberOfBytes) LPVOID lpBuffer, + DWORD dwNumberOfBytes, + _Out_ LPOVERLAPPED lpOverlapped); + + STDMETHOD(RawReadCommand)(THIS_ + _Out_writes_bytes_(*lpdwNumberOfBytes) LPVOID lpBuffer, + _Out_ LPDWORD lpdwNumberOfBytes, + _Out_ LPOVERLAPPED lpOverlapped); + + STDMETHOD(RawWriteCommand)(THIS_ + _In_reads_bytes_(dwNumberOfBytes) LPVOID lpBuffer, + DWORD dwNumberOfBytes, + _Out_ LPOVERLAPPED lpOverlapped); + + STDMETHOD(SetNotificationHandle)(THIS_ _In_ HANDLE hEvent); + + STDMETHOD(GetNotificationData)(THIS_ _In_ LPSTINOTIFY lpNotify); + + STDMETHOD(GetLastErrorInfo)(THIS_ _Out_ STI_ERROR_INFO *pLastErrorInfo); + + ///////////////////////////////////////////////////////////////////////// + // IWiaMiniDrv Interface Section (for all WIA drivers) // + ///////////////////////////////////////////////////////////////////////// + + STDMETHOD(drvInitializeWia)(THIS_ + _Inout_ BYTE *pWiasContext, + LONG lFlags, + _In_ BSTR bstrDeviceID, + _In_ BSTR bstrRootFullItemName, + _In_ IUnknown *pStiDevice, + _In_ IUnknown *pIUnknownOuter, + _Out_ IWiaDrvItem **ppIDrvItemRoot, + _Out_ IUnknown **ppIUnknownInner, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvAcquireItemData)(THIS_ + _In_ BYTE *pWiasContext, + LONG lFlags, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvInitItemProperties)(THIS_ + _Inout_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvValidateItemProperties)(THIS_ + _Inout_ BYTE *pWiasContext, + LONG lFlags, + ULONG nPropSpec, + _In_ const PROPSPEC *pPropSpec, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvWriteItemProperties)(THIS_ + _Inout_ BYTE *pWiasContext, + LONG lFlags, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvReadItemProperties)(THIS_ + _In_ BYTE *pWiasContext, + LONG lFlags, + ULONG nPropSpec, + _In_ const PROPSPEC *pPropSpec, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvLockWiaDevice)(THIS_ + _In_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvUnLockWiaDevice)(THIS_ + _In_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvAnalyzeItem)(THIS_ + _In_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvGetDeviceErrorStr)(THIS_ + LONG lFlags, + LONG lDevErrVal, + _Out_ LPOLESTR *ppszDevErrStr, + _Out_ LONG *plDevErr); + + STDMETHOD(drvDeviceCommand)(THIS_ + _Inout_ BYTE *pWiasContext, + LONG lFlags, + _In_ const GUID *plCommand, + _Out_ IWiaDrvItem **ppWiaDrvItem, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvGetCapabilities)(THIS_ + _In_ BYTE *pWiasContext, + LONG ulFlags, + _Out_ LONG *pcelt, + _Out_ WIA_DEV_CAP_DRV **ppCapabilities, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvDeleteItem)(THIS_ + _Inout_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvFreeDrvItemContext)(THIS_ + LONG lFlags, + _Inout_updates_bytes_(sizeof(WIA_DRIVER_ITEM_CONTEXT)) BYTE *pSpecContext, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvGetWiaFormatInfo)(THIS_ + _In_ BYTE *pWiasContext, + LONG lFlags, + _Out_ LONG *pcelt, + _Out_ WIA_FORMAT_INFO **ppwfi, + _Out_ LONG *plDevErrVal); + + STDMETHOD(drvNotifyPnpEvent)(THIS_ + _In_ const GUID *pEventGUID, + _In_ BSTR bstrDeviceID, + ULONG ulReserved); + + STDMETHOD(drvUnInitializeWia)(THIS_ _Inout_ BYTE *pWiasContext); + +public: + + ///////////////////////////////////////////////////////////////////////// + // INonDelegating Interface Section (for all WIA drivers) // + ///////////////////////////////////////////////////////////////////////// + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,LPVOID *ppvObj); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + +private: + + ///////////////////////////////////////////////////////////////////////// + // Minidriver private methods specific Section // + ///////////////////////////////////////////////////////////////////////// + + UINT GetBitmapResourceIDFromCategory(const GUID &guidItemCategory); + + HRESULT DownloadToStream( LONG lFlags, + _In_ BYTE *pWiasContext, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + const GUID &guidItemCategory, + const GUID &guidFormatID, + __callback IWiaMiniDrvTransferCallback *pTransferCallback, + _Out_ LONG *plDevErrVal); + + HRESULT DownloadRawHeader(_In_ IStream *pDestination, + _Inout_ BYTE *pWiasContext, + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc); + + HRESULT UploadFromStream( LONG lFlags, + _In_ BYTE *pWiasContext, + const GUID &guidItemCategory, + __callback IWiaMiniDrvTransferCallback *pTransferCallback, + _Out_ LONG *plDevErrVal); + + HRESULT LegacyDownload(LONG lFlags, + BYTE *pWiasContext, + const GUID &guidItemCategory, + PMINIDRV_TRANSFER_CONTEXT pmdtc, + LONG *plDevErrVal); + + HRESULT BuildDriverItemTree(); + + HRESULT DestroyDriverItemTree(); + + HRESULT DoSynchronizeCommand(_Inout_ BYTE *pWiasContext); + +}; diff --git a/wia/wiadriverex/usd/wiadriver.rc b/wia/wiadriverex/usd/wiadriver.rc new file mode 100644 index 00000000..f0e20cde --- /dev/null +++ b/wia/wiadriverex/usd/wiadriver.rc @@ -0,0 +1,39 @@ +#include "resource.h" +#include <windows.h> +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WIA DRIVER" +#define VER_INTERNALNAME_STR "WIADRIVER" +#define VER_LEGALCOPYRIGHT_YEARS "1996-2003" +#define VER_ORIGINALFILENAME_STR "WIADRIVER.DLL" + +#include <common.ver> + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_FLATBED BITMAP "flatbed.bmp" +IDB_FEEDER BITMAP "feeder.bmp" +IDB_FILM BITMAP "film.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN +IDS_EVENT_DEVICE_CONNECTED_NAME "Device connected" +IDS_EVENT_DEVICE_DISCONNECTED_NAME "Device disconnected" +IDS_EVENT_DEVICE_CONNECTED_DESCRIPTION "This event is sent when the device is initially connected to the computer" +IDS_EVENT_DEVICE_DISCONNECTED_DESCRIPTION "This event is sent when the device is disconnected from the computer" +IDS_EVENT_TREE_UPDATED_NAME "WIA item tree updated" +IDS_EVENT_TREE_UPDATED_DESCRIPTION "This event is sent when the WIA item tree is updated by other clients" +IDS_CMD_SYNCHRONIZE_NAME "WIA Synchronize command" +IDS_CMD_SYNCHRONIZE_DESCRIPTION "This command instrcuts the driver to rebuild its driver item tree" +END + diff --git a/wia/wiadriverex/usd/wiadriverex.def b/wia/wiadriverex/usd/wiadriverex.def new file mode 100644 index 00000000..97e225f0 --- /dev/null +++ b/wia/wiadriverex/usd/wiadriverex.def @@ -0,0 +1,9 @@ +LIBRARY WIADRIVEREX + +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + + diff --git a/wia/wiadriverex/usd/wiadriverex.vcxproj b/wia/wiadriverex/usd/wiadriverex.vcxproj new file mode 100644 index 00000000..583c90f4 --- /dev/null +++ b/wia/wiadriverex/usd/wiadriverex.vcxproj @@ -0,0 +1,218 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{88DE1C8B-C13E-41C9-BE8A-0B396AB9B33C}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{E44EBA16-D9FB-4AFC-81C6-07C50096899B}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>wiadriverex</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>wiadriverex</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>wiadriverex</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>wiadriverex</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;wiaservc.lib;gdiplus.lib;ADVAPI32.lib;GDI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shlwapi.lib;sti.lib</AdditionalDependencies> + <ModuleDefinitionFile>wiadriverex.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;wiaservc.lib;gdiplus.lib;ADVAPI32.lib;GDI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shlwapi.lib;sti.lib</AdditionalDependencies> + <ModuleDefinitionFile>wiadriverex.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;wiaservc.lib;gdiplus.lib;ADVAPI32.lib;GDI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shlwapi.lib;sti.lib</AdditionalDependencies> + <ModuleDefinitionFile>wiadriverex.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + <AdditionalOptions>/Wv:18 %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(SDK_INC_PATH)\gdiplus;$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);wiaguid.lib;wiaservc.lib;gdiplus.lib;ADVAPI32.lib;GDI32.lib;KERNEL32.lib;user32.lib;oleaut32.lib;ole32.lib;uuid.lib;shlwapi.lib;sti.lib</AdditionalDependencies> + <ModuleDefinitionFile>wiadriverex.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="wiacapabilitymanager.cpp" /> + <ClCompile Include="wiadriver.cpp" /> + <ClCompile Include="wiahelpers.cpp" /> + <ClCompile Include="wiapropertymanager.cpp" /> + <ResourceCompile Include="wiadriver.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/wia/wiadriverex/usd/wiadriverex.vcxproj.Filters b/wia/wiadriverex/usd/wiadriverex.vcxproj.Filters new file mode 100644 index 00000000..f5822806 --- /dev/null +++ b/wia/wiadriverex/usd/wiadriverex.vcxproj.Filters @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{5A17B657-93EC-45EA-AE35-CD1375BFE01F}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{D58CAFEA-84E5-4E30-A9F2-50761FA7532B}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{00737C7B-9E91-4724-BAC5-A9BA1ED5E756}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="wiacapabilitymanager.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="wiadriver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="wiahelpers.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="wiapropertymanager.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="wiadriverex.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="wiadriver.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/wia/wiadriverex/usd/wiahelpers.cpp b/wia/wiadriverex/usd/wiahelpers.cpp new file mode 100644 index 00000000..ba4afa08 --- /dev/null +++ b/wia/wiadriverex/usd/wiahelpers.cpp @@ -0,0 +1,1866 @@ +/************************************************************************** +* +* Copyright (c) 2003 Microsoft Corporation +* +* Title: wiahelpers.cpp +* +* Description: This file contains a number of helper functions +* for child item creation etc. +* +***************************************************************************/ +#include "stdafx.h" +#include <strsafe.h> + +static FILM_FRAME g_FilmFrames[] = { { 36, 27, 222, 167 }, + { 36, 221, 222, 167 }, + { 37, 418, 222, 167 }, + { 37, 614, 221, 172 } }; + + +/** + * This function creates a full WIA item name + * from a given WIA item name. + * + * The new full item name is created by concatinating + * the WIA item name with the parent's full item name. + * + * (e.g. 0000\Root + MyItem = 0000\Root\MyItem) + * + * @param pParent IWiaDrvItem interface of the parent WIA driver item + * @param bstrItemName + * Name of the WIA item + * @param pbstrFullItemName + * Returned full item name. This parameter + * cannot be NULL. + * @return S_OK - if successful + * E_XXXXXXXX - failure result + */ +HRESULT MakeFullItemName( + _In_ IWiaDrvItem *pParent, + _In_ BSTR bstrItemName, + _Out_ BSTR *pbstrFullItemName) +{ + HRESULT hr = S_OK; + if((pParent)&&(bstrItemName)&&(pbstrFullItemName)) + { + BSTR bstrParentFullItemName = NULL; + hr = pParent->GetFullItemName(&bstrParentFullItemName); + if(SUCCEEDED(hr)) + { + CBasicStringWide cswFullItemName; + cswFullItemName.Format(TEXT("%ws\\%ws"),bstrParentFullItemName,bstrItemName); + *pbstrFullItemName = SysAllocString(cswFullItemName.String()); + if(*pbstrFullItemName) + { + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for BSTR full item name, hr = 0x%lx",hr)); + } + SysFreeString(bstrParentFullItemName); + bstrParentFullItemName = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Failed to get full item name from parent IWiaDrvItem, hr = 0x%lx",hr)); + } + } + else + { + hr = E_INVALIDARG; + WIAS_ERROR((g_hInst, "Invalid parameters were passed, hr = 0x%lx",hr)); + } + return hr; +} + +/** + * This function creates a WIA child item + * + * @param wszItemName + * Item name + * @param pIWiaMiniDrv + * WIA minidriver interface + * @param pParent Parent's WIA driver item interface + * @param lItemFlags Item flags + * @param guidItemCategory + * Item category + * @param ppChild Pointer to the newly created child item + * @param wszStoragePath + * Storage data path + * @return + */ +HRESULT CreateWIAChildItem( + _In_ LPOLESTR wszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent, + LONG lItemFlags, + GUID guidItemCategory, + _Out_opt_ IWiaDrvItem **ppChild, + _In_opt_ PCWSTR wszStoragePath) +{ + HRESULT hr = E_INVALIDARG; + if((wszItemName)&&(pIWiaMiniDrv)&&(pParent)) + { + BSTR bstrItemName = SysAllocString(wszItemName); + BSTR bstrFullItemName = NULL; + IWiaDrvItem *pIWiaDrvItem = NULL; + + if (bstrItemName) + { + hr = MakeFullItemName(pParent,bstrItemName,&bstrFullItemName); + if(SUCCEEDED(hr)) + { + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; + hr = wiasCreateDrvItem(lItemFlags, + bstrItemName, + bstrFullItemName, + pIWiaMiniDrv, + sizeof(WIA_DRIVER_ITEM_CONTEXT), + (BYTE **)&pWiaDriverItemContext, + &pIWiaDrvItem); + if(SUCCEEDED(hr)) + { + pWiaDriverItemContext->ulFeederTransferCount = 0; + pWiaDriverItemContext->guidItemCategory = guidItemCategory; + if(wszStoragePath) + { + pWiaDriverItemContext->bstrStorageDataPath = SysAllocString(wszStoragePath); + if(!pWiaDriverItemContext->bstrStorageDataPath) + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for BSTR storage item path, hr = 0x%lx",hr)); + } + } + + if(SUCCEEDED(hr)) + { + hr = pIWiaDrvItem->AddItemToFolder(pParent); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add the new WIA item (%ws) to the specified parent item, hr = 0x%lx",bstrFullItemName,hr)); + pIWiaDrvItem->Release(); + pIWiaDrvItem = NULL; + } + + // + // If a child iterface pointer parameter was specified, then the caller + // expects to have the newly created child interface pointer returned to + // them. (do not release the newly created item, in this case) + // + + if(ppChild) + { + *ppChild = pIWiaDrvItem; + pIWiaDrvItem = NULL; + } + else if (pIWiaDrvItem) + { + // + // The newly created child has been added to the tree, and is no longer + // needed. Release it. + // + + pIWiaDrvItem->Release(); + pIWiaDrvItem = NULL; + } + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to create the new WIA driver item, hr = 0x%lx",hr)); + } + + SysFreeString(bstrItemName); + bstrItemName = NULL; + SysFreeString(bstrFullItemName); + bstrFullItemName = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Failed to create the new WIA item's full item name, hr = 0x%lx",hr)); + } + } + else + { + // + // Failed to allocate memory for bstrItemName. + // + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for BSTR storage item name")); + } + + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function creates a WIA flatbed item. WIA + * flatbed items will automatically have the + * WIA category setting of WIA_CATEGORY_FLATBED. + * + * @param wszItemName + * Item name + * @param pIWiaMiniDrv + * WIA minidriver interface + * @param pParent Parent's WIA driver item interface + * @return + */ +HRESULT CreateWIAFlatbedItem( + _In_ LPOLESTR wszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent) +{ + LONG lItemFlags = WiaItemTypeImage | WiaItemTypeTransfer | WiaItemTypeFile | WiaItemTypeProgrammableDataSource | WiaItemTypeFolder; + return CreateWIAChildItem(wszItemName,pIWiaMiniDrv,pParent,lItemFlags, WIA_CATEGORY_FLATBED,NULL); +} + +/** + * This function creates a WIA feeder item. WIA + * feeder items will automatically have the + * WIA category setting of WIA_CATEGORY_FEEDER. + * + * @param wszItemName + * Item name + * @param pIWiaMiniDrv + * WIA minidriver interface + * @param pParent Parent's WIA driver item interface + * @return + */ +HRESULT CreateWIAFeederItem( + _In_ LPOLESTR wszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent) +{ + LONG lItemFlags = WiaItemTypeImage | WiaItemTypeTransfer | WiaItemTypeFile | WiaItemTypeProgrammableDataSource; + return CreateWIAChildItem(wszItemName,pIWiaMiniDrv,pParent,lItemFlags, WIA_CATEGORY_FEEDER,NULL); +} + +/** + * This function creates a WIA film item. WIA + * film items will automatically have the + * WIA category setting of WIA_CATEGORY_FILM. + * + * @param wszItemName + * Item name + * @param pIWiaMiniDrv + * WIA minidriver interface + * @param pParent Parent's WIA driver item interface + * @return + */ +HRESULT CreateWIAFilmItem( + _In_ LPOLESTR wszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent) +{ + LONG lItemFlags = WiaItemTypeImage | WiaItemTypeTransfer | WiaItemTypeFolder | WiaItemTypeProgrammableDataSource; + IWiaDrvItem *pChild = NULL; + HRESULT hr = S_OK; + hr = CreateWIAChildItem(wszItemName,pIWiaMiniDrv,pParent,lItemFlags, WIA_CATEGORY_FILM,&pChild); + if(SUCCEEDED(hr)) + { + if(pChild) + { + lItemFlags = WiaItemTypeImage | WiaItemTypeTransfer | WiaItemTypeFile | WiaItemTypeProgrammableDataSource; + hr = CreateWIAChildItem(L"Frame1",pIWiaMiniDrv,pChild,lItemFlags, WIA_CATEGORY_FILM,NULL); + if(SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(L"Frame2",pIWiaMiniDrv,pChild,lItemFlags, WIA_CATEGORY_FILM,NULL); + } + if(SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(L"Frame3",pIWiaMiniDrv,pChild,lItemFlags, WIA_CATEGORY_FILM,NULL); + } + if(SUCCEEDED(hr)) + { + hr = CreateWIAChildItem(L"Frame4",pIWiaMiniDrv,pChild,lItemFlags, WIA_CATEGORY_FILM,NULL); + } + + pChild->Release(); + pChild = NULL; + } + } + return hr; +} + +/** + * This function creates the main sample WIA storage item. + * WIA storage items should have either the WIA category + * of WIA_CATEGORY_FINISHED_FILE (for stored image files) + * or WIA_CATEGORY_FOLDER (for storage folder items). + * + * @param wszItemName + * Item name + * @param pIWiaMiniDrv + * WIA minidriver interface + * @param pParent + * Parent's WIA driver item interface + * @return + */ +HRESULT CreateWIAStorageItem( + _In_ LPOLESTR wszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent, + _In_ const WCHAR * wszStoragePath) +{ + LONG lItemFlags = WiaItemTypeFolder | WiaItemTypeStorage; + + IWiaDrvItem *pChild = NULL; + HRESULT hr = S_OK; + + hr = CreateWIAChildItem(wszItemName, pIWiaMiniDrv, pParent, lItemFlags, WIA_CATEGORY_FOLDER, &pChild); + if (SUCCEEDED(hr)) + { + if (pChild) + { + lItemFlags = WiaItemTypeTransfer | WiaItemTypeFile; + + //TBD: This function only searches the first level for + // content. It ignores any directories found. + + CBasicStringWide cswSearchPath = wszStoragePath; + cswSearchPath += L"\\*.*"; + + WIN32_FIND_DATA *pFindData = (WIN32_FIND_DATA*) LocalAlloc(LPTR, sizeof(WIN32_FIND_DATA)); + + if(!pFindData) + { + hr = E_OUTOFMEMORY; + } + else + { + HANDLE hFindFile = FindFirstFile(cswSearchPath.String(),pFindData); + if(INVALID_HANDLE_VALUE != hFindFile) + { + do + { + if(!(pFindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + CBasicStringWide cswFileDataPath = wszStoragePath; + cswFileDataPath += L"\\"; + cswFileDataPath += pFindData->cFileName; + hr = CreateWIAChildItem(pFindData->cFileName, + pIWiaMiniDrv, + pChild, + lItemFlags, + WIA_CATEGORY_FINISHED_FILE, + NULL, + cswFileDataPath.String()); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to create WIA child storage item, hr = 0x%lx",hr)); + break; + } + } + + } while(FindNextFile(hFindFile,pFindData)); + + FindClose(hFindFile); + } + + LocalFree(pFindData); + pFindData = NULL; + } + + pChild->Release(); + pChild = NULL; + } + } + + return hr; +} + +/** + * This function initializes any root item properties + * needed for this WIA driver. + * + * @param pWiasContext + * Pointer to the WIA item context + * @return + */ +HRESULT InitializeRootItemProperties( + _In_ BYTE *pWiasContext) +{ + HRESULT hr = E_INVALIDARG; + if(pWiasContext) + { + CWIAPropertyManager PropertyManager; + GUID guidItemCategory = WIA_CATEGORY_ROOT; + hr = PropertyManager.AddProperty(WIA_IPA_ITEM_CATEGORY, WIA_IPA_ITEM_CATEGORY_STR, RN, guidItemCategory); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPA_ITEM_CATEGORY property to the property manager, hr = 0x%lx", hr)); + } + + 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)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPA_ACCESS_RIGHTS property to the property manager, hr = 0x%lx", hr)); + } + } + + if(SUCCEEDED(hr)) + { + LONG lDocumentHandlingCapabilities = FLAT | FEED | DUP | FILM_TPA | STOR; + hr = PropertyManager.AddProperty(WIA_DPS_DOCUMENT_HANDLING_CAPABILITIES, + WIA_DPS_DOCUMENT_HANDLING_CAPABILITIES_STR , RN, lDocumentHandlingCapabilities); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_DPS_DOCUMENT_HANDLING_CAPABILITIES property to the property manager, hr = 0x%lx", hr)); + } + } + + if(SUCCEEDED(hr)) + { + LONG lDocumentHandlingStatus = FEED_READY | FILM_TPA_READY | STORAGE_READY | FLAT_READY; + hr = PropertyManager.AddProperty(WIA_DPS_DOCUMENT_HANDLING_STATUS, + WIA_DPS_DOCUMENT_HANDLING_STATUS_STR, RN, lDocumentHandlingStatus); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_DPS_DOCUMENT_HANDLING_STATUS property to the property manager, hr = 0x%lx", hr)); + } + } + + if (SUCCEEDED(hr)) + { + BSTR bstrFirmware = SysAllocString(L"0.9.1"); + if ( bstrFirmware ) + { + hr = PropertyManager.AddProperty(WIA_DPA_FIRMWARE_VERSION, WIA_DPA_FIRMWARE_VERSION_STR, RN, bstrFirmware); + if (FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_DPA_FIRMWARE_VERSION to prop manager, hr = 0x%lx", hr)); + } + SysFreeString(bstrFirmware); + } + else + { + hr = E_OUTOFMEMORY; + } + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.SetItemProperties(pWiasContext); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA root item properties, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPA_ITEM_CATEGORY property to the property manager, hr = 0x%lx",hr)); + } + + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function initializes child item properties + * needed for this WIA driver. The uiResourceID parameter + * determines what image properties will be used. + * + * @param pWiasContext + * Pointer to the WIA item context + * @param hInstance HINSTANCE of the resource location containing uiResourceIDs + * @param uiResourceID + * Resource ID of a bitmap resource loaded as source data + * and a source of WIA item properties. + * FALSE - Child item WIA properties will be added to the item. + * @return + */ +HRESULT InitializeWIAItemProperties( + _In_ BYTE *pWiasContext, + _In_ HINSTANCE hInstance, + UINT uiResourceID) +{ + // WARNING: No checks for failed CBasicDynamicArray::Append() calls. + // For robustness, error handling should be added. + + HRESULT hr = E_INVALIDARG; + BOOL bRootFilm = FALSE; + + if((pWiasContext)&&(hInstance)) + { + // + // Reset the feeder image transfer count: + // + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; + hr = wiasGetDriverItemPrivateContext(pWiasContext, (BYTE**)&pWiaDriverItemContext); + if ((SUCCEEDED(hr)) && (!pWiaDriverItemContext)) + { + hr = E_POINTER; + } + if (SUCCEEDED(hr)) + { + pWiaDriverItemContext->ulFeederTransferCount = 0; + } + + if (SUCCEEDED(hr)) + { + CWIAPropertyManager PropertyManager; + + LONG lXPosition = 0; + LONG lYPosition = 0; + LONG lXExtent = 0; + LONG lYExtent = 0; + LONG lPixWidth = 0; + LONG lPixHeight = 0; + LONG lXResolution = 75; // Our sample images are 75 dpi + LONG lYResolution = 75; // Our sample images are 75 dpi + LONG lHorizontalSize = 0; + LONG lVerticalSize = 0; + LONG lMinHorizontalSize = 1; //0.001" + LONG lMinVerticalSize = 1; //0.001" + LONG lItemType = 0; + + HBITMAP hBitmap = static_cast<HBITMAP>(LoadImage(hInstance, MAKEINTRESOURCE(uiResourceID), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION)); + + if (hBitmap) + { + Bitmap *pBitmap = Bitmap::FromHBITMAP(hBitmap, NULL); + + if (pBitmap) + { + lXExtent = (LONG)pBitmap->GetWidth(); + lYExtent = (LONG)pBitmap->GetHeight(); + lPixWidth = lXExtent; + lPixHeight = lYExtent; + lHorizontalSize = ConvertTo1000thsOfAnInch(lXExtent, lXResolution); + lVerticalSize = ConvertTo1000thsOfAnInch(lYExtent, lYResolution); + + SAFE_DELETE (pBitmap); + } + + DeleteObject(hBitmap); + hBitmap = NULL; + } + + // + // Set coordinates for fixed frames + // + if (IDB_FILM == uiResourceID) + { + ULONG ulFrame = NO_FIXED_FRAME; + BSTR bstrItemName = NULL; + // Get the item name + hr = wiasReadPropStr(pWiasContext, WIA_IPA_ITEM_NAME, &bstrItemName, NULL, TRUE); + + if (S_OK == hr) + { + if (!lstrcmp(bstrItemName, L"Frame1")) + { + ulFrame = 0; + } + else if (!lstrcmp(bstrItemName, L"Frame2")) + { + ulFrame = 1; + } + else if (!lstrcmp(bstrItemName, L"Frame3")) + { + ulFrame = 2; + } + else if (!lstrcmp(bstrItemName, L"Frame4")) + { + ulFrame = 3; + } + else + { + bRootFilm = TRUE; + } + + if (ulFrame != NO_FIXED_FRAME) + { + lXPosition = g_FilmFrames[ulFrame].XPOS; + lYPosition = g_FilmFrames[ulFrame].YPOS; + lXExtent = g_FilmFrames[ulFrame].XEXTENT; + lYExtent = g_FilmFrames[ulFrame].YEXTENT; + } + + SysFreeString(bstrItemName); + bstrItemName = NULL; + } + } + + hr = wiasGetItemType(pWiasContext,&lItemType); + if(SUCCEEDED(hr)) + { + if(lItemType & WiaItemTypeGenerated) + { + WIAS_TRACE((g_hInst,"WIA item was created by application.")); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to get the WIA item type, hr = 0x%lx",hr)); + } + + // + // Add all common item properties first + // + + if((lXExtent)&&(lYExtent)&&(lXResolution)&&(lYResolution)&&(lHorizontalSize)&&(lVerticalSize)) + { + LONG lAccessRights = WIA_ITEM_READ; + hr = PropertyManager.AddProperty(WIA_IPA_ACCESS_RIGHTS ,WIA_IPA_ACCESS_RIGHTS_STR ,RF, lAccessRights, lAccessRights); + + if(SUCCEEDED(hr)) + { + LONG lOpticalXResolution = lXResolution; + hr = PropertyManager.AddProperty(WIA_IPS_OPTICAL_XRES ,WIA_IPS_OPTICAL_XRES_STR ,RN,lOpticalXResolution); + } + + if(SUCCEEDED(hr)) + { + LONG lOpticalYResolution = lYResolution; + hr = PropertyManager.AddProperty(WIA_IPS_OPTICAL_YRES ,WIA_IPS_OPTICAL_YRES_STR ,RN,lOpticalYResolution); + } + + if(SUCCEEDED(hr)) + { + CBasicDynamicArray<LONG> lPreviewArray; + lPreviewArray.Append(WIA_FINAL_SCAN); + lPreviewArray.Append(WIA_PREVIEW_SCAN); + hr = PropertyManager.AddProperty(WIA_IPS_PREVIEW ,WIA_IPS_PREVIEW_STR ,RWLC,lPreviewArray[0],lPreviewArray[0],&lPreviewArray); + } + + if(SUCCEEDED(hr)) + { + LONG lShowPreviewControl = WIA_SHOW_PREVIEW_CONTROL; + hr = PropertyManager.AddProperty(WIA_IPS_SHOW_PREVIEW_CONTROL ,WIA_IPS_SHOW_PREVIEW_CONTROL_STR ,RN,lShowPreviewControl); + } + + if(SUCCEEDED(hr)) + { + // + // Support creation of child items underneath the base flatbed item: + // + BOOL bChildItemCreation = FALSE; + + if(uiResourceID == IDB_FLATBED) + { + LONG lItemFlags = 0; + hr = wiasReadPropLong(pWiasContext, WIA_IPA_ITEM_FLAGS, &lItemFlags, NULL, TRUE); + if ((S_OK == hr) && (lItemFlags & WiaItemTypeFolder)) + { + bChildItemCreation = TRUE; + } + } + + hr = PropertyManager.AddProperty(WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION, WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION_STR, RN, bChildItemCreation); + } + + if((uiResourceID == IDB_FLATBED) || (uiResourceID == IDB_FILM)) + { + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_MAX_HORIZONTAL_SIZE ,WIA_IPS_MAX_HORIZONTAL_SIZE_STR ,RN,lHorizontalSize); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_MAX_VERTICAL_SIZE ,WIA_IPS_MAX_VERTICAL_SIZE_STR ,RN,lVerticalSize); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_MIN_HORIZONTAL_SIZE ,WIA_IPS_MIN_HORIZONTAL_SIZE_STR ,RN,lMinHorizontalSize); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_MIN_VERTICAL_SIZE ,WIA_IPS_MIN_VERTICAL_SIZE_STR ,RN,lMinVerticalSize); + } + + if(SUCCEEDED(hr)) + { + LONG lSegmentation = (IDB_FLATBED == uiResourceID) ? WIA_USE_SEGMENTATION_FILTER : WIA_DONT_USE_SEGMENTATION_FILTER; + hr = PropertyManager.AddProperty(WIA_IPS_SEGMENTATION ,WIA_IPS_SEGMENTATION_STR ,RN, lSegmentation); + } + + if (SUCCEEDED(hr) && (IDB_FILM == uiResourceID)) + { + if (bRootFilm) + { + CBasicDynamicArray<LONG> lFilmScanModeArray; + lFilmScanModeArray.Append(WIA_FILM_COLOR_SLIDE); + hr = PropertyManager.AddProperty(WIA_IPS_FILM_SCAN_MODE, WIA_IPS_FILM_SCAN_MODE_STR, RWL, lFilmScanModeArray[0], lFilmScanModeArray[0], &lFilmScanModeArray); + } + } + } + else if(uiResourceID == IDB_FEEDER) + { + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_MAX_HORIZONTAL_SIZE ,WIA_IPS_MAX_HORIZONTAL_SIZE_STR ,RN,lHorizontalSize); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_MAX_VERTICAL_SIZE ,WIA_IPS_MAX_VERTICAL_SIZE_STR ,RN,lVerticalSize); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_MIN_HORIZONTAL_SIZE ,WIA_IPS_MIN_HORIZONTAL_SIZE_STR ,RN,lMinHorizontalSize); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_MIN_VERTICAL_SIZE ,WIA_IPS_MIN_VERTICAL_SIZE_STR ,RN,lMinVerticalSize); + } + + if(SUCCEEDED(hr)) + { + LONG lSheetFeederRegistration = LEFT_JUSTIFIED; + hr = PropertyManager.AddProperty(WIA_IPS_SHEET_FEEDER_REGISTRATION ,WIA_IPS_SHEET_FEEDER_REGISTRATION_STR ,RN,lSheetFeederRegistration); + } + + if(SUCCEEDED(hr)) + { + // + // Just basic duplex mode supported (no single back side scan): + // + 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(SUCCEEDED(hr)) + { + LONG lMaxPages = 100; + LONG lDefaultPagesSetting = 1; + LONG lPages = 1; + hr = PropertyManager.AddProperty(WIA_IPS_PAGES ,WIA_IPS_PAGES_STR ,RWR,lDefaultPagesSetting,lDefaultPagesSetting,0,lMaxPages,lPages); + } + + // + // For the Feeder item implement support for WIA_IPS_PAGE_SIZE (just AUTO supported for now, + // in a real case standard and possibly document sizes would have to be added here): + // + if (SUCCEEDED(hr)) + { + LONG lAutoPageSize = WIA_PAGE_AUTO; + hr = PropertyManager.AddProperty(WIA_IPS_PAGE_SIZE, WIA_IPS_PAGE_SIZE_STR, RN, lAutoPageSize); + + CBasicDynamicArray<LONG> lPageSizeArray; + lPageSizeArray.Append(WIA_PAGE_AUTO); + hr = PropertyManager.AddProperty(WIA_IPS_PAGE_SIZE, WIA_IPS_PAGE_SIZE_STR, RWL, lPageSizeArray[0], lPageSizeArray[0], &lPageSizeArray); + } + + // + // WIA_IPS_PAGE_WIDTH and WIA_IPS_PAGE_HEIGHT are required for feeder item + // + if (SUCCEEDED(hr)) { + hr = PropertyManager.AddProperty(WIA_IPS_PAGE_WIDTH, WIA_IPS_PAGE_WIDTH_STR, RN, lHorizontalSize); + } + + if (SUCCEEDED(hr)) { + hr = PropertyManager.AddProperty(WIA_IPS_PAGE_HEIGHT, WIA_IPS_PAGE_HEIGHT_STR, RN, lVerticalSize); + } + + if (SUCCEEDED(hr)) { + CBasicDynamicArray<LONG> lOrientationArray; + lOrientationArray.Append(PORTRAIT); + lOrientationArray.Append(LANSCAPE); + lOrientationArray.Append(ROT180); + lOrientationArray.Append(ROT270); + hr = PropertyManager.AddProperty(WIA_IPS_ORIENTATION, WIA_IPS_ORIENTATION_STR, RWL, lOrientationArray[0], lOrientationArray[0], &lOrientationArray); + } + } + + if(SUCCEEDED(hr)) + { + LONG lCurrentIntent = WIA_INTENT_NONE; + LONG lCurrentIntentValidValues = WIA_INTENT_IMAGE_TYPE_COLOR | WIA_INTENT_MINIMIZE_SIZE | WIA_INTENT_MAXIMIZE_QUALITY; + hr = PropertyManager.AddProperty(WIA_IPS_CUR_INTENT ,WIA_IPS_CUR_INTENT_STR ,RWF,lCurrentIntent,lCurrentIntentValidValues); + } + + if(SUCCEEDED(hr)) + { + GUID guidItemCategory = WIA_CATEGORY_FLATBED; + switch(uiResourceID) + { + case IDB_FLATBED: + guidItemCategory = WIA_CATEGORY_FLATBED; + break; + case IDB_FEEDER: + guidItemCategory = WIA_CATEGORY_FEEDER; + break; + case IDB_FILM: + guidItemCategory = WIA_CATEGORY_FILM; + break; + default: + guidItemCategory = GUID_NULL; + break; + } + + hr = PropertyManager.AddProperty(WIA_IPA_ITEM_CATEGORY,WIA_IPA_ITEM_CATEGORY_STR,RN,guidItemCategory); + } + + if(SUCCEEDED(hr)) + { + CBasicDynamicArray<LONG> lXResolutionArray; + lXResolutionArray.Append(lXResolution); + hr = PropertyManager.AddProperty(WIA_IPS_XRES ,WIA_IPS_XRES_STR ,RWLC,lXResolutionArray[0],lXResolutionArray[0],&lXResolutionArray); + } + + if(SUCCEEDED(hr)) + { + CBasicDynamicArray<LONG> lYResolutionArray; + lYResolutionArray.Append(lYResolution); + hr = PropertyManager.AddProperty(WIA_IPS_YRES ,WIA_IPS_YRES_STR ,RWLC,lYResolutionArray[0],lYResolutionArray[0],&lYResolutionArray); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_XPOS, WIA_IPS_XPOS_STR, RWRC, lXPosition, lXPosition, 0, lPixWidth - 1, 1); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_YPOS, WIA_IPS_YPOS_STR, RWRC, lYPosition, lYPosition, 0, lPixHeight -1, 1); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_XEXTENT ,WIA_IPS_XEXTENT_STR ,RWRC, lXExtent, lXExtent, 1, lPixWidth - lXPosition, 1); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_YEXTENT ,WIA_IPS_YEXTENT_STR ,RWRC, lYExtent, lYExtent, 1, lPixHeight - lYPosition, 1); + } + + if(SUCCEEDED(hr)) + { + CBasicDynamicArray<LONG> lRotationArray; + lRotationArray.Append(PORTRAIT); + lRotationArray.Append(LANSCAPE); + lRotationArray.Append(ROT180); + lRotationArray.Append(ROT270); + + hr = PropertyManager.AddProperty(WIA_IPS_ROTATION ,WIA_IPS_ROTATION_STR ,RWLC,lRotationArray[0],lRotationArray[0],&lRotationArray); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_DESKEW_X ,WIA_IPS_DESKEW_X_STR ,RWRC,0,0,0,lXExtent,1); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPS_DESKEW_Y ,WIA_IPS_DESKEW_Y_STR ,RWRC,0,0,0,lYExtent,1); + } + + if(SUCCEEDED(hr)) + { + LONG lBrightness = 0; + hr = PropertyManager.AddProperty(WIA_IPS_BRIGHTNESS,WIA_IPS_BRIGHTNESS_STR,RWRC,lBrightness,lBrightness,-1000,1000,1); + } + + if(SUCCEEDED(hr)) + { + LONG lContrast = 0; + hr = PropertyManager.AddProperty(WIA_IPS_CONTRAST ,WIA_IPS_CONTRAST_STR ,RWRC,lContrast,lContrast,-1000,1000,1); + } + + if(SUCCEEDED(hr)) + { + LONG lErrorHandler = ERROR_HANDLING_NONE; + LONG lErrorHandlerValidValues = ERROR_HANDLING_WARMING_UP | ERROR_HANDLING_COVER_OPEN | ERROR_HANDLING_PRIVATE_ERROR | ERROR_HANDLING_UNHANDLED_STATUS | ERROR_HANDLING_UNHANDLED_ERROR; + + hr = PropertyManager.AddProperty(MY_WIA_ERROR_HANDLING_PROP ,MY_WIA_ERROR_HANDLING_PROP_STR ,RWF,lErrorHandler,lErrorHandlerValidValues); + } + + if(SUCCEEDED(hr)) + { + CBasicDynamicArray<LONG> lTestFilterArray; + lTestFilterArray.Append(0); + lTestFilterArray.Append(1); + + hr = PropertyManager.AddProperty(MY_TEST_FILTER_PROP ,MY_TEST_FILTER_PROP_STR ,RWLC,lTestFilterArray[0],lTestFilterArray[0],&lTestFilterArray); + } + + if(SUCCEEDED(hr)) + { + LONG lItemSize = 0; + hr = PropertyManager.AddProperty(WIA_IPA_ITEM_SIZE ,WIA_IPA_ITEM_SIZE_STR ,RN,lItemSize); + } + + if(SUCCEEDED(hr)) + { + // TBD: This property is assuming that the source image is color. Should be changed to be + // more dynamic. + CBasicDynamicArray<LONG> lDataTypeArray; + lDataTypeArray.Append(WIA_DATA_COLOR); + hr = PropertyManager.AddProperty(WIA_IPA_DATATYPE ,WIA_IPA_DATATYPE_STR ,RWL,lDataTypeArray[0],lDataTypeArray[0],&lDataTypeArray); + } + + if(SUCCEEDED(hr)) + { + // TBD: This property is assuming that the source image is 24-bit color. Should be changed to be + // more dynamic. + CBasicDynamicArray<LONG> lBitDepthArray; + lBitDepthArray.Append(24); + hr = PropertyManager.AddProperty(WIA_IPA_DEPTH ,WIA_IPA_DEPTH_STR ,RWLC,lBitDepthArray[0],lBitDepthArray[0],&lBitDepthArray); + } + + if(SUCCEEDED(hr)) + { + GUID guidPreferredFormat = WiaImgFmt_BMP; + hr = PropertyManager.AddProperty(WIA_IPA_PREFERRED_FORMAT ,WIA_IPA_PREFERRED_FORMAT_STR ,RN,guidPreferredFormat); + } + + if(SUCCEEDED(hr)) + { + CBasicDynamicArray<GUID> guidFormatArray; + guidFormatArray.Append(WiaImgFmt_BMP); + guidFormatArray.Append(WiaImgFmt_RAW); + hr = PropertyManager.AddProperty(WIA_IPA_FORMAT ,WIA_IPA_FORMAT_STR ,RWL,guidFormatArray[0],guidFormatArray[0],&guidFormatArray); + } + + if(SUCCEEDED(hr)) + { + CBasicDynamicArray<LONG> lCompressionArray; + lCompressionArray.Append(WIA_COMPRESSION_NONE); + hr = PropertyManager.AddProperty(WIA_IPA_COMPRESSION ,WIA_IPA_COMPRESSION_STR ,RWL, lCompressionArray[0], lCompressionArray[0], &lCompressionArray); + } + + 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(SUCCEEDED(hr)) + { + // TBD: This property is assuming that the source image is 24-bit color and has 3 channels. Should be changed to be + // more dynamic. + LONG lChannelsPerPixel = 3; + hr = PropertyManager.AddProperty(WIA_IPA_CHANNELS_PER_PIXEL ,WIA_IPA_CHANNELS_PER_PIXEL_STR ,RN,lChannelsPerPixel); + } + + if(SUCCEEDED(hr)) + { + // TBD: This property is assuming that the source image is 24-bit color and has 8 bits per channel. Should be changed to be + // more dynamic. + LONG lBitsPerChannel = 8; + hr = PropertyManager.AddProperty(WIA_IPA_BITS_PER_CHANNEL ,WIA_IPA_BITS_PER_CHANNEL_STR ,RN,lBitsPerChannel); + } + + if(SUCCEEDED(hr)) + { + // + // According with the limited type of input image data we use in this sample + // we'll initialize this property for 24-bit color / 3 channels RGB image data. + // (see also above the initialization of WIA_IPA_CHANNELS_PER_PIXEL and WIA_IPA_BITS_PER_CHANNEL) + // A real solution may need however to consider more than just this single format: + // + BYTE bBitsPerChannel[] = { 8, 8, 8 }; + hr = PropertyManager.AddProperty(WIA_IPA_RAW_BITS_PER_CHANNEL, WIA_IPA_RAW_BITS_PER_CHANNEL_STR, RN, &bBitsPerChannel[0], 3); + } + + if(SUCCEEDED(hr)) + { + // + // WIA_IPS_PHOTOMETRIC_INTERP is needed for the Raw transfer format: + // (It shall have WIA_PROP_LIST (with single valid value) | WIA_PROP_RW + // + CBasicDynamicArray<LONG> lPhotometricInterpArray; + lPhotometricInterpArray.Append(WIA_PHOTO_WHITE_1); + hr = PropertyManager.AddProperty(WIA_IPS_PHOTOMETRIC_INTERP, WIA_IPS_PHOTOMETRIC_INTERP_STR, RWL, + lPhotometricInterpArray[0], lPhotometricInterpArray[0], &lPhotometricInterpArray); + } + + if(SUCCEEDED(hr)) + { + LONG lPlanar = WIA_PACKED_PIXEL; + hr = PropertyManager.AddProperty(WIA_IPA_PLANAR ,WIA_IPA_PLANAR_STR ,RN,lPlanar); + } + + if(SUCCEEDED(hr)) + { + // TBD: A small buffer size was used here to allow slower transfers with more progress. Real + // drivers should use a higher value to increase performance. + LONG lBufferSize = DEFAULT_BUFFER_SIZE; + hr = PropertyManager.AddProperty(WIA_IPA_BUFFER_SIZE ,WIA_IPA_BUFFER_SIZE_STR ,RN,lBufferSize); + } + + if(SUCCEEDED(hr)) + { + BSTR bstrFileExtension = SysAllocString(L"BMP"); + if(bstrFileExtension) + { + hr = PropertyManager.AddProperty(WIA_IPA_FILENAME_EXTENSION ,WIA_IPA_FILENAME_EXTENSION_STR ,RN,bstrFileExtension); + + SysFreeString(bstrFileExtension); + bstrFileExtension = NULL; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Could not allocate the file name extension property value, hr = 0x%lx.",hr)); + } + } + + /* Optional property + if(SUCCEEDED(hr)) + { + GUID guidStreamCompatID = GUID_NULL; + hr = PropertyManager.AddProperty(WIA_IPA_PROP_STREAM_COMPAT_ID,WIA_IPA_PROP_STREAM_COMPAT_ID_STR,RN,guidStreamCompatID); + }*/ + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.SetItemProperties(pWiasContext); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA flatbed item properties, hr = 0x%lx",hr)); + } + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to obtain valid information from flatbed bitmap file resource to build a WIA property set")); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to obtain driver item context data")); + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function initializes child item properties + * needed for this WIA driver's storage item. The + * WIA_DRIVER_ITEM_CONTEXT structure stored as the + * the WIA driver item context will be used to + * properly set the WIA_IPA_FILENAME_EXTENSION property + * value. + * + * @param pWiasContext + * Pointer to the WIA item context + * @param bRootItem TRUE - Legacy WIA properties that belong on the root item + * of the device will be added. + * FALSE - Child item WIA properties will be added to the item. + * @param bFolderItem + * TRUE - storage folder (WIA_CATEGORY_FOLDER) + * FALSE - finished file (WIA_CATEGORY_FINISHED_FILE) + * @return + */ +HRESULT InitializeWIAStorageItemProperties( + _In_ BYTE *pWiasContext, + BOOL bRootItem, + BOOL bFolderItem) +{ + UNREFERENCED_PARAMETER(bRootItem); + + HRESULT hr = E_INVALIDARG; + if(pWiasContext) + { + CWIAPropertyManager PropertyManager; + LONG lItemType = 0; + hr = wiasGetItemType(pWiasContext,&lItemType); + if(SUCCEEDED(hr)) + { + GUID guidItemCategory = bFolderItem ? WIA_CATEGORY_FOLDER : WIA_CATEGORY_FINISHED_FILE; + hr = PropertyManager.AddProperty(WIA_IPA_ITEM_CATEGORY,WIA_IPA_ITEM_CATEGORY_STR,RN,guidItemCategory); + if(SUCCEEDED(hr)) + { + if(!(lItemType & WiaItemTypeGenerated)) + { + WIA_DRIVER_ITEM_CONTEXT *pWiaDriverItemContext = NULL; + hr = wiasGetDriverItemPrivateContext(pWiasContext,(BYTE**)&pWiaDriverItemContext); + if(SUCCEEDED(hr)) + { + if(lItemType & WiaItemTypeStorage) + { + // + // This is the parent storage item, update the number of items stored and + // proper access rights + // + + LONG lAccessRights = WIA_ITEM_READ; + hr = PropertyManager.AddProperty(WIA_IPA_ACCESS_RIGHTS ,WIA_IPA_ACCESS_RIGHTS_STR ,RF, lAccessRights, lAccessRights); + if(SUCCEEDED(hr)) + { + hr = PropertyManager.AddProperty(WIA_IPA_ITEMS_STORED, + WIA_IPA_ITEMS_STORED_STR, + RN, + pWiaDriverItemContext->lNumItemsStored); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPA_ITEMS_STORED property to the property manager, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPA_ACCESS_RIGHTS property to the property manager, hr = 0x%lx",hr)); + } + + // + // Support creation of child items underneath the root storage item: + // + + BOOL bChildItemCreation = TRUE; + hr = PropertyManager.AddProperty(WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION, WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION_STR, RN, bChildItemCreation); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION(TRUE) property to the property manager, hr = 0x%lx",hr)); + } + } + else + { + // + // This must be a child item of some kind + // + + if (SUCCEEDED(hr)) + { + // Let enable delete for this item for better WIA testing + LONG lAccessRights = WIA_ITEM_READ | WIA_ITEM_CAN_BE_DELETED; + hr = PropertyManager.AddProperty(WIA_IPA_ACCESS_RIGHTS ,WIA_IPA_ACCESS_RIGHTS_STR ,RF, lAccessRights, lAccessRights); + } + + if(SUCCEEDED(hr)) + { + LONG lItemSize = 0; + hr = PropertyManager.AddProperty(WIA_IPA_ITEM_SIZE ,WIA_IPA_ITEM_SIZE_STR ,RN,lItemSize); + } + + if(SUCCEEDED(hr)) + { + GUID guidPreferredFormat = WiaImgFmt_UNDEFINED; + hr = PropertyManager.AddProperty(WIA_IPA_PREFERRED_FORMAT ,WIA_IPA_PREFERRED_FORMAT_STR ,RN,guidPreferredFormat); + } + + if(SUCCEEDED(hr)) + { + CBasicDynamicArray<GUID> guidFormatArray; + guidFormatArray.Append(WiaImgFmt_UNDEFINED); + hr = PropertyManager.AddProperty(WIA_IPA_FORMAT ,WIA_IPA_FORMAT_STR ,RWL,guidFormatArray[0],guidFormatArray[0],&guidFormatArray); + } + + 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(SUCCEEDED(hr)) + { + // TBD: A small buffer size was used here to allow slower transfers with more progress. Real + // drivers should use a higher value to increase performance. + LONG lBufferSize = DEFAULT_BUFFER_SIZE; + hr = PropertyManager.AddProperty(WIA_IPA_BUFFER_SIZE ,WIA_IPA_BUFFER_SIZE_STR ,RN,lBufferSize); + } + + if(SUCCEEDED(hr)) + { + BSTR bstrFileExtension = NULL; + if(pWiaDriverItemContext->bstrStorageDataPath) + { + hr = GetFileExtensionFromPath(pWiaDriverItemContext->bstrStorageDataPath, &bstrFileExtension); + } + else + { + bstrFileExtension = SysAllocString(L"UNDEFINED"); + hr = S_OK; + } + if(SUCCEEDED(hr)) + { + if(bstrFileExtension) + { + hr = PropertyManager.AddProperty(WIA_IPA_FILENAME_EXTENSION ,WIA_IPA_FILENAME_EXTENSION_STR ,RN,bstrFileExtension); + SysFreeString(bstrFileExtension); + bstrFileExtension = NULL; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Could not allocate the file name extension property value, hr = 0x%lx.",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to extract file extension from path (%ws), hr = 0x%lx",pWiaDriverItemContext->bstrStorageDataPath,hr)); + } + } + + if (SUCCEEDED(hr)) + { + // + // Support creation of child items underneath folder items: + // + + if (bFolderItem) + { + BOOL bChildItemCreation = TRUE; + hr = PropertyManager.AddProperty(WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION, WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION_STR, RN, bChildItemCreation); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION property to the property manager, hr = 0x%lx",hr)); + } + } + else + { + // + // This is a child item (image item). So we add some image only properties here. + // + // This sample driver supports only 24-bpp color data. A real driver would have to consider separate WIA_IPA_DEPTH + // values for each supported WIA_IPA_DATATYPE and update the available and current WIA_IPA_DEPTH values + // every time the current WIA_IPA_DATATYPE is changed. + // + + CBasicDynamicArray<LONG> lDataTypeArray; + lDataTypeArray.Append(WIA_DATA_COLOR); + hr = PropertyManager.AddProperty(WIA_IPA_DATATYPE ,WIA_IPA_DATATYPE_STR ,RWL,lDataTypeArray[0],lDataTypeArray[0],&lDataTypeArray); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPA_DATATYPE property to the property manager, hr = 0x%lx",hr)); + } + + CBasicDynamicArray<LONG> lBitDepthArray; + lBitDepthArray.Append(24); + hr = PropertyManager.AddProperty(WIA_IPA_DEPTH ,WIA_IPA_DEPTH_STR ,RWLC,lBitDepthArray[0],lBitDepthArray[0],&lBitDepthArray); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPA_DEPTH property to the property manager, hr = 0x%lx",hr)); + } + } + + } + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to obtain the WIA_DRIVER_ITEM_CONTEXT structure from the WIA driver item, hr = 0x%lx",hr)); + } + } + else + { + WIAS_TRACE((g_hInst,"WIA item was created by application")); + + // + // Support creation of child items underneath generated folder items: + // + if (bFolderItem) + { + BOOL bChildItemCreation = TRUE; + hr = PropertyManager.AddProperty(WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION, WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION_STR, RN, bChildItemCreation); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPS_SUPPORTS_CHILD_ITEM_CREATION property to the property manager, hr = 0x%lx",hr)); + } + } + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to add WIA_IPA_ITEM_CATEGORY property to the property manager, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to get the WIA item type, hr = 0x%lx",hr)); + } + + if(SUCCEEDED(hr)) + { + hr = PropertyManager.SetItemProperties(pWiasContext); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "CWIAPropertyManager::SetItemProperties failed to set WIA storage item properties, hr = 0x%lx",hr)); + } + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function returns the WIA driver item context + * data stored with the driver item. NOT ALL DRIVER ITEMS + * HAVE CONTEXTS STORED WITH THEM. The context is initialized + * and stored at WIA item creation. See CreateWIAChildItem + * function. + * + * @param pWiasContext + * Pointer to the WIA item context + * @param ppWiaDriverItemContext + * Pointer to the WIA driver item context data + * @return + */ +HRESULT wiasGetDriverItemPrivateContext( + _In_ BYTE *pWiasContext, + _Out_ BYTE **ppWiaDriverItemContext) +{ + HRESULT hr = E_INVALIDARG; + if((pWiasContext)&&(ppWiaDriverItemContext)) + { + IWiaDrvItem *pIWiaDrvItem = NULL; + hr = wiasGetDrvItem(pWiasContext, &pIWiaDrvItem); + if(SUCCEEDED(hr)) + { + hr = pIWiaDrvItem->GetDeviceSpecContext(ppWiaDriverItemContext); + // + // The caller will handle the failure case. A failure, may mean that the + // the WIA item does not have a private device specific context + // stored. This is OK, because is is not required. + // + } + else + { + WIAS_ERROR((g_hInst, "Failed to get the WIA driver item from the application item, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function returns the application item's + * parent WIA item context. The returned context + * can be used to access the parent's WIA property + * set. + * + * @param pWiasContext + * Pointer to the WIA item context + * @param ppWiasContext + * Pointer to the parent WIA item context + * @return + */ +HRESULT wiasGetAppItemParent( + _In_ BYTE *pWiasContext, + _Out_ BYTE **ppWiasContext) +{ + HRESULT hr = E_INVALIDARG; + if((pWiasContext) && (ppWiasContext)) + { + // FIX! This helper function is actually getting the backing driver + // item and returning it as the parent. This will make the + // driver always associate the newly created child item with its + // proper backing driver item. This function should be fixed to + // return the parent application item. + // + + IWiaDrvItem *pIWiaDrvItemParent = NULL; + hr = wiasGetDrvItem(pWiasContext,&pIWiaDrvItemParent); + if(SUCCEEDED(hr)) + { + BSTR bstrFullItemName = NULL; + hr = pIWiaDrvItemParent->GetFullItemName(&bstrFullItemName); + if(SUCCEEDED(hr)) + { + hr = wiasGetContextFromName(pWiasContext,0,bstrFullItemName,ppWiasContext); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to get the parent's application item from the item name (%ws), hr = 0x%lx",bstrFullItemName,hr)); + } + SysFreeString(bstrFullItemName); + bstrFullItemName = NULL; + } + else + { + WIAS_ERROR((g_hInst, "Failed to get full item name from parent IWiaDrvItem, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to get the WIA driver item from the application item, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function converts a unit (in pixels) to + * another unit (1/1000ths of an inch). + * + * @param lPixelLength + * Unit length in pixels + * @param lResolution + * Resolution of Pixel unit length (in Dots Per Inch "DPI") + * @return + */ +LONG ConvertTo1000thsOfAnInch( + LONG lPixelLength, + LONG lResolution) +{ + LONG lConvertedValue = 0; + if((lPixelLength)&&(lResolution)) + { + lConvertedValue = (LONG)((((lPixelLength * 1000) + lResolution - 1) / lResolution)); + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return lConvertedValue; +} + +/** + * This function populates a BITMAPINFOHEADER structure + * using data contained in a Gdiplus::BitmapData object. + * This function only works with 24-bit data. + * + * @param pGDIPlusBitmapData + * Pointer to a GDI+ BitmapData object + * @param pBitmapInfoHeader + * Pointer to a BITMAPINFOHEADER structure + * @return + */ +HRESULT GetBitmapHeaderFromBitmapData( + _In_ Gdiplus::BitmapData *pGDIPlusBitmapData, + _Out_ BITMAPINFOHEADER *pBitmapInfoHeader) +{ + HRESULT hr = E_INVALIDARG; + if((pGDIPlusBitmapData) && (pBitmapInfoHeader) && (pGDIPlusBitmapData->PixelFormat == PixelFormat24bppRGB)) + { + memset(pBitmapInfoHeader, 0, sizeof(BITMAPINFOHEADER)); + pBitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER); + pBitmapInfoHeader->biPlanes = 1; + pBitmapInfoHeader->biWidth = pGDIPlusBitmapData->Width; + pBitmapInfoHeader->biHeight = pGDIPlusBitmapData->Height; + + // We cannot use the stride to calculate the size, because if there is no + // format conversion, we might get the original bits... + // We need to calculate the size based on the width + pBitmapInfoHeader->biSizeImage = ((((pGDIPlusBitmapData->Width * 3) + 3) & ~3) * pGDIPlusBitmapData->Height); + + pBitmapInfoHeader->biBitCount = 24; + hr = S_OK; + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function returns a Gdiplus::Rect structure + * initialized with the current WIA extent setting + * values. This function assumes that the WIA item + * passed in supports WIA_IPS_XPOS, WIA_IPS_YPOS, + * WIA_IPS_XEXTENT and WIA_IPS_YEXTENT properties. + * + * @param pWiasContext + * Pointer to the WIA item context + * @param pRect Pointer to a Gdiplus::Rect object + * @return + */ +HRESULT GetSelectionAreaRect( + _In_ BYTE* pWiasContext, + _Out_ Gdiplus::Rect *pRect) +{ + HRESULT hr = E_INVALIDARG; + LONG lXPos = 0; + LONG lYPos = 0; + LONG lXExtent = 0; + LONG lYExtent = 0; + + if((pWiasContext)&&(pRect)) + { + hr = wiasReadPropLong(pWiasContext,WIA_IPS_XPOS,&lXPos,NULL,TRUE); + if(SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext,WIA_IPS_YPOS,&lYPos,NULL,TRUE); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_IPS_YPOS property, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_IPS_XPOS property, hr = 0x%lx",hr)); + } + if(SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext,WIA_IPS_YEXTENT,&lYExtent,NULL,TRUE); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_IPS_YEXTENT property, hr = 0x%lx",hr)); + } + } + if(SUCCEEDED(hr)) + { + hr = wiasReadPropLong(pWiasContext,WIA_IPS_XEXTENT,&lXExtent,NULL,TRUE); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_IPS_XEXTENT property, hr = 0x%lx",hr)); + } + } + if(SUCCEEDED(hr)) + { + Gdiplus::Rect rFrame((INT)lXPos,(INT)lYPos,(INT)lXExtent,(INT)lYExtent); + *pRect = rFrame; + hr = S_OK; + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function locks down a portion of a bitmap using + * the current WIA extent setting values. This function assumes that the WIA item + * passed in supports WIA_IPS_XPOS, WIA_IPS_YPOS, + * WIA_IPS_XEXTENT and WIA_IPS_YEXTENT properties. + * + * @param pWiasContext + * Pointer to the WIA item context + * @param pBitmap Pointer to a Gdiplus::Bitmap object containing the + * bitmap data. + * @param pBitmapData + * Pointer to a Gdiplus::BitmapData object + * @param pbmih Pointer to a BITMAPINFOHEADER structure that will + * receive the information about the locked area of the + * bitmap. + * @param ppBitmapBits + * Pointer to the first scan line of data of the locked + * portion of the bitmap + * @return + */ +HRESULT LockSelectionAreaOnBitmap( + _In_ BYTE *pWiasContext, + _In_ Gdiplus::Bitmap *pBitmap, + _Out_ Gdiplus::BitmapData *pBitmapData, + _In_ BITMAPINFOHEADER *pbmih, + _Outptr_result_maybenull_ + BYTE **ppBitmapBits) +{ + HRESULT hr = E_INVALIDARG; + + if((pBitmapData)&&(pbmih)&&(ppBitmapBits)) + { + Gdiplus::Rect rFrame(0,0,0,0); + hr = GetSelectionAreaRect(pWiasContext,&rFrame); + + if(SUCCEEDED(hr)) + { + if(pBitmap->LockBits(&rFrame, + ImageLockModeRead, + PixelFormat24bppRGB, + pBitmapData) == Ok) + { + hr = GetBitmapHeaderFromBitmapData(pBitmapData,pbmih); + if(SUCCEEDED(hr)) + { + *ppBitmapBits = (BYTE*)pBitmapData->Scan0; + } + else + { + WIAS_ERROR((g_hInst, "Failed to get the BITMAPINFOHEADER information from the GDI+ bitmap data object, hr = 0x%lx",hr)); + } + } + else + { + hr = E_FAIL; + WIAS_ERROR((g_hInst, "Failed to LockBits on GDI+ bitmap object, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to get selection area rect from WIA extent settings properties, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function unlocks a portion of a bitmap previously locked + * by LockSelectionAreaOnBitmap function. + * + * @param pBitmap Pointer to a Gdiplus::Bitmap object containing the + * bitmap data. + * @param pBitmapData + * Pointer to a Gdiplus::BitmapData object + */ +void UnlockSelectionAreaOnBitmap( + _In_ Gdiplus::Bitmap *pBitmap, + _In_ Gdiplus::BitmapData *pBitmapData) +{ + if((pBitmap)&&(pBitmapData)) + { + if(pBitmap->UnlockBits(pBitmapData) != Ok) + { + WIAS_ERROR((g_hInst, "Failed to UnlockBits on GDI+ bitmap object")); + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } +} + +/** + * This helper function attempts to grab a IWiaMiniDrvTransferCallback interface + * from a PMINIDRV_TRANSFER_CONTEXT structure. + * + * If successful, caller must Release. + * + * @param pmdtc The PMINIDRV_TRANSFER_CONTEXT handed in during drvAcquireItemData. + * @param ppIWiaMiniDrvTransferCallback + * Address of a interface pointer which receives the callback. + * @return HRESULT return value. + */ +HRESULT GetTransferCallback( + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + __callback IWiaMiniDrvTransferCallback **ppIWiaMiniDrvTransferCallback) +{ + HRESULT hr = E_INVALIDARG; + if (pmdtc && ppIWiaMiniDrvTransferCallback) + { + if (pmdtc->pIWiaMiniDrvCallBack) + { + hr = pmdtc->pIWiaMiniDrvCallBack->QueryInterface(IID_IWiaMiniDrvTransferCallback, + (void**) ppIWiaMiniDrvTransferCallback); + } + else + { + hr = E_UNEXPECTED; + WIAS_ERROR((g_hInst, "A NULL pIWiaMiniDrvCallBack was passed in the MINIDRV_TRANSFER_CONTEXT structure, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function allocates a buffer to be used during + * data transfers. FreeTransferBuffer should be called + * to free the memory allocated by this function. + * + * @param pWiasContext + * Pointer to the WIA item context + * @param ppBuffer Pointer to the allocated buffer. The caller should call + * FreeTransferBuffer() when finished with this buffer. + * @param pulBufferSize + * Size of the buffer allocated. + * @return + */ +HRESULT AllocateTransferBuffer( + _In_ BYTE *pWiasContext, + _Out_ BYTE **ppBuffer, + _In_ ULONG *pulBufferSize) +{ + HRESULT hr = S_OK; + + if (pWiasContext && ppBuffer && pulBufferSize) + { + // + // Set the buffer size to DEFAULT_BUFFER_SIZE + // + *pulBufferSize = DEFAULT_BUFFER_SIZE; + + // Allocate the memory + *ppBuffer = (BYTE*) CoTaskMemAlloc(*pulBufferSize); + if (*ppBuffer) + { + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for transfer buffer, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + hr = E_INVALIDARG; + } + return hr; +} + +/** + * This function frees any memory allocated using AllocateTransferBuffer() + * function. + * + * @param pBuffer Pointer to a buffer allocated with the AllocateTransferBuffer() + * function. + */ +void FreeTransferBuffer( + _In_ BYTE *pBuffer) +{ + // Free the memory + if (pBuffer) + { + CoTaskMemFree(pBuffer); + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed. (Attempted to free NULL transfer buffer)")); + } +} + +/** + * This function attempts to extract the file + * extension from a file path. It is assumed that + * the passed in path contains an extension of some + * type. (e.g. x:\xxxxx\xxx\xxxxxx.xxx) + * + * @param bstrFullPath + * Full path containing extension + * @param pbstrExtension + * Extracted extension + * @return + */ +HRESULT GetFileExtensionFromPath( + _In_ BSTR bstrFullPath, + _Out_ BSTR *pbstrExtension) +{ + HRESULT hr = E_INVALIDARG; + if((bstrFullPath)&&(pbstrExtension)) + { + CBasicStringWide cswPath = bstrFullPath; + CBasicStringWide cswExtension; + if(cswPath.Length()) + { + size_t iEndIndex = cswPath.Length(); + size_t iStartIndex = cswPath.ReverseFind(TEXT(".")); + if(iStartIndex > 0) + { + cswExtension = cswPath.SubStr((iStartIndex + 1),iEndIndex); + cswExtension = cswExtension.ToUpper(); + } + } + *pbstrExtension = SysAllocString(cswExtension.String()); + if(*pbstrExtension) + { + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + WIAS_ERROR((g_hInst, "Failed to allocate memory for BSTR file extension string, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Invalid parameters were passed")); + } + return hr; +} + +/** + * This function returns TRUE is the WIA item passed + * in contains the WIA item flag setting of + * WiaItemTypeProgrammableDataSource. + * + * @param pWiasContext + * Pointer to the WIA item context + * @return + */ +bool IsProgrammableItem( + _In_ BYTE *pWiasContext) +{ + LONG lItemType = 0; + HRESULT hr = S_OK; + hr = wiasGetItemType(pWiasContext,&lItemType); + return ((lItemType & WiaItemTypeProgrammableDataSource) == WiaItemTypeProgrammableDataSource); +} + +/** + * This function queues a WIA event using the passed in + * WIA item context. + * + * @param pWiasContext + * Pointer to the WIA item context + * @param guidWIAEvent + * WIA event to queue + */ +void QueueWIAEvent( + _In_ BYTE *pWiasContext, + const GUID &guidWIAEvent) +{ + HRESULT hr = S_OK; + BSTR bstrDeviceID = NULL; + BSTR bstrFullItemName = NULL; + BYTE *pRootItemContext = NULL; + + hr = wiasReadPropStr(pWiasContext, WIA_IPA_FULL_ITEM_NAME, &bstrFullItemName, NULL,TRUE); + if(SUCCEEDED(hr)) + { + hr = wiasGetRootItem(pWiasContext,&pRootItemContext); + if(SUCCEEDED(hr)) + { + hr = wiasReadPropStr(pRootItemContext, WIA_DIP_DEV_ID,&bstrDeviceID, NULL,TRUE); + if(SUCCEEDED(hr)) + { + hr = wiasQueueEvent(bstrDeviceID,&guidWIAEvent,bstrFullItemName); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "Failed to queue WIA event, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to read the WIA_DIP_DEV_ID property, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to get the Root item from child item, using wiasGetRootItem, hr = 0x%lx",hr)); + } + } + else + { + WIAS_ERROR((g_hInst, "Failed to read WIA_IPA_FULL_ITEM_NAME property, hr = %lx",hr)); + } + + if(bstrFullItemName) + { + SysFreeString(bstrFullItemName); + bstrFullItemName = NULL; + } + + if(bstrDeviceID) + { + SysFreeString(bstrDeviceID); + bstrDeviceID = NULL; + } +} diff --git a/wia/wiadriverex/usd/wiahelpers.h b/wia/wiadriverex/usd/wiahelpers.h new file mode 100644 index 00000000..15a8bdd0 --- /dev/null +++ b/wia/wiadriverex/usd/wiahelpers.h @@ -0,0 +1,121 @@ +/************************************************************************** +* +* Copyright (c) 2003 Microsoft Corporation +* +* Title: wiahelpers.h +* +* Description: This contains the WIA driver class helper functions. +* +***************************************************************************/ +#pragma once + +#define NO_FIXED_FRAME 0xFFFFFFFF + +typedef struct _FILM_FRAME { + LONG XPOS; + LONG YPOS; + LONG XEXTENT; + LONG YEXTENT; +} FILM_FRAME; + +HRESULT MakeFullItemName( + _In_ IWiaDrvItem *pParent, + _In_ BSTR bstrItemName, + _Out_ BSTR *pbstrFullItemName); + +HRESULT CreateWIAChildItem( + _In_ LPOLESTR wszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent, + LONG lItemFlags, + GUID guidItemCategory, + _Out_opt_ IWiaDrvItem **ppChild = NULL, + _In_opt_ PCWSTR wszStoragePath = NULL); +HRESULT CreateWIAFlatbedItem( + _In_ LPOLESTR wszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent); + +HRESULT CreateWIAFeederItem( + _In_ LPOLESTR wszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent); + +HRESULT CreateWIAFilmItem( + _In_ LPOLESTR wszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent); + +HRESULT CreateWIAStorageItem( + _In_ LPOLESTR wszItemName, + _In_ IWiaMiniDrv *pIWiaMiniDrv, + _In_ IWiaDrvItem *pParent, + _In_ const WCHAR *wszStoragePath); + +HRESULT InitializeRootItemProperties( + _In_ BYTE *pWiasContext); + +HRESULT InitializeWIAItemProperties( + _In_ BYTE *pWiasContext, + _In_ HINSTANCE hInstance, + UINT uiResourceID); + +HRESULT InitializeWIAStorageItemProperties( + _In_ BYTE *pWiasContext, + BOOL bRootItem, + BOOL bFolderItem); + +HRESULT wiasGetDriverItemPrivateContext( + _In_ BYTE *pWiasContext, + _Out_ BYTE **ppWiaDriverItemContext); + +HRESULT wiasGetAppItemParent( + _In_ BYTE *pWiasContext, + _Out_ BYTE **ppWiasContext); + +LONG ConvertTo1000thsOfAnInch( + LONG lPixelSize, + LONG lResolution); + +HRESULT GetBitmapHeaderFromBitmapData( + _In_ Gdiplus::BitmapData *pGDIPlusBitmapData, + _Out_ BITMAPINFOHEADER *pBitmapInfoHeader); + +HRESULT GetSelectionAreaRect( + _In_ BYTE *pWiasContext, + _Out_ Gdiplus::Rect *pRect); + +HRESULT LockSelectionAreaOnBitmap( + _In_ BYTE *pWiasContext, + _In_ Gdiplus::Bitmap *pBitmap, + _Out_ Gdiplus::BitmapData *pBitmapData, + _In_ BITMAPINFOHEADER *pbmih, + _Outptr_result_maybenull_ + BYTE **ppBitmapBits); + +void UnlockSelectionAreaOnBitmap( + _In_ Gdiplus::Bitmap *pBitmap, + _In_ Gdiplus::BitmapData *pBitmapData); + +HRESULT GetTransferCallback( + _In_ PMINIDRV_TRANSFER_CONTEXT pmdtc, + __callback IWiaMiniDrvTransferCallback **ppIWiaMiniDrvTransferCallback); + +HRESULT AllocateTransferBuffer( + _In_ BYTE *pWiasContext, + _Out_ BYTE **ppBuffer, + _In_ ULONG *pulBufferSize); + +void FreeTransferBuffer( + _In_ BYTE *pBuffer); + +HRESULT GetFileExtensionFromPath( + _In_ BSTR bstrFullPath, + _Out_ BSTR *pbstrExtension); + +bool IsProgrammableItem( + _In_ BYTE *pWiasContext); + +void QueueWIAEvent( + _In_ BYTE *pWiasContext, + const GUID &guidWIAEvent); diff --git a/wia/wiadriverex/usd/wiapropertymanager.cpp b/wia/wiadriverex/usd/wiapropertymanager.cpp new file mode 100644 index 00000000..03e1a1a5 --- /dev/null +++ b/wia/wiadriverex/usd/wiapropertymanager.cpp @@ -0,0 +1,1127 @@ +/************************************************************************** +* +* Copyright (c) 2003 Microsoft Corporation +* +* Title: wiapropertymanager.cpp +* +* Date: +* +* Description: This file contains the class implementation of the +* CWIAPropertyManager class that encapsulates simple WIA +* property creation. +* +***************************************************************************/ +#include "stdafx.h" + +CWIAPropertyManager::CWIAPropertyManager() +{ + ; +} + +CWIAPropertyManager::~CWIAPropertyManager() +{ + + // + // cleanup any items contained in the property list + // before exiting + // + + for(INT i = 0; i < m_List.Size(); i++) + { + PWIA_PROPERTY_INFO_DATA pPropertyData = m_List[i]; + + if(pPropertyData) + { + // + // delete contents + // + + DeletePropertyData(pPropertyData); + + // + // delete container + // + + delete pPropertyData; + } + } +} + +/***************************************************************************** + Function Name: FindProperty + + Arguments: + + LONG lPropertyID - Property ID of the property to find + + Description: + + This function finds the specified property, and removes it from the list + of properties + + *****************************************************************************/ + +PWIA_PROPERTY_INFO_DATA CWIAPropertyManager::FindProperty(LONG lPropertyID) +{ + + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + if(0 <= lPropertyID) + { + for(INT i = 0; i< m_List.Size(); i++) + { + PWIA_PROPERTY_INFO_DATA pPropertyData = m_List[i]; + if(pPropertyData->pid == (ULONG) lPropertyID) + { + pInfo = pPropertyData; + break; + } + } + } + + return pInfo; +} + +/***************************************************************************** + Function Name: DeletePropertyData + + Arguments: + + PWIA_PROPERTY_INFO_DATA pInfo - pointer containing the property data + + Description: + + This function deletes the contents of a WIA_PROPERTY_DATA structure. + + *****************************************************************************/ + +HRESULT CWIAPropertyManager::DeletePropertyData(_In_ PWIA_PROPERTY_INFO_DATA pInfo) +{ + + HRESULT hr = E_INVALIDARG; + if (pInfo) + { + + // + // delete any allocated LISTS + // + + if (pInfo->wpi.lAccessFlags & WIA_PROP_LIST) + { + if(pInfo->pv.vt & VT_I4) + { + WIAS_TRACE((g_hInst,"Freeing LONG List for %d",pInfo->pid)); + if (pInfo->wpi.ValidVal.List.pList) + { + LocalFree(pInfo->wpi.ValidVal.List.pList); + pInfo->wpi.ValidVal.List.pList = NULL; + } + } + + if(pInfo->pv.vt & VT_CLSID) + { + WIAS_TRACE((g_hInst,"Freeing GUID List for %d",pInfo->pid)); + if (pInfo->wpi.ValidVal.ListGuid.pList) + { + LocalFree(pInfo->wpi.ValidVal.ListGuid.pList); + pInfo->wpi.ValidVal.ListGuid.pList = NULL; + } + } + } + + // + // free any allocated BSTRS + // + + if (pInfo->pv.vt == VT_BSTR) + { + SysFreeString(pInfo->pv.bstrVal); + pInfo->pv.bstrVal = NULL; + } + + // + // delete any allocated GUIDS + // + + if (pInfo->pv.vt == VT_CLSID) + { + delete pInfo->pv.puuid; + pInfo->pv.puuid = NULL; + } + + hr = S_OK; + } + return hr; +} + +/***************************************************************************** + Function Name: AllocatePropertyData + + Arguments: + + NONE + + Description: + + This function allocates a WIA_PROPERTY_INFO_DATA strucuture, and initializes + the members. + + *****************************************************************************/ + +PWIA_PROPERTY_INFO_DATA CWIAPropertyManager::AllocatePropertyData() +{ + + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + pInfo = new WIA_PROPERTY_INFO_DATA; + if (pInfo) + { + // + // erase all values in newly allocated property data structure + // + + memset(pInfo,0,sizeof(WIA_PROPERTY_INFO_DATA)); + + // + // properly initialize the property variant + // + + PropVariantInit(&pInfo->pv); + } + return pInfo; +} + +/***************************************************************************** + Function Name: RemovePropertyAndDeleteData + + Arguments: + + LONG lPropertyID - Property ID of the property to remove and delete + + Description: + + This function finds the property specified by lPropertyID and deletes the + contents of the WIA_PROPERTY_INFO_DATA. + + *****************************************************************************/ + +HRESULT CWIAPropertyManager::RemovePropertyAndDeleteData(LONG lPropertyID) +{ + + // + // find any existing property with the same ID, and remove it from the list + // + + PWIA_PROPERTY_INFO_DATA pInfo = FindProperty(lPropertyID); + if (pInfo) + { + + // + // find and remove the property info from the list and delete the + // contents + // + + m_List.Delete(m_List.Find(pInfo)); + delete pInfo; + pInfo = NULL; + } + return S_OK; +} + +/***************************************************************************** + Function Name: AddProperty + + Arguments: + + LONG lPropertyID - Property ID + LPOLESTR szName - Property NAME + LONG lAccessFlags - Property Access Flags + LONG lCurrValue - Current Property Value + + Description: + + This function adds a new property to the property list. + + Remarks: + If a property exists with the same property ID: + 1. The old property is removed from the list, and the contents + destroyed + 2. The new property is added to the list. + + *****************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, LONG lCurrValue) +{ + + HRESULT hr = E_INVALIDARG; + if(szName) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // when a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the lastest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // allocate a property info structure + // + + pInfo = AllocatePropertyData(); + if(pInfo) + { + + // + // populate the data in the structure, and add it to the property list + // + + pInfo->szName = szName; + pInfo->pid = lPropertyID; + pInfo->pv.lVal = lCurrValue; + pInfo->pv.vt = VT_I4; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + +/***************************************************************************** + Function Name: AddProperty + + Arguments: + + LONG lPropertyID - Property ID + LPOLESTR szName - Property NAME + LONG lAccessFlags - Property Access Flags + BYTE *pbCurrValue - Current Property Value (BYTE vector) + ULONG ulNumItems - Number of items in the current propery value vector + + Description: + + This function adds a new VT_UI1 | VT_VECTOR property to the property list. + + Remarks: + If a property exists with the same property ID: + 1. The old property is removed from the list, and the contents + destroyed + 2. The new property is added to the list. + + *****************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty(LONG lPropertyID, + _In_ LPOLESTR szName, + LONG lAccessFlags, + _In_ BYTE *pbCurrValue, + ULONG ulNumItems) +{ + + HRESULT hr = E_INVALIDARG; + if(szName) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // when a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the lastest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // allocate a property info structure + // + + pInfo = AllocatePropertyData(); + if(pInfo) + { + + // + // populate the data in the structure, and add it to the property list + // + // Note: for a VT_VECTOR | VT_UI1 the correct PROPVARIANT member is: caub (type: CAUB) + // + // From MSDN: + // + // "If the type indicator is combined with VT_VECTOR by using an OR operator, the value is one of the counted array values. + // This creates a DWORD count of elements, followed by a pointer to the specified repetitions of the value. + // For example, a type indicator of VT_LPSTR|VT_VECTOR has a DWORD element count, followed by a pointer to an array of LPSTR elements. + // VT_VECTOR can be combined by an OR operator with the following types: VT_I1, VT_UI1, VT_I2, VT_UI2, VT_BOOL, VT_I4, VT_UI4, VT_R4, + // VT_R8, VT_ERROR, VT_I8, VT_UI8, VT_CY, VT_DATE, VT_FILETIME, VT_CLSID, VT_CF, VT_BSTR, VT_LPSTR, VT_LPWSTR, and VT_VARIANT". + // + pInfo->szName = szName; + pInfo->pid = lPropertyID; + pInfo->pv.caub.cElems = ulNumItems; + pInfo->pv.caub.pElems = pbCurrValue; + pInfo->pv.vt = VT_UI1 | VT_VECTOR; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + +/***************************************************************************** + Function Name: AddProperty + + Arguments: + + LONG lPropertyID - Property ID + LPOLESTR szName - Property NAME + LONG lAccessFlags - Property Access Flags + LONG lCurrValue - Current Property Value + LONG lValidBits - Valid bit values + + Description: + + This function adds a new property to the property list. + + Remarks: + If a property exists with the same property ID: + 1. The old property is removed from the list, and the contents + destroyed + 2. The new property is added to the list. + + *****************************************************************************/ + + +HRESULT CWIAPropertyManager::AddProperty(LONG lPropertyID, + _In_ LPOLESTR szName, + LONG lAccessFlags, + LONG lCurrValue, + LONG lValidBits) +{ + + HRESULT hr = E_INVALIDARG; + if(szName) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // when a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the lastest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // allocate a property info structure + // + + pInfo = AllocatePropertyData(); + if(pInfo) + { + + // + // populate the data in the structure, and add it to the property list + // + + pInfo->szName = szName; + pInfo->pid = lPropertyID; + pInfo->pv.lVal = lCurrValue; + pInfo->pv.vt = VT_I4; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + pInfo->wpi.ValidVal.Flag.Nom = lCurrValue; + pInfo->wpi.ValidVal.Flag.ValidBits = lValidBits; + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + +/***************************************************************************** + Function Name: AddProperty + + Arguments: + + LONG lPropertyID - Property ID + LPOLESTR szName - Property NAME + LONG lAccessFlags - Property Access Flags + LONG lCurrValue - Current Property Value + LONG lNomValue - Property Nominal Value + LONG lMinValue - Property Minimum Value + LONG lMaxValue - Property Maximum Value + LONG lInc - Property Increment Value + + Description: + + This function adds a new property to the property list. + + Remarks: + If a property exists with the same property ID: + 1. The old property is removed from the list, and the contents + destroyed + 2. The new property is added to the list. + + *****************************************************************************/ + + +HRESULT CWIAPropertyManager::AddProperty(LONG lPropertyID, + _In_ LPOLESTR szName, + LONG lAccessFlags, + LONG lCurrValue, + LONG lNomValue, + LONG lMinValue, + LONG lMaxValue, + LONG lInc) +{ + + HRESULT hr = E_INVALIDARG; + if((szName)&& + (lMinValue <= lMaxValue) && + (lNomValue >= lMinValue) && + (lNomValue <= lMaxValue) && + (lCurrValue >= lMinValue) && + (lCurrValue <= lMaxValue)) // TODO: validate lInc value??? + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // when a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the lastest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // allocate a property info structure + // + + pInfo = AllocatePropertyData(); + if(pInfo) + { + + // + // populate the data in the structure, and add it to the property list + // + + pInfo->szName = szName; + pInfo->pid = lPropertyID; + pInfo->pv.lVal = lCurrValue; + pInfo->pv.vt = VT_I4; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + pInfo->wpi.ValidVal.Range.Inc = lInc; + pInfo->wpi.ValidVal.Range.Min = lMinValue; + pInfo->wpi.ValidVal.Range.Max = lMaxValue; + pInfo->wpi.ValidVal.Range.Nom = lNomValue; + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + +/***************************************************************************** + Function Name: AddProperty + + Arguments: + + LONG lPropertyID - Property ID + LPOLESTR szName - Property NAME + LONG lAccessFlags - Property Access Flags + LONG lCurrValue - Current Property Value + LONG lNomValue - Property Nominal Value + CBasicDynamicArray<LONG> - LONG Array + + Description: + + This function adds a new property to the property list. + + Remarks: + If a property exists with the same property ID: + 1. The old property is removed from the list, and the contents + destroyed + 2. The new property is added to the list. + + *****************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, LONG lCurrValue, + LONG lNomValue, _In_ CBasicDynamicArray<LONG> *pValueList) +{ + + HRESULT hr = E_INVALIDARG; + if((szName)&&(pValueList)&&(pValueList->Size())) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + LONG *pLongList = NULL; + + // + // when a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the lastest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + if(pValueList) + { + LONG lNumValues = (LONG)pValueList->Size(); + if(lNumValues) + { + pLongList = (LONG*)LocalAlloc(LPTR,(sizeof(LONG)*lNumValues)); + if(pLongList) + { + for(INT iIndex = 0; iIndex < pValueList->Size(); iIndex++) + { + pLongList[iIndex] = ((*pValueList)[iIndex]); + } + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + + if(SUCCEEDED(hr)) + { + + // + // allocate a property info structure + // + + pInfo = AllocatePropertyData(); + if(pInfo) + { + + // + // populate the data in the structure, and add it to the property list + // + + pInfo->szName = szName; + pInfo->pid = lPropertyID; + pInfo->pv.lVal = lCurrValue; + pInfo->pv.vt = VT_I4; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + pInfo->wpi.ValidVal.List.pList = (BYTE*)pLongList; + pInfo->wpi.ValidVal.List.Nom = lNomValue; + pInfo->wpi.ValidVal.List.cNumList = lNumValues; + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + } + else + { + hr = E_INVALIDARG; + } + } + else + { + hr = E_INVALIDARG; + } + + if(FAILED(hr)) + { + if(pLongList) + { + LocalFree(pLongList); + pLongList = NULL; + } + } + } + return hr; +} + +/***************************************************************************** + Function Name: AddProperty + + Arguments: + + LONG lPropertyID - Property ID + LPOLESTR szName - Property NAME + LONG lAccessFlags - Property Access Flags + BSTR bstrCurrValue - Current Property Value + + Description: + + This function adds a new property to the property list. + + Remarks: + If a property exists with the same property ID: + 1. The old property is removed from the list, and the contents + destroyed + 2. The new property is added to the list. + + *****************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, _In_ BSTR bstrCurrValue) +{ + + HRESULT hr = E_INVALIDARG; + if((szName)&&(bstrCurrValue)) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // when a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the lastest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + // + // allocate a property info structure + // + + pInfo = AllocatePropertyData(); + if(pInfo) + { + + // + // populate the data in the structure, and add it to the property list + // + + pInfo->szName = szName; + pInfo->pid = lPropertyID; + pInfo->pv.bstrVal = SysAllocString(bstrCurrValue); + pInfo->pv.vt = VT_BSTR; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + +/***************************************************************************** + Function Name: AddProperty + + Arguments: + + LONG lPropertyID - Property ID + LPOLESTR szName - Property NAME + LONG lAccessFlags - Property Access Flags + GUID guidCurrValue - Current Property Value + + Description: + + This function adds a new property to the property list. + + Remarks: + If a property exists with the same property ID: + 1. The old property is removed from the list, and the contents + destroyed + 2. The new property is added to the list. + + *****************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, GUID guidCurrValue) +{ + + HRESULT hr = E_INVALIDARG; + if(szName) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + + // + // when a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the lastest. + // + + RemovePropertyAndDeleteData(lPropertyID); + +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "pguid is freed by DeletePropertyData() when m_List is destroyed.") + GUID *pguid = new GUID; + if(pguid) + { + *pguid = guidCurrValue; + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + + if(SUCCEEDED(hr)) + { + + // + // allocate a property info structure + // + + pInfo = AllocatePropertyData(); + if(pInfo) + { + // + // populate the data in the structure, and add it to the property list + // + + pInfo->szName = szName; + pInfo->pid = lPropertyID; + pInfo->pv.puuid = pguid; + pInfo->pv.vt = VT_CLSID; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + m_List.Append(pInfo); + hr = S_OK; + } + else + { + // + // Cleanup locally allocated memory + // + delete pguid; + pguid = NULL; + + hr = E_OUTOFMEMORY; + } + } + } + return hr; +} + +/***************************************************************************** + Function Name: AddProperty + + Arguments: + + LONG lPropertyID - Property ID + LPOLESTR szName - Property NAME + LONG lAccessFlags - Property Access Flags + GUID guidCurrValue - Current Property Value + GUID guidNomValue - Property Nominal Value + CBasicDynamicArray<GUID> - GUID List + + Description: + + This function adds a new property to the property list. + + Remarks: + If a property exists with the same property ID: + 1. The old property is removed from the list, and the contents + destroyed + 2. The new property is added to the list. + + *****************************************************************************/ + +HRESULT CWIAPropertyManager::AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, GUID guidCurrValue, + GUID guidNomValue, _In_ CBasicDynamicArray<GUID> *pValueList) +{ + + HRESULT hr = E_INVALIDARG; + if((szName)&&(pValueList)) + { + PWIA_PROPERTY_INFO_DATA pInfo = NULL; + GUID *pguid = NULL; + GUID *pguidList = NULL; + + // + // when a property is being added, always remove any existing property that has the same + // property ID. Any call to AddProperty() means that the property being added should be + // treated as the lastest. + // + + RemovePropertyAndDeleteData(lPropertyID); + + if(pValueList) + { + LONG lNumValues = (LONG)pValueList->Size(); + if(lNumValues) + { + pguidList = (GUID*)LocalAlloc(LPTR,(sizeof(GUID)*lNumValues)); + if(pguidList) + { + for(INT iIndex = 0; iIndex < pValueList->Size(); iIndex++) + { + pguidList[iIndex] = ((*pValueList)[iIndex]); + } + + hr = S_OK; + + if(SUCCEEDED(hr)) + { +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "pguid is freed by DeletePropertyData() when m_List is destroyed.") + pguid = new GUID; + if(pguid) + { + *pguid = guidCurrValue; + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + } + + if(SUCCEEDED(hr)) + { + + // + // allocate a property info structure + // + + pInfo = AllocatePropertyData(); + if(pInfo) + { + + // + // populate the data in the structure, and add it to the property list + // + + pInfo->szName = szName; + pInfo->pid = lPropertyID; + pInfo->pv.puuid = pguid; + pInfo->pv.vt = VT_CLSID; + pInfo->ps.ulKind = PRSPEC_PROPID; + pInfo->ps.propid = pInfo->pid; + pInfo->wpi.lAccessFlags = lAccessFlags; + pInfo->wpi.vt = pInfo->pv.vt; + pInfo->wpi.ValidVal.ListGuid.pList = pguidList; + pInfo->wpi.ValidVal.ListGuid.Nom = guidNomValue; + pInfo->wpi.ValidVal.ListGuid.cNumList = lNumValues; + + m_List.Append(pInfo); + hr = S_OK; + } + else + { + hr = E_OUTOFMEMORY; + } + } + else + { + hr = E_OUTOFMEMORY; + } + } + else + { + hr = E_INVALIDARG; + } + } + else + { + hr = E_INVALIDARG; + } + + if(FAILED(hr)) + { + // free memory any allocated memory if failure occurs + if(pguidList) + { + LocalFree(pguidList); + pguidList = NULL; + } + + if(pguid) + { + delete pguid; + pguid = NULL; + } + } + } + return hr; +} + +/***************************************************************************** + Function Name: RemoveProperty + + Arguments: + + LONG lPropertyID - Property ID + + Description: + + This function removes a property from the property list. + + *****************************************************************************/ + +HRESULT CWIAPropertyManager::RemoveProperty(LONG lPropertyID) +{ + + return RemovePropertyAndDeleteData(lPropertyID); +} + +/***************************************************************************** + Function Name: SetItemProperties + + Arguments: + + BYTE *pWiasContext - WIA Context provided by the WIA service + + Description: + + This function uses WIA helper functions to upload the properties to the + WIA service. + + *****************************************************************************/ + +HRESULT CWIAPropertyManager::SetItemProperties(_Inout_ BYTE *pWiasContext) +{ + + HRESULT hr = E_INVALIDARG; + if(pWiasContext) + { + hr = S_OK; + + // + // get current number of properties in the list + // + + LONG lNumProps = m_List.Size(); + if(lNumProps) + { + LONG lIndex = 0; + + LPOLESTR *pszName = (LPOLESTR*) LocalAlloc(LPTR,sizeof(LPOLESTR)*lNumProps); + PROPID *ppid = (PROPID*) LocalAlloc(LPTR,sizeof(PROPID)*lNumProps); + PROPVARIANT *ppv = (PROPVARIANT*) LocalAlloc(LPTR,sizeof(PROPVARIANT)*lNumProps); + PROPSPEC *pps = (PROPSPEC*) LocalAlloc(LPTR,sizeof(PROPSPEC)*lNumProps); + WIA_PROPERTY_INFO *pwpi = (WIA_PROPERTY_INFO*) LocalAlloc(LPTR,sizeof(WIA_PROPERTY_INFO)*lNumProps); + + if((pszName)&&(ppid)&&(ppv)&&(pps)&&(pwpi)) + { + + // + // copy the property data into the proper structures + // + + for(INT i = 0; i < m_List.Size(); i++) + { + PWIA_PROPERTY_INFO_DATA pPropertyData = m_List[i]; + if(pPropertyData) + { + pszName[lIndex] = pPropertyData->szName; + ppid[lIndex] = pPropertyData->pid; + memcpy(&ppv[lIndex],&pPropertyData->pv,sizeof(PROPVARIANT)); + memcpy(&pps[lIndex],&pPropertyData->ps, sizeof(PROPSPEC)); + memcpy(&pwpi[lIndex],&pPropertyData->wpi,sizeof(WIA_PROPERTY_INFO)); + lIndex++; + } + } + + // + // send the property names to the WIA service + // + + hr = wiasSetItemPropNames(pWiasContext,lNumProps,ppid,pszName); + if(SUCCEEDED(hr)) + { + + // + // send the property values to the WIA service + // + + hr = wiasWriteMultiple(pWiasContext,lNumProps,pps,ppv); + if(SUCCEEDED(hr)) + { + + // + // send the property valid values to the WIA service + // + + hr = wiasSetItemPropAttribs(pWiasContext,lNumProps,pps,pwpi); + if(FAILED(hr)) + { + WIAS_ERROR((g_hInst, "CWIAPropertyManager_SetItemProperties - wiasSetItemPropAttribs failed")); + } + } + else + { + WIAS_ERROR((g_hInst, "CWIAPropertyManager_SetItemProperties - wiasWriteMultiple failed")); + } + } + else + { + WIAS_ERROR((g_hInst, "CWIAPropertyManager_SetItemProperties - wiasSetItemPropNames failed")); + } + } + else + { + WIAS_ERROR((g_hInst, "CWIAPropertyManager_SetItemProperties - failed to allocate memory for property arrays")); + hr = E_OUTOFMEMORY; + } + + // + // always delete any temporary memory allocated before exiting the function. The WIA + // service makes a copy of the information during the "wias" helper calls. + // + + if(pszName) + { + LocalFree(pszName); + pszName = NULL; + } + + if(ppid) + { + LocalFree(ppid); + ppid = NULL; + } + + if(ppv) + { + LocalFree(ppv); + ppv = NULL; + } + + if(pps) + { + LocalFree(pps); + pps = NULL; + } + + if(pwpi) + { + LocalFree(pwpi); + pwpi = NULL; + } + } + } + return hr; +} diff --git a/wia/wiadriverex/usd/wiapropertymanager.h b/wia/wiadriverex/usd/wiapropertymanager.h new file mode 100644 index 00000000..a1c75597 --- /dev/null +++ b/wia/wiadriverex/usd/wiapropertymanager.h @@ -0,0 +1,82 @@ +/************************************************************************** +* +* Copyright (c) 2003 Microsoft Corporation +* +* Title: wiapropertymanager.h +* +* Description: This file contains the class definition of the +* CWIAPropertyManager class that encapsulates simple WIA +* property creation. +* +***************************************************************************/ +#pragma once + +///////////////////////////////////////////////////////////////////////////// +// structure definitions + +typedef struct _WIA_PROPERTY_INFO_DATA{ + LPOLESTR szName; // property name + PROPID pid; // property id + PROPVARIANT pv; // property variant + PROPSPEC ps; // property spec + WIA_PROPERTY_INFO wpi; // property info +}WIA_PROPERTY_INFO_DATA,*PWIA_PROPERTY_INFO_DATA; + +///////////////////////////////////////////////////////////////////////////// +// #define WIA flags to make shorter arguments + +#define RN WIA_PROP_READ|WIA_PROP_NONE +#define RF WIA_PROP_READ|WIA_PROP_FLAG +#define RWL WIA_PROP_READ|WIA_PROP_WRITE|WIA_PROP_LIST +#define RWR WIA_PROP_READ|WIA_PROP_WRITE|WIA_PROP_RANGE +#define RWF WIA_PROP_READ|WIA_PROP_WRITE|WIA_PROP_FLAG +#define RWLC WIA_PROP_READ|WIA_PROP_WRITE|WIA_PROP_LIST|WIA_PROP_CACHEABLE +#define RWRC WIA_PROP_READ|WIA_PROP_WRITE|WIA_PROP_RANGE|WIA_PROP_CACHEABLE +#define RWFC WIA_PROP_READ|WIA_PROP_WRITE|WIA_PROP_FLAG|WIA_PROP_CACHEABLE + +class CWIAPropertyManager { +private: + CBasicDynamicArray<PWIA_PROPERTY_INFO_DATA> m_List; + PWIA_PROPERTY_INFO_DATA FindProperty(LONG lPropertyID); + HRESULT DeletePropertyData(_In_ PWIA_PROPERTY_INFO_DATA pInfo); + PWIA_PROPERTY_INFO_DATA AllocatePropertyData(); + HRESULT RemovePropertyAndDeleteData(LONG lPropertyID); +public: + CWIAPropertyManager(); + ~CWIAPropertyManager(); + + // + // LONG type properties + // + + HRESULT AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, LONG lCurrValue); + HRESULT AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, _In_ BYTE *pbCurrValue, ULONG ulNumItems); + HRESULT AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, LONG lCurrValue, + LONG lNomValue, + LONG lMinValue, + LONG lMaxValue, + LONG lInc); + HRESULT AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, LONG lCurrValue, + LONG lNomValue, _In_ LONG *plValues, LONG lNumValues); + HRESULT AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, LONG lCurrValue, + LONG lNomValue, _In_ CBasicDynamicArray<LONG> *pValueList); + HRESULT AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, LONG lCurrValue, LONG lValidBits); + + // + // BSTR type properties + // + + HRESULT AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, _In_ BSTR bstrCurrValue); + + // + // GUID type properties + // + + HRESULT AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, GUID guidCurrValue); + HRESULT AddProperty(LONG lPropertyID, _In_ LPOLESTR szName, LONG lAccessFlags, GUID guidCurrValue, + GUID guidNomValue, _In_ CBasicDynamicArray<GUID> *pValueList); + + + HRESULT RemoveProperty(LONG lPropertyID); + HRESULT SetItemProperties(_Inout_ BYTE *pWiasContext); +}; diff --git a/wia/wiadriverex/wiadriver.inf b/wia/wiadriverex/wiadriver.inf new file mode 100644 index 00000000..c478af70 --- /dev/null +++ b/wia/wiadriverex/wiadriver.inf @@ -0,0 +1,118 @@ +; WIADRIVER.INF -- WIA Driver setup file +; Copyright (c) 2003 Microsoft Corporation +; Manufacturer: Microsoft Windows Imaging Acquisition Team + +[Version] +Signature="$WINDOWS NT$" +Class=Image +ClassGUID={6bdd1fc6-810f-11d0-bec7-08002be2092f} +Provider=%ProviderString% +DriverVer=09/20/2004,1.0.0.7 +CatalogFile=wiadriver.cat + +[SourceDisksFiles] +wiadriverex.dll=1 +segfilter.dll=1 +imgfilter.dll=1 +errhandler.dll=1 +uiext2.dll=1 +sample.bmp=1 + +[SourceDisksNames] +1=%Location%,,, + +[DestinationDirs] +DefaultDestDir=11 +WIADRIVER.StorageFiles=10,ServiceProfiles\LocalService\Documents\WIADRIVER\STORAGE + +[Manufacturer] +%ManufacturerName%=Models, NTx86, NTAMD64, NTIA64, NTARM, NTARM64 + +; This is the models section for the x86 driver +[Models.NTx86] +%WIADRIVER.DeviceDesc% = WIADRIVER.Device, WIADRIVER_PNP_ID, USB\MS_COMP_SCAN&MS_SUBCOMP_WIAPNPID + +; This is the models section for the AMD64 driver +[Models.NTAMD64] +%WIADRIVER.DeviceDesc% = WIADRIVER.Device, WIADRIVER_PNP_ID, USB\MS_COMP_SCAN&MS_SUBCOMP_WIAPNPID + +; This is the models section for the IA64 driver +[Models.NTIA64] +%WIADRIVER.DeviceDesc% = WIADRIVER.Device, WIADRIVER_PNP_ID, USB\MS_COMP_SCAN&MS_SUBCOMP_WIAPNPID + +; This is the models section for the ARM driver +[Models.NTARM] +%WIADRIVER.DeviceDesc% = WIADRIVER.Device, WIADRIVER_PNP_ID, USB\MS_COMP_SCAN&MS_SUBCOMP_WIAPNPID + +; This is the models section for the ARM64 driver +[Models.NTARM64] +%WIADRIVER.DeviceDesc% = WIADRIVER.Device, WIADRIVER_PNP_ID, USB\MS_COMP_SCAN&MS_SUBCOMP_WIAPNPID + +[WIADRIVER.Device] +Include=sti.inf +Needs=STI.SerialSection +PortSelect=no +SubClass=StillImage +DeviceType=1 +DeviceSubType=0x1 +Capabilities=0x30 +Events=WIADRIVER.Events +DeviceData=WIADRIVER.DeviceData +AddReg=WIADRIVER.AddReg +CopyFiles=WIADRIVER.CopyFiles,WIADRIVER.StorageFiles +ICMProfiles="sRGB Color Space Profile.icm" + +[WIADRIVER.Events] + +[WIADRIVER.Device.Services] +Include=sti.inf +Needs=STI.SerialSection.Services + +[WIADRIVER.DeviceData] +UI Class ID={07DD9E07-ECC0-438a-B5EB-C5227ECA910E} +StoragePath=%10%\ServiceProfiles\LocalService\Documents\WIADRIVER\STORAGE + +[WIADRIVER.AddReg] +HKR,,HardwareConfig,1,1 +HKR,,USDClass,,"{EEA1E6F7-A59C-487a-BFFA-BD8AA99FE503}" +HKCR,CLSID\{EEA1E6F7-A59C-487a-BFFA-BD8AA99FE503},,,"Extended WIA Driver" +HKCR,CLSID\{EEA1E6F7-A59C-487a-BFFA-BD8AA99FE503}\InProcServer32,,0x00020000,%%SystemRoot%%\System32\wiadriverex.dll +HKCR,CLSID\{EEA1E6F7-A59C-487a-BFFA-BD8AA99FE503}\InProcServer32,ThreadingModel,,"Both" + +HKCR,CLSID\{07DD9E07-ECC0-438a-B5EB-C5227ECA910E},,,"WIA Driver UI Extension" +HKCR,CLSID\{07DD9E07-ECC0-438a-B5EB-C5227ECA910E}\shellex\SegmentationFilter\{7B6D704B-A4F2-4ecf-8B86-8E0CF1A707F5} +HKCR,CLSID\{07DD9E07-ECC0-438a-B5EB-C5227ECA910E}\shellex\ImageProcessingFilter\{AA9198F3-3B91-47d3-A371-EBE7D243F606} +HKCR,CLSID\{07DD9E07-ECC0-438a-B5EB-C5227ECA910E}\shellex\ErrorHandler\{CFC1A4D4-5F27-4881-81E4-1BE314EB22F7} +HKCR,CLSID\{07DD9E07-ECC0-438a-B5EB-C5227ECA910E}\shellex\WiaDialogExtensionHandlers\{61364062-0593-4eda-84d2-f5531d8c3259} + +HKCR,CLSID\{7B6D704B-A4F2-4ecf-8B86-8E0CF1A707F5},,,"WIA Sample Segmentation Filter" +HKCR,CLSID\{7B6D704B-A4F2-4ecf-8B86-8E0CF1A707F5}\InProcServer32,,0x00020000,%%SystemRoot%%\System32\segfilter.dll +HKCR,CLSID\{7B6D704B-A4F2-4ecf-8B86-8E0CF1A707F5}\InProcServer32,ThreadingModel,,"Both" + +HKCR,CLSID\{AA9198F3-3B91-47d3-A371-EBE7D243F606},,,"WIA Sample Image Processing Filter" +HKCR,CLSID\{AA9198F3-3B91-47d3-A371-EBE7D243F606}\InProcServer32,,0x00020000,%%SystemRoot%%\System32\imgfilter.dll +HKCR,CLSID\{AA9198F3-3B91-47d3-A371-EBE7D243F606}\InProcServer32,ThreadingModel,,"Both" + +HKCR,CLSID\{CFC1A4D4-5F27-4881-81E4-1BE314EB22F7},,,"WIA Sample Error Handler" +HKCR,CLSID\{CFC1A4D4-5F27-4881-81E4-1BE314EB22F7}\InProcServer32,,0x00020000,%%SystemRoot%%\System32\errhandler.dll +HKCR,CLSID\{CFC1A4D4-5F27-4881-81E4-1BE314EB22F7}\InProcServer32,ThreadingModel,,"Both" + +HKCR,CLSID\{61364062-0593-4eda-84d2-f5531d8c3259},,,"WIA Dialog Extension Handler" +HKCR,CLSID\{61364062-0593-4eda-84d2-f5531d8c3259}\InProcServer32,,0x00020000,%%SystemRoot%%\System32\uiext2.dll +HKCR,CLSID\{61364062-0593-4eda-84d2-f5531d8c3259}\InProcServer32,ThreadingModel,,"Both" + +[WIADRIVER.CopyFiles] +wiadriverex.dll +segfilter.dll +imgfilter.dll +errhandler.dll +uiext2.dll + +[WIADRIVER.StorageFiles] +sample.bmp + +[Strings] +ManufacturerName="TODO-Set-Manufacturer" +ProviderString="TODO-Set-Provider" +Location="WIA Monster Device Driver Installation Source" +WIADRIVER.DeviceDesc="Extended WIA Monster Device" |
