/******************************************************************************* * * (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 #include #include #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; }