|
|
/*******************************************************************************
* * (C) COPYRIGHT MICROSOFT CORP., 1998 * * TITLE: WiaServc.Cpp * * VERSION: 2.0 * * AUTHOR: ReedB * * DATE: 20 Aug, 1998 * * DESCRIPTION: * Implementation of mini driver services in the WIA device class driver. * *******************************************************************************/ #include "precomp.h"
#define STD_PROPS_IN_CONTEXT
#include "stiexe.h"
#include <wiamindr.h>
#include <wiamdef.h>
#include <wiadbg.h>
#include "helpers.h"
#include "wiatiff.h"
#define DOWNSAMPLE_DPI 50
#define ENDORSER_TOKEN_DELIMITER L"$"
#define ESCAPE_CHAR L'\\'
/**************************************************************************\
* wiasDebugTrace * * Print a debug trace string in the device manager debug console. * * Arguments: * * hInstance - Module handle of calling module. * pszFormat - ANSI format string. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
VOID __cdecl wiasDebugTrace( HINSTANCE hInstance, LPCSTR pszFormat, ... ) { #if defined(WIA_DEBUG)
_try { CHAR szMsg[1024 + MAX_PATH]; CHAR szModuleName[MAX_PATH]= { 0 }; va_list arglist;
// Get the module name
GetModuleFileNameA( hInstance, szModuleName, sizeof(szModuleName)/sizeof(szModuleName[0]) - 1); // Nuke the path
WORD wLen = sizeof(szMsg)/sizeof(szMsg[0]); GetFileTitleA( szModuleName, szMsg, wLen ); // Nuke the extension
for (LPSTR pszCurr = szMsg + lstrlenA(szMsg); pszCurr>szMsg; pszCurr--) { if (*(pszCurr-1)=='.') { *(pszCurr-1)='\0'; break; } } // Append a colon:
lstrcatA( szMsg, ": " );
va_start(arglist, pszFormat); ::_vsnprintf(szMsg+lstrlenA(szMsg), sizeof(szMsg) - lstrlenA(szMsg) - 1, pszFormat, arglist); va_end(arglist); //
// NULL terminate the string
//
szMsg[sizeof(szMsg)/sizeof(szMsg[0]) - 1] = '\0';
DBG_TRC((szMsg)); } _except(EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("::wiasDebugTrace, Error processing output string!"));
} #endif
}
/**************************************************************************\
* wiasDebugError * * Print a debug error string in the device manager debug console. The * output color is always red. * * Arguments: * * hInstance - Module handle of calling module. * pszFormat - ANSI format string. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
VOID __cdecl wiasDebugError( HINSTANCE hInstance, LPCSTR pszFormat, ... ) { #if defined(WIA_DEBUG)
_try { CHAR szMsg[1024 + MAX_PATH]; CHAR szModuleName[MAX_PATH]= { 0 }; va_list arglist;
// Get the module name
GetModuleFileNameA( hInstance, szModuleName, sizeof(szModuleName)/sizeof(szModuleName[0]) - 1); // Nuke the path
WORD wLen = sizeof(szMsg)/sizeof(szMsg[0]); GetFileTitleA( szModuleName, szMsg, wLen ); // Nuke the extension
for (LPSTR pszCurr = szMsg + lstrlenA(szMsg); pszCurr>szMsg; pszCurr--) { if (*(pszCurr-1)=='.') { *(pszCurr-1)='\0'; break; } } // Append a colon:
lstrcatA( szMsg, ": " );
va_start(arglist, pszFormat); ::_vsnprintf(szMsg+lstrlenA(szMsg), sizeof(szMsg) - lstrlenA(szMsg) - 1, pszFormat, arglist); va_end(arglist); //
// NULL terminate the string
//
szMsg[sizeof(szMsg)/sizeof(szMsg[0]) - 1] = '\0';
DBG_ERR((szMsg)); } _except (EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("::wiasDebugError, Error processing output string!"));
} #endif
}
/**************************************************************************\
* wiasPrintDebugHResult * * Print an HRESULT string on the device manager debug console. * * Arguments: * * hInstance - Module handle of calling module. * hr - HRESULT to pe printed. * * Return Value: * * None. * * History: * * 1/19/1999 Original Version * \**************************************************************************/
VOID __stdcall wiasPrintDebugHResult( HINSTANCE hInstance, HRESULT hr ) { #if defined(WIA_DEBUG)
DBG_ERR(("HResult = 0x%X", hr)); #endif
}
/**************************************************************************\
* wiasFormatArgs * * Format an argument list into a packaged string for logging, * NOTE: This function adds a format signature, that tells the * logging engine that it is ok to FREE it. * * Arguments: * * BSTR pszFormat - ANSI format string. * * Return Value: * * None. * * History: * * 8/26/1999 Original Version * \**************************************************************************/ BSTR __cdecl wiasFormatArgs(LPCSTR lpszFormat, ...) {
USES_CONVERSION;
CHAR pszbuffer[4*MAX_PATH];
//
// Signature needs to be defined somewhere else
// It is here, until the old debugging system is
// replaced.
//
CHAR pszFormatSignature[] = "F9762DD2679F";
va_list arglist;
//
// Add signature value, because we are being used to format an
// argument list
//
*pszbuffer = '\0'; lstrcpynA(pszbuffer,pszFormatSignature,lstrlenA(pszFormatSignature) + 1 );
va_start(arglist, lpszFormat); ::_vsnprintf(pszbuffer+lstrlenA(pszbuffer), sizeof(pszbuffer) - lstrlenA(pszbuffer) - 1, lpszFormat, arglist); va_end(arglist); //
// NULL terminate the string
//
pszbuffer[sizeof(pszbuffer)/sizeof(pszbuffer[0]) - 1] = '\0';
return SysAllocString(CSimpleStringConvert::WideString(pszbuffer).String()); }
/**************************************************************************\
* wiasCreateDrvItem * * Create a driver item. * * Arguments: * * lObjectFlags - Object flags. * bstrItemName - Item name. * bstrFullItemName - Full item name. Includes path info. * pIMiniDrv - Pointer to mini-driver interface. * cbDevSpecContext - Size of device specific context. * ppDevSpecContext - Pointer to returned device specific context. Optional. * ppIWiaDrvItem - Pointer to returned driver item. * * Return Value: * * Status * * History: * * 1/18/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasCreateDrvItem( LONG lObjectFlags, BSTR bstrItemName, BSTR bstrFullItemName, IWiaMiniDrv *pIMiniDrv, LONG cbDevSpecContext, BYTE **ppDevSpecContext, IWiaDrvItem **ppIWiaDrvItem) { DBG_FN(::wiasCreateDrvItem); HRESULT hr = E_FAIL;
//
// Objects can be either folders, files or both
//
if (!(lObjectFlags & (WiaItemTypeFolder | WiaItemTypeFile))) {
DBG_ERR(("wiasCreateDrvItem, bad object flags")); return E_INVALIDARG; }
//
// Validate the item name strings.
//
if (IsBadStringPtrW(bstrItemName, SysStringLen(bstrItemName))) { DBG_ERR(("wiasCreateDrvItem, invalid bstrItemName pointer")); return E_POINTER; }
if (IsBadStringPtrW(bstrFullItemName, SysStringLen(bstrFullItemName))) { DBG_ERR(("wiasCreateDrvItem, invalid bstrFullItemName pointer")); return E_POINTER; }
//
// Validate the rest of the pointers
//
if (IsBadReadPtr(pIMiniDrv, sizeof(IWiaMiniDrv))) { DBG_ERR(("wiasCreateDrvItem, invalid pIMiniDrv pointer")); return E_POINTER; }
if (!ppIWiaDrvItem) { DBG_ERR(("wiasCreateDrvItem, bad ppIWiaItemControl parameter")); return E_POINTER; }
if (ppDevSpecContext) { if (IsBadWritePtr(ppDevSpecContext, sizeof(BYTE*))) { DBG_ERR(("wiasCreateDrvItem, invalid ppDevSpecContext pointer")); return E_POINTER; } }
if (IsBadWritePtr(ppIWiaDrvItem, sizeof(IWiaDrvItem*))) { DBG_ERR(("wiasCreateDrvItem, invalid ppIWiaDrvItem pointer")); return E_POINTER; }
CWiaDrvItem *pItem = new CWiaDrvItem();
if (pItem) {
hr = pItem->Initialize(lObjectFlags, bstrItemName, bstrFullItemName, pIMiniDrv, cbDevSpecContext, ppDevSpecContext);
if (hr == S_OK) { hr = pItem->QueryInterface(IID_IWiaDrvItem,(void **)ppIWiaDrvItem); if (FAILED(hr)) { DBG_ERR(("wiasCreateDrvItem, QI for IID_IWiaDrvItem failed")); } } else { delete pItem; } } else { DBG_ERR(("wiasCreateDrvItem, out of memory!")); hr = E_OUTOFMEMORY; } return hr; }
/**************************************************************************\
* wiasReadMultiple * * Read multiple properties helper. * * Arguments: * * pWiasContext - Pointer to WIA item * ulCount - Number of properties to read. * ps - A caller allocated array of PROPSPEC. * pv - A caller allocated array of PROPVARIANTS. * pvOld - A caller allocated array of PROPVARIANTS for previous values. * pvOld - A caller allocated array of PROPVARIANTS for the previous values. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasReadMultiple( BYTE *pWiasContext, ULONG ulCount, const PROPSPEC *ps, PROPVARIANT *pv, PROPVARIANT *pvOld) { DBG_FN(::wiasReadMultiple); IWiaItem *pItem = (IWiaItem*) pWiasContext; HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasReadMultiple, invalid pItem")); return hr; }
if (IsBadReadPtr(ps, sizeof(PROPSPEC) * ulCount)) { DBG_ERR(("wiasReadMultiple, invalid ps pointer")); return E_POINTER; }
if (IsBadWritePtr(pv, sizeof(PROPVARIANT) * ulCount)) { DBG_ERR(("wiasReadMultiple, invalid pv pointer")); return E_POINTER; }
if ((pvOld) && IsBadWritePtr(pvOld, sizeof(PROPVARIANT) * ulCount)) { DBG_ERR(("wiasReadMultiple, invalid pvOld pointer")); return E_POINTER; }
IPropertyStorage *pIPropStg, *pIPropOldStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, &pIPropOldStg); if (FAILED(hr)) { return hr; }
//
// Get the current values
//
hr = pIPropStg->ReadMultiple(ulCount, ps, pv); if (hr == S_OK) {
//
// If requested, get the old values.
//
if (pvOld) { hr = pIPropOldStg->ReadMultiple(ulCount, ps, pvOld); }; if (FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasReadMultiple", "old value", TRUE, ulCount, ps); } } else { ReportReadWriteMultipleError(hr, "wiasReadMultiple", "current value", TRUE, ulCount, ps); } return hr; }
/**************************************************************************\
* wiasReadPropStr * * Read property string helper. * * Arguments: * * pWiasContext - Pointer to WIA item * propid - Property ID * pbstr - Pointer to returned BSTR * pbstrOld - Pointer to old returned BSTR for previous value. Can * be NULL * bMustExist - Boolean value indicating whether the property must * exist. If this is true and the property is not found, * an E_INVALIDARG is returned. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasReadPropStr( BYTE *pWiasContext, PROPID propid, BSTR *pbstr, BSTR *pbstrOld, BOOL bMustExist) { DBG_FN(::wiasReadPropStr); IWiaItem *pItem = (IWiaItem*) pWiasContext; HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasReadPropStr, invalid pItem")); return hr; }
if (IsBadWritePtr(pbstr, sizeof(BSTR*))) { DBG_ERR(("wiasReadPropStr, invalid pbstr pointer")); return E_POINTER; }
if ((pbstrOld) && IsBadWritePtr(pbstrOld, sizeof(BSTR*))) { DBG_ERR(("wiasReadMultiple, invalid pbstrOld pointer")); return E_POINTER; }
IPropertyStorage *pIPropStg, *pIPropOldStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, &pIPropOldStg); if (FAILED(hr)) { return hr; }
//
// Return the current value
//
PROPSPEC propSpec; PROPVARIANT propVar;
propSpec.ulKind = PRSPEC_PROPID; propSpec.propid = propid;
hr = pIPropStg->ReadMultiple(1, &propSpec, &propVar); if (hr == S_OK) {
//
// NULL is a valid bstr value
//
if (propVar.bstrVal == NULL) { *pbstr = NULL; if (pbstrOld) { *pbstrOld = NULL; } return S_OK; }
*pbstr = SysAllocString(propVar.bstrVal); PropVariantClear(&propVar); if (*pbstr) {
//
// Check whether we must return the old value.
//
if (pbstrOld) { hr = pIPropOldStg->ReadMultiple(1, &propSpec, &propVar); if (hr == S_OK) { *pbstrOld = SysAllocString(propVar.bstrVal); PropVariantClear(&propVar);
//
// Clear allocated memory.
//
if (!(*pbstrOld)) { SysFreeString(*pbstr); *pbstr = NULL; DBG_ERR(("wiasReadPropStr, run out of memory")); return E_OUTOFMEMORY; } } } } else { DBG_ERR(("wiasReadPropStr, out of memory error")); return E_OUTOFMEMORY; } } if (((hr == S_FALSE) && bMustExist) || FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasReadPropStr", NULL, TRUE, 1, &propSpec); if (bMustExist) { hr = E_INVALIDARG; } } return hr; }
/**************************************************************************\
* wiasReadPropLong * * Read property long helper. * * Arguments: * * pWiasContext - Pointer to WIA item * propid - Property ID * plVal - Pointer to returned LONG * plValOld - Pointer to returned LONG for previous value * bMustExist - Boolean value indicating whether the property must * exist. If this is true and the property is not found, * an E_INVALIDARG is returned. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasReadPropLong( BYTE *pWiasContext, PROPID propid, LONG *plVal, LONG *plValOld, BOOL bMustExist) { DBG_FN(::wiasReadPropLong); IWiaItem *pItem = (IWiaItem*) pWiasContext; HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasReadPropLong, invalid pItem")); return hr; }
if (IsBadWritePtr(plVal, sizeof(LONG))) { DBG_ERR(("wiasReadPropLong, invalid plVal pointer")); return E_POINTER; }
if (plValOld && IsBadWritePtr(plValOld, sizeof(LONG))) { DBG_ERR(("wiasReadPropLong, invalid plValOld pointer")); return E_POINTER; }
IPropertyStorage *pIPropStg, *pIPropOldStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, &pIPropOldStg); if (FAILED(hr)) { return hr; }
//
// Return the current value
//
PROPSPEC propSpec; PROPVARIANT propVar;
propSpec.ulKind = PRSPEC_PROPID; propSpec.propid = propid;
hr = pIPropStg->ReadMultiple(1, &propSpec, &propVar); if (hr == S_OK) { *plVal = propVar.lVal;
//
// Check whether we must return the old value.
//
if (plValOld) { hr = pIPropOldStg->ReadMultiple(1, &propSpec, &propVar); if (hr == S_OK) { *plValOld = propVar.lVal; } } } if (((hr == S_FALSE) && bMustExist) || FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasReadPropLong", NULL, TRUE, 1, &propSpec); if (bMustExist) { hr = E_INVALIDARG; } } return hr; }
/**************************************************************************\
* wiasReadPropFloat * * Read property floating point value helper. * * Arguments: * * pWiasContext - Pointer to WIA item * propid - Property ID * pfVal - Pointer to returned float * pfValOld - Pointer to returned float for previous value * bMustExist - Boolean value indicating whether the property must * exist. If this is true and the property is not found, * an E_INVALIDARG is returned. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasReadPropFloat( BYTE *pWiasContext, PROPID propid, FLOAT *pfVal, FLOAT *pfValOld, BOOL bMustExist) { DBG_FN(::wiasReadPropFloat); IWiaItem *pItem = (IWiaItem*) pWiasContext; HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasReadPropFloat, invalid pItem")); return hr; }
if (IsBadWritePtr(pfVal, sizeof(float))) { DBG_ERR(("wiasReadPropFloat, invalid pfVal pointer")); return E_POINTER; }
if (pfValOld && (IsBadWritePtr(pfValOld, sizeof(float)))) { DBG_ERR(("wiasReadPropFloat, invalid pfValOld pointer")); return E_POINTER; }
IPropertyStorage *pIPropStg, *pIPropOldStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, &pIPropOldStg); if (FAILED(hr)) { return hr; }
//
// Return the current value
//
PROPSPEC propSpec; PROPVARIANT propVar;
propSpec.ulKind = PRSPEC_PROPID; propSpec.propid = propid;
hr = pIPropStg->ReadMultiple(1, &propSpec, &propVar); if (hr == S_OK) { *pfVal = propVar.fltVal;
//
// Check whether we must return the old value.
//
if (pfValOld) { hr = pIPropOldStg->ReadMultiple(1, &propSpec, &propVar); if (hr == S_OK) { *pfValOld = propVar.fltVal; } } } if (((hr == S_FALSE) && bMustExist) || FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasReadPropFloat", NULL, TRUE, 1, &propSpec); if (bMustExist) { hr = E_INVALIDARG; } } return hr; }
/**************************************************************************\
* wiasReadPropGuid * * Read property long helper. * * Arguments: * * pWiasContext - Pointer to WIA item * propid - Property ID * pguidVal - Pointer to returned LONG * pguidValOld - Pointer to returned LONG for previous value * bMustExist - Boolean value indicating whether the property must * exist. If this is true and the property is not found, * an E_INVALIDARG is returned. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasReadPropGuid( BYTE *pWiasContext, PROPID propid, GUID *pguidVal, GUID *pguidValOld, BOOL bMustExist) { DBG_FN(::wiasReadPropGuid); IWiaItem *pItem = (IWiaItem*) pWiasContext; HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasReadPropGuid, invalid pItem")); return hr; }
if (IsBadWritePtr(pguidVal, sizeof(WIA_FORMAT_INFO))) { DBG_ERR(("wiasReadPropGuid, invalid plVal pointer")); return E_POINTER; }
if (pguidValOld && IsBadWritePtr(pguidValOld, sizeof(WIA_FORMAT_INFO))) { DBG_ERR(("wiasReadPropGuid, invalid plValOld pointer")); return E_POINTER; }
IPropertyStorage *pIPropStg, *pIPropOldStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, &pIPropOldStg); if (FAILED(hr)) { return hr; }
//
// Return the current value
//
PROPSPEC propSpec; PROPVARIANT propVar;
propSpec.ulKind = PRSPEC_PROPID; propSpec.propid = propid;
hr = pIPropStg->ReadMultiple(1, &propSpec, &propVar); if (hr == S_OK) { memcpy(pguidVal, propVar.puuid, sizeof(GUID)); PropVariantClear(&propVar);
//
// Check whether we must return the old value.
//
if (pguidValOld) { hr = pIPropOldStg->ReadMultiple(1, &propSpec, &propVar); if (hr == S_OK) { memcpy(pguidValOld, propVar.puuid, sizeof(GUID)); PropVariantClear(&propVar); } } } if (((hr == S_FALSE) && bMustExist) || FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasReadPropGuid", NULL, TRUE, 1, &propSpec); if (bMustExist) { hr = E_INVALIDARG; } } return hr; }
/**************************************************************************\
* wiasReadPropBin * * Read property binary helper. * * Arguments: * * pWiasContext - Pointer to WIA item * propid - Property ID * pbVal - Pointer to caller allocated buffer. * pbValOld - Pointer to caller allocated buffer for previous value. * bMustExist - Boolean value indicating whether the property must * exist. If this is true and the property is not found, * an E_INVALIDARG is returned. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasReadPropBin( BYTE *pWiasContext, PROPID propid, BYTE **ppbVal, BYTE **ppbValOld, BOOL bMustExist) { DBG_FN(::wiasReadPropBin); IWiaItem *pItem = (IWiaItem*) pWiasContext; HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasReadPropBin, invalid pItem")); return hr; }
if (IsBadWritePtr(ppbVal, sizeof(BYTE*))) { DBG_ERR(("wiasReadPropBin, invalid ppbVal pointer")); return E_POINTER; }
if (ppbValOld && (IsBadWritePtr(ppbValOld, sizeof(BYTE*)))) { DBG_ERR(("wiasReadPropBin, invalid ppbVal pointer")); return E_POINTER; }
*ppbVal = NULL;
IPropertyStorage *pIPropStg, *pIPropOldStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, &pIPropOldStg); if (FAILED(hr)) { return hr; }
//
// Return the current value
//
PROPSPEC propSpec; PROPVARIANT propVar;
propSpec.ulKind = PRSPEC_PROPID; propSpec.propid = propid;
hr = pIPropStg->ReadMultiple(1, &propSpec, &propVar); if (hr == S_OK) { if (propVar.vt == (VT_VECTOR | VT_UI1)) { *ppbVal = propVar.caub.pElems; } else { DBG_ERR(("wiasReadPropBin, invalid property type: %X", propVar.vt)); PropVariantClear(&propVar); return E_INVALIDARG; }
//
// If requested, get the old value.
//
if (ppbValOld) { hr = pIPropOldStg->ReadMultiple(1, &propSpec, &propVar); if (hr == S_OK) { if (propVar.vt == (VT_VECTOR | VT_UI1)) { *ppbValOld = propVar.caub.pElems; } else { DBG_ERR(("wiasReadPropBin, invalid property type: %X", propVar.vt)); PropVariantClear(&propVar); return E_INVALIDARG; } } } }
if (((hr == S_FALSE) && bMustExist) || FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasReadPropBin", NULL, TRUE, 1, &propSpec); if (bMustExist) { hr = E_INVALIDARG; } } return hr; }
/**************************************************************************\
* wiasWriteMultiple * * Write multiple properties helper. * * Arguments: * * pWiasContext - Pointer to WIA item * ulCount - Number of properties to write. * ps - A caller alocated array of PROPSPEC. * pv - A caller alocated array of PROPVARIANTS. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasWriteMultiple( BYTE *pWiasContext, ULONG ulCount, const PROPSPEC *ps, const PROPVARIANT *pv) { DBG_FN(::wiasWriteMultiple); IWiaItem *pItem = (IWiaItem*) pWiasContext; HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasWriteMultiple, invalid pItem")); return hr; }
if (IsBadReadPtr(ps, sizeof(PROPSPEC) * ulCount)) { DBG_ERR(("wiasWriteMultiple, invalid ps pointer")); return E_POINTER; }
if (IsBadReadPtr(pv, sizeof(PROPVARIANT) * ulCount)) { DBG_ERR(("wiasWriteMultiple, invalid pv pointer")); return E_POINTER; }
IPropertyStorage *pIPropStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, NULL); if (FAILED(hr)) { return hr; }
//
// Set the property to the new value
//
hr = pIPropStg->WriteMultiple(ulCount, ps, pv, WIA_DIP_FIRST); if (FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasWriteMultiple", NULL, FALSE, ulCount, ps); } return hr;
}
/**************************************************************************\
* wiasWritePropStr * * Write property string helper. * * Arguments: * * pWiasContext - Pointer to WIA item * propid - Property ID * bstr - BSTR to be written. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasWritePropStr( BYTE *pWiasContext, PROPID propid, BSTR bstr) { DBG_FN(::wiasWritePropStr); IWiaItem *pItem = (IWiaItem*) pWiasContext; BSTR bstrOld; HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasWritePropStr, invalid pItem")); return hr; }
// NULL is a valid BSTR value.
if (bstr) { if (IsBadStringPtrW(bstr, SysStringLen(bstr))) { DBG_ERR(("wiasWriteMultiple, invalid bstr pointer")); return E_POINTER; } }
IPropertyStorage *pIPropStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, NULL); if (FAILED(hr)) { return hr; }
//
// Set the property to the new value
//
hr = WritePropStr(propid, pIPropStg, bstr); if (FAILED(hr)) { DBG_ERR(("wiasWriteMultiple, error writing new value")); }
return hr; }
/**************************************************************************\
* wiasWritePropLong * * Write property long helper * * Arguments: * * pWiasContext - Pointer to WIA item * propid - Property ID * lVal - Value to write. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasWritePropLong( BYTE *pWiasContext, PROPID propid, LONG lVal) { DBG_FN(::wiasWritePropLong); IWiaItem *pItem = (IWiaItem*) pWiasContext; LONG lValOld;
HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasWritePropLong, invalid pItem")); return hr; }
IPropertyStorage *pIPropStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, NULL); if (FAILED(hr)) { return hr; }
//
// Set new value
//
WritePropLong(propid, pIPropStg, lVal);
return hr; }
/**************************************************************************\
* wiasWritePropFloat * * Write property float helper * * Arguments: * * pWiasContext - Pointer to WIA item * propid - Property ID * fVal - Float to be written. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasWritePropFloat( BYTE *pWiasContext, PROPID propid, float fVal) { DBG_FN(::wiasWritePropFloat); IWiaItem *pItem = (IWiaItem*) pWiasContext; float fValOld;
HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasWritePropFloat, invalid pItem")); return hr; }
IPropertyStorage *pIPropStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, NULL); if (FAILED(hr)) { return hr; }
PROPSPEC propSpec; PROPVARIANT propVar;
propSpec.ulKind = PRSPEC_PROPID; propSpec.propid = propid;
//
// Write new value
//
PropVariantInit(&propVar); propVar.vt = VT_R4; propVar.fltVal = fVal;
hr = pIPropStg->WriteMultiple(1, &propSpec, &propVar, WIA_DIP_FIRST); if (FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasWritePropFloat", NULL, FALSE, 1, &propSpec); } return hr; }
/**************************************************************************\
* wiasWritePropGuid * * Write property float helper * * Arguments: * * pWiasContext - Pointer to WIA item * propid - Property ID * pguidVal - pointer to GUID to be written. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasWritePropGuid( BYTE *pWiasContext, PROPID propid, GUID guidVal) { DBG_FN(::wiasWritePropGuid); IWiaItem *pItem = (IWiaItem*) pWiasContext; GUID guidValOld;
HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasWritePropFloat, invalid pItem")); return hr; }
IPropertyStorage *pIPropStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, NULL); if (FAILED(hr)) { return hr; }
PROPSPEC propSpec; PROPVARIANT propVar;
propSpec.ulKind = PRSPEC_PROPID; propSpec.propid = propid;
//
// Write new value
//
PropVariantInit(&propVar); propVar.vt = VT_CLSID; propVar.puuid = &guidVal;
hr = pIPropStg->WriteMultiple(1, &propSpec, &propVar, WIA_DIP_FIRST); if (FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasWritePropFloat", NULL, FALSE, 1, &propSpec); } return hr; }
/**************************************************************************\
* wiasWritePropBin * * Write property binary helper * * Arguments: * * pWiasContext - Pointer to WIA item * propid - Property ID * cbVal - Number of bytes to write. * pbVal - Pointer to binary value to write. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasWritePropBin( BYTE *pWiasContext, PROPID propid, LONG cbVal, BYTE *pbVal) { DBG_FN(::wiasWritePropBin); IWiaItem *pItem = (IWiaItem*) pWiasContext;
HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasWritePropBin, invalid pItem")); return hr; }
if (IsBadReadPtr(pbVal, cbVal)) { DBG_ERR(("wiasWritePropBin, invalid pbVal pointer")); return E_POINTER; }
IPropertyStorage *pIPropStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, NULL); if (FAILED(hr)) { return hr; }
PROPSPEC propSpec; PROPVARIANT propVar;
propSpec.ulKind = PRSPEC_PROPID; propSpec.propid = propid;
//
// Write the new value
//
propVar.vt = VT_VECTOR | VT_UI1; propVar.caub.pElems = pbVal; propVar.caub.cElems = cbVal;
hr = pIPropStg->WriteMultiple(1, &propSpec, &propVar, WIA_DIP_FIRST); if (FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasWritePropBin", NULL, FALSE, 1, &propSpec); } return hr; }
/**************************************************************************\
* wiasGetPropertyAttributes * * Get the access flags and valid values for a property. * * Arguments: * * pWiasContext - Pointer to WIA item * cPropSpec - The number of properties * pPropSpec - array of property specification. * pulAccessFlags - array of LONGs access flags. * pPropVar - Pointer to returned valid values. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasGetPropertyAttributes( BYTE *pWiasContext, LONG cPropSpec, PROPSPEC *pPropSpec, ULONG *pulAccessFlags, PROPVARIANT *pPropVar) { DBG_FN(::wiasGetPropertyAttributes); IWiaItem *pItem = (IWiaItem*) pWiasContext;
//
// Do parameter validation.
//
HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasGetPropertyAttributes, invalid pItem")); return hr; }
if (IsBadReadPtr(pPropSpec, sizeof(PROPSPEC) * cPropSpec)) { DBG_ERR(("wiasGetPropertyAttributes, bad pPropSpec parameter")); return E_POINTER; }
if (IsBadWritePtr(pulAccessFlags, sizeof(ULONG) * cPropSpec)) { DBG_ERR(("wiasGetPropertyAttributes, bad pulAccessFlags parameter")); return E_POINTER; }
if (IsBadWritePtr(pPropVar, sizeof(PROPVARIANT) * cPropSpec)) { DBG_ERR(("wiasGetPropertyAttributes, bad pPropVar parameter")); return E_POINTER; }
//
// Now that validation has been done, call helper function to get
// the property attributes
//
return GetPropertyAttributesHelper(pItem, cPropSpec, pPropSpec, pulAccessFlags, pPropVar); }
/**************************************************************************\
* wiasSetPropertyAttributes * * Set the access flags and valid values for a set of properties. * * Arguments: * * pWiasContext - Pointer to WIA item * cPropSpec - The number of properties * pPropSpec - Pointer to a property specification. * pulAccessFlags - Access flags. * pPropVar - Pointer to valid values. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSetPropertyAttributes( BYTE *pWiasContext, LONG cPropSpec, PROPSPEC *pPropSpec, ULONG *pulAccessFlags, PROPVARIANT *pPropVar) { DBG_FN(::wiasSetPropertyAttributes); IWiaItem *pItem = (IWiaItem*) pWiasContext;
//
// May be called by driver or application, do parameter validation.
//
HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasSetPropertyAttributes, invalid pItem")); return hr; }
if (IsBadReadPtr(pPropSpec, sizeof(PROPSPEC) * cPropSpec)) { DBG_ERR(("wiasSetPropertyAttributes, bad pPropSpec parameter")); return E_POINTER; }
if (IsBadWritePtr(pulAccessFlags, sizeof(ULONG) * cPropSpec)) { DBG_ERR(("wiasSetPropertyAttributes, bad pulAccessFlags parameter")); return E_POINTER; }
if (IsBadWritePtr(pPropVar, sizeof(PROPVARIANT) * cPropSpec)) { DBG_ERR(("wiasSetPropertyAttributes, bad pPropVar parameter")); return E_POINTER; }
//
// Get the item's internal property storage pointers.
//
IPropertyStorage *pIPropAccessStg; IPropertyStorage *pIPropValidStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(NULL, &pIPropAccessStg, &pIPropValidStg, NULL); if (FAILED(hr)) { return hr; }
//
// Set the Access flags for the properties.
//
PROPVARIANT *pVar;
pVar = (PROPVARIANT*) LocalAlloc(LPTR, sizeof(PROPVARIANT) * cPropSpec); if (pVar) { for (int flagIndex = 0; flagIndex < cPropSpec; flagIndex++) { pVar[flagIndex].vt = VT_UI4; pVar[flagIndex].ulVal = pulAccessFlags[flagIndex]; }
hr = pIPropAccessStg->WriteMultiple(cPropSpec, pPropSpec, pVar, WIA_DIP_FIRST); LocalFree(pVar); if (SUCCEEDED(hr)) {
//
// Set the valid values
//
hr = pIPropValidStg->WriteMultiple(cPropSpec, pPropSpec, pPropVar, WIA_DIP_FIRST); if (FAILED(hr)) { DBG_ERR(("wiasSetPropertyAttributes, could not set valid values")); } } else { DBG_ERR(("wiasSetPropertyAttributes, could not set access flags")); } } else { DBG_ERR(("wiasSetPropertyAttributes, out of memory")); return E_OUTOFMEMORY; }
if (FAILED(hr)) { ReportReadWriteMultipleError(hr, "wiasSetPropertyAttributes", NULL, FALSE, cPropSpec, pPropSpec); }
return hr; }
/**************************************************************************\
* RangeToPropVariant * * Move information from a WIA_PROPERTY_INFO struct to a PROPVARIANT. The * WIA_PROPERTY_INFO is known to be of type WIA_PROP_RANGE. * * Arguments: * * pwpi - pointer to WIA_PROPERTY_INFO structure * ppv - pointer to PROPVARIANT structure * * Return Value: * * Status - S_OK if successful * - E_INVALIDARG if the vt type is not supported. * - E_OUTOFMEMORY if storage for the range could not be * allocated. * * * History: * * 10/29/1998 Original Version * \**************************************************************************/
//
// Helper macro
//
#define MAKE_RANGE(WPI, PV, Type, VName, RType) { \
\ Type *pArray = (Type*) CoTaskMemAlloc(sizeof(Type) * WIA_RANGE_NUM_ELEMS);\ \ if (pArray) { \ PV->VName.cElems = WIA_RANGE_NUM_ELEMS; \ PV->VName.pElems = (Type*)pArray; \ PV->VName.pElems[WIA_RANGE_MIN] = (Type) WPI->ValidVal.RType.Min; \ PV->VName.pElems[WIA_RANGE_NOM] = (Type) WPI->ValidVal.RType.Nom; \ PV->VName.pElems[WIA_RANGE_MAX] = (Type) WPI->ValidVal.RType.Max; \ PV->VName.pElems[WIA_RANGE_STEP] = (Type) WPI->ValidVal.RType.Inc; \ } else { \ DBG_ERR(("RangeToPropVariant, unable to allocate range list")); \ hr = E_OUTOFMEMORY; \ } \ };
HRESULT RangeToPropVariant( WIA_PROPERTY_INFO *pwpi, PROPVARIANT *ppv) { DBG_FN(::RangeToPropVariant); HRESULT hr = S_OK;
ppv->vt = VT_VECTOR | pwpi->vt;
switch (pwpi->vt) { case (VT_UI1): MAKE_RANGE(pwpi, ppv, UCHAR, caub, Range); break; case (VT_UI2): MAKE_RANGE(pwpi, ppv, USHORT, caui, Range); break; case (VT_UI4): MAKE_RANGE(pwpi, ppv, ULONG, caul, Range); break; case (VT_I2): MAKE_RANGE(pwpi, ppv, SHORT, cai, Range); break; case (VT_I4): MAKE_RANGE(pwpi, ppv, LONG, cal, Range); break; case (VT_R4): MAKE_RANGE(pwpi, ppv, FLOAT, caflt, RangeFloat); break; case (VT_R8): MAKE_RANGE(pwpi, ppv, DOUBLE, cadbl, RangeFloat); break; default:
//
// Type not supported
//
DBG_ERR(("RangeToPropVariant, type not supported")); hr = E_INVALIDARG; } return hr; }
/**************************************************************************\
* ListToPropVariant * * Move information from a WIA_PROPERTY_INFO struct to a PROPVARIANT. The * WIA_PROPERTY_INFO is known to be of type WIA_PROP_LIST. * * Arguments: * * pwpi - pointer to WIA_PROPERTY_INFO structure * ppv - pointer to PROPVARIANT structure * * Return Value: * * Status - S_OK if successful * - E_INVALIDARG if the vt type is not supported. * - E_OUTOFMEMORY if storage for the range could not be * allocated. * * * History: * * 10/29/1998 Original Version * \**************************************************************************/
//
// Helper macros
//
#define MAKE_LIST(WPI, PV, Type, Num, VName, LType) { \
\ if (IsBadReadPtr(WPI->ValidVal.LType.pList, sizeof(Type) * Num)) { \ hr = E_POINTER; \ break; \ }; \ \ Type *pArray = (Type*) CoTaskMemAlloc(sizeof(Type) * (Num + WIA_LIST_VALUES));\ \ if (pArray) { \ PV->VName.cElems = Num + WIA_LIST_VALUES; \ pArray[WIA_LIST_COUNT] = (Type) Num; \ pArray[WIA_LIST_NOM] = (Type) WPI->ValidVal.LType.Nom; \ \ memcpy(&pArray[WIA_LIST_VALUES], \ WPI->ValidVal.LType.pList, \ Num * sizeof(Type)); \ PV->VName.pElems = pArray; \ } else { \ DBG_ERR(("ListToPropVariant (MAKE_LIST), unable to allocate list"));\ hr = E_OUTOFMEMORY; \ } \ };
#define MAKE_LIST_GUID(WPI, PV, Type, Num) { \
\ if (IsBadReadPtr(WPI->ValidVal.ListGuid.pList, sizeof(GUID) * Num)) { \ hr = E_POINTER; \ break; \ }; \ \ GUID *pArray = (GUID*) CoTaskMemAlloc(sizeof(GUID) * (Num + WIA_LIST_VALUES));\ \ if (pArray) { \ PV->cauuid.cElems = Num + WIA_LIST_VALUES; \ pArray[WIA_LIST_COUNT] = WiaImgFmt_UNDEFINED; \ pArray[WIA_LIST_NOM] = WPI->ValidVal.ListGuid.Nom; \ \ memcpy(&pArray[WIA_LIST_VALUES], \ WPI->ValidVal.ListGuid.pList, \ Num * sizeof(GUID)); \ PV->cauuid.pElems = pArray; \ } else { \ DBG_ERR(("ListToPropVariant (MAKE_LIST), unable to allocate list"));\ hr = E_OUTOFMEMORY; \ } \ };
#define MAKE_LIST_BSTR(WPI, PV, Type, Num) { \
\ if (IsBadReadPtr(WPI->ValidVal.ListBStr.pList, sizeof(Type) * Num)) { \ DBG_ERR(("ListToPropVariant (MAKE_LIST_BSTR), pList pointer is bad"));\ hr = E_POINTER; \ break; \ }; \ \ Type *pArray = (Type*) CoTaskMemAlloc(sizeof(Type) * (Num + WIA_LIST_VALUES));\ \ if (pArray) { \ PV->cabstr.cElems = Num + WIA_LIST_VALUES; \ pArray[WIA_LIST_COUNT] = SysAllocString(L""); \ \ if(IsBadStringPtrW(WPI->ValidVal.ListBStr.Nom, SysStringLen(WPI->ValidVal.ListBStr.Nom))) {\ DBG_ERR(("ListToPropVariant (MAKE_LIST_BSTR), Nom BSTR is bad"));\ hr = E_POINTER; \ break; \ } \ pArray[WIA_LIST_NOM] = SysAllocString(WPI->ValidVal.ListBStr.Nom);\ if (!pArray[WIA_LIST_NOM]) { \ DBG_ERR(("ListToPropVariant (MAKE_LIST_BSTR), out of memory"));\ hr = E_OUTOFMEMORY; \ break; \ } \ \ for (ULONG i = 0; i < Num; i++) { \ if(IsBadStringPtrW(WPI->ValidVal.ListBStr.pList[i], SysStringLen(WPI->ValidVal.ListBStr.pList[i]))) {\ DBG_ERR(("ListToPropVariant (MAKE_LIST_BSTR), Nom BSTR is bad"));\ hr = E_POINTER; \ break; \ } \ pArray[WIA_LIST_VALUES + i] = SysAllocString(WPI->ValidVal.ListBStr.pList[i]);\ if (!pArray[WIA_LIST_VALUES + i]) { \ DBG_ERR(("ListToPropVariant (MAKE_LIST_BSTR), out of memory"));\ hr = E_OUTOFMEMORY; \ break; \ } \ } \ PV->cabstr.pElems = pArray; \ } else { \ DBG_ERR(("ListToPropVariant (MAKE_LIST_BSTR), unable to allocate list"));\ hr = E_OUTOFMEMORY; \ } \ };
HRESULT ListToPropVariant( WIA_PROPERTY_INFO *pwpi, PROPVARIANT *ppv) { DBG_FN(::ListToPropVariant); ULONG cList; HRESULT hr = S_OK;
cList = pwpi->ValidVal.List.cNumList; ppv->vt = VT_VECTOR | pwpi->vt;
switch (pwpi->vt) { case (VT_UI1): MAKE_LIST(pwpi, ppv, UCHAR, cList, caub, List); break; case (VT_UI2): MAKE_LIST(pwpi, ppv, USHORT, cList, caui, List); break; case (VT_UI4): MAKE_LIST(pwpi, ppv, ULONG, cList, caul, List); break; case (VT_I2): MAKE_LIST(pwpi, ppv, SHORT, cList, cai, List); break; case (VT_I4): MAKE_LIST(pwpi, ppv, LONG, cList, cal, List); break; case (VT_R4): MAKE_LIST(pwpi, ppv, FLOAT, cList, caflt, ListFloat); break; case (VT_R8): MAKE_LIST(pwpi, ppv, DOUBLE, cList, cadbl, ListFloat); break; case (VT_CLSID): MAKE_LIST_GUID(pwpi, ppv, GUID, cList); break; case (VT_BSTR): MAKE_LIST_BSTR(pwpi, ppv, BSTR, cList); break; default:
//
// Type not supported
//
DBG_ERR(("ListToPropVariant, type (%d) not supported", pwpi->vt)); hr = E_INVALIDARG; }
if (FAILED(hr)) { PropVariantClear(ppv); }
return hr; }
/**************************************************************************\
* FlagToPropVariant * * Move information from a WIA_PROPERTY_INFO struct to a PROPVARIANT. The * WIA_PROPERTY_INFO is known to be of type WIA_PROP_FLAG. * * Arguments: * * pwpi - pointer to WIA_PROPERTY_INFO structure * ppv - pointer to PROPVARIANT structure * * Return Value: * * Status - S_OK if successful * - E_OUTOFMEMORY if storage for the range could not be * allocated. * * * History: * * 10/29/1998 Original Version * \**************************************************************************/
HRESULT FlagToPropVariant( WIA_PROPERTY_INFO *pwpi, PROPVARIANT *ppv) { DBG_FN(::FlagToPropVariant);
//
// Check flag is of a valid VT
//
switch (pwpi->vt) { case VT_I4: case VT_UI4: case VT_I8: case VT_UI8: break;
default: DBG_ERR(("FlagToPropVariant, Invalid VT type (%d) for flag", pwpi->vt)); return E_INVALIDARG; }
ppv->caul.pElems = (ULONG*) CoTaskMemAlloc(sizeof(ULONG) * WIA_FLAG_NUM_ELEMS); if (ppv->caul.pElems) { ppv->vt = VT_VECTOR | pwpi->vt; ppv->caul.cElems = WIA_FLAG_NUM_ELEMS;
ppv->caul.pElems[WIA_FLAG_NOM] = pwpi->ValidVal.Flag.Nom; ppv->caul.pElems[WIA_FLAG_VALUES] = pwpi->ValidVal.Flag.ValidBits; } else { DBG_ERR(("FlagToPropVariant, out of memory")); return E_OUTOFMEMORY; }
return S_OK; }
/**************************************************************************\
* NoneToPropVariant * * Move information from a WIA_PROPERTY_INFO struct to a PROPVARIANT. The * WIA_PROPERTY_INFO is known to be of type WIA_PROP_NONE. * * Arguments: * * pwpi - pointer to WIA_PROPERTY_INFO structure * ppv - pointer to PROPVARIANT structure * * Return Value: * * Status - S_OK if successful * - E_OUTOFMEMORY if storage for the range could not be * allocated. * * * History: * * 10/29/1998 Original Version * \**************************************************************************/
HRESULT NoneToPropVariant( WIA_PROPERTY_INFO *pwpi, PROPVARIANT *ppv) { DBG_FN(::NoneToPropVariant);
RPC_STATUS rpcs = RPC_S_OK;
ppv->vt = pwpi->vt;
switch (pwpi->vt) { case VT_CLSID: ppv->puuid = (GUID*) CoTaskMemAlloc(sizeof(GUID)); if (!ppv->puuid) { return E_OUTOFMEMORY; } rpcs = UuidCreateNil(ppv->puuid); if (rpcs != RPC_S_OK) { DBG_WRN(("::NoneToPropVariant, UuidCreateNil returned 0x%08X", rpcs)); } break;
default: ppv->lVal = 0; }
return S_OK; }
/**************************************************************************\
* WiaPropertyInfoToPropVariant * * Move information from a WIA_PROPERTY_INFO struct to a PROPVARIANT. * * Arguments: * * * * Return Value: * * Status * * History: * * 10/29/1998 Original Version * \**************************************************************************/
HRESULT WiaPropertyInfoToPropVariant( WIA_PROPERTY_INFO *pwpi, PROPVARIANT *ppv) { DBG_FN(::WiaPropertyInfoToPropVariant); HRESULT hr = S_OK;
memset(ppv, 0, sizeof(PROPVARIANT));
if (pwpi->lAccessFlags & WIA_PROP_NONE) { hr = NoneToPropVariant(pwpi, ppv); } else if (pwpi->lAccessFlags & WIA_PROP_RANGE) { hr = RangeToPropVariant(pwpi, ppv); } else if (pwpi->lAccessFlags & WIA_PROP_LIST) { hr = ListToPropVariant(pwpi, ppv); } else if (pwpi->lAccessFlags & WIA_PROP_FLAG) { hr = FlagToPropVariant(pwpi, ppv); } else { DBG_ERR(("WiaPropertyInfoToPropVariant, bad access flags")); return E_INVALIDARG; } return hr; }
/**************************************************************************\
* wiasSetItemPropAttribs * * Set the access flags and valid values for a set of properties from * an array of WIA_PROPERTY_INFO structures. * * Arguments: * * pWiasContext - Pointer to WIA item * cPropSpec - The number of properties to set. * pPropSpec - Pointer to an array of property specifications. * pwpi - Pointer to an array of property information. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSetItemPropAttribs( BYTE *pWiasContext, LONG cPropSpec, PROPSPEC *pPropSpec, PWIA_PROPERTY_INFO pwpi) { DBG_FN(::wiasSetItemPropAttribs); IWiaItem *pItem = (IWiaItem*) pWiasContext;
//
// Do parameter validation.
//
HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasSetItemPropAttribs, invalid pItem")); return hr; }
if (IsBadReadPtr(pPropSpec, sizeof(PROPSPEC) * cPropSpec)) { DBG_ERR(("wiasSetItemPropAttribs, bad pPropSpec parameter")); return E_POINTER; }
if (IsBadReadPtr(pwpi, sizeof(WIA_PROPERTY_INFO) * cPropSpec)) { DBG_ERR(("wiasSetItemPropAttribs, bad pwpi parameter")); return E_POINTER; }
//
// Get the item's internal property storage pointers.
//
IPropertyStorage *pIPropAccessStg; IPropertyStorage *pIPropValidStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(NULL, &pIPropAccessStg, &pIPropValidStg, NULL); if (FAILED(hr)) { return hr; }
//
// Set the access flags and valid values for the items properties.
//
for (LONG i = 0; i < cPropSpec; i++) {
PROPVARIANT propvar;
PropVariantInit(&propvar);
hr = WiaPropertyInfoToPropVariant(&pwpi[i], &propvar); if (FAILED(hr)) { break; }
hr = wiasSetPropertyAttributes(pWiasContext, 1, &pPropSpec[i], &pwpi[i].lAccessFlags, &propvar); //
// Free any memory used by the propvariant
//
PropVariantClear(&propvar);
if (FAILED(hr)) { DBG_ERR(("wiasSetItemPropAttribs, call to wiasSetPropertyAttributes failed")); break; } }
return hr; }
/**************************************************************************\
* * wiasSetItemPropNames * * Sets the item property names for all three backing * property storages (property, access and valid values). * * Arguments: * * pWiasContext - WIA item pointer. * cItemProps - Number of property names to write. * ppId - Caller allocated array of PROPID's. * ppszNames - Caller allocated array of property names. * * Return Value: * * status * * History: * * 9/3/1998 Original Version * \**************************************************************************/
#define MAX_STR_LEN 65535
HRESULT _stdcall wiasSetItemPropNames( BYTE *pWiasContext, LONG cItemProps, PROPID *ppId, LPOLESTR *ppszNames) { DBG_FN(::wiasSetItemPropNames); IWiaItem *pItem = (IWiaItem*) pWiasContext;
HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasSetItemPropNames, invalid pItem")); return hr; }
if (IsBadWritePtr(ppId, sizeof(PROPID) * cItemProps)) { DBG_ERR(("wiasSetItemPropNames, bad ppId parameter")); return E_POINTER; }
if (IsBadWritePtr(ppszNames, sizeof(LPOLESTR) * cItemProps)) { DBG_ERR(("wiasSetItemPropNames, bad ppId parameter")); return E_POINTER; }
for (LONG i = 0; i < cItemProps; i++) { if (IsBadStringPtrW(ppszNames[i], MAX_STR_LEN)) { DBG_ERR(("wiasSetItemPropName, invalid ppszNames pointer, index: %d", i)); return E_POINTER; } }
return ((CWiaItem*)pItem)->WriteItemPropNames(cItemProps, ppId, ppszNames); }
/**************************************************************************\
* DetermineBMISize * * Determine the size of the needed BITMAPINFO structure * * Arguments: * * headerSize - size of BITMAPINFOHEADER or * BITMAPV4HEADER or BITMAPV5HEADER * depth - bits per pixel * biCompression - BI_RGB,BI_BITFIELDS,BI_RLE4,BI_RLE8,BI_JPEG,BI_PNG * pcbBMI - required size/bytes written * pcbColorMap - size of color map alone * * Return Value: * * Status * * History: * * 11/6/1998 Original Version * \**************************************************************************/
HRESULT DetermineBMISize( LONG headerSize, LONG depth, LONG biCompression, LONG* pcbBMI, LONG* pcbColorMap ) { DBG_FN(::DetermineBMISize); //
// Validate header size
//
*pcbBMI = NULL; *pcbColorMap = NULL;
if ( #if (WINVER >= 0x0500)
(headerSize != sizeof(BITMAPINFOHEADER)) && (headerSize != sizeof(BITMAPV4HEADER)) && (headerSize != sizeof(BITMAPV5HEADER)) #else
(headerSize != sizeof(BITMAPINFOHEADER)) && (headerSize != sizeof(BITMAPV4HEADER)) #endif
) {
DBG_ERR(("WriteBMI, unexpected headerSize: %d",headerSize )); return E_INVALIDARG; }
//
// Calculate color table size.
//
LONG ColorMapSize = 0;
if ( (biCompression == BI_RGB) || (biCompression == BI_BITFIELDS) || (biCompression == BI_RLE4) || (biCompression == BI_RLE8) ) {
switch (depth) {
case 1: ColorMapSize = 2; break;
case 4: ColorMapSize = 16; break;
case 8: ColorMapSize = 256; break;
case 15: case 16: ColorMapSize = 3; break;
case 24: ColorMapSize = 0; break;
case 32: if (biCompression == BI_BITFIELDS) { ColorMapSize = 0; } else { ColorMapSize = 3; } break;
default: DBG_ERR(("WriteBMI, unexpected depth: %d", depth)); return E_INVALIDARG; } }
//
// Calculate the BMI size.
//
*pcbColorMap = ColorMapSize; *pcbBMI = (ColorMapSize * sizeof(RGBQUAD)) + sizeof(BITMAPINFOHEADER);
return S_OK; }
/**************************************************************************\
* WriteDibHeader * * Write the DIB header to a buffer. * * Arguments: * * pmdtc - Pointer to mini driver transfer context. * * Return Value: * * Status * * History: * * 4/5/1999 Original Version * \**************************************************************************/
HRESULT WriteDibHeader( LONG lColorMapSize, PMINIDRV_TRANSFER_CONTEXT pmdtc) { DBG_FN(::WriteDibHeader); UNALIGNED BITMAPINFO* pbmi = (BITMAPINFO*)pmdtc->pTransferBuffer; UNALIGNED BITMAPFILEHEADER* pbmf = NULL;
//
// If this is a file, fill in file header.
//
if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_BMP)) {
//
// Setup file header pointers.
//
pbmf = (BITMAPFILEHEADER*)pmdtc->pTransferBuffer; pbmi = (BITMAPINFO*)((PBYTE)pbmf + sizeof(BITMAPFILEHEADER));
//
// fill in bitmapfileheader
//
pbmf->bfType = 'MB'; pbmf->bfSize = pmdtc->lImageSize + pmdtc->lHeaderSize; pbmf->bfReserved1 = 0; pbmf->bfReserved2 = 0; pbmf->bfOffBits = pmdtc->lHeaderSize; }
UNALIGNED BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)pbmi;
pbmih->biSize = sizeof(BITMAPINFOHEADER); pbmih->biWidth = pmdtc->lWidthInPixels; pbmih->biHeight = pmdtc->lLines;
pbmih->biPlanes = 1; pbmih->biBitCount = (USHORT)pmdtc->lDepth; pbmih->biCompression = BI_RGB; pbmih->biSizeImage = pmdtc->lLines * pmdtc->cbWidthInBytes; pbmih->biXPelsPerMeter = MulDiv(pmdtc->lXRes,10000,254); pbmih->biYPelsPerMeter = MulDiv(pmdtc->lYRes,10000,254); pbmih->biClrUsed = 0; pbmih->biClrImportant = 0;
//
// Fill in the palette, if any.
//
// !!! Palette or bitfields must come from
// driver. We can't assume gray scale
//
if (lColorMapSize) { PBYTE pPal = (PBYTE)pbmih + sizeof(BITMAPINFOHEADER);
for (INT i = 0; i < lColorMapSize; i++) { if (pmdtc->lDepth == 1) { memset(pPal, (i * 0xFF), 3); } else if (pmdtc->lDepth == 4) { memset(pPal, (i * 0x3F), 3); } else if (pmdtc->lDepth == 8) { memset(pPal, i, 3); } pPal += 3; *pPal++ = 0; }
pbmih->biClrUsed = lColorMapSize; }
return S_OK; }
/**************************************************************************\
* GetDIBImageInfo * * Calc size of DIB header and file, if adequate header is provided then * fill it out * * Arguments: * * pmdtc - Pointer to mini driver transfer context. * * Return Value: * * Status * * History: * * 4/5/1999 Original Version * \**************************************************************************/
HRESULT GetDIBImageInfo(PMINIDRV_TRANSFER_CONTEXT pmdtc) { DBG_FN(::GetDIBImageInfo); //
// Map WIA compression to bitmap info compression.
//
LONG biCompression;
switch (pmdtc->lCompression) { case WIA_COMPRESSION_NONE: biCompression = BI_RGB; break; case WIA_COMPRESSION_BI_RLE4: biCompression = BI_RLE4; break; case WIA_COMPRESSION_BI_RLE8: biCompression = BI_RLE8; break;
default: DBG_ERR(("GetDIBImageInfo, unsupported compression type: 0x%08X", pmdtc->lCompression)); return E_INVALIDARG; }
//
// find out bitmapinfoheader size
//
LONG lColorMapSize; LONG lHeaderSize;
HRESULT hr = DetermineBMISize(sizeof(BITMAPINFOHEADER), pmdtc->lDepth, biCompression, &lHeaderSize, &lColorMapSize);
if (hr != S_OK) { DBG_ERR(("GetDIBImageInfo, DetermineBMISize calc size error")); return hr; }
//
// if this is a file, add file header to size
//
if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_BMP)) { lHeaderSize += sizeof(BITMAPFILEHEADER); }
//
// Calculate number of bytes per line, width must be
// aligned to 4 byte boundary.
//
pmdtc->cbWidthInBytes = (pmdtc->lWidthInPixels * pmdtc->lDepth) + 31; pmdtc->cbWidthInBytes = (pmdtc->cbWidthInBytes / 8) & 0xfffffffc;
//
// Always fill in mini driver context with image size information.
//
pmdtc->lImageSize = pmdtc->cbWidthInBytes * pmdtc->lLines; pmdtc->lHeaderSize = lHeaderSize;
//
// With compression, image size is unknown.
//
if (pmdtc->lCompression != WIA_COMPRESSION_NONE) {
pmdtc->lItemSize = 0; } else {
pmdtc->lItemSize = pmdtc->lImageSize + lHeaderSize; }
//
// If the buffer is null, then just return sizes.
//
if (pmdtc->pTransferBuffer == NULL) {
return S_OK; } else {
//
// make sure passed in header buffer is large enough
//
if (pmdtc->lBufferSize < lHeaderSize) { DBG_ERR(("GetDIBImageInfo, buffer won't hold header, need: %d", lHeaderSize)); return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); }
//
// Fill in the header
//
return WriteDibHeader(lColorMapSize, pmdtc); } }
/**************************************************************************\
* GetJPEGImageInfo * * Calc size of JPEG header and file, if adequate header is provided then * fill it out * * Arguments: * * pmdtc - Pointer to mini driver transfer context. * * Return Value: * * Status * * History: * * 4/5/1999 Original Version * \**************************************************************************/
HRESULT GetJPEGImageInfo(PMINIDRV_TRANSFER_CONTEXT pmdtc) { DBG_FN(::GetJPEGImageInfo); //
// width in bytes is not defined
//
pmdtc->cbWidthInBytes = 0;
//
// JPEG requires no separate header
//
pmdtc->lHeaderSize = 0;
//
// lItemSize comes from the WIA_IPA_ITEM_SIZE property
// which is set/validated by the mini driver. Since there
// is no separate header for JPEG it is the total transfer size.
//
pmdtc->lImageSize = pmdtc->lItemSize;
return S_OK; }
/**************************************************************************\
* wiasGetImageInformation * * Calulate full file size, header size, or fill in header * * Arguments: * * pWiasContext - WIA item pointer. * lFlags - Operation flags. * pmdtc - Pointer to mini driver transfer context. * * Return Value: * * Status * * History: * * 11/6/1998 Original Version * \**************************************************************************/
HRESULT _stdcall wiasGetImageInformation( BYTE *pWiasContext, LONG lFlags, PMINIDRV_TRANSFER_CONTEXT pmdtc) { DBG_FN(::wiasGetImageInformation); IWiaItem *pItem = (IWiaItem*) pWiasContext;
HRESULT hr = ValidateWiaItem(pItem);
if (FAILED(hr)) { DBG_ERR(("wiasGetImageInformation, invalid pItem")); return hr; }
if (IsBadWritePtr(pmdtc, sizeof(MINIDRV_TRANSFER_CONTEXT))) { DBG_ERR(("wiasGetImageInformation, bad input parameters, pmdtc")); return E_INVALIDARG; }
//
// Init the mini driver context from item properties if requested.
//
if (lFlags == WIAS_INIT_CONTEXT) { hr = InitMiniDrvContext(pItem, pmdtc); if (FAILED(hr)) { return hr; } }
if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_BMP) || (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_MEMORYBMP))) {
return GetDIBImageInfo(pmdtc);
} else if ((IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_JPEG)) || (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_FLASHPIX))) {
return GetJPEGImageInfo(pmdtc);
} else if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_TIFF)) {
//
// For callback style data transfers, send single page TIFF
// since we can not rewind the buffer for page offset updates.
//
if (pmdtc->bTransferDataCB) { return GetTIFFImageInfo(pmdtc); } else { return GetMultiPageTIFFImageInfo(pmdtc); }
} else { return S_FALSE; } }
/**************************************************************************\
* CopyItemPropsAndAttribsHelper * * Helper for wiasCopyItemPropsAndAttribs. * * Arguments: * * pItemSrc - WIA item source. * pItemDst - WIA item destination. * * Return Value: * * Status * * History: * * 10/2/1998 Original Version * \**************************************************************************/
HRESULT _stdcall CopyItemPropsAndAttribsHelper( IPropertyStorage *pIPropStgSrc, IPropertyStorage *pIPropStgDst, PROPSPEC *pps, LPSTR pszErr) { DBG_FN(::CopyItemPropsAndAttribsHelper); PROPVARIANT pv[1];
HRESULT hr = pIPropStgSrc->ReadMultiple(1, pps, pv); if (SUCCEEDED(hr)) {
hr = pIPropStgDst->WriteMultiple(1, pps, pv, WIA_DIP_FIRST); if (FAILED(hr)) { ReportReadWriteMultipleError(hr, "CopyItemPropsAndAttribsHelper", pszErr, FALSE, 1, pps); } PropVariantClear(pv); } else { ReportReadWriteMultipleError(hr, "wiasCopyItemPropsAndAttribs", pszErr, TRUE, 1, pps); } return hr; }
/**************************************************************************\
* ValidateListProp * * Validates a List property. This is a helper function for * wiasValidateItemProperties. A data type that is not supported * is skipped and S_OK is returned; * * Arguments: * * cur - current property value * valid - valid values * * Return Value: * * Status * * History: * * 20/4/1998 Original Version * \**************************************************************************/
//
// Macro used for error output
//
#define REP_LIST_ERROR(x, name) { \
DBG_WRN(("wiasValidateItemProperties, invalid LIST value for : ")); \ if (pPropSpec->ulKind == PRSPEC_LPWSTR) { \ DBG_WRN((" (Name) %S, value = %d", pPropSpec->lpwstr, cur->x));\ } else { \ DBG_WRN((" (propID) %S, value = %d", \ GetNameFromWiaPropId(pPropSpec->propid), \ cur->x)); \ }; \ DBG_WRN(("Valid values are:")); \ for (ULONG j = 0; j < WIA_PROP_LIST_COUNT(valid); j++) { \ DBG_WRN((" %d", valid->name.pElems[WIA_LIST_VALUES + j])); \ }; \ };
//
// Macro used to check that an element is in the list. Only used for
// lists of numbers.
//
#define LIST_CHECK(value, name) { \
for (ULONG i = 0; i < WIA_PROP_LIST_COUNT(valid); i++) {\ if (cur->value == valid->name.pElems[WIA_LIST_VALUES + i]) { \ return S_OK; \ }; \ }; \ REP_LIST_ERROR(value, name); \ return E_INVALIDARG; \ };
HRESULT ValidateListProp( PROPVARIANT *cur, PROPVARIANT *valid, PROPSPEC *pPropSpec) { DBG_FN(::ValidateListProp); ULONG ulType; ulType = cur->vt & ~((ULONG) VT_VECTOR); switch (ulType) { case (VT_UI1): LIST_CHECK(bVal, caub); break; case (VT_UI2): LIST_CHECK(iVal, cai); break; case (VT_I4): LIST_CHECK(lVal, cal); break; case (VT_UI4): LIST_CHECK(ulVal, caul); break; case (VT_R4): LIST_CHECK(fltVal, caflt); break; case (VT_R8): LIST_CHECK(dblVal, cadbl); break; case (VT_CLSID): { for (ULONG i = 0; i < WIA_PROP_LIST_COUNT(valid); i++) { if (*cur->puuid == valid->cauuid.pElems[WIA_LIST_VALUES + i]) { return S_OK; }; };
UCHAR *curVal;
if (UuidToStringA(cur->puuid, &curVal) != RPC_S_OK) { DBG_WRN(("wiasValidateItemProperties, Out of memory")); return E_OUTOFMEMORY; }; DBG_WRN(("wiasValidateItemProperties, invalid LIST value for : ")); if (pPropSpec->ulKind == PRSPEC_LPWSTR) { DBG_WRN((" (Name) %d, value = %s", pPropSpec->lpwstr, curVal)); } else { DBG_WRN((" (propID) %S, value = %s", GetNameFromWiaPropId(pPropSpec->propid), curVal)); }; RpcStringFreeA(&curVal); DBG_WRN(("Valid values are:")); for (ULONG j = 0; j < WIA_PROP_LIST_COUNT(valid); j++) { if (UuidToStringA(&valid->cauuid.pElems[WIA_LIST_VALUES + j], &curVal) == RPC_S_OK) { DBG_WRN((" %s", curVal)); RpcStringFreeA(&curVal); } };
return E_INVALIDARG;
} break; case (VT_BSTR): {
//
// Loop through elements and compare to current value. Loop
// counter max is (cElemens - 2) to take into account
// Nominal and Count values which are skipped.
//
if (!cur->bstrVal) { return S_OK; } for (ULONG i = 0; i < WIA_PROP_LIST_COUNT(valid); i++) { if (!wcscmp(cur->bstrVal, valid->cabstr.pElems[WIA_LIST_VALUES + i])) { return S_OK; }; }; DBG_WRN(("wiasValidateItemProperties, invalid LIST value for : ")); if (pPropSpec->ulKind == PRSPEC_LPWSTR) { DBG_WRN((" (Name) %S, value = %S", pPropSpec->lpwstr, cur->bstrVal)); } else { DBG_WRN((" (propID) %S, value = %S", GetNameFromWiaPropId(pPropSpec->propid), cur->bstrVal)); }; DBG_WRN(("Valid values are:")); for (ULONG j = 0; j < WIA_PROP_LIST_COUNT(valid); j++) { DBG_WRN((" %S", valid->cabstr.pElems[WIA_LIST_VALUES + j])); }; return E_INVALIDARG; } break;
default:
//
// Type not supported, assume S_OK
//
return S_OK; } return S_OK; }
/**************************************************************************\
* ValidateRangeProp * * Validates a Range property. This is a helper function for * wiasValidateItemProperties. A data type that is not supported * is skipped and S_OK is returned; * * Arguments: * * cur - current property value * valid - valid values * * Return Value: * * Status * * History: * * 20/4/1998 Original Version * \**************************************************************************/
//
// Macro used for error output, for integers
//
#define REP_RANGE_ERROR(x, name) { \
DBG_WRN(("wiasValidateItemProperties, invalid RANGE value for : ")); \ if (pPropSpec->ulKind == PRSPEC_LPWSTR) { \ DBG_WRN((" (Name) %S, value = %d", pPropSpec->lpwstr, cur->x)); \ } else { \ DBG_WRN((" (propID) %S, value = %d", \ GetNameFromWiaPropId(pPropSpec->propid), \ cur->x)); \ }; \ DBG_WRN(("Valid RANGE is: MIN = %d, MAX = %d, STEP = %d", \ valid->name.pElems[WIA_RANGE_MIN], \ valid->name.pElems[WIA_RANGE_MAX], \ valid->name.pElems[WIA_RANGE_STEP])); \ return E_INVALIDARG; \ };
//
// Macro used for error output, for reals
//
#define REP_REAL_RANGE_ERROR(x, name) { \
DBG_WRN(("wiasValidateItemProperties, invalid RANGE value for : ")); \ if (pPropSpec->ulKind == PRSPEC_LPWSTR) { \ DBG_WRN((" (Name) %S, value = %2.3f", pPropSpec->lpwstr, cur->x));\ } else { \ DBG_WRN((" (propID) %S, value = %2.3f", \ GetNameFromWiaPropId(pPropSpec->propid), \ cur->x)); \ }; \ DBG_WRN(("Valid RANGE is: MIN = %2.3f, MAX = %2.3f, STEP = %2.3f", \ valid->name.pElems[WIA_RANGE_MIN], \ valid->name.pElems[WIA_RANGE_MAX], \ valid->name.pElems[WIA_RANGE_STEP])); \ return E_INVALIDARG; \ };
//
// Macro used to check that x is within the range and matches the correct step
// (only used for integer ranges)
//
#define RANGE_CHECK(x, name) { \
if (valid->name.pElems[WIA_RANGE_STEP] == 0) \ { \ REP_RANGE_ERROR(x, name); \ } \ if ((cur->x < valid->name.pElems[WIA_RANGE_MIN]) || \ (cur->x > valid->name.pElems[WIA_RANGE_MAX]) || \ ((cur->x - valid->name.pElems[WIA_RANGE_MIN]) % \ valid->name.pElems[WIA_RANGE_STEP])) { \ REP_RANGE_ERROR(x, name); \ }; \ };
HRESULT ValidateRangeProp( PROPVARIANT *cur, PROPVARIANT *valid, PROPSPEC *pPropSpec) { DBG_FN(::ValidateRangeProp); LONG ulType;
//
// Decide what to do based on type of data
//
ulType = cur->vt & ~((ULONG) VT_VECTOR);
switch (ulType) { case (VT_UI1): RANGE_CHECK(bVal, caub); break; case (VT_UI2): RANGE_CHECK(uiVal, caui); break; case (VT_UI4): RANGE_CHECK(ulVal, caul); break; case (VT_I2): RANGE_CHECK(iVal, cai); break; case (VT_I4): RANGE_CHECK(lVal, cal); break; case (VT_R4): if ((cur->fltVal < valid->caflt.pElems[WIA_RANGE_MIN]) || (cur->fltVal > valid->caflt.pElems[WIA_RANGE_MAX])) { REP_REAL_RANGE_ERROR(fltVal, caflt); } break; case (VT_R8): if ((cur->dblVal < valid->cadbl.pElems[WIA_RANGE_MIN]) || (cur->dblVal > valid->cadbl.pElems[WIA_RANGE_MAX])) { REP_REAL_RANGE_ERROR(dblVal, cadbl); } break; default:
//
// Type not supported, assume S_OK
//
return S_OK; } return S_OK; }
/**************************************************************************\
* wiasValidateItemProperties * * Validates a list of properties against their valid values for a given * item. * NOTE: Validation can only be done on Read/Write properties of type * WIA_PROP_FLAG, WIA_PROP_RANGE and WIA_PROP_LIST. Any other * type will simply be skipped over. * * Arguments: * * pWiasContext - Wia item * nPropSpec - number of properties * pPropSpec - array of PROPSPEC indicating which properties are to be * validated. * * Return Value: * * Status * * History: * * 20/4/1998 Original Version * \**************************************************************************/
//
// Macro for error output
//
#if defined(_DEBUG) || defined(DBG) || defined(WIA_DEBUG)
#define REP_ERR(text, i) { \
DBG_WRN((text)); \ if (pPropSpec[i].ulKind == PRSPEC_LPWSTR) { \ DBG_WRN((" (Name) %S, value = %d", \ pPropSpec[i].lpwstr, \ curVal.ulVal)); \ } else { \ DBG_WRN((" (propID) %S, value = %d", \ GetNameFromWiaPropId(pPropSpec[i].propid), \ curVal.ulVal)); \ }; \ }; #else
#define REP_ERR(text, i)
#endif
HRESULT _stdcall wiasValidateItemProperties( BYTE *pWiasContext, ULONG nPropSpec, const PROPSPEC *pPropSpec) { DBG_FN(::wiasValidateItemProperties); IWiaItem *pItem = (IWiaItem*) pWiasContext;
PROPVARIANT curVal, validVal; ULONG lAccess; HRESULT hr;
//
// May be called by driver or application, do parameter validation.
//
hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasValidateItemProperties, invalid pItem")); return hr; }
if (IsBadReadPtr(pPropSpec, sizeof(PROPSPEC) * nPropSpec)) { DBG_ERR(("wiasValidateItemProperties, bad pPropSpec parameter")); return E_POINTER; }
//
// Get the Item's property streams
//
IPropertyStorage *pIProp; IPropertyStorage *pIPropAccessStgDst; IPropertyStorage *pIPropValidStgDst;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIProp, &pIPropAccessStgDst, &pIPropValidStgDst, NULL);
if (FAILED(hr)) { DBG_WRN(("wiasValidateItemProperties, GetItemPropStreams failed")); return E_FAIL; }
//
// Loop through properties
//
for (ULONG i = 0; i < nPropSpec; i++) {
//
// Get the access flag and valid values for the property
//
lAccess = 0; hr = wiasGetPropertyAttributes((BYTE*)pItem, 1, (PROPSPEC*) &pPropSpec[i], &lAccess, &validVal); if (hr != S_OK) { return hr; }
//
// If the access flag is not RW or one of the three supported types
// (FLAG, RANGE, LIST) then skip it
//
if (!(lAccess & WIA_PROP_RW)) { ULONG ulType;
ulType = lAccess & ~((ULONG)WIA_PROP_RW);
if ((ulType != WIA_PROP_FLAG) && (ulType != WIA_PROP_RANGE) && (ulType != WIA_PROP_LIST)) { PropVariantClear(&validVal); continue; } }
//
// Get the current value
//
hr = pIProp->ReadMultiple(1, (PROPSPEC*) &pPropSpec[i], &curVal); if (hr != S_OK) { ReportReadWriteMultipleError(hr, "wiasValidateItemProperties", NULL, TRUE, 1, &pPropSpec[i]); } else { //
// Check whether the value is valid
//
ULONG BitsToRemove = (ULONG) (WIA_PROP_RW | WIA_PROP_CACHEABLE); switch (lAccess & ~BitsToRemove) { case (WIA_PROP_FLAG):
//
// Check that current bits are valid.
//
if (curVal.ulVal & ~(ULONG) validVal.caul.pElems[WIA_FLAG_VALUES]) { DBG_WRN(("wiasValidateItemProperties, invalid value for FLAG :", i)); DBG_WRN(("Valid mask is: %d", validVal.caul.pElems[WIA_FLAG_VALUES])); hr = E_INVALIDARG; }; break;
case (WIA_PROP_RANGE):
hr = ValidateRangeProp(&curVal, &validVal, (PROPSPEC*)&pPropSpec[i]); break;
case (WIA_PROP_LIST):
hr = ValidateListProp(&curVal, &validVal, (PROPSPEC*)&pPropSpec[i]); break;
default: hr = S_OK; } } PropVariantClear(&validVal); PropVariantClear(&curVal);
if (hr != S_OK) { break; } }; return hr; }
/**************************************************************************\
* wiasWritePageBufToFile * * Write from a mini driver allocated temporary page buffer * to the image file. This is specifically used by drivers to write a * page to a multi-page TIFF file. Therefore this function treats * WiaImgFmt_TIFF formats as a special case, since it will update * the IFD entries correctly. With all other formats, the buffer is * simply written to the file as-is. * * Arguments: * * pmdtc - Pointer to mini driver transfer context. * * Return Value: * * Status * * History: * * 11/6/1998 Original Version * \**************************************************************************/
HRESULT _stdcall wiasWritePageBufToFile(PMINIDRV_TRANSFER_CONTEXT pmdtc) { DBG_FN(::wiasWritePageBufToFile); HRESULT hr = S_OK;
if (pmdtc == NULL) { hr = E_POINTER; DBG_ERR(("wiasWritePageBufToFile, received NULL pmdtc pointer, 0x%08x", hr)); return hr; }
//
// Multipage TIFF requires special handling since the TIFF
// header must be updated for each page added.
//
if (IsEqualGUID(pmdtc->guidFormatID, WiaImgFmt_TIFF)) {
hr = WritePageToMultiPageTiff(pmdtc); } else { ULONG ulWritten; BOOL bRet;
if (pmdtc->lItemSize <= pmdtc->lBufferSize) {
bRet = WriteFile((HANDLE)pmdtc->hFile, pmdtc->pTransferBuffer, pmdtc->lItemSize, &ulWritten, NULL);
if (!bRet) { hr = HRESULT_FROM_WIN32(::GetLastError()); DBG_ERR(("wiasWritePageBufToFile, WriteFile failed (0x%X)", hr)); } } else { DBG_ERR(("wiasWritePageBufToFile, lItemSize is larger than buffer")); hr = E_FAIL;
} } return hr; }
/**************************************************************************\
* wiasWriteBufToFile * * Write from a specified buffer to the image file. * * Arguments: * * lFlags - Operation flags. Should be 0. * pmdtc - Pointer to mini driver transfer context. * * Return Value: * * Status * * History: * * 11/6/1998 Original Version * \**************************************************************************/
HRESULT _stdcall wiasWriteBufToFile( LONG lFlags, PMINIDRV_TRANSFER_CONTEXT pmdtc) { DBG_FN(::wiasWritePageBufToFile); HRESULT hr = S_OK;
ULONG ulWritten; BOOL bRet;
if (pmdtc == NULL) { hr = E_POINTER; DBG_ERR(("wiasWriteBufToFile, received NULL pmdtc pointer, 0x%08x", hr)); return hr; }
if (pmdtc->lItemSize <= pmdtc->lBufferSize) {
bRet = WriteFile((HANDLE)pmdtc->hFile, pmdtc->pTransferBuffer, pmdtc->lItemSize, &ulWritten, NULL);
if (!bRet) { hr = HRESULT_FROM_WIN32(::GetLastError()); DBG_ERR(("wiasWritePageBufToFile, WriteFile failed (0x%X)", hr)); } } else { DBG_ERR(("wiasWritePageBufToFile, lItemSize is larger than buffer")); hr = E_FAIL;
}
return hr; }
/**************************************************************************\
* wiasSendEndOfPage * * Call client with total page count. * * Arguments: * * pWiasContext - WIA item pointer. * lPageCount - Zero based count of total pages. * pmdtc - Pointer to mini driver transfer context. * * Return Value: * * Status * * History: * * 11/6/1998 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSendEndOfPage( BYTE *pWiasContext, LONG lPageCount, PMINIDRV_TRANSFER_CONTEXT pmdtc) { DBG_FN(::wiasSendEndOfPage); IWiaItem *pItem = (IWiaItem*) pWiasContext;
HRESULT hr = ValidateWiaItem(pItem);
if (FAILED(hr)) { DBG_ERR(("wiasSendEndOfPage, invalid pItem")); return hr; }
if (IsBadWritePtr(pmdtc, sizeof(MINIDRV_TRANSFER_CONTEXT))) { DBG_ERR(("wiasSendEndOfPage, bad input parameters, pmdtc")); return E_INVALIDARG; }
return ((CWiaItem*)pItem)->SendEndOfPage(lPageCount, pmdtc); }
/**************************************************************************\
* wiasGetItemType * * Returns the item type. * * Arguments: * * pWiasContext - Pointer to Wia item * plType - Address of LONG to receive Item Type value. * * Return Value: * * Status * * History: * * 5/07/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasGetItemType( BYTE *pWiasContext, LONG *plType) { DBG_FN(::wiasGetItemType); IWiaItem *pItem = (IWiaItem*) pWiasContext; HRESULT hr = ValidateWiaItem(pItem);
if (FAILED(hr)) { DBG_ERR(("wiasGetItemType, invalid pItem")); return hr; }
if (plType) { return pItem->GetItemType(plType); } else { DBG_ERR(("wiasGetItemType, invalid ppIWiaDrvItem")); return E_POINTER; } }
/**************************************************************************\
* wiasGetDrvItem * * Returns the WIA item's corresponding driver item. * * Arguments: * * pWiasContext - Pointer to Wia item * ppIWiaDrvItem - Address which receives pointer to the Driver Item. * * Return Value: * * Status * * History: * * 5/07/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasGetDrvItem( BYTE *pWiasContext, IWiaDrvItem **ppIWiaDrvItem) { DBG_FN(::wiasGetDrvItem); IWiaItem *pItem = (IWiaItem*) pWiasContext; IWiaDrvItem *pIWiaDrvItem; HRESULT hr = ValidateWiaItem(pItem);
if (FAILED(hr)) { DBG_ERR(("wiasGetDrvItem, invalid pItem")); return hr; }
if (!ppIWiaDrvItem) { DBG_ERR(("wiasGetDrvItem, invalid ppIWiaDrvItem")); return E_POINTER; }
pIWiaDrvItem = ((CWiaItem*)pItem)->GetDrvItemPtr(); if (pIWiaDrvItem) { *ppIWiaDrvItem = pIWiaDrvItem; } else { DBG_ERR(("wiasGetDrvItem, Driver Item is NULL")); hr = E_FAIL; }
return hr; }
/**************************************************************************\
* wiasGetRootItem * * Returns the WIA item's corresponding root item item. * * Arguments: * * pWiasContext - Wia item * ppIWiaItem - Address which receives pointer to the root Item. * * Return Value: * * Status * * History: * * 5/07/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasGetRootItem( BYTE *pWiasContext, BYTE **ppWiasContext) { DBG_FN(::wiasGetRootItem); IWiaItem *pItem = (IWiaItem*) pWiasContext; HRESULT hr = ValidateWiaItem(pItem); if (FAILED(hr)) { DBG_ERR(("wiasGetRootItem, invalid pItem")); return hr; }
if (ppWiasContext) { hr = pItem->GetRootItem((IWiaItem**)ppWiasContext); ((IWiaItem*)(*ppWiasContext))->Release(); return hr; } else { DBG_ERR(("wiasGetRootItem, invalid ppIWiaItem")); return E_POINTER; } }
/**************************************************************************\
* SetValidValueHelper * * Helper to write the valid values for a property. It first does a check * that the property is of the specified type. * * Arguments: * * pWiasContext - Wia item * ulType - specifies type (WIA_PROP_FLAG, WIA_PROP_LIST, * WIA_PROP_RANGE) * ps - Identifies the property * pv - The new valid value * * Return Value: * * Status * * History: * * 07/21/1999 Original Version * \**************************************************************************/
HRESULT _stdcall SetValidValueHelper( BYTE *pWiasContext, ULONG ulType, PROPSPEC *ps, PROPVARIANT *pv) { DBG_FN(::SetValidValueHelper); HRESULT hr; PROPVARIANT pvAccess[1];
//
// Get the access flag and valid value storage. Check that the property
// is a WIA_PROP_RANGE, and write the new values if it is.
//
IPropertyStorage *pIPropAccessStg; IPropertyStorage *pIPropValidStg;
hr = ((CWiaItem*)pWiasContext)->GetItemPropStreams(NULL, &pIPropAccessStg, &pIPropValidStg, NULL); if (SUCCEEDED(hr)) {
hr = pIPropAccessStg->ReadMultiple(1, ps, pvAccess); if (SUCCEEDED(hr)) {
if (pvAccess[0].ulVal & ulType) {
hr = pIPropValidStg->WriteMultiple(1, ps, pv, WIA_DIP_FIRST); if (FAILED(hr)) { DBG_ERR(("SetValidValueHelper, Error writing (Property %S)", GetNameFromWiaPropId(ps[0].propid))); } } else { DBG_ERR(("SetValidValueHelper, (PropID %S) is not of the correct type", GetNameFromWiaPropId(ps[0].propid))); DBG_ERR(("Expected type %d but got type %d", ulType, pvAccess[0].ulVal)); hr = E_INVALIDARG; } } else { DBG_ERR(("SetValidValueHelper, Could not get access flags (0x%X)", hr)); } } else { DBG_ERR(("SetValidValueHelper, GetItemPropStreams failed (0x%X)", hr)); }
return hr; }
/**************************************************************************\
* wiasSetValidFlag * * Sets the valid values for a WIA_PROP_FLAG property. This function * assumes the flag type to be VT_UI4. * * Arguments: * * pWiasContext - Wia item * propid - Identifies the property * ulNom - The flag's nominal value * ulValidBits - The flag's valid bits * * Return Value: * * Status * * History: * * 07/21/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSetValidFlag( BYTE* pWiasContext, PROPID propid, ULONG ulNom, ULONG ulValidBits) { DBG_FN(::wiasSetValidFlag); HRESULT hr; PROPVARIANT pv[1]; PROPSPEC ps[1]; ULONG *pFlags;
//
// Validate params
//
hr = ValidateWiaItem((IWiaItem*)pWiasContext); if (FAILED(hr)) { DBG_ERR(("wiasSetValidFlag, invalid pItem (0x%X)", hr)); return hr; }
pFlags = (ULONG*) CoTaskMemAlloc(sizeof(LONG) * WIA_FLAG_NUM_ELEMS); if (!pFlags) { DBG_ERR(("wiasSetValidFlag, Out of memory")); return E_OUTOFMEMORY; }
//
// Set up the propvariant
//
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
pFlags[0] = ulNom; pFlags[1] = ulValidBits;
pv[0].vt = VT_VECTOR | VT_UI4; pv[0].caul.cElems = WIA_FLAG_NUM_ELEMS; pv[0].caul.pElems = pFlags;
hr = SetValidValueHelper(pWiasContext, WIA_PROP_FLAG, ps, pv); if (FAILED(hr)) { DBG_ERR(("wiasSetValidFlag, SetValidValueHelper failed (0x%X)", hr)); }
PropVariantClear(pv); return hr; }
/**************************************************************************\
* wiasSetValidRangeLong * * Sets the valid values for a WIA_PROP_RANGE property. This function * assumes the property is of type VT_I4. * * Arguments: * * pWiasContext - Wia item * propid - Identifies the property * lMin - minimum * lNom - nominal * lMax - maximum * lStep - step * * Return Value: * * Status * * History: * * 07/21/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSetValidRangeLong( BYTE* pWiasContext, PROPID propid, LONG lMin, LONG lNom, LONG lMax, LONG lStep) { DBG_FN(::wiasSetValidRangeLong); HRESULT hr; PROPVARIANT pv[1]; PROPSPEC ps[1]; LONG *pRange;
//
// Validate params
//
hr = ValidateWiaItem((IWiaItem*)pWiasContext); if (FAILED(hr)) { DBG_ERR(("wiasSetValidRangeLong, invalid pItem (0x%X)", hr)); return hr; }
pRange = (LONG*) CoTaskMemAlloc(sizeof(LONG) * WIA_RANGE_NUM_ELEMS); if (!pRange) { DBG_ERR(("wiasSetValidRangeLong, Out of memory")); return E_OUTOFMEMORY; }
//
// Set up the propvariant
//
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
pRange[WIA_RANGE_MIN] = lMin; pRange[WIA_RANGE_NOM] = lNom; pRange[WIA_RANGE_MAX] = lMax; pRange[WIA_RANGE_STEP] = lStep;
pv[0].vt = VT_VECTOR | VT_I4; pv[0].cal.cElems = WIA_RANGE_NUM_ELEMS; pv[0].cal.pElems = pRange;
//
// Call the helper to set the valid value
//
hr = SetValidValueHelper(pWiasContext, WIA_PROP_RANGE, ps, pv); if (FAILED(hr)) { DBG_ERR(("wiasSetValidRangeLong, Helper failed (0x%X)", hr)); }
PropVariantClear(pv); return hr; }
/**************************************************************************\
* wiasSetValidRangeFloat * * Sets the valid values for a WIA_PROP_RANGE property. This function * assumes the property is of type VT_R4. * * Arguments: * * pWiasContext - Wia item * propid - Identifies the property * lMin - minimum * lNom - nominal * lMax - maximum * lStep - step * * Return Value: * * Status * * History: * * 07/21/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSetValidRangeFloat( BYTE* pWiasContext, PROPID propid, FLOAT fMin, FLOAT fNom, FLOAT fMax, FLOAT fStep) { DBG_FN(::wiasSetValidRangeFloat); HRESULT hr; PROPVARIANT pv[1]; PROPSPEC ps[1]; FLOAT *pRange;
//
// Validate params
//
hr = ValidateWiaItem((IWiaItem*)pWiasContext); if (FAILED(hr)) { DBG_ERR(("wiasSetValidRangeFloat, invalid pItem (0x%X)", hr)); return hr; }
pRange = (FLOAT*) CoTaskMemAlloc(sizeof(FLOAT) * WIA_RANGE_NUM_ELEMS); if (!pRange) { DBG_ERR(("wiasSetValidRangeFloat, Out of memory")); return E_OUTOFMEMORY; }
//
// Set up the propvariant
//
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
pRange[WIA_RANGE_MIN] = fMin; pRange[WIA_RANGE_NOM] = fNom; pRange[WIA_RANGE_MAX] = fMax; pRange[WIA_RANGE_STEP] = fStep;
pv[0].vt = VT_VECTOR | VT_R4; pv[0].caflt.cElems = WIA_RANGE_NUM_ELEMS; pv[0].caflt.pElems = pRange;
//
// Call the helper to set the valid value
//
hr = SetValidValueHelper(pWiasContext, WIA_PROP_RANGE, ps, pv); if (FAILED(hr)) { DBG_ERR(("wiasSetValidRangeFloat, Helper failed (0x%X)", hr)); }
PropVariantClear(pv); return hr; }
/**************************************************************************\
* wiasSetValidFlag * * Sets the valid values for a WIA_PROP_LIST property. This function * assumes the property is of type VT_I4. * * Arguments: * * pWiasContext - Wia item * propid - Identifies the property * ulCount - the number of elements in the list * lNom - the list's nominal value * plValues - the array of LONGs that make up the valid list * * Return Value: * * Status * * History: * * 07/21/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSetValidListLong( BYTE *pWiasContext, PROPID propid, ULONG ulCount, LONG lNom, LONG *plValues) { DBG_FN(::wiasSetValidListLong); HRESULT hr; PROPVARIANT pv[1]; PROPSPEC ps[1]; LONG *pList; ULONG cList;
//
// Validate params
//
hr = ValidateWiaItem((IWiaItem*)pWiasContext); if (FAILED(hr)) { DBG_ERR(("wiasSetValidListLong, invalid pItem (0x%X)", hr)); return hr; }
if (IsBadReadPtr(plValues, sizeof(LONG) * ulCount)) { DBG_ERR(("wiasSetValidListLong, plValues is an invalid pointer (0x%X)", hr)); return E_POINTER; }
cList = WIA_LIST_NUM_ELEMS + ulCount; pList = (LONG*) CoTaskMemAlloc(sizeof(LONG) * cList); if (!pList) { DBG_ERR(("wiasSetValidListLong, Out of memory")); return E_OUTOFMEMORY; }
//
// Set up the propvariant
//
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
pList[WIA_LIST_COUNT] = (LONG) ulCount; pList[WIA_LIST_NOM] = lNom; memcpy(&pList[WIA_LIST_VALUES], plValues, sizeof(LONG) * ulCount);
pv[0].vt = VT_VECTOR | VT_I4; pv[0].cal.cElems = cList; pv[0].cal.pElems = pList;
//
// Call the helper to set the valid value
//
hr = SetValidValueHelper(pWiasContext, WIA_PROP_LIST, ps, pv); if (FAILED(hr)) { DBG_ERR(("wiasSetValidListLong, Helper failed (0x%X)", hr)); }
PropVariantClear(pv); return hr; }
/**************************************************************************\
* wiasSetValidListFloat * * Sets the valid values for a WIA_PROP_LIST property. This function * assumes the property is of type VT_R4. * * Arguments: * * pWiasContext - Wia item * propid - Identifies the property * ulCount - the number of elements in the list * fNom - the list's nominal value * pfValues - the array of FLOATs that make up the valid list * * Return Value: * * Status * * History: * * 07/21/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSetValidListFloat( BYTE *pWiasContext, PROPID propid, ULONG ulCount, FLOAT fNom, FLOAT *pfValues) { DBG_FN(::wiasSetValidListFloat); HRESULT hr; PROPVARIANT pv[1]; PROPSPEC ps[1]; FLOAT *pList; ULONG cList;
//
// Validate params
//
hr = ValidateWiaItem((IWiaItem*)pWiasContext); if (FAILED(hr)) { DBG_ERR(("wiasSetValidListFloat, invalid pItem (0x%X)", hr)); return hr; }
if (IsBadReadPtr(pfValues, sizeof(FLOAT) * ulCount)) { DBG_ERR(("wiasSetValidListFloat, plValues is an invalid pointer")); return E_POINTER; }
cList = WIA_LIST_NUM_ELEMS + ulCount; pList = (FLOAT*) CoTaskMemAlloc(sizeof(FLOAT) * cList); if (!pList) { DBG_ERR(("wiasSetValidListFloat, Out of memory")); return E_OUTOFMEMORY; }
//
// Set up the propvariant
//
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
pList[WIA_LIST_COUNT] = (FLOAT) ulCount; pList[WIA_LIST_NOM] = fNom; memcpy(&pList[WIA_LIST_VALUES], pfValues, sizeof(LONG) * ulCount);
pv[0].vt = VT_VECTOR | VT_R4; pv[0].caflt.cElems = cList; pv[0].caflt.pElems = pList;
//
// Call the helper to set the valid value
//
hr = SetValidValueHelper(pWiasContext, WIA_PROP_LIST, ps, pv); if (FAILED(hr)) { DBG_ERR(("wiasSetValidListFloat, Helper failed (0x%X)", hr)); }
PropVariantClear(pv); return hr; }
/**************************************************************************\
* wiasSetValidListGUID * * Sets the valid values for a WIA_PROP_LIST property. This function * assumes the property is of type VT_CLSID. * * Arguments: * * pWiasContext - Wia item * propid - Identifies the property * ulCount - the number of elements in the list * fNom - the list's nominal value * pfValues - the array of FLOATs that make up the valid list * * Return Value: * * Status * * History: * * 07/21/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSetValidListGuid( BYTE *pWiasContext, PROPID propid, ULONG ulCount, GUID guidNom, GUID *pguidValues) { DBG_FN(::wiasSetValidListGuid); HRESULT hr; PROPVARIANT pv[1]; PROPSPEC ps[1]; GUID *pList; ULONG cList;
//
// Validate params
//
hr = ValidateWiaItem((IWiaItem*)pWiasContext); if (FAILED(hr)) { DBG_ERR(("wiasSetValidListGuid, invalid pItem (0x%X)", hr)); return hr; }
if (IsBadReadPtr(pguidValues, sizeof(GUID) * ulCount)) { DBG_ERR(("wiasSetValidListGuid, plValues is an invalid pointer")); return E_POINTER; }
cList = WIA_LIST_NUM_ELEMS + ulCount; pList = (GUID*) CoTaskMemAlloc(sizeof(GUID) * cList); if (!pList) { DBG_ERR(("wiasSetValidListGuid, Out of memory")); return E_OUTOFMEMORY; }
//
// Set up the propvariant
//
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
pList[WIA_LIST_COUNT] = WiaImgFmt_UNDEFINED; pList[WIA_LIST_NOM] = guidNom; for (ULONG index = 0; index < ulCount; index++) { pList[WIA_LIST_VALUES + index] = pguidValues[index]; }
pv[0].vt = VT_VECTOR | VT_CLSID; pv[0].cauuid.cElems = cList; pv[0].cauuid.pElems = pList;
//
// Call the helper to set the valid value
//
hr = SetValidValueHelper(pWiasContext, WIA_PROP_LIST, ps, pv); if (FAILED(hr)) { DBG_ERR(("wiasSetValidListGuid, Helper failed (0x%X)", hr)); }
PropVariantClear(pv);
return hr; }
/**************************************************************************\
* wiasSetValidListStr * * Sets the valid values for a WIA_PROP_LIST property. This function * assumes the property is of type VT_BSTR. * * Arguments: * * pWiasContext - Wia item * propid - Identifies the property * ulCount - the number of elements in the list * bstrNom - the list's nominal value * bstrValues - the array of BSTRs that make up the valid list * * Return Value: * * Status * * History: * * 07/21/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSetValidListStr( BYTE *pWiasContext, PROPID propid, ULONG ulCount, BSTR bstrNom, BSTR *bstrValues) { DBG_FN(::wiasSetValidListStr); HRESULT hr = S_OK; PROPVARIANT pv[1]; PROPSPEC ps[1]; BSTR *pList; ULONG cList;
//
// Validate params
//
hr = ValidateWiaItem((IWiaItem*)pWiasContext); if (FAILED(hr)) { DBG_ERR(("wiasSetValidListStr, invalid pItem (0x%X)", hr)); return hr; }
if (IsBadReadPtr(bstrValues, sizeof(BSTR) * ulCount)) { DBG_ERR(("wiasSetValidListStr, plValues is an invalid pointer")); return E_POINTER; }
for (ULONG ulIndex = 0; ulIndex < ulCount; ulIndex++) { if (IsBadStringPtrW(bstrValues[ulIndex], SysStringLen(bstrValues[ulIndex]))) { DBG_ERR(("wiasSetValidListStr, bstrValues[%d] is an invalid string", ulIndex)); return E_POINTER; } }
cList = WIA_LIST_NUM_ELEMS + ulCount; pList = (BSTR*) CoTaskMemAlloc(sizeof(BSTR) * cList); if (!pList) { DBG_ERR(("wiasSetValidListStr, Out of memory")); return E_OUTOFMEMORY; }
//
// Set up the propvariant
//
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
pList[WIA_LIST_COUNT] = SysAllocString(L""); pList[WIA_LIST_NOM] = SysAllocString(bstrNom); for (ulIndex = 0; ulIndex < ulCount; ulIndex++) { pList[WIA_LIST_VALUES + ulIndex] = SysAllocString(bstrValues[ulIndex]); if (!pList[ulIndex]) { DBG_ERR(("wiasSetValidListStr, Out of memory")); hr = E_OUTOFMEMORY; } }
pv[0].vt = VT_VECTOR | VT_BSTR; pv[0].cabstr.cElems = cList; pv[0].cabstr.pElems = pList;
if (SUCCEEDED(hr)) { //
// Call the helper to set the valid value
//
hr = SetValidValueHelper(pWiasContext, WIA_PROP_LIST, ps, pv); if (FAILED(hr)) { DBG_ERR(("wiasSetValidListStr, Helper failed (0x%X)", hr)); } }
PropVariantClear(pv); return hr; }
/**************************************************************************\
* wiasCreatePropContext * * Allocates and fills in the values for a WIA_PROPERTY_CONTEXT. * Entries in the property context are propids of properties that either have * dependants, or are themselves dependant on other properties. A context * is used to mark which properties are being changed. A property context * always has the standard properties listed in the WIA_StdPropsInContext * array. The driver can specify optional properties that it is interested * in by specifying them in pProps. The Properties that are being written * (changed) by an application are specified by an array of PROPSPECs. * * Arguments: * * cPropSpec - the number of PropSpecs * pPropSpec - an array of propspecs identifying which properties * cProps - number of properties, can be 0 * pProps - array of propids identifying the properties to put into * the property context, can be NULL. * pContext - a pointer to a property context. * * Return Value: * * Status - S_OK if successful * E_POINTER if one of the pointer agruments is bad * E_OUTOFMEMORY if the space could not be allocated * * History: * * 04/04/1999 Original Version * 07/22/1999 Moved from drivers to service * \**************************************************************************/
HRESULT _stdcall wiasCreatePropContext( ULONG cPropSpec, PROPSPEC *pPropSpec, ULONG cProps, PROPID *pProps, WIA_PROPERTY_CONTEXT *pContext) { DBG_FN(::wiasCreatePropContext); PROPID *pids; BOOL *pChanged; ULONG ulNumProps;
//
// Validate params
//
if (IsBadReadPtr(pPropSpec, cPropSpec)) { DBG_ERR(("wiasCreatePropContext, pPropSpec is a bad (read) pointer")); return E_POINTER; }
if (IsBadReadPtr(pProps, cProps)) { DBG_ERR(("wiasCreatePropContext, pProps is a bad (read) pointer")); return E_POINTER; }
if (IsBadWritePtr(pContext, sizeof(WIA_PROPERTY_CONTEXT))) { DBG_ERR(("wiasCreatePropContext, pContext is a bad (write) pointer")); return E_POINTER; }
//
// Allocate the arrays needed for the property context
//
ulNumProps = (cProps + NUM_STD_PROPS_IN_CONTEXT); pids = (PROPID*) CoTaskMemAlloc( sizeof(PROPID) * ulNumProps); pChanged = (BOOL*) CoTaskMemAlloc(sizeof(BOOL) * ulNumProps);
if ((!pids) || (!pChanged)) { DBG_ERR(("wiasCreatePropContext, pContext is a bad (write) pointer")); return E_OUTOFMEMORY; }
//
// Initialize the property context. First insert the standard context
// properties from WIA_StdPropsInContext, then the ones specified by
// pProps.
//
memcpy(pids, WIA_StdPropsInContext, sizeof(PROPID) * NUM_STD_PROPS_IN_CONTEXT);
memcpy(&pids[NUM_STD_PROPS_IN_CONTEXT], pProps, sizeof(PROPID) * cProps);
memset(pChanged, FALSE, sizeof(PROPID) * ulNumProps); pContext->cProps = ulNumProps; pContext->pProps = pids; pContext->pChanged = pChanged;
//
// Scan through list of PropSpecs and mark the bChanged field TRUE
// if a property matches one in the Context.
//
ULONG psIndex; ULONG pcIndex; for (psIndex = 0; psIndex < cPropSpec; psIndex++) { for (pcIndex = 0; pcIndex < pContext->cProps; pcIndex++) { if (pContext->pProps[pcIndex] == pPropSpec[psIndex].propid) { pContext->pChanged[pcIndex] = TRUE; } } }
return S_OK; }
/**************************************************************************\
* wiasFreePropContext * * Frees up the memory used by a WIA_PROPERTY_CONTEXT. * * Arguments: * * pContext - a pointer to a property context. * * Return Value: * * Status - S_OK if successful * E_POINTER if the context pointer is bad. * * History: * * 04/04/1999 Original Version * 07/22/1999 Moved from drivers to service * \**************************************************************************/
HRESULT _stdcall wiasFreePropContext( WIA_PROPERTY_CONTEXT *pContext) { DBG_FN(::wiasFreePropContext); //
// Validate params
//
if (IsBadReadPtr(pContext, sizeof(WIA_PROPERTY_CONTEXT))) { DBG_ERR(("wiasFreePropContext, pContext is a bad (read) pointer")); return E_POINTER; }
//
// Free the arrays used by the property context
//
CoTaskMemFree(pContext->pProps); CoTaskMemFree(pContext->pChanged);
memset(pContext, 0, sizeof(WIA_PROPERTY_CONTEXT));
return S_OK; }
/**************************************************************************\
* wiasIsPropChanged * * Sets a BOOL parameter to indicate whether a property is being changed * or not by looking at the BOOL (bChanged) value in the Property context. * Used by driver in property validation to check when an independant * property has been changed so that its dependants may be updated. * * Arguments: * * propid - identifies the property we're looking for. * pContext - the property context * pbChanged - the address of where to store the BOOL indicating that * the property is being changed. * * Return Value: * * Status - E_INVALIDARG will be returned if the property is not * found in the context. * E_POINTER is returned if any of the pointer arguments * are bad. * S_OK if the property is found. * * History: * * 22/07/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasIsPropChanged( PROPID propid, WIA_PROPERTY_CONTEXT *pContext, BOOL *pbChanged) { DBG_FN(::wiasIsPropChanged); //
// Validate params
//
if (IsBadReadPtr(pContext, sizeof(WIA_PROPERTY_CONTEXT))) { DBG_ERR(("wiasIsPropChanged, pContext is a bad (read) pointer")); return E_POINTER; }
if (IsBadReadPtr(pContext->pProps, sizeof(PROPID) * pContext->cProps)) { DBG_ERR(("wiasIsPropChanged, pContext->pProps is a bad (read) pointer")); return E_POINTER; }
if (IsBadReadPtr(pContext->pChanged, sizeof(BOOL) * pContext->cProps)) { DBG_ERR(("wiasIsPropChanged, pContext->pChanged is a bad (read) pointer")); return E_POINTER; }
if (IsBadWritePtr(pbChanged, sizeof(BOOL))) { DBG_ERR(("wiasIsPropChanged, pulIndex is a bad (write) pointer")); return E_POINTER; }
//
// Look for the property in the property context
//
for (ULONG index = 0; index < pContext->cProps; index++) {
//
// Property found, so set the BOOL return.
//
if (pContext->pProps[index] == propid) { *pbChanged = pContext->pChanged[index]; return S_OK; } }
//
// Property wasn't found
//
return E_INVALIDARG;; }
/**************************************************************************\
* wiasSetPropChanged * * Sets the pChanged value for the specified property in the property * context to indicate that a property is being changed or not. This * should be used when a driver changes a property that has dependant * properties in validation. E.g. By changing "Current Intent", the * "Horizontal Resolution" will be changed and should be marked as changed, * so that validation of XResolution and its dependants will still take * place. * * Arguments: * * propid - identifies the property we're looking for. * pContext - the property context * bChanged - the BOOL indicating the new pChanged value. * * Return Value: * * Status - E_INVALIDARG will be returned if the property is not * found in the context. * E_POINTER is returned if any of the pointer arguments * are bad. * S_OK if the property is found. * * History: * * 22/07/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasSetPropChanged( PROPID propid, WIA_PROPERTY_CONTEXT *pContext, BOOL bChanged) { DBG_FN(::wiasSetPropChanged); //
// Validate params
//
if (IsBadReadPtr(pContext, sizeof(WIA_PROPERTY_CONTEXT))) { DBG_ERR(("wiasIsPropChanged, pContext is a bad (read) pointer")); return E_POINTER; }
if (IsBadReadPtr(pContext->pProps, sizeof(PROPID) * pContext->cProps)) { DBG_ERR(("wiasIsPropChanged, pContext->pProps is a bad (read) pointer")); return E_POINTER; }
if (IsBadReadPtr(pContext->pChanged, sizeof(BOOL) * pContext->cProps)) { DBG_ERR(("wiasIsPropChanged, pContext->pChanged is a bad (read) pointer")); return E_POINTER; }
//
// Look for the property in the property context
//
for (ULONG index = 0; index < pContext->cProps; index++) {
//
// Property found, so set the pChanged[index] BOOL.
//
if (pContext->pProps[index] == propid) { pContext->pChanged[index] = bChanged; return S_OK; } }
//
// Property wasn't found
//
return E_INVALIDARG;; }
/**************************************************************************\
* wiasGetChangedValueLong * * This helper method is called to check whether a property is changed, * return it's current value and its old value. The properties are assumed * to be LONG. * * Arguments: * * pWiasContext - A pointer to the Wia item context. * bNoValidation - If TRUE, it skips validation of the property. * Validation should be skipped when a property's * valid values have yet to be updated. * pContext - A pointer to the Property Context. * propID - Identifies the property. * pInfo - A pointer to a WIAS_CHANGED_VALUE_INFO struct * where the values to be returned are set. * * Return Value: * * Status - S_OK if successful. * - E_INVALIDARG if the property fails validation. * * History: * * 04/04/1999 Original Version * 07/22/1999 Moved from drivers to service * \**************************************************************************/
HRESULT _stdcall wiasGetChangedValueLong( BYTE *pWiasContext, WIA_PROPERTY_CONTEXT *pContext, BOOL bNoValidation, PROPID propID, WIAS_CHANGED_VALUE_INFO *pInfo) { DBG_FN(::wiasGetChangedValueLong); LONG lIndex; HRESULT hr = S_OK;
//
// Parameter validation for pWiasContext, propID
// will be done by wiasReadPropLong.
// Parameter validation for pContex and bChanged will be done by
// wiasIsChangedValue.
//
if(IsBadWritePtr(pInfo, sizeof(WIAS_CHANGED_VALUE_INFO))) { DBG_ERR(("wiasGetChangedValueLong, pInfo is a bad (write) pointer")); return E_POINTER; } pInfo->vt = VT_I4;
//
// Get the current and old value of the property
//
hr = wiasReadPropLong(pWiasContext, propID, &pInfo->Current.lVal, &pInfo->Old.lVal, TRUE);
if (SUCCEEDED(hr)) {
//
// Check whether validation should be skipped or not.
//
if (!bNoValidation) { PROPSPEC ps[1];
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propID;
//
// Do validation
//
hr = wiasValidateItemProperties(pWiasContext, 1, ps); }
//
// Set whether the property has changed or not.
//
if (SUCCEEDED(hr)) { hr = wiasIsPropChanged(propID, pContext, &pInfo->bChanged); } else { DBG_ERR(("wiasGetChangedValueLong, validate prop %d failed hr: 0x%X", propID, hr)); } } else { DBG_ERR(("wiasGetChangedValueLong, read property %d failed hr: 0x%X", propID, hr)); }
return hr; }
/**************************************************************************\
* wiasGetChangedValueFloat * * This helper method is called to check whether a property is changed, * return it's current value and its old value. The properties are assumed * to be FLOAT. * * Arguments: * * pWiasContext - A pointer to the Wia item context. * bNoValidation - If TRUE, it skips validation of the property. * Validation should be skipped when a property's * valid values have yet to be updated. * pContext - A pointer to the Property Context. * propID - Identifies the property. * pInfo - A pointer to a WIAS_CHANGED_VALUE_INFO struct * where the values to be returned are set. * * Return Value: * * Status - S_OK if successful. * - E_INVALIDARG if the property fails validation. * * History: * * 04/04/1999 Original Version * 07/22/1999 Moved from drivers to service * \**************************************************************************/
HRESULT _stdcall wiasGetChangedValueFloat( BYTE *pWiasContext, WIA_PROPERTY_CONTEXT *pContext, BOOL bNoValidation, PROPID propID, WIAS_CHANGED_VALUE_INFO *pInfo) { DBG_FN(::wiasGetChangedValueFloat); LONG lIndex; HRESULT hr = S_OK;
//
// Parameter validation for pWiasContext, propID,
// will be done by wiasReadPropLong.
// Parameter validation for pContex and bChanged will be done by
// wiasIsChangedValue.
//
if(IsBadWritePtr(pInfo, sizeof(WIAS_CHANGED_VALUE_INFO))) { DBG_ERR(("wiasGetChangedValueFloat, pInfo is a bad (write) pointer")); return E_POINTER; } pInfo->vt = VT_R4;
//
// Get the current and old value of the property
//
hr = wiasReadPropFloat(pWiasContext, propID, &pInfo->Current.fltVal, &pInfo->Old.fltVal, TRUE);
if (SUCCEEDED(hr)) {
//
// Check whether validation should be skipped or not.
//
if (!bNoValidation) { PROPSPEC ps[1];
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propID;
//
// Do validation
//
hr = wiasValidateItemProperties(pWiasContext, 1, ps); }
//
// Set whether the property has changed or not.
//
if (SUCCEEDED(hr)) { hr = wiasIsPropChanged(propID, pContext, &pInfo->bChanged); } else { DBG_ERR(("wiasGetChangedValueFloat, validate prop %d failed (0x%X)", propID, hr)); } } else { DBG_ERR(("wiasGetChangedValueFloat, read property %d failed (0x%X)", propID, hr)); }
return hr; }
/**************************************************************************\
* wiasGetChangedValueGuid * * This helper method is called to check whether a property is changed, * return it's current value and its old value. The properties are assumed * to be FLOAT. * * Arguments: * * pWiasContext - A pointer to the Wia item context. * bNoValidation - If TRUE, it skips validation of the property. * Validation should be skipped when a property's * valid values have yet to be updated. * pContext - A pointer to the Property Context. * propID - Identifies the property. * pInfo - A pointer to a WIAS_CHANGED_VALUE_INFO struct * where the values to be returned are set. * * Return Value: * * Status - S_OK if successful. * - E_INVALIDARG if the property fails validation. * * History: * * 04/04/1999 Original Version * 07/22/1999 Moved from drivers to service * \**************************************************************************/
HRESULT _stdcall wiasGetChangedValueGuid( BYTE *pWiasContext, WIA_PROPERTY_CONTEXT *pContext, BOOL bNoValidation, PROPID propID, WIAS_CHANGED_VALUE_INFO *pInfo) { DBG_FN(::wiasGetChangedValueGuid); LONG lIndex; HRESULT hr = S_OK;
//
// Parameter validation for pWiasContext, propID,
// will be done by wiasReadPropLong.
// Parameter validation for pContex and bChanged will be done by
// wiasIsChangedValue.
//
if(IsBadWritePtr(pInfo, sizeof(WIAS_CHANGED_VALUE_INFO))) { DBG_ERR(("wiasGetChangedValueFloat, pInfo is a bad (write) pointer")); return E_POINTER; } pInfo->vt = VT_CLSID;
//
// Get the current and old value of the property
//
hr = wiasReadPropGuid(pWiasContext, propID, &pInfo->Current.guidVal, &pInfo->Old.guidVal, TRUE);
if (SUCCEEDED(hr)) {
//
// Check whether validation should be skipped or not.
//
if (!bNoValidation) { PROPSPEC ps[1];
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propID;
//
// Do validation
//
hr = wiasValidateItemProperties(pWiasContext, 1, ps); }
//
// Set whether the property has changed or not.
//
if (SUCCEEDED(hr)) { hr = wiasIsPropChanged(propID, pContext, &pInfo->bChanged); } else { DBG_ERR(("wiasGetChangedValueFloat, validate prop %d failed (0x%X)", propID, hr)); } } else { DBG_ERR(("wiasGetChangedValueFloat, read property %d failed (0x%X)", propID, hr)); }
return hr; }
/**************************************************************************\
* wiasGetChangedValueStr * * This helper method is called to check whether a property is changed, * return it's current value and its old value. The properties are assumed * to be BSTR. * * Arguments: * * pWiasContext - A pointer to the Wia item context. * bNoValidation - If TRUE, it skips validation of the property. * Validation should be skipped when a property's * valid values have yet to be updated. * pContext - A pointer to the Property Context. * propID - Identifies the property. * pInfo - A pointer to a WIAS_CHANGED_VALUE_INFO struct * where the values to be returned are set. * * Return Value: * * Status - S_OK if successful. * - E_INVALIDARG if the property fails validation. * * History: * * 04/04/1999 Original Version * 07/22/1999 Moved from drivers to service * \**************************************************************************/
HRESULT _stdcall wiasGetChangedValueStr( BYTE *pWiasContext, WIA_PROPERTY_CONTEXT *pContext, BOOL bNoValidation, PROPID propID, WIAS_CHANGED_VALUE_INFO *pInfo) { DBG_FN(::wiasGetChangedValueStr); LONG lIndex; HRESULT hr = S_OK;
//
// Parameter validation for pWiasContext, propID,
// will be done by wiasReadPropLong.
// Parameter validation for pContex and bChanged will be done by
// wiasIsChangedValue.
//
if(IsBadWritePtr(pInfo, sizeof(WIAS_CHANGED_VALUE_INFO))) { DBG_ERR(("wiasGetChangedValueStr, pInfo is a bad (write) pointer")); return E_POINTER; } pInfo->vt = VT_BSTR;
//
// Get the current and old value of the property
//
hr = wiasReadPropStr(pWiasContext, propID, &pInfo->Current.bstrVal, &pInfo->Old.bstrVal, TRUE);
if (SUCCEEDED(hr)) {
//
// Check whether validation should be skipped or not.
//
if (!bNoValidation) { PROPSPEC ps[1];
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propID;
//
// Do validation
//
hr = wiasValidateItemProperties(pWiasContext, 1, ps); }
//
// Set whether the property has changed or not.
//
if (SUCCEEDED(hr)) { hr = wiasIsPropChanged(propID, pContext, &pInfo->bChanged); } else { DBG_ERR(("wiasGetChangedValueStr, validate prop %d failed (0x%X)", propID, hr)); } } else { DBG_ERR(("wiasGetChangedValueStr, read property %d failed (0x%X)", propID, hr)); }
return hr; }
/**************************************************************************\
* wiasGetContextFromName * * This helper method is called to find a WIA Item by name. * * Arguments: * * pWiasContext - A pointer to a Wia item context. * lFlags - operational flags. * bstrName - The name of the context we are looking for. * ppWiasContext - The address where to return the Wia Item context. * * Return Value: * * Status - S_OK if the item was found. * S_FALSE if the item wasn't found, but there was no error. * A standard COM error code if an error occurred. * * History: * * 07/28/1999 Original version * \**************************************************************************/
HRESULT _stdcall wiasGetContextFromName( BYTE *pWiasContext, LONG lFlags, BSTR bstrName, BYTE **ppWiasContext) { DBG_FN(::wiasGetContextFromName); HRESULT hr;
//
// Validate params
//
hr = ValidateWiaItem((IWiaItem*)pWiasContext); if (FAILED(hr)) { DBG_ERR(("wiasGetContextFromName, invalid pItem (0x%X)", hr)); return hr; }
hr = ((CWiaItem*) pWiasContext)->FindItemByName(lFlags, bstrName, (IWiaItem**)ppWiasContext); return hr; }
/**************************************************************************\
* wiasUpdateScanRect * * This helper method is called to update the properties making up the * scan rect. The appropriate changes are made to the properties which are * dependant on those that make up the scan rect. (e.g. a change in * horizontal resolution will affect the horizontal extent). This function * assumes that the valid values for the vertical and horizontal extents, * and vertical and horizontal positions have not been updated yet. * The width and height arguments are the maxiumum and minimum dimensions * of the scan area in one thousandth's of an inch. * Normally, these would be the scan bed dimensions. * * Arguments: * * pWiasContext - A pointer to a Wia item context. * pContext - A pointer to a WIA property context (created * previsouly with wiasCreatePropertyContext). * lWidth - the width of the maximum scan area in one thousandth's * of an inch. Generally, this would be the horizontal * bed size. * lHeight - the height of the maximum scan area in one * thousandth's of an inch. Generally, this would be * the vertical bed size. * * Return Value: * * Status * * History: * * 07/30/1999 Original version * \**************************************************************************/
HRESULT _stdcall wiasUpdateScanRect( BYTE *pWiasContext, WIA_PROPERTY_CONTEXT *pContext, LONG lWidth, LONG lHeight) { DBG_FN(::wiasUpdateScanRect); HRESULT hr = S_OK;
//
// Validation of pWiasContext will be done by wiasGetRootItem so
// just need to validate pContext
//
if (IsBadReadPtr(pContext, sizeof(WIA_PROPERTY_CONTEXT))) { DBG_ERR(("wiasUpdateScanRect, pContext is a bad (read) pointer")); return E_POINTER; } else if (IsBadReadPtr(pContext->pProps, sizeof(PROPID) * pContext->cProps)) { DBG_ERR(("wiasUpdateScanRect, pContext->pProps is a bad (read) pointer")); return E_POINTER; } else if (IsBadReadPtr(pContext->pChanged, sizeof(BOOL) * pContext->cProps)) { DBG_ERR(("wiasUpdateScanRect, pContext->pChanged is a bad (read) pointer")); return E_POINTER; }
//
// Make adjustments to the required properties.
//
if (SUCCEEDED(hr)) { hr = CheckXResAndUpdate(pWiasContext, pContext, lWidth); if (SUCCEEDED(hr)) { hr = CheckYResAndUpdate(pWiasContext, pContext, lHeight); if (FAILED(hr)) { DBG_ERR(("wiasUpdateScanRect, CheckYResAndUpdate failed (0x%X)", hr)); } } else { DBG_ERR(("wiasUpdateScanRect, CheckXResAndUpdate failed (0x%X)", hr)); } }
return hr; }
/**************************************************************************\
* wiasUpdateValidFormat * * This helper method is called to update the valid values of the FORMAT * property, based on the current TYMED setting. This call uses the * drvGetFormatEtc method of the specified mini-driver item to find out * the valid FORMAT values for the current TYMED. If the property context * indicates that the FORMAT property is not being set, and the current * value for FORMAT is not compatible with the current TYMED, then a * new value for FORMAT will be chosen (the first item in the list of * valid FORMAT values). * * Arguments: * * pWiasContext - a pointer to the item context whose properties have * changed. * pContext - a pointer to the property context (which indicates * which properties are being written). * pIMiniDrv - a pointer to the calling WIA minidriver. * * Return Value: * * Status * * History: * * 07/27/1999 Original Version * \**************************************************************************/
HRESULT _stdcall wiasUpdateValidFormat( BYTE *pWiasContext, WIA_PROPERTY_CONTEXT *pContext, IWiaMiniDrv *pIMiniDrv) { DBG_FN(::wiasUpdateValidFormat); HRESULT hr; LONG tymed; WIAS_CHANGED_VALUE_INFO cviTymed, cviFormat; BOOL bFormatValid = FALSE; GUID guidFirstFormat; GUID *pFormatTbl; LONG cFormatTbl = 0; LONG celt; WIA_FORMAT_INFO *pwfi; LONG errVal;
if (IsBadReadPtr(pIMiniDrv, sizeof(IWiaMiniDrv))) { DBG_ERR(("wiasUpdateValidFormat, invalid pIMiniDrv pointer")); return E_POINTER; }
cviFormat.bChanged = FALSE;
//
// Call wiasGetChangedValue for Tymed. Tymed is checked first
// since it's not dependant on any other property. All properties in
// this method that follow are dependant properties of CurrentIntent.
//
hr = wiasGetChangedValueLong(pWiasContext, pContext, FALSE, WIA_IPA_TYMED, &cviTymed); if (SUCCEEDED(hr)) { if (cviTymed.bChanged) {
//
// Get the current Format value and set bFormatChanged to indicate whether Format
// is being changed.
//
hr = wiasGetChangedValueGuid(pWiasContext, pContext, TRUE, WIA_IPA_FORMAT, &cviFormat); if (FAILED(hr)) { DBG_ERR(( "wiasUpdateValidFormat, wiasGetChangedValue (format) failed (0x%X)", hr)); return hr; }
//
// Update the valid values for Format. First get the supported
// TYMED/FORMAT pairs.
//
hr = pIMiniDrv->drvGetWiaFormatInfo(pWiasContext, 0, &celt, &pwfi, &errVal); if (SUCCEEDED(hr)) {
pFormatTbl = (GUID*) LocalAlloc(LPTR, sizeof(GUID) * celt); if (!pFormatTbl) { DBG_ERR(("wiasUpdateValidFormat, out of memory")); return E_OUTOFMEMORY; }
//
// Now store each supported format for the current tymed value
// in the pFormatTbl array.
//
for (LONG index = 0; index < celt; index++) { if (((LONG) pwfi[index].lTymed) == cviTymed.Current.lVal) { pFormatTbl[cFormatTbl] = pwfi[index].guidFormatID; cFormatTbl++;
//
// Check whether lFormat is one of the valid values.
//
if (cviFormat.Current.guidVal == pwfi[index].guidFormatID) { bFormatValid = TRUE; } } } guidFirstFormat = pFormatTbl[0];
//
// Update the valid values for Format
//
hr = wiasSetValidListGuid(pWiasContext, WIA_IPA_FORMAT, cFormatTbl, pFormatTbl[0], pFormatTbl); if (FAILED(hr)) { DBG_ERR(( "wiasUpdateValidFormat, wiasSetValidListGuid failed. (0x%X)", hr)); }
LocalFree(pFormatTbl);
} else { DBG_ERR(( "wiasUpdateValidFormat, drvGetWiaFormatInfo failed. (0x%X)", hr)); } } } else { DBG_ERR(( "wiasUpdateValidFormat, wiasGetChangedValue (tymed) failed (0x%X)", hr)); }
if (FAILED(hr)) { return hr; }
//
// If the Format is not being set by the app, an it's current value
// is not in the valid list, fold it to a valid value.
//
if (cviTymed.bChanged && !cviFormat.bChanged && !bFormatValid) {
hr = wiasWritePropGuid(pWiasContext, WIA_IPA_FORMAT, guidFirstFormat); if (FAILED(hr)) { DBG_ERR(( "wiasUpdateValidFormat, wiasWritePropLong failed. (0x%X)", hr)); } }
return hr; }
/**************************************************************************\
* wiasCreateLogInstance * * This helper method is called to create an instance of the logging * object. * * Arguments: * * lModuleHandle - The module handle. Used to filter output. * ppIWiaLog - The address of a pointer to receive the logging * interface. * * Return Value: * * Status * * History: * * 01/07/2000 Original Version * \**************************************************************************/
HRESULT _stdcall wiasCreateLogInstance( BYTE *pModuleHandle, IWiaLogEx **ppIWiaLogEx) { HRESULT hr;
if (ppIWiaLogEx == NULL) { DBG_ERR(("wiasCreateLogInstance, Invalid pointer argument")); return E_POINTER; }
//
// Validate the parameter.
//
if (IsBadWritePtr((VOID*) *ppIWiaLogEx, sizeof(IWiaLog*))) { DBG_ERR(("wiasCreateLogInstance, Invalid pointer argument")); return E_POINTER; } *ppIWiaLogEx = NULL;
//
// CoCreate an instance of the logging object. If successful, initialize
// it with the module handle passed in to us.
//
hr = CoCreateInstance(CLSID_WiaLog, NULL, CLSCTX_INPROC_SERVER, IID_IWiaLogEx,(VOID**)ppIWiaLogEx);
if (SUCCEEDED(hr)) { hr = (*ppIWiaLogEx)->InitializeLogEx(pModuleHandle); } else {
DBG_ERR(("wiasCreateLogInstance, Failed to CoCreateInstance on Logging object (0x%X)", hr)); }
return hr; }
HRESULT _stdcall wiasGetChildrenContexts( BYTE *pParentContext, ULONG *pulNumChildren, BYTE ***pppChildren) { HRESULT hr = S_OK; ULONG ulCount = 0; IWiaItem *pParentItem = (IWiaItem*) pParentContext; IWiaItem *pWiaItem = NULL; BYTE **ppChildItems = NULL; IEnumWiaItem *pEnum = NULL;
hr = ValidateWiaItem((IWiaItem*) pParentContext); if (FAILED(hr)) { DBG_ERR(("wiasGetChildrenContexts, invalid pParentContext")); return hr; }
if (!pParentContext || !pulNumChildren || !pppChildren) { DBG_ERR(("wiasGetChildrenContexts, Invalid pointer argument")); return E_POINTER; }
*pulNumChildren = 0; *pppChildren = NULL;
hr = pParentItem->EnumChildItems(&pEnum); if (SUCCEEDED(hr)) {
//
// Get the number of children.
//
hr = pEnum->GetCount(&ulCount); if (SUCCEEDED(hr) && ulCount) {
if (ulCount == 0) { DBG_WRN(("wiasGetChildrenContexts, No children - returning S_FALSE")); hr = S_FALSE; } else {
//
// Allocate the return array
//
ppChildItems = (BYTE**) CoTaskMemAlloc(sizeof(BYTE*) * ulCount); if (ppChildItems) {
//
// Enumerate through the children and store them in the array
//
ULONG ulIndex = 0; while ((pEnum->Next(1, &pWiaItem, NULL) == S_OK) && (ulIndex < ulCount)) {
ppChildItems[ulIndex] = (BYTE*)pWiaItem; pWiaItem->Release(); ulIndex++; }
*pulNumChildren = ulIndex; *pppChildren = ppChildItems; hr = S_OK; } else { DBG_ERR(("wiasGetChildrenContexts, Out of memory")); hr = E_OUTOFMEMORY; } } } else { DBG_ERR(("wiasGetChildrenContexts, GetCount failed (0x%X)", hr)); }
pEnum->Release(); } else { DBG_ERR(("wiasGetChildrenContexts, Failed to get item enumerator (0x%X)", hr)); }
if (FAILED(hr)) { if (ppChildItems) { CoTaskMemFree(ppChildItems); ppChildItems = NULL; } }
return hr; }
HRESULT _stdcall wiasDownSampleBuffer( LONG lFlags, WIAS_DOWN_SAMPLE_INFO *pInfo ) { DBG_FN(::wiasDownSampleBuffer);
HRESULT hr = S_OK; BOOL bAllocatedBuf = FALSE;
//
// Do some parameter validation
//
if (IsBadWritePtr(pInfo, sizeof(WIAS_DOWN_SAMPLE_INFO))) { DBG_ERR(("wiasDownSampleBuffer, cannot write to WIAS_DOWN_SAMPLE_INFO!")); return E_INVALIDARG; }
//
// We try to sample the input data to DOWNSAMPLE_DPI, so if asked let's set the
// downsampled width and height.
//
if (pInfo->ulDownSampledWidth == 0) { pInfo->ulDownSampledHeight = (pInfo->ulOriginalHeight * DOWNSAMPLE_DPI) / pInfo->ulXRes; pInfo->ulDownSampledWidth = (pInfo->ulOriginalWidth * DOWNSAMPLE_DPI) / pInfo->ulXRes;
//
// NOTE: if the resolution is over 300dpi, our in-box WiaFBDrv driver has a problem
// with the chunk it is giving us, in that it doesn't hold enough pixel lines for us to
// downsample to 50dpi. For example if the input is at 600dpi and we want a 50dpi
// sample, we need at least 600 / 50 = 12 input lines to equal one output line.
// Since the chunk size cannot hold 12 lines, the ulDownSampledHeight becomes zero,
// and we cannot scale.
//
// So for now, we special case anything above 300 dpi
// to simply be 1/4 the width and height. This slows us down a lot at 600dpi,
// but cannot be solved without changes to the driver (and possibly adding
// some service helpers)
//
if (pInfo->ulXRes > 300) { pInfo->ulDownSampledHeight = pInfo->ulOriginalHeight >> 2; pInfo->ulDownSampledWidth = pInfo->ulOriginalWidth >> 2; } }
if ((pInfo->ulDownSampledHeight == 0) || (pInfo->ulOriginalHeight == 0)) { DBG_WRN(("wiasDownSampleBuffer, height is zero, nothing to do...")); return S_FALSE; }
//
// We need to work out the DWORD aligned width in bytes. Normally we would do this in one step
// using the supplied bit depth, but we avoid arithmetic overflow conditions that happen
// in 24bit if we do it in 2 steps like this instead.
//
ULONG ulAlignedWidth; if (pInfo->ulBitsPerPixel == 1) { ulAlignedWidth = (pInfo->ulDownSampledWidth + 7) / 8; } else { ulAlignedWidth = (pInfo->ulDownSampledWidth * (pInfo->ulBitsPerPixel / 8)); } ulAlignedWidth += (ulAlignedWidth % sizeof(DWORD)) ? (sizeof(DWORD) - (ulAlignedWidth % sizeof(DWORD))) : 0;
pInfo->ulActualSize = ulAlignedWidth * pInfo->ulDownSampledHeight;
//
// If the flag is WIAS_GET_DOWNSAMPLED_SIZE_ONLY, then all we've been requested to do is
// fill the above information in, so we return here.
//
if (lFlags == WIAS_GET_DOWNSAMPLED_SIZE_ONLY) { return S_OK; }
//
// If a destination buffer hasn't been given, then allocate one.
//
if (!pInfo->pDestBuffer) {
//
// NOTE: We allocate more than we actually need. This is to account for
// when the driver asks us to allocate on the first band, and then
// re-uses this buffer for the rest. Since the bands may change
// size, the pInfo->ulActualSize may be too small.
// It is recommended that the driver allocates the buffer instead,
// and that the size of this allocation is as large as the largest
// chunk it requests from the scanner, so that in the case of
// downsampling, this will always be larger than the downsampled
// pixels.
//
pInfo->pDestBuffer = (BYTE*)CoTaskMemAlloc(pInfo->ulActualSize * 2); if (pInfo->pDestBuffer) { pInfo->ulDestBufSize = pInfo->ulActualSize;
//
// Mark that we allocated the buffer
//
bAllocatedBuf = TRUE; } else { DBG_ERR(("wiasDownSampleBuffer, Out of memory")); hr = E_OUTOFMEMORY; } } else { if (IsBadWritePtr(pInfo->pDestBuffer, pInfo->ulActualSize)) { DBG_ERR(("wiasDownSampleBuffer, cannot write ulActualSize bytes to pDestBuffer, it's too small!")); hr = E_INVALIDARG; } }
//
// Validate source buffer
//
if (IsBadReadPtr(pInfo->pSrcBuffer, pInfo->ulSrcBufSize)) { DBG_ERR(("wiasDownSampleBuffer, cannot read ulSrcBufSize bytes from pSrcBuffer!")); return E_INVALIDARG; }
if (SUCCEEDED(hr)) {
//
// Do the down sampling.
//
_try { hr = BQADScale(pInfo->pSrcBuffer, pInfo->ulOriginalWidth, pInfo->ulOriginalHeight, pInfo->ulBitsPerPixel, pInfo->pDestBuffer, pInfo->ulDownSampledWidth, pInfo->ulDownSampledHeight); } _except (EXCEPTION_EXECUTE_HANDLER) { DBG_ERR(("wiasDownSampleBuffer, Exception occurred while scaling!")); hr = E_UNEXPECTED; } }
if (FAILED(hr) && bAllocatedBuf) {
//
// Free the buffer
//
CoTaskMemFree(pInfo->pDestBuffer); pInfo->pDestBuffer = NULL; } return hr; }
/**************************************************************************\
* wiasParseEndorserString * * This helper function is called by drivers to get the resulting endorser * string. Applications set the WIA_DPS_ENDORSER_STRING property to * a string that may contain tokens (e.g. $DATE$) which need to be replaced * by the values they represent. For example, if the application set * the endorser string to "This page was scanned on $DATE$", the resulting * string would be "This page was scanned on 2000/10/1", assuming the date * was October 1, 2000. * The list of standard WIA endorser tokens can be found in wiadef.h. * Also, drivers may ask wiasParseEndorserString to substitute their own * values for custom tokens by filling out the appropriate WIAS_ENDORSER_INFO * struct. For example: * * HRESULT hr = S_OK; * BSTR bstrResultingEndorser = NULL; * * WIAS_ENDORSER_VALUE pMyValues[] = {L"$MY_TOKEN$", L"My value"}; * WIAS_ENDORSER_INFO weiInfo = {0, 1, pMyValues}; * * hr = wiasParseEndorserString(pWiasContext, 0, &weiInfo, &bstrResultingEndorser); * if (SUCCEEDED(hr)) { * //
* // bstrResultingEndorser now contains the resulting endorser string.
* //
* } * * Arguments: * pWiasContext - The context of the item containing the * WIA_DPS_ENDORSER_STRING property. * lFlags - Operational flags * pInfo - Structure containing page count and custom list * of token/value pairs. Can be NULL. * pOutputString - Address of BSTR that receives the resulting * endorser string. If (*pOutputString) is non-NULL * on entry, then it is assumed the caller allocated * the buffer, else the WIA service will allocate it. * If the driver caller allocates the buffer, it * should zero it out before using this function. * If the buffer is not large enough to hold the * resulting string, the resulting string will be truncated * and copied into the buffer, and HRESULT_FROM_WIN32(ERROR_MORE_DATA) * is returned. * * Return Value: * * Status * * History: * * 10/20/2000 Original Version * \**************************************************************************/
HRESULT _stdcall wiasParseEndorserString( BYTE *pWiasContext, LONG lFlags, WIAS_ENDORSER_INFO *pInfo, BSTR *pOutputString ) { DBG_FN(::wiasParseEndorserString);
WIAS_ENDORSER_INFO weiTempInfo; BSTR bstrEndorser = NULL; HRESULT hr = S_OK;
//
// Do some parameter validation
//
if (!pOutputString) { DBG_ERR(("wiasParseEndorserString, pOutputString parameter cannot be NULL!")); return E_INVALIDARG; }
/*
if ((lFlags != 0) && (!(*pOutputString))) { DBG_ERR(("wiasParseEndorserString, (*pOutputString) is NULL. lFlags is not 0, so you MUST specify your own output buffer!")); return E_INVALIDARG; } */
if (!pInfo) { memset(&weiTempInfo, 0, sizeof(weiTempInfo)); pInfo = &weiTempInfo; }
if (pInfo->ulNumEndorserValues > 0) { if (IsBadReadPtr(pInfo->pEndorserValues, sizeof(WIAS_ENDORSER_VALUE) * pInfo->ulNumEndorserValues)) { DBG_ERR(("wiasParseEndorserString, cannot read %d values from pInfo->pEndorserValues!", pInfo->ulNumEndorserValues)); return E_INVALIDARG; } }
if (!pWiasContext) { DBG_ERR(("wiasParseEndorserString, pWiasContext parameter is NULL!")); return E_INVALIDARG; }
//
// Read the endorser string
//
hr = wiasReadPropStr(pWiasContext, WIA_DPS_ENDORSER_STRING, &bstrEndorser, NULL, TRUE); if (FAILED(hr)) {
//
// Maybe caller forgot to pass the correct item, so try getting the root item
// and reading from there.
//
BYTE *pRoot;
hr = wiasGetRootItem(pWiasContext, &pRoot); if (SUCCEEDED(hr)) { hr = wiasReadPropStr(pWiasContext, WIA_DPS_ENDORSER_STRING, &bstrEndorser, NULL, TRUE); }
if (FAILED(hr)) { return hr; } }
//
// If there is no endorser string value, return S_FALSE, because there's nothing
// for us to do.
//
if (!bstrEndorser) { return S_FALSE; }
//
// Parse the string, substituting values for their tokens.
//
//
// Create a list of the Token/Value pairs. Remember to first add our
// default token/value pairs. These are:
// Date
// Time
// PageCount
// Day
// Month
// Year
//
SimpleTokenReplacement::TokenValueList EndorserList; CSimpleStringWide cswTempToken; CSimpleStringWide cswTempValue; SYSTEMTIME sysTime;
GetLocalTime(&sysTime);
// Date
cswTempToken = WIA_ENDORSER_TOK_DATE; cswTempValue.Format(L"%04d/%02d/%02d", sysTime.wYear, sysTime.wMonth, sysTime.wDay); EndorserList.Add(cswTempToken, cswTempValue); // Time
cswTempToken = WIA_ENDORSER_TOK_TIME; cswTempValue.Format(L"%02d:%02d:%02d", sysTime.wHour, sysTime.wMinute, sysTime.wSecond); EndorserList.Add(cswTempToken, cswTempValue); // Page Count
cswTempToken = WIA_ENDORSER_TOK_PAGE_COUNT; cswTempValue.Format(L"%03d", pInfo->ulPageCount); EndorserList.Add(cswTempToken, cswTempValue); // Day
cswTempToken = WIA_ENDORSER_TOK_DAY; cswTempValue.Format(L"%02d", sysTime.wDay); EndorserList.Add(cswTempToken, cswTempValue); // Month
cswTempToken = WIA_ENDORSER_TOK_MONTH; cswTempValue.Format(L"%02d", sysTime.wMonth); EndorserList.Add(cswTempToken, cswTempValue); // Year
cswTempToken = WIA_ENDORSER_TOK_YEAR; cswTempValue.Format(L"%04d", sysTime.wYear); EndorserList.Add(cswTempToken, cswTempValue);
//
// Next, we need to add any vendor defined token/value pairs
//
for (DWORD dwIndex = 0; dwIndex < pInfo->ulNumEndorserValues; dwIndex++) { cswTempToken = pInfo->pEndorserValues[dwIndex].wszTokenName; cswTempValue = pInfo->pEndorserValues[dwIndex].wszValue;
EndorserList.Add(cswTempToken, cswTempValue); }
//
// Now, let's make the substitutions
//
SimpleTokenReplacement EndorserResult(bstrEndorser); EndorserResult.ExpandArrayOfTokensIntoString(EndorserList);
//
// We have the result. Let's see whether we need to allocate it, or
// whether whether one was provided and we should simply copy the contents
//
if (!(*pOutputString)) { *pOutputString = SysAllocString(EndorserResult.getString().String()); if (!(*pOutputString)) { DBG_ERR(("wiasParseEndorserString, could not allocate space for the endorser string - we are out of memory.")); hr = E_OUTOFMEMORY; } } else { //
// The caller provided a pre-allocated BSTR. Copy as much of the endorser as can fit into
// this buffer. If it cannot fit, return HRESULT_FROM_WIN32(ERROR_MORE_DATA)
//
DWORD dwAllocatedLen = SysStringLen(*pOutputString); // This does NOT include the NULL
wcsncpy(*pOutputString, EndorserResult.getString().String(), dwAllocatedLen); if (EndorserResult.getString().Length() > dwAllocatedLen) { DBG_ERR(("wiasParseEndorserString, the caller allocated BSTR is too small! String will be truncated.")); hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA); } //
// Make sure we NULL terminate this BSTR. Remember that dwAllocatedLen is the size in WHCARs of the
// allocated string, not including the space for the NULL.
//
(*pOutputString)[dwAllocatedLen] = L'\0'; }
return hr; }
|