You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5702 lines
167 KiB
5702 lines
167 KiB
/*******************************************************************************
|
|
*
|
|
* (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;
|
|
}
|
|
|