|
|
/*******************************************************************************
* * (C) COPYRIGHT MICROSOFT CORP., 1997 * * TITLE: Helpers.Cpp * * VERSION: 2.0 * * AUTHOR: ReedB * * DATE: 12 Mar, 1999 * * DESCRIPTION: * Helpers for WIA device manager. * *******************************************************************************/ #include "precomp.h"
#include "stiexe.h"
#include <wiadef.h>
#include <icm.h>
#include "wiamindr.h"
#include "devinfo.h"
#define WIA_DECLARE_MANAGED_PROPS
#include "helpers.h"
#include "shpriv.h"
#include "sticfunc.h"
extern "C" { //
// From Terminal services
//
#include <winsta.h>
#include <syslib.h>
}
/**************************************************************************\
* LockWiaDevice * * Wrapper to request Lock Manager to lock device. * * Arguments: * * pIWiaMiniDrv - Pointer to mini-driver interface. * pIWiaItem - Pointer to the wia item * * Return Value: * * Status * * History: * * 3/1/1999 Original Version * \**************************************************************************/
HRESULT _stdcall LockWiaDevice(IWiaItem *pIWiaItem) { DBG_FN(::LockWiaDevice);
HRESULT hr = WIA_ERROR_OFFLINE; LONG lFlags = 0; CWiaItem *pItem = (CWiaItem*) pIWiaItem;
if (pItem->m_pActiveDevice) { hr = pItem->m_pActiveDevice->m_DrvWrapper.WIA_drvLockWiaDevice( (BYTE*) pItem, lFlags, &(pItem->m_lLastDevErrVal)); } return hr; }
/**************************************************************************\
* UnLockWiaDevice * * Wrapper to request Lock Manager to unlock device. * * Arguments: * * pIWiaMiniDrv - Pointer to mini-driver interface. * pIWiaItem - Pointer to the wia item * * Return Value: * * Status * * History: * * 3/1/1999 Original Version * \**************************************************************************/
HRESULT _stdcall UnLockWiaDevice(IWiaItem *pIWiaItem) { DBG_FN(::UnLockWiaDevice);
HRESULT hr = WIA_ERROR_OFFLINE; LONG lFlags = 0; LONG lDevErrVal; CWiaItem *pItem = (CWiaItem*) pIWiaItem;
if (pItem->m_pActiveDevice) { hr = pItem->m_pActiveDevice->m_DrvWrapper.WIA_drvUnLockWiaDevice( (BYTE*) pItem, lFlags, &(pItem->m_lLastDevErrVal)); }
return hr; }
/**************************************************************************\
* ValidateWiaItem * * Validate a CWiaItem. * * Arguments: * * * Return Value: * * None * * History: * * 3/1/1999 Original Version * \**************************************************************************/
HRESULT _stdcall ValidateWiaItem( IWiaItem *pIWiaItem) { DBG_FN(::ValidateWiaItem); HRESULT hr = E_POINTER;
if (pIWiaItem) {
CWiaItem *pWiaItem = (CWiaItem*)pIWiaItem;
if (!IsBadReadPtr(pWiaItem, sizeof(CWiaItem))) { if (pWiaItem->m_ulSig == CWIAITEM_SIG) { return S_OK; } else { DBG_ERR(("ValidateWiaItem, invalid signature: %X", pWiaItem->m_ulSig)); hr = E_INVALIDARG; } } else { DBG_ERR(("ValidateWiaItem, NULL WIA item pointer")); } } else { DBG_ERR(("ValidateWiaItem, NULL WIA item pointer")); } return hr; }
/**************************************************************************\
* ValidateWiaDrvItemAccess * * Validate a CWiaDrvItem. * * Arguments: * * * Return Value: * * None * * History: * * 3/1/1999 Original Version * \**************************************************************************/
HRESULT _stdcall ValidateWiaDrvItemAccess( CWiaDrvItem *pWiaDrvItem) { DBG_FN(::ValidateWiaDrvItemAccess); HRESULT hr = S_OK;
if (pWiaDrvItem) {
//
// Verify access to the driver item.
//
if (IsBadReadPtr(pWiaDrvItem, sizeof(CWiaDrvItem))) { DBG_ERR(("ValidateWiaDrvItemAccess, bad pointer, pWiaDrvItem: %X", pWiaDrvItem)); return E_INVALIDARG; }
//
// Get the driver item flags.
//
LONG lItemFlags;
pWiaDrvItem->GetItemFlags(&lItemFlags);
//
// Verify the item has been initialized and was inserted in the
// driver item tree at one time.
//
if (lItemFlags == WiaItemTypeFree) { DBG_ERR(("ValidateWiaDrvItemAccess, application attempting access of unintialized or free item: %0x08X", pWiaDrvItem)); return E_INVALIDARG; }
if (lItemFlags & WiaItemTypeDeleted) { DBG_ERR(("ValidateWiaDrvItemAccess, application attempting access of deleted item: %0x08X", pWiaDrvItem)); return WIA_ERROR_ITEM_DELETED; }
if (lItemFlags & WiaItemTypeDisconnected) { DBG_ERR(("ValidateWiaDrvItemAccess, application attempting access of disconnected item: %0x08X", pWiaDrvItem)); return WIA_ERROR_OFFLINE; }
hr = S_OK; } else { DBG_ERR(("ValidateWiaDrvItemAccess, Bad pWiaDrvItem pointer")); hr = E_INVALIDARG; } return hr; }
/**************************************************************************\
* GetNameFromWiaPropId * * Map a WIA property ID to it's corresponding string name. * * Arguments: * * * Return Value: * * None * * History: * * 3/1/1999 Original Version * \**************************************************************************/
#define MAP_SIZE (sizeof(g_wiaPropIdToName) / sizeof(WIA_PROPID_TO_NAME))
LPOLESTR GetNameFromWiaPropId(PROPID propid) { for (INT i = 0; g_wiaPropIdToName[i].propid != 0; i++) { if (propid == g_wiaPropIdToName[i].propid) { return g_wiaPropIdToName[i].pszName; } }
return g_wiaPropIdToName[i].pszName; }
/**************************************************************************\
* ReportReadWriteMultipleError * * Report errors that occur during ReadMultiple and WriteMultiple calls. * * Arguments: * * hr - Result from ReadMultiple or WriteMultiple call. * pszWhere - Where the API was called from (function/method name). * pszWhat - Optional, which Read/WriteMultiple, used if more than * one Read/WriteMultiple called in function/method. * bRead - TRUE for ReadMultiple. * cpspec - Count of PROPSPEC's in rgpspec. * rgpspec - Array of PROPSPEC's. * * Return Value: * * None * * History: * * 3/1/1999 Original Version * \**************************************************************************/
void _stdcall ReportReadWriteMultipleError( HRESULT hr, LPSTR pszWhere, LPSTR pszWhat, BOOL bRead, ULONG cpspec, const PROPSPEC propspec[]) { DBG_FN(::ReportReadWriteMultipleError); if (SUCCEEDED(hr)) { if (hr == S_FALSE) { if (bRead) { if (pszWhat) { DBG_ERR(("%s, ReadMultiple property not found, %s", pszWhere, pszWhat)); } else { DBG_ERR(("%s, ReadMultiple property not found", pszWhere)); } } else { if (pszWhat) { DBG_ERR(("%s, WriteMultiple returned S_FALSE, %s", pszWhere, pszWhat)); } else { DBG_ERR(("%s, WriteMultiple returned S_FALSE", pszWhere)); } } } else { return; // No error.
} } else { if (bRead) { DBG_ERR(("%s, ReadMultiple failed, %s Error 0x%X", pszWhere, pszWhat ? pszWhat : "(null)", hr)); } else { DBG_ERR(("%s, WriteMultiple failed, %s Error 0x%X", pszWhere, pszWhat ? pszWhat : "(null)", hr)); } }
//
// Output specification information.
//
if (cpspec == 0) { DBG_ERR((" count of PROPSPEC's is zero")); } else if (cpspec == 1) { if (propspec[0].ulKind == PRSPEC_PROPID) { DBG_ERR((" property ID: %d, property name: %S", propspec[0].propid, GetNameFromWiaPropId(propspec[0].propid))); } else if (propspec[0].ulKind == PRSPEC_LPWSTR) { DBG_ERR((" property name: %S", propspec[0].lpwstr)); } else { DBG_ERR((" bad property specification")); } } else { DBG_ERR((" count of PROPSPEC's is: %d", cpspec)); for (UINT i = 0; i < cpspec; i++) { if (propspec[i].ulKind == PRSPEC_PROPID) { DBG_ERR((" property ID: %d, property name: %S", propspec[i].propid, GetNameFromWiaPropId(propspec[i].propid))); } else if (propspec[i].ulKind == PRSPEC_LPWSTR) { DBG_ERR((" index: %d, property name: %S", i, propspec[i].lpwstr)); } else { DBG_ERR((" index: %d, bad property specification", i)); } } } }
/*******************************************************************************
* * ReadPropStr * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
HRESULT _stdcall ReadPropStr( PROPID propid, IPropertyStorage *pIPropStg, BSTR *pbstr) { DBG_FN(::ReadPropStr); HRESULT hr; PROPSPEC PropSpec[1]; PROPVARIANT PropVar[1]; UINT cbSize;
*pbstr = NULL; memset(PropVar, 0, sizeof(PropVar)); PropSpec[0].ulKind = PRSPEC_PROPID; PropSpec[0].propid = propid; hr = pIPropStg->ReadMultiple(1, PropSpec, PropVar); if (SUCCEEDED(hr)) { if (PropVar[0].pwszVal) { *pbstr = SysAllocString(PropVar[0].pwszVal); } else { *pbstr = SysAllocString(L""); } if (*pbstr == NULL) { DBG_ERR(("ReadPropStr, SysAllocString failed")); hr = E_OUTOFMEMORY; } PropVariantClear(PropVar); } else { DBG_ERR(("ReadPropStr, ReadMultiple of propid: %d, failed", propid)); } return hr; }
HRESULT _stdcall ReadPropStr( PROPID propid, IWiaPropertyStorage *pIWiaPropStg, BSTR *pbstr) { DBG_FN(::ReadPropStr); HRESULT hr; PROPSPEC PropSpec[1]; PROPVARIANT PropVar[1]; UINT cbSize;
*pbstr = NULL; memset(PropVar, 0, sizeof(PropVar)); PropSpec[0].ulKind = PRSPEC_PROPID; PropSpec[0].propid = propid; hr = pIWiaPropStg->ReadMultiple(1, PropSpec, PropVar); if (SUCCEEDED(hr)) { if (PropVar[0].pwszVal) { *pbstr = SysAllocString(PropVar[0].pwszVal); } else { *pbstr = SysAllocString(L""); } if (*pbstr == NULL) { DBG_ERR(("ReadPropStr, SysAllocString failed")); hr = E_OUTOFMEMORY; } PropVariantClear(PropVar); } else { DBG_ERR(("ReadPropStr, ReadMultiple of propid: %d, failed", propid)); } return hr; }
HRESULT _stdcall ReadPropStr(IUnknown *pDevice, PROPID propid, BSTR *pbstr) { DBG_FN(::ReadPropStr); HRESULT hr; PROPVARIANT pv[1]; PROPSPEC ps[1]; IWiaPropertyStorage *pIWiaPropStg;
*pbstr = NULL; hr = pDevice->QueryInterface(IID_IWiaPropertyStorage, (void**)&pIWiaPropStg); if (SUCCEEDED(hr)) { PropVariantInit(pv); ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
hr = pIWiaPropStg->ReadMultiple(1, ps, pv); if (hr == S_OK) { *pbstr = SysAllocString(pv[0].pwszVal); } else { DBG_ERR(("ReadPropStr, ReadMultiple for propid: %d, failed", propid)); } PropVariantClear(pv); pIWiaPropStg->Release(); } else { DBG_ERR(("ReadPropStr, QI for IWiaPropertyStorage failed")); } return hr; }
/*******************************************************************************
* * ReadPropLong * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
HRESULT _stdcall ReadPropLong(PROPID propid, IPropertyStorage *pIPropStg, LONG *plval) { DBG_FN(::ReadPropLong); HRESULT hr; PROPSPEC PropSpec[1]; PROPVARIANT PropVar[1]; UINT cbSize;
memset(PropVar, 0, sizeof(PropVar)); PropSpec[0].ulKind = PRSPEC_PROPID; PropSpec[0].propid = propid; hr = pIPropStg->ReadMultiple(1, PropSpec, PropVar); if (SUCCEEDED(hr)) { *plval = PropVar[0].lVal; } else { DBG_ERR(("ReadPropLong, ReadMultiple of propid: %d, failed", propid));
} return hr; }
HRESULT _stdcall ReadPropLong(IUnknown *pDevice, PROPID propid, LONG *plval) { DBG_FN(::ReadPropLong); HRESULT hr; PROPVARIANT pv[1]; PROPSPEC ps[1]; IWiaPropertyStorage *pIWiaPropStg;
*plval = 0;
hr = pDevice->QueryInterface(IID_IWiaPropertyStorage, (void**)&pIWiaPropStg); if (SUCCEEDED(hr)) { PropVariantInit(pv); ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
hr = pIWiaPropStg->ReadMultiple(1, ps, pv); if (hr == S_OK) { *plval = pv[0].lVal; } else { DBG_ERR(("ReadPropLong, ReadMultiple of propid: %d, failed", propid)); } pIWiaPropStg->Release(); } else { DBG_ERR(("ReadPropLong, QI of IID_IWiaPropertyStorage failed")); } return hr; }
/**************************************************************************\
* WritePropStr * * Writes a string property to the specified property storage. This is an * overloaded function. * * Arguments: * * propid - propid of the property * pIPropStg - a pointer to the property storage * bstr - the string to write * * Return Value: * * Status * * History: * * 10/5/1999 Original Version * \**************************************************************************/
HRESULT _stdcall WritePropStr(PROPID propid, IPropertyStorage *pIPropStg, BSTR bstr) { DBG_FN(::WritePropStr); HRESULT hr; PROPSPEC propspec[1]; PROPVARIANT propvar[1];
propspec[0].ulKind = PRSPEC_PROPID; propspec[0].propid = propid;
propvar[0].vt = VT_BSTR; propvar[0].pwszVal = bstr;
hr = pIPropStg->WriteMultiple(1, propspec, propvar, 2); if (FAILED(hr)) { ReportReadWriteMultipleError( hr, "Helpers WritePropStr", NULL, FALSE, 1, propspec); } return hr; }
/**************************************************************************\
* WritePropStr * * Writes a string property. This is an overloaded function which calls * the other WritePropStr. * * * Arguments: * * pDevice - A pointer to a device item which will be queried for * it's IWiaPropertyStorage. * propid - propid of the property * bstr - the string to write * * Return Value: * * Status * * History: * * 10/5/1999 Original Version * \**************************************************************************/
HRESULT _stdcall WritePropStr(IUnknown *pDevice, PROPID propid, BSTR bstr) { DBG_FN(::WritePropStr); HRESULT hr; PROPVARIANT pv[1]; PROPSPEC ps[1]; IWiaPropertyStorage *pIWiaPropStg;
PropVariantInit(pv);
hr = pDevice->QueryInterface(IID_IWiaPropertyStorage, (void**)&pIWiaPropStg); if (SUCCEEDED(hr)) { ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
pv[0].vt = VT_BSTR; pv[0].pwszVal = bstr;
hr = pIWiaPropStg->WriteMultiple(1, ps, pv, 2); if (FAILED(hr)) { ReportReadWriteMultipleError( hr, "Helpers WritePropStr", NULL, FALSE, 1, ps); }
pIWiaPropStg->Release(); } else { DBG_ERR(("WritePropStr, QI of IID_IWiaPropertyStorage failed")); } return hr; }
/**************************************************************************\
* WritePropLong * * Writes a long property to the specified property storage. This is an * overloaded function. * * Arguments: * * propid - propid of the property * pIPropStg - a pointer to the property storage * lVal - the LONG value to write * * Return Value: * * Status * * History: * * 10/5/1999 Original Version * \**************************************************************************/
HRESULT _stdcall WritePropLong(PROPID propid, IPropertyStorage *pIPropStg, LONG lVal) { DBG_FN(::WritePropLong); HRESULT hr; PROPSPEC propspec[1]; PROPVARIANT propvar[1];
propspec[0].ulKind = PRSPEC_PROPID; propspec[0].propid = propid;
propvar[0].vt = VT_I4; propvar[0].lVal = lVal;
hr = pIPropStg->WriteMultiple(1, propspec, propvar, 2); if (FAILED(hr)) { ReportReadWriteMultipleError( hr, "Helpers WritePropLong", NULL, FALSE, 1, propspec); } return hr; }
/**************************************************************************\
* WritePropLong * * Writes a long property. This is an overloaded function which calls * the other WritePropLong. * * * Arguments: * * pDevice - A pointer to a device item which will be queried for * it's IWiaPropertyStorage. * propid - propid of the property * lVal - the LONG value to write * * Return Value: * * Status * * History: * * 10/5/1999 Original Version * \**************************************************************************/ HRESULT _stdcall WritePropLong(IUnknown *pDevice, PROPID propid, LONG lVal) { DBG_FN(::WritePropLong); HRESULT hr; PROPVARIANT pv[1]; PROPSPEC ps[1]; IWiaPropertyStorage *pIWiaPropStg;
hr = pDevice->QueryInterface(IID_IWiaPropertyStorage, (void**)&pIWiaPropStg); if (SUCCEEDED(hr)) { PropVariantInit(pv); ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
pv[0].vt = VT_I4; pv[0].lVal = lVal;
hr = pIWiaPropStg->WriteMultiple(1, ps, pv, 2); if (FAILED(hr)) { ReportReadWriteMultipleError( hr, "Helpers WritePropLong", NULL, FALSE, 1, ps); } pIWiaPropStg->Release(); } else { DBG_ERR(("WritePropLong, QI of IID_IWiaPropertyStorage failed")); } return hr; }
/**************************************************************************\
* InitMiniDrvContext * * Initialize a mini driver context from an items properties. * * Arguments: * * pItem - Pointer to the wia item * pmdtc - pointer to mini driver context * * Return Value: * * Status * * History: * * 6/16/1999 Original Version * \**************************************************************************/
HRESULT _stdcall InitMiniDrvContext( IWiaItem *pItem, PMINIDRV_TRANSFER_CONTEXT pmdtc) { DBG_FN(::InitMiniDrvContext); //
// Get a property storage from the item.
//
HRESULT hr; IPropertyStorage *pIPropStg;
hr = ((CWiaItem*)pItem)->GetItemPropStreams(&pIPropStg, NULL, NULL, NULL); if (FAILED(hr)) { return hr; }
//
// Setup the minidriver transfer context. Fill in transfer context
// members which derive from item properties.
//
memset(pmdtc, 0, sizeof(MINIDRV_TRANSFER_CONTEXT));
pmdtc->lSize = sizeof(MINIDRV_TRANSFER_CONTEXT);
#define NUM_IMAGE_SPEC 9
static PROPSPEC PropSpec[NUM_IMAGE_SPEC] = { {PRSPEC_PROPID, WIA_IPA_PIXELS_PER_LINE}, {PRSPEC_PROPID, WIA_IPA_NUMBER_OF_LINES}, {PRSPEC_PROPID, WIA_IPA_DEPTH}, {PRSPEC_PROPID, WIA_IPS_XRES}, {PRSPEC_PROPID, WIA_IPS_YRES}, {PRSPEC_PROPID, WIA_IPA_COMPRESSION}, {PRSPEC_PROPID, WIA_IPA_ITEM_SIZE}, {PRSPEC_PROPID, WIA_IPA_FORMAT}, {PRSPEC_PROPID, WIA_IPA_TYMED} };
PROPVARIANT PropVar[NUM_IMAGE_SPEC];
memset(PropVar, 0, sizeof(PropVar));
hr = pIPropStg->ReadMultiple(NUM_IMAGE_SPEC, PropSpec, PropVar); if (SUCCEEDED(hr)) {
pmdtc->lWidthInPixels = PropVar[0].lVal; pmdtc->lLines = PropVar[1].lVal; pmdtc->lDepth = PropVar[2].lVal; pmdtc->lXRes = PropVar[3].lVal; pmdtc->lYRes = PropVar[4].lVal; pmdtc->lCompression = PropVar[5].lVal; pmdtc->lItemSize = PropVar[6].lVal; pmdtc->guidFormatID = *PropVar[7].puuid; pmdtc->tymed = PropVar[8].lVal;
FreePropVariantArray(NUM_IMAGE_SPEC, PropVar); } else { ReportReadWriteMultipleError(hr, "InitMiniDrvContext", NULL, TRUE, NUM_IMAGE_SPEC, PropSpec); } return hr; }
/**************************************************************************\
* GetPropertyAttributesHelper * * Get the access flags and valid values for a property. Used by * GetPropertyAttributes in the service and by WIA Items. Parameter * validation is done beforehand by caller. * * Arguments: * * pItem - Pointer to WIA item * cPropSpec - The number of properties * pPropSpec - array of property specification. * pulAccessFlags - array of LONGs access flags. * ppvValidValues - Pointer to returned valid values. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * 05/14/1999 Updated to return multiple attribute values * 30/06/1999 Parameter validation removed, * \**************************************************************************/
HRESULT _stdcall GetPropertyAttributesHelper( IWiaItem *pItem, LONG cPropSpec, PROPSPEC *pPropSpec, ULONG *pulAccessFlags, PROPVARIANT *ppvValidValues) { DBG_FN(::GetPropertyAttributesHelper); HRESULT hr;
memset(pulAccessFlags, 0, sizeof(ULONG) * cPropSpec); memset(ppvValidValues, 0, sizeof(PROPVARIANT) * cPropSpec);
//
// 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; }
//
// Get the Access flags for the properties. Use pPropVar as
// temporary storage.
//
hr = pIPropAccessStg->ReadMultiple(cPropSpec, pPropSpec, ppvValidValues); if (SUCCEEDED(hr)) {
//
// Fill in the returned access flags
//
for (int flagIndex = 0; flagIndex < cPropSpec; flagIndex++) { pulAccessFlags[flagIndex] = ppvValidValues[flagIndex].ulVal; }
//
// Get the valid values
//
hr = pIPropValidStg->ReadMultiple(cPropSpec, pPropSpec, ppvValidValues); if (FAILED(hr)) { DBG_ERR(("GetPropertyAttributesHelper, ReadMultiple failed, could not get valid values (0x%X)", hr)); } } else { DBG_ERR(("GetPropertyAttributesHelper, ReadMultiple failed, could not get access flags (0x%X)", hr)); }
if (FAILED(hr)) {
//
// Was not successful, so clear the return values and report
// which properties caused the error.
//
FreePropVariantArray(cPropSpec, ppvValidValues); memset(pulAccessFlags, 0, sizeof(ULONG) * cPropSpec);
ReportReadWriteMultipleError(hr, "GetPropertyAttributesHelper", NULL, TRUE, cPropSpec, pPropSpec); } return hr; }
/**************************************************************************\
* GetMinAndMaxLong * * This helper method is called to get the Min and Max values for a * WIA_PROP_RANGE property of type VT_I4. * * Arguments: * * pWiasContext - a pointer to the item context * propid - identifies the property we're interested in. * plMin - the address of a LONG to receive the min value * plMax - the address of a LONG to receive the max value * * Return Value: * * Status * * History: * * 04/04/1999 Original Version * \**************************************************************************/
HRESULT _stdcall GetMinAndMaxLong( BYTE* pWiasContext, PROPID propid, LONG *plMin, LONG *plMax) { DBG_FN(::GetMinAndMaxLong); IPropertyStorage *pIValidStg; PROPSPEC ps[1]; PROPVARIANT pv[1]; HRESULT hr;
ps[0].ulKind = PRSPEC_PROPID; ps[0].propid = propid;
PropVariantInit(pv);
hr = ((CWiaItem*) pWiasContext)->GetItemPropStreams(NULL, NULL, &pIValidStg, NULL); if (SUCCEEDED(hr)) { hr = pIValidStg->ReadMultiple(1, ps, pv); if (SUCCEEDED(hr)) { if (plMin) { *plMin = pv[0].cal.pElems[WIA_RANGE_MIN]; }; if (plMax) { *plMax = pv[0].cal.pElems[WIA_RANGE_MAX]; }; PropVariantClear(pv); } else { DBG_ERR(("GetMinAndMaxLong, Reading property %d (%ws) failed",propid,GetNameFromWiaPropId(propid))); }; } else { DBG_ERR(("GetMinAndMaxLong, Could not get valid property stream")); } return hr; }
/**************************************************************************\
* CheckXResAndUpdate * * This helper method is called to check whether WIA_IPS_XRES property * is changed. When this property changes, other dependant * properties and their valid values must also be changed. * * 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). * lWidth - the width of the maximum scan area in one thousandth's * of an inch. Generally, this would be the horizontal * bed size. * * Return Value: * * Status * * History: * * 04/04/1999 Original Version * \**************************************************************************/
HRESULT _stdcall CheckXResAndUpdate( BYTE *pWiasContext, WIA_PROPERTY_CONTEXT *pContext, LONG lWidth) { DBG_FN(::CheckXResAndUpdate);
LONG lMinXExt, lMaxXExtOld, lMaxXPosOld; LONG lMax, lExt; WIAS_CHANGED_VALUE_INFO cviXRes, cviXPos, cviXExt; HRESULT hr = S_OK;
//
// Call wiasGetChangedValue for XResolution. XResolution is checked first
// since it's not dependant on any other property. All properties in
// this method that follow are dependant properties of XResolution.
//
hr = wiasGetChangedValueLong(pWiasContext, pContext, FALSE, WIA_IPS_XRES, &cviXRes); if (FAILED(hr)) { return hr; }
//
// Call wiasGetChangedValue for XPos. XPos is a dependant property of
// XResolution whose valid value changes according to what the current
// value of XResolution is. This is so that when the resoltuion changes,
// the XPos will be in the same relative position.
//
hr = wiasGetChangedValueLong(pWiasContext, pContext, cviXRes.bChanged, WIA_IPS_XPOS, &cviXPos); if (FAILED(hr)) { return hr; }
//
// Get the minimum and maximum extent values
//
hr = GetMinAndMaxLong(pWiasContext, WIA_IPS_XEXTENT, &lMinXExt, &lMaxXExtOld ); if (FAILED(hr)) { return hr; }
hr = GetMinAndMaxLong(pWiasContext, WIA_IPS_XPOS, NULL, &lMaxXPosOld ); if (FAILED(hr)) { return hr; }
//
// lMax is the maximum horizontal position (in pixels) that XPos can be
// set to. lXRes is DPI, lWidth is in one thousandth's of an inch,
// and lMinXExt is in pixels.
//
lMax = ((cviXRes.Current.lVal * lWidth) / 1000) - lMinXExt;
if (cviXRes.bChanged) {
//
// XRes changed, so calc and set new XPos valid values.
//
hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_XPOS, 0, 0, lMax, 1); if (SUCCEEDED(hr)) {
//
// If XPos is not one of the properties being written, then fold
// it's current value.
//
if (!cviXPos.bChanged) {
cviXPos.Current.lVal = (cviXPos.Old.lVal * lMax) / lMaxXPosOld; hr = wiasWritePropLong(pWiasContext, WIA_IPS_XPOS, cviXPos.Current.lVal); if (FAILED(hr)) { DBG_ERR(("CheckXResAndUpdate, could not write value for WIA_IPS_XPOS")); } } } } if (FAILED(hr)) { return hr; }
//
// Call wiasGetChangedValue for XExtent. XExtent is a dependant property of
// both XResolution and XPos. The extent should be the same relative
// size no matter what the resolution. However, if the resolution changes
// or if the XPos is set, then the extent has the possibility of being
// too large and so must be folded to a valid value.
//
hr = wiasGetChangedValueLong(pWiasContext, pContext, cviXRes.bChanged || cviXPos.bChanged, WIA_IPS_XEXTENT, &cviXExt); if (FAILED(hr)) { return hr; }
lExt = cviXExt.Current.lVal;
if (cviXRes.bChanged || cviXPos.bChanged) {
//
// XRes or XPos changed, so calc and set new XExtent valid values.
// The maximum valid value for XExtent is the maximum width allowed,
// starting at XPos.
//
lExt = (lMax - cviXPos.Current.lVal) + lMinXExt;
hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_XEXTENT, lMinXExt, lExt, lExt, 1); if (SUCCEEDED(hr)) {
//
// If XExtent is not one of the properties being written, then fold
// it's current value.
//
if (!cviXExt.bChanged) { LONG lXExtScaled;
//
// First scale the extent and then check whether it has to be
// truncated. The old extent should be scaled to keep the
// same relative size. If the resolution has not changed,
// then the scaling simply keeps the extent the same size.
//
lXExtScaled = (cviXExt.Old.lVal * lExt) / lMaxXExtOld; if (lXExtScaled > lExt) {
//
// The extent is too large, so clip it.
//
lXExtScaled = lExt; } hr = wiasWritePropLong(pWiasContext, WIA_IPS_XEXTENT, lXExtScaled); if (FAILED(hr)) { DBG_ERR(("CheckXResAndUpdate, could not write value for WIA_IPS_XEXTENT")); } } } } if (FAILED(hr)) { return hr; }
//
// Update read-only property : PIXELS_PER_LINE. The width in pixels
// of the scanned image is the same size as the XExtent.
//
hr = wiasReadPropLong(pWiasContext, WIA_IPS_XEXTENT, &lExt, NULL, TRUE); if (SUCCEEDED(hr)) { hr = wiasWritePropLong(pWiasContext, WIA_IPA_PIXELS_PER_LINE, lExt); } return hr; }
/**************************************************************************\
* CheckYResAndUpdate * * This helper method is called to check whether WIA_IPS_YRES property * is changed. When this property changes, other dependant * properties and their valid values must also be changed. This is * similar to the CheckXResAndUpdateChanged function. * * 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). * 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: * * 04/04/1999 Original Version * \**************************************************************************/
HRESULT _stdcall CheckYResAndUpdate( BYTE *pWiasContext, WIA_PROPERTY_CONTEXT *pContext, LONG lHeight) { DBG_FN(::CheckYResAndUpdate); LONG lMinYExt, lMaxYExtOld, lMaxYPosOld; LONG lMax, lExt; WIAS_CHANGED_VALUE_INFO cviYRes, cviYPos, cviYExt; HRESULT hr = S_OK;
//
// Call wiasGetChangedValue for YResolution. YResolution is checked first
// since it's not dependant on any other property. All properties in
// this method that follow are dependant properties of YResolution.
//
hr = wiasGetChangedValueLong(pWiasContext, pContext, FALSE, WIA_IPS_YRES, &cviYRes); if (FAILED(hr)) { return hr; }
//
// Call wiasGetChangedValue for YPos. YPos is a dependant property of
// YResolution whose valid value changes according to what the current
// value of YResolution is. This is so that when the resoltuion changes,
// the YPos will be in the same relative position.
//
hr = wiasGetChangedValueLong(pWiasContext, pContext, cviYRes.bChanged, WIA_IPS_YPOS, &cviYPos); if (FAILED(hr)) { return hr; }
//
// Get the minimum and maximum pos and extent values
//
hr = GetMinAndMaxLong(pWiasContext, WIA_IPS_YEXTENT, &lMinYExt, &lMaxYExtOld); if (FAILED(hr)) { return hr; }
hr = GetMinAndMaxLong(pWiasContext, WIA_IPS_YPOS, NULL, &lMaxYPosOld); if (FAILED(hr)) { return hr; }
//
// lMax is the maximum vertical position (in pixels) that YPos can be
// set to. lYRes is DPI, lPageHeight is in one thousandth's of an inch,
// and lMinYExt is in pixels.
//
lMax = ((cviYRes.Current.lVal * lHeight) / 1000) - lMinYExt;
if (cviYRes.bChanged) {
//
// YRes changed, so calc and set new YPos valid values.
//
hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_YPOS, 0, 0, lMax, 1); if (SUCCEEDED(hr)) {
//
// If YPos is not one of the properties being written, then fold
// it's current value.
//
if (!cviYPos.bChanged) {
cviYPos.Current.lVal = (cviYPos.Old.lVal * lMax) / lMaxYPosOld; hr = wiasWritePropLong(pWiasContext, WIA_IPS_YPOS, cviYPos.Current.lVal); if (FAILED(hr)) { DBG_ERR(("CheckYResAndUpdate, could not write value for WIA_IPS_YPOS")); } } } } if (FAILED(hr)) { return hr; }
//
// Call wiasGetChangedValue for YExtent. YExtent is a dependant property of
// both YResolution and YPos. The extent should be the same relative
// size no matter what the resolution. However, if the resolution changes
// or if the YPos is set, then the extent has the possibility of being
// too large and so must be folded to a valid value.
//
hr = wiasGetChangedValueLong(pWiasContext, pContext, cviYRes.bChanged || cviYPos.bChanged, WIA_IPS_YEXTENT, &cviYExt); if (FAILED(hr)) { return hr; } lExt = cviYExt.Current.lVal;
if (cviYRes.bChanged || cviYPos.bChanged) {
//
// YRes or YPos changed, so calc and set new YExtent valid values.
// The maximum valid value for YExtent is the maximum height allowed,
// starting at YPos.
//
lExt = (lMax - cviYPos.Current.lVal) + lMinYExt;
hr = wiasSetValidRangeLong(pWiasContext, WIA_IPS_YEXTENT, lMinYExt, lExt, lExt, 1); if (SUCCEEDED(hr)) {
//
// If YExtent is not one of the properties being written, then fold
// it's current value.
//
if (!cviYExt.bChanged) { LONG lYExtScaled;
//
// First scale the extent and then check whether it has to be
// truncated. The old extent should be scaled to keep the
// same relative size. If the resolution has not changed,
// then the scaling simply keeps the extent the same size.
//
lYExtScaled = (cviYExt.Old.lVal * lExt) / lMaxYExtOld; if (lYExtScaled > lExt) {
//
// The extent is too large, so clip it.
//
lYExtScaled = lExt; } hr = wiasWritePropLong(pWiasContext, WIA_IPS_YEXTENT, lYExtScaled); if (FAILED(hr)) { DBG_ERR(("CheckYResAndUpdate, could not write value for WIA_IPS_YEXTENT")); } } } } if (FAILED(hr)) { return hr; }
//
// Update read-only property : NUMBER_OF_LINES. The number of lines in the scanned
// image is the same as the vertical (Y) extent.
//
hr = wiasReadPropLong(pWiasContext, WIA_IPS_YEXTENT, &lExt, NULL, TRUE); if (SUCCEEDED(hr)) { hr = wiasWritePropLong(pWiasContext, WIA_IPA_NUMBER_OF_LINES, lExt); } return hr; }
/**************************************************************************\
* AreWiaInitializedProps * * This helper method is called to check whether a given set of propspecs * identifies only the WIA managed properties. It is used to help * performance with lazy intialization. * * Arguments: * * cPropSpec - count of propecs in the array * pPropSpec - the propspec array * * Return Value: * * TRUE - if all properties in the propspec array are WIA managed ones. * FALSE - if at least one property is not a WIA managed one. * * History: * * 10/10/1999 Original Version * \**************************************************************************/ BOOL _stdcall AreWiaInitializedProps( ULONG cPropSpec, PROPSPEC *pPropSpec) { DBG_FN(::AreWiaInitializedProps); ULONG index; ULONG propIndex; BOOL bFoundProp = FALSE;
for (index = 0; index < cPropSpec; index++) { bFoundProp = FALSE;
for (propIndex = 0; propIndex < NUM_WIA_MANAGED_PROPS; propIndex++) {
if (pPropSpec[index].ulKind == PRSPEC_LPWSTR) { if (wcscmp(s_pszItemNameType[propIndex], pPropSpec[index].lpwstr) == 0) { bFoundProp = TRUE; break; } } else if (s_piItemNameType[propIndex] == pPropSpec[index].propid) { bFoundProp = TRUE; break; } }
if (!bFoundProp) { break; } }
return bFoundProp; }
HRESULT _stdcall SetValidProfileNames( BYTE *pbData, DWORD dwSize, IWiaItem *pIWiaItem) { DBG_FN(::StripProfileNames); HRESULT hr; ULONG ulNumStrings = 0; LPTSTR szProfileName = (LPTSTR) pbData; BSTR bstrDefault = NULL; BSTR *bstrValidProfiles = NULL; ULONG ulIndex = 0;
USES_CONVERSION;
//
// Count number of strings
//
while ((BYTE*)szProfileName < (pbData + dwSize)) { if (szProfileName[0] != TEXT('\0')) { ulNumStrings++; szProfileName += lstrlen(szProfileName); } szProfileName++; }
if (ulNumStrings == 0) { DBG_ERR(("StripProfileNames, No profile names!")); return E_FAIL; }
//
// Allocate memory for the string array
//
szProfileName = (LPTSTR)pbData;
bstrDefault = SysAllocString(T2W(szProfileName)); bstrValidProfiles = (BSTR*) LocalAlloc(LPTR, ulNumStrings * sizeof(BSTR)); if (!bstrValidProfiles || !bstrDefault) { DBG_ERR(("StripProfileNames, could not allocate memory!")); hr = E_OUTOFMEMORY; } else { memset(bstrValidProfiles, 0, ulNumStrings * sizeof(BSTR)); }
if (SUCCEEDED(hr)) {
//
// Set the string values.
//
for (ulIndex = 0; ulIndex < ulNumStrings; ulIndex++) { if (szProfileName[0] != TEXT('\0')) { bstrValidProfiles[ulIndex] = SysAllocString(T2W(szProfileName)); if (!bstrValidProfiles[ulIndex]) { DBG_ERR(("StripProfileNames, could not allocate strings!")); hr = E_OUTOFMEMORY; break; } szProfileName += (lstrlen(szProfileName) + 1); } }
//
// Set the valid values and the current value
//
if (SUCCEEDED(hr)) { hr = wiasSetValidListStr((BYTE*) pIWiaItem, WIA_IPA_ICM_PROFILE_NAME, ulNumStrings, bstrDefault, bstrValidProfiles); if (SUCCEEDED(hr)) { hr = wiasWritePropStr((BYTE*) pIWiaItem, WIA_IPA_ICM_PROFILE_NAME, bstrDefault); if (FAILED(hr)) { DBG_ERR(("StripProfileNames, could not set default color profiles!")); }
} else { DBG_ERR(("StripProfileNames, could not set valid list of color profiles!")); } } }
//
// Free memory
//
if (bstrDefault) { SysFreeString(bstrDefault); bstrDefault = NULL; }
if (bstrValidProfiles) { for (ulIndex = 0; ulIndex < ulNumStrings; ulIndex++) { if (bstrValidProfiles[ulIndex]) { SysFreeString(bstrValidProfiles[ulIndex]); } } LocalFree(bstrValidProfiles); bstrValidProfiles = NULL; }
return hr; }
/**************************************************************************\
* FillICMPropertyFromRegistry * * This helper method is called to fill the item properties with the ICM * color profile names from a specified device's registry entries. * NOTE: This function assumes this is called on a Root before it's called * on its children! * * Arguments: * * IWiaItem - WIA item * * Return Value: * * Status * * History: * * 10/10/1999 Original Version * \**************************************************************************/
HRESULT _stdcall FillICMPropertyFromRegistry( IWiaPropertyStorage *pDevInfoProps, IWiaItem *pIWiaItem) { DBG_FN(::FillICMPropertyFromRegistry); PROPSPEC pspec[1] = {{PRSPEC_PROPID, WIA_DIP_DEV_ID}}; PROPVARIANT pvName[1]; HRESULT hr = E_FAIL; BYTE *pbData = NULL; DWORD dwType = 0; DWORD dwSize = 0; LONG lItemType = 0;
CWiaItem *pRoot = NULL;
USES_CONVERSION;
//
// Check whether this is the root item. If it is, read the ICM values from the
// registry, and cache it.
// NOTE: This should be moved into the STI_WIA_DEVICE_INFORMATION member of
// ACTIVE_DEVICE, and filled in when STI_WIA_DEVICE_INFORMATION is
// filled for the first time. This should increase performance.
// If it isn't the root item, then get the cached ICM values from the root, and
// fill them in.
//
hr = pIWiaItem->GetItemType(&lItemType); if (SUCCEEDED(hr)) {
if (lItemType & WiaItemTypeRoot) {
//
// This is a root item, so cache the ICM values.
// Start by getting the device name...
//
pRoot = (CWiaItem*) pIWiaItem;
if (pDevInfoProps) { //
// Get the color profile names. First get the size, then get the value.
//
hr = g_pDevMan->GetDeviceValue(pRoot->m_pActiveDevice, STI_DEVICE_VALUE_ICM_PROFILE, &dwType, NULL, &dwSize); if (SUCCEEDED(hr)) {
pbData = (BYTE*) LocalAlloc(LPTR, dwSize); if (pbData) { dwType = REG_BINARY; hr = g_pDevMan->GetDeviceValue(pRoot->m_pActiveDevice, STI_DEVICE_VALUE_ICM_PROFILE, &dwType, pbData, &dwSize); if (SUCCEEDED(hr)) {
//
// Store the ICM value with this root item.
//
pRoot->m_pICMValues = pbData; pRoot->m_lICMSize = dwSize;
} else { DBG_WRN(("FillICMPropertyFromRegistry, could not get ICM profile value!")); LocalFree(pbData); } } else { hr = E_OUTOFMEMORY; DBG_ERR(("FillICMPropertyFromRegistry, not enough memory for ICM values!")); } } else { DBG_WRN(("FillICMPropertyFromRegistry, could not get ICM profile size!")); } } else { DBG_ERR(("FillICMPropertyFromRegistry, no property stream provided!")); }
//
// Always set the return to S_OK if this is the root. Even if the color profile could not
// be read, when it comes time for the child items to have their profile property filled in,
// they'll simply get the standard sRGB one instead.
//
hr = S_OK; } else {
//
// This is not a root item, so get the cached ICM values from the root
// and fill in the ICM property.
//
hr = pIWiaItem->GetRootItem((IWiaItem**) &pRoot); if (SUCCEEDED(hr)) {
//
// Check whether a cached ICM profile list exists. Get a standard one if it doesn't, else
// just set the property.
//
if (!pRoot->m_pICMValues || FAILED(hr = SetValidProfileNames(pRoot->m_pICMValues, pRoot->m_lICMSize, pIWiaItem))) { TCHAR szSRGB[MAX_PATH] = {TEXT('\0')};
dwSize = sizeof(szSRGB); if (GetStandardColorSpaceProfile(NULL, LCS_sRGB, szSRGB, &dwSize)) { hr = SetValidProfileNames((BYTE*)szSRGB, dwSize, pIWiaItem); DBG_TRC(("FillICMPropertyFromRegistry, using default color space profile"));
} else { DBG_ERR(("FillICMPropertyFromRegistry, GetStandardColorSpaceProfile failed!")); hr = E_FAIL; } }
pRoot->Release(); } else { DBG_ERR(("FillICMPropertyFromRegistry, could not get root item!")); } } } else { DBG_ERR(("FillICMPropertyFromRegistry, could not get item type!")); } return hr; }
/**************************************************************************\
* GetParentItem * * Returns the item's parent * * Arguments: * * pItem - WIA item * ppItem - address to store the parent item. * * Return Value: * * Status * * History: * * 01/14/2000 Original Version * \**************************************************************************/
HRESULT _stdcall GetParentItem(CWiaItem *pItem, CWiaItem **ppParent) { DBG_FN(::GetParentItem); CWiaTree *pTree, *pParentTree; HRESULT hr = S_OK;
pTree = pItem->GetTreePtr(); if (pTree) {
hr = pTree->GetParentItem(&pParentTree); if (SUCCEEDED(hr)) {
if (hr == S_OK) { pParentTree->GetItemData((VOID**) ppParent); } } else { DBG_ERR(("GetParentItem, could not get root item tree!")); } } else { DBG_ERR(("GetParentItem, item's tree ptr is NULL!")); hr = E_INVALIDARG; }
return hr; }
/**************************************************************************\
* GetBufferValues * * Fills in the buffer size properties of the WIA_EXTENDED_TRANSFER_INFO * struct. * * Arguments: * * pCWiaItem - WIA item * pTransInfo - Pointer to the extended transfer information struct. * * Return Value: * * Status * * History: * * 01/23/2000 Original Version * \**************************************************************************/
HRESULT _stdcall GetBufferValues( CWiaItem *pCWiaItem, PWIA_EXTENDED_TRANSFER_INFO pTransInfo) { DBG_FN(::GetBufferValues); HRESULT hr = S_OK; IPropertyStorage *pIValidStg = NULL; PROPSPEC ps[1] = {{PRSPEC_PROPID, WIA_IPA_BUFFER_SIZE}}; PROPVARIANT pv[1];
//
// Get the valid values for the WIA_IPA_BUFFER_SIZE property.
// NOTE: The WIA_IPA_BUFFER_SIZE property used to be the
// WIA_IPA_MIN_BUFFER_SIZE property. If we can't
// read the valid values for WIA_IPA_BUFFER_SIZE,
// we must read the current value of WIA_IP_MIN_BUFFER_SIZE
// and "guess" the other values instead.
// This is to facilitate drivers that were made with early versions
// of the WIA DDK.
//
hr = pCWiaItem->GetItemPropStreams(NULL, NULL, &pIValidStg, NULL); if (SUCCEEDED(hr)) {
PropVariantInit(pv);
hr = pIValidStg->ReadMultiple(1, ps, pv); if (hr == S_OK) {
//
// Check that the returned property really has enough elements
// to specify min, max and nominal values. If not, set hr to
// fail so that we catch our attempt to reach MIN_BUFFER_SIZE
// instead.
//
if (pv[0].cal.cElems == WIA_RANGE_NUM_ELEMS) {
//
// Valid values for WIA_IPA_BUFFER_SIZE found, so
// set the returns.
pTransInfo->ulMinBufferSize = pv[0].cal.pElems[WIA_RANGE_MIN]; pTransInfo->ulOptimalBufferSize = pv[0].cal.pElems[WIA_RANGE_NOM]; pTransInfo->ulMaxBufferSize = pv[0].cal.pElems[WIA_RANGE_MAX]; } else {
hr = E_FAIL; } }
if (hr != S_OK) {
//
// Attempt to read the current value of WIA_IPA_MIN_BUFFER_SIZE,
// since we couldn't find the values we wanted under
// WIA_IPA_BUFFER_SIZE.
//
IPropertyStorage *pICurrentStg = NULL;
PropVariantClear(pv);
hr = pCWiaItem->GetItemPropStreams(&pICurrentStg, NULL, NULL, NULL); if (SUCCEEDED(hr)) {
//
// Note that we can re-use ps, since the propid's of
// MIN_BUFFER_SIZE and BUFFER_SIZE are the same.
//
hr = pICurrentStg->ReadMultiple(1, ps, pv); if (hr == S_OK) {
//
// Current value for WIA_IPA_MIN_BUFFER_SIZE found, so
// set the returns.
pTransInfo->ulMinBufferSize = pv[0].lVal; pTransInfo->ulOptimalBufferSize = pv[0].lVal; pTransInfo->ulMaxBufferSize = LONG_MAX; } else { DBG_ERR(("GetBufferValues, Could not read (valid) WIA_IPA_BUFFER_SIZE or (current) WIA_IPA_MIN_BUFFER_SIZE!")); hr = E_INVALIDARG; } } else { DBG_ERR(("GetBufferValues, Could not get item prop streams!")); } } PropVariantClear(pv); } else { DBG_ERR(("GetBufferValues, failed to get item prop streams!")); } return hr; }
/**************************************************************************\
* BQADScale * * This routine implements Byron's Quick And Dirty scaling algorithm. This * specific implementation is meant for 1, 8, or 24bit only. Caller * is responsible for all parameter checks! * * Please note: this is assumed to scale a band of BITMAP data. As such, * the source should contain DWORD aligned pixel data, and the ouput buffer * will contain DWORD aligned pixel data upon return. * * Arguments: * * pSrcBuffer - Pointer to the source buffer * lSrcWidth - the source data width in pixels * lSrcHeight - the source data height in pixels * lSrcDepth - the bit depth of the source data * pDestBuffer - Pointer to the destination buffer * lDestWidth - the resultant width in pixels * lDestHeight - the resultant height in pixels * * Return Value: * * Status * * History: * * 08/28/2000 Original Version * \**************************************************************************/
HRESULT _stdcall BQADScale(BYTE* pSrcBuffer, LONG lSrcWidth, LONG lSrcHeight, LONG lSrcDepth, BYTE* pDestBuffer, LONG lDestWidth, LONG lDestHeight) { //
// We only deal with 1, 8 and 24 bit data
//
if ((lSrcDepth != 8) && (lSrcDepth != 1) && (lSrcDepth != 24)) { DBG_ERR(("BQADScale, We only scale 1bit, 8bit or 24bit data right now, data is %dbit\n", lSrcDepth)); return E_INVALIDARG; }
//
// Make adjustments so we also work in all supported bit depths. We can get a performance increase
// by having separate implementations of all of these, but for now, we stick to a single generic
// implementation.
//
LONG lBytesPerPixel = (lSrcDepth + 7) / 8; // This is the ceiling of the number of
// bytes needed to hold a single pixel
ULONG lSrcRawWidth = ((lSrcWidth * lSrcDepth) + 7) / 8; // This is the width in bytes
ULONG lSrcWidthInBytes; // This is the DWORD-aligned width
ULONG lDestWidthInBytes; // This is the DWORD-aligned width
//
// We need to work out the DWORD aligned width in bytes. Normally we would do this in one step
// using the supplied lSrcDepth, but we avoid arithmetic overflow conditions that happen
// in 24bit if we do it in 2 steps like this instead.
//
if (lSrcDepth == 1) { lSrcWidthInBytes = (lSrcWidth + 7) / 8; lDestWidthInBytes = (lDestWidth + 7) / 8; } else { lSrcWidthInBytes = (lSrcWidth * lBytesPerPixel); lDestWidthInBytes = (lDestWidth * lBytesPerPixel); } lSrcWidthInBytes += (lSrcWidthInBytes % sizeof(DWORD)) ? (sizeof(DWORD) - (lSrcWidthInBytes % sizeof(DWORD))) : 0; lDestWidthInBytes += (lDestWidthInBytes % sizeof(DWORD)) ? (sizeof(DWORD) - (lDestWidthInBytes % sizeof(DWORD))) : 0;
//
// Define local variables and do the initial calculations needed for
// the scaling algorithm
//
BYTE *pDestPixel = NULL; BYTE *pSrcPixel = NULL; BYTE *pEnd = NULL; BYTE *pDestLine = NULL; BYTE *pSrcLine = NULL; BYTE *pEndLine = NULL;
LONG lXEndSize = lBytesPerPixel * lDestWidth;
LONG lXNum = lSrcWidth; // Numerator in X direction
LONG lXDen = lDestWidth; // Denomiator in X direction
LONG lXInc = (lXNum / lXDen) * lBytesPerPixel; // Increment in X direction
LONG lXDeltaInc = lXNum % lXDen; // DeltaIncrement in X direction
LONG lXRem = 0; // Remainder in X direction
LONG lYNum = lSrcHeight; // Numerator in Y direction
LONG lYDen = lDestHeight; // Denomiator in Y direction
LONG lYInc = (lYNum / lYDen) * lSrcWidthInBytes; // Increment in Y direction
LONG lYDeltaInc = lYNum % lYDen; // DeltaIncrement in Y direction
LONG lYDestInc = lDestWidthInBytes; LONG lYRem = 0; // Remainder in Y direction
pSrcLine = pSrcBuffer; // This is where we start in the source
pDestLine = pDestBuffer; // This is the start of the destination buffer
// This is where we end overall
pEndLine = pDestBuffer + (lDestWidthInBytes * lDestHeight);
while (pDestLine < pEndLine) { // Start LoopY (Decides where the src and dest lines start)
pSrcPixel = pSrcLine; // We're starting at the beginning of a new line
pDestPixel = pDestLine; // Calc. where we end the line
pEnd = pDestPixel + lXEndSize; lXRem = 0; // Reset the remainder for the horizontal direction
while (pDestPixel < pEnd) { // Start LoopX (puts pixels in the destination line)
// Put the pixel
if (lBytesPerPixel > 1) { pDestPixel[0] = pSrcPixel[0]; pDestPixel[1] = pSrcPixel[1]; pDestPixel[2] = pSrcPixel[2]; } else { *pDestPixel = *pSrcPixel; } // Move the destination pointer to the next pixel
pDestPixel += lBytesPerPixel; pSrcPixel += lXInc; // Move the source pointer over by the horizontal increment
lXRem += lXDeltaInc; // Increase the horizontal remainder - this decides when we "overflow"
if (lXRem >= lXDen) { // This is our "overflow" condition. It means we're now one
// pixel off.
// In Overflow case, we need to shift one pixel over
pSrcPixel += lBytesPerPixel; lXRem -= lXDen; // Decrease the remainder by the X denominator. This is essentially
// lXRem MOD lXDen.
} } // End LoopX (puts pixels in the destination line)
pSrcLine += lYInc; // We've finished a horizontal line, time to move to the next one
lYRem += lYDeltaInc; // Increase our vertical remainder. This decides when we "overflow"
if (lYRem > lYDen) { // This is our vertical overflow condition.
// We need to move to the next line down
pSrcLine += lSrcWidthInBytes; lYRem -= lYDen; // Decrease the remainder by the Y denominator. This is essentially
// lYRem MOD lYDen.
} pDestLine += lYDestInc; // Move the destination pointer to the start of the next line in the
// destination buffer
} // End LoopY (Decides where the src and dest lines start)
return S_OK; }
/**************************************************************************\
* AllocReadRegistryString * * This function reads a REG_SZ value from the registry. The memory for * the srting value ius allocated with new. The caller should use * "delete" when it is finished with it. * * Arguments: * * hKey - Registry key to read from * *wszValueName - Value to read * **pwszReturnValue - Addess of pointer that will receive the allocated * string * * Return Value: * * Status. * * History: * * 11/06/2000 Original Version * \**************************************************************************/ HRESULT AllocReadRegistryString( HKEY hKey, WCHAR *wszValueName, WCHAR **pwszReturnValue) { HRESULT hr = S_OK; DWORD dwError = 0; DWORD cbData = 0; DWORD dwType = REG_SZ;
if (!wszValueName || !pwszReturnValue) { DBG_WRN(("::AllocReadRegistryString, NULL parameter")); return E_INVALIDARG; }
*pwszReturnValue = NULL;
//
// Get the number of bytes neded to store the string value.
//
dwError = RegQueryValueExW(hKey, wszValueName, NULL, &dwType, NULL, &cbData); if (dwError == ERROR_SUCCESS) {
//
// Allocate the correct number of bytes (leave space for terminator)
//
*pwszReturnValue = (WCHAR*) new BYTE[cbData + sizeof(L"\0")]; if (*pwszReturnValue) { memset(*pwszReturnValue, 0, cbData + sizeof(L"\0"));
//
// Get the string
//
dwError = RegQueryValueExW(hKey, wszValueName, NULL, &dwType, (LPBYTE)(*pwszReturnValue), &cbData); if (dwError == ERROR_SUCCESS) { } else { DBG_WRN(("::AllocReadRegistryString, second RegQueryValueExW returned %d", dwError)); hr = HRESULT_FROM_WIN32(dwError); } } else { DBG_WRN(("::AllocReadRegistryString, Out of memory!")); hr = E_OUTOFMEMORY; } } else { hr = S_FALSE; }
if (hr != S_OK) { if (*pwszReturnValue) { delete[] *pwszReturnValue; } *pwszReturnValue = NULL; }
return hr; }
/**************************************************************************\
* AllocCopyString * * This function copies a widestring. The memory for the string is * allocated with new. The caller should use "delete" to free the string * when it is finished with it. * * Arguments: * * wszString - WideString to copy. * * Return Value: * * Pointer to newly allocated string. Null otherwise. * * History: * * 11/06/2000 Original Version * \**************************************************************************/ WCHAR* AllocCopyString( WCHAR* wszString) { WCHAR *wszOut = NULL; ULONG ulLen = 0;
//
// Get length of string including terminating NULL
//
ulLen = lstrlenW(wszString) + 2;
//
// Allocate memory for the string
//
wszOut = new WCHAR[ulLen]; if (wszOut) {
//
// Copy it
//
lstrcpynW(wszOut, wszString, ulLen); } return wszOut; }
/**************************************************************************\
* AllocCatString * * This function concatenates 2 strings. The memory for the string is * allocated with new. The caller should use "delete []" to free the string * when it is finished with it. * * Arguments: * * wszString1 - First WideString. * wszString2 - Second WideString to add to first. * * Return Value: * * Pointer to newly allocated string. Null otherwise. * * History: * * 16/02/2001 Original Version * \**************************************************************************/ WCHAR* AllocCatString(WCHAR* wszString1, WCHAR* wszString2) { WCHAR *wszOut = NULL; ULONG ulLen = 0;
//ASSERT (!wszString1 && !wszString2)
//
// Get length of string including terminating NULL
//
ulLen = lstrlenW(wszString1) + lstrlenW(wszString2) + 1;
//
// Allocate memory for the string
//
wszOut = new WCHAR[ulLen]; if (wszOut) {
//
// Copy 1st string
//
lstrcpynW(wszOut, wszString1, ulLen);
//
// Concatenate the strings
//
lstrcpynW(wszOut + lstrlenW(wszOut), wszString2, ulLen - lstrlenW(wszOut));
//
// Always terminate the string
//
wszOut[ulLen - 1] = L'\0'; } return wszOut; }
/**************************************************************************\
* ReadRegistryDWORD * * This function reads a dword value from the registry. * * Arguments: * * hKey - Registry key to read from * wszValueName - Value to read from key * pdwReturnValue - Address of variable to receive the data * * Return Value: * * Status * * History: * * 11/06/2000 Original Version * \**************************************************************************/ HRESULT ReadRegistryDWORD( HKEY hKey, WCHAR *wszValueName, DWORD *pdwReturnValue) { HRESULT hr = S_OK; DWORD dwError = 0; DWORD cbData = sizeof(DWORD); DWORD dwType = REG_DWORD;
if (!pdwReturnValue || !wszValueName) { DBG_WRN(("::ReadRegistryDWORD called with NULL")); return E_UNEXPECTED; }
*pdwReturnValue = 0; dwError = RegQueryValueExW(hKey, wszValueName, NULL, &dwType, (LPBYTE)pdwReturnValue, &cbData); if (dwError != ERROR_SUCCESS) {
DBG_TRC(("::ReadRegistryDWORD, RegQueryValueExW returned %d", dwError)); hr = HRESULT_FROM_WIN32(dwError); } if (FAILED(hr)) { *pdwReturnValue = 0; }
return hr; }
/**************************************************************************\
* CreateDevInfoFromHKey * * This function creates and fills out a DEVICE_INFO struct. Most of * the information is read from the registry. This is called for Devnode * and interface devices (volume devices don't have registry entries) * * Arguments: * * hKeyDev - Device registry key * dwDeviceState - The device state * pspDevInfoData - The devnode data * pspDevInterfaceData - The interface data - will be NULL for devnode * devices. * Return Value: * * Pointer to newly created DEVICE_INFO struct. NULL if one could not * be allocated. * * History: * * 11/06/2000 Original Version * \**************************************************************************/ DEVICE_INFO* CreateDevInfoFromHKey( HKEY hKeyDev, DWORD dwDeviceState, SP_DEVINFO_DATA *pspDevInfoData, SP_DEVICE_INTERFACE_DATA *pspDevInterfaceData) { HRESULT hr = E_OUTOFMEMORY; DEVICE_INFO *pDeviceInfo = NULL; HKEY hDeviceDataKey = NULL; DWORD dwMajorType = 0; DWORD dwMinorType = 0; BOOL bFatalError = FALSE;
DWORD dwTemp; WCHAR *wszTemp = NULL;
pDeviceInfo = new DEVICE_INFO; if (!pDeviceInfo) { DBG_WRN(("CWiaDevMan::CreateDevInfoFromHKey, Out of memory")); return NULL; } memset(pDeviceInfo, 0, sizeof(DEVICE_INFO)); pDeviceInfo->bValid = FALSE; pDeviceInfo->dwDeviceState = dwDeviceState; //
// Copy the SP_DEVINFO_DATA and SP_DEVICE_INTERFACE_DATA
//
if (pspDevInfoData) { memmove(&pDeviceInfo->spDevInfoData, pspDevInfoData, sizeof(SP_DEVINFO_DATA)); if (pspDevInterfaceData) { memmove(&pDeviceInfo->spDevInterfaceData, pspDevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA)); } }
//
// NOTE: To avoid any alignment faults, we read into &wszTemp, then assign wszTemp to
// the appropriate structure member.
//
hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICE_ID_W, &wszTemp); if (FAILED(hr)) { DBG_WRN(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for this device (NULL name)", REGSTR_VAL_DEVICE_ID_W)); bFatalError = TRUE; } else { pDeviceInfo->wszDeviceInternalName = wszTemp; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICE_ID_W, &wszTemp); if (FAILED(hr)) { DBG_WRN(("::CreateDevInfoFromHKey, Failed to read %ws (remote), fatal for this device (NULL name)", REGSTR_VAL_DEVICE_ID_W)); bFatalError = TRUE; } else { pDeviceInfo->wszDeviceRemoteName = wszTemp; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_USD_CLASS_W, &wszTemp); if (FAILED(hr)) { DBG_WRN(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for this device (%ws)", REGSTR_VAL_USD_CLASS_W, pDeviceInfo->wszDeviceInternalName)); bFatalError = TRUE; } else { pDeviceInfo->wszUSDClassId = wszTemp; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_VENDOR_NAME_W, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_VENDOR_NAME_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszVendorDescription = wszTemp; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICE_NAME_W, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_DEVICE_NAME_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszDeviceDescription = wszTemp; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICEPORT_W, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_DEVICEPORT_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszPortName = wszTemp; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_PROP_PROVIDER_W, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_PROP_PROVIDER_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszPropProvider = wszTemp; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_FRIENDLY_NAME_W, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_FRIENDLY_NAME_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszLocalName = wszTemp; } hr = ReadRegistryDWORD(hKeyDev, REGSTR_VAL_HARDWARE_W, &dwTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_HARDWARE_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->dwHardwareConfiguration = dwTemp; } hr = ReadRegistryDWORD(hKeyDev, REGSTR_VAL_DEVICETYPE_W, &dwMajorType); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_DEVICETYPE_W, pDeviceInfo->wszDeviceInternalName)); } hr = ReadRegistryDWORD(hKeyDev, REGSTR_VAL_DEVICESUBTYPE_W, &dwMinorType); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_DEVICESUBTYPE_W, pDeviceInfo->wszDeviceInternalName)); } pDeviceInfo->DeviceType = MAKELONG(dwMinorType,dwMajorType); hr = ReadRegistryDWORD(hKeyDev, REGSTR_VAL_GENERIC_CAPS_W, &dwTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_GENERIC_CAPS_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->DeviceCapabilities.dwGenericCaps = dwTemp; }
//
// Set the Internal Device type
//
pDeviceInfo->dwInternalType = INTERNAL_DEV_TYPE_REAL; if (pDeviceInfo->DeviceCapabilities.dwGenericCaps & STI_GENCAP_WIA) { pDeviceInfo->dwInternalType |= INTERNAL_DEV_TYPE_WIA; } if (pspDevInterfaceData) { pDeviceInfo->dwInternalType |= INTERNAL_DEV_TYPE_INTERFACE; }
//
// Read everything we can from DeviceData section under Device Registry Key
//
hr = RegCreateKeyExW(hKeyDev, REGSTR_VAL_DATA_W, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hDeviceDataKey, NULL); hr = AllocReadRegistryString(hDeviceDataKey, WIA_DIP_SERVER_NAME_STR, &wszTemp); if (FAILED(hr)) { DBG_WRN(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for device (%ws)", WIA_DIP_SERVER_NAME_STR, pDeviceInfo->wszDeviceInternalName)); bFatalError = TRUE; } else { pDeviceInfo->wszServer = wszTemp; if (!pDeviceInfo->wszServer) { pDeviceInfo->wszServer = AllocCopyString(LOCAL_DEVICE_STR); } if (pDeviceInfo->wszServer) { if (lstrcmpiW(pDeviceInfo->wszServer, LOCAL_DEVICE_STR) == 0) { //
// Mark this device as being local
//
pDeviceInfo->dwInternalType |= INTERNAL_DEV_TYPE_LOCAL; } } } hr = AllocReadRegistryString(hDeviceDataKey, WIA_DIP_UI_CLSID_STR, &wszTemp); if (FAILED(hr)) { DBG_WRN(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for device (%ws)", WIA_DIP_SERVER_NAME_STR, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszUIClassId = wszTemp; if (!pDeviceInfo->wszUIClassId) { pDeviceInfo->wszUIClassId = AllocCopyString(DEF_UI_CLSID_STR); } } hr = AllocReadRegistryString(hDeviceDataKey, REGSTR_VAL_BAUDRATE, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_BAUDRATE, pDeviceInfo->wszDeviceInternalName)); } else {
if (( pDeviceInfo->dwHardwareConfiguration & STI_HW_CONFIG_SERIAL ) && (hr == S_FALSE)) { //
// Only for serial devices we need to set default baud rate in case it is not set in the
// registry.
pDeviceInfo->wszBaudRate = AllocCopyString(DEF_BAUD_RATE_STR); } else { pDeviceInfo->wszBaudRate = wszTemp; } DBG_TRC(("::CreateDevInfoFromHKey, Read baud rate %ws ",pDeviceInfo->wszBaudRate)); } hr = ReadRegistryDWORD(hDeviceDataKey, STI_DEVICE_VALUE_HOLDINGTIME_W, &dwTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", STI_DEVICE_VALUE_HOLDINGTIME_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->dwLockHoldingTime = dwTemp; } hr = ReadRegistryDWORD(hDeviceDataKey, STI_DEVICE_VALUE_TIMEOUT, &dwTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", STI_DEVICE_VALUE_TIMEOUT, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->dwPollTimeout = dwTemp; } hr = ReadRegistryDWORD(hDeviceDataKey, STI_DEVICE_VALUE_DISABLE_NOTIFICATIONS, &dwTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", STI_DEVICE_VALUE_DISABLE_NOTIFICATIONS, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->dwDisableNotifications = dwTemp; } RegCloseKey(hDeviceDataKey);
if (!bFatalError) { pDeviceInfo->bValid = TRUE; } else { DBG_WRN(("::CreateDevInfoFromHKey, marking device info. as invalid")); }
return pDeviceInfo; }
/**************************************************************************\
* RefreshDevInfoFromHKey * * This function refreshes fields that are subject to change * * Arguments: * * pDeviceInfo - Pointer to the DEVICE_INFO struct to update * hKeyDev - Device registry key * dwDeviceState - The new device state * pspDevInfoData - The devnode data * pspDevInterfaceData - The interface data - will be NULL for devnode * devices. * * Return Value: * * True - Everything successfully updated * False - Could not update * * History: * * 11/06/2000 Original Version * \**************************************************************************/ BOOL RefreshDevInfoFromHKey( DEVICE_INFO *pDeviceInfo, HKEY hKeyDev, DWORD dwDeviceState, SP_DEVINFO_DATA *pspDevInfoData, SP_DEVICE_INTERFACE_DATA *pspDevInterfaceData) { HRESULT hr = E_OUTOFMEMORY; BOOL Succeeded = TRUE;
WCHAR *wszTemp = NULL;
//
// Set new device state
//
pDeviceInfo->dwDeviceState = dwDeviceState;
//
// Copy the SP_DEVINFO_DATA and SP_DEVICE_INTERFACE_DATA
//
if (pspDevInfoData) { memcpy(&pDeviceInfo->spDevInfoData, pspDevInfoData, sizeof(SP_DEVINFO_DATA)); if (pspDevInterfaceData) { memcpy(&pDeviceInfo->spDevInterfaceData, pspDevInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA)); } }
//
// Set new port name. First free the old one if it exists
//
if (pDeviceInfo->wszPortName) { delete [] pDeviceInfo->wszPortName; pDeviceInfo->wszPortName = NULL; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICEPORT_W, &wszTemp); if (FAILED(hr)) { DBG_WRN(("::RefreshDevInfoFromHKey, Failed to update %ws, may be fatal for device (%ws)", REGSTR_VAL_DEVICEPORT_W, pDeviceInfo->wszDeviceInternalName)); Succeeded = FALSE; } else { pDeviceInfo->wszPortName = wszTemp; }
//
// Grab new Local name. First free the old one...
//
if (pDeviceInfo->wszLocalName) { delete [] pDeviceInfo->wszLocalName; pDeviceInfo->wszLocalName = NULL; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_FRIENDLY_NAME_W, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::RefreshDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_FRIENDLY_NAME_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszLocalName = wszTemp; }
//
// Grab new Device Description. First free the old one...
//
if (pDeviceInfo->wszDeviceDescription) { delete [] pDeviceInfo->wszDeviceDescription; pDeviceInfo->wszDeviceDescription = NULL; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_DEVICE_NAME_W, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::RefreshDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_DEVICE_NAME_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszDeviceDescription = wszTemp; }
//
// Grab new Vendor name. First free the old one...
//
if (pDeviceInfo->wszVendorDescription) { delete [] pDeviceInfo->wszVendorDescription; pDeviceInfo->wszVendorDescription = NULL; } hr = AllocReadRegistryString(hKeyDev, REGSTR_VAL_VENDOR_NAME_W, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::RefreshDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", REGSTR_VAL_VENDOR_NAME_W, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszVendorDescription = wszTemp; }
return Succeeded; }
/**************************************************************************\
* RefreshDevInfoFromMountPoint * * This function refreshes fields that are subject to change for volume * devices. * * Arguments: * * pDeviceInfo - Pointer to the DEVICE_INFO struct to update * * Return Value: * * True - Everything successfully updated * False - Could not update * * History: * * 16/03/2001 Original Version * \**************************************************************************/ BOOL RefreshDevInfoFromMountPoint( DEVICE_INFO *pDeviceInfo, WCHAR *wszMountPoint) { HRESULT hr = E_OUTOFMEMORY; BOOL Succeeded = TRUE;
WCHAR wszLabel[MAX_PATH];
//
// Grab the friendly name of the FS device
//
hr = GetMountPointLabel(wszMountPoint, wszLabel, sizeof(wszLabel) / sizeof(wszLabel[0])); if (FAILED(hr)) { DBG_WRN(("RefreshDevInfoFromMountPoint, GetMountPointLabel failed - could not get display name - using mount point instead")); lstrcpynW(wszLabel, wszMountPoint, sizeof(wszLabel) / sizeof(wszLabel[0])); }
//
// Update the appropriate fields that rely on the display name.
//
if (pDeviceInfo->wszVendorDescription) { delete [] pDeviceInfo->wszVendorDescription; pDeviceInfo->wszVendorDescription = NULL; } if (pDeviceInfo->wszDeviceDescription) { delete [] pDeviceInfo->wszDeviceDescription; pDeviceInfo->wszDeviceDescription = NULL; } if (pDeviceInfo->wszLocalName) { delete [] pDeviceInfo->wszLocalName; pDeviceInfo->wszLocalName = NULL; }
pDeviceInfo->wszVendorDescription = AllocCopyString(wszLabel); pDeviceInfo->wszDeviceDescription = AllocCopyString(wszLabel); pDeviceInfo->wszLocalName = AllocCopyString(wszLabel);
return Succeeded; }
/**************************************************************************\
* CreateDevInfoForFSDriver * * Create a device info struct containing all the relevant info for our * volume devices. * * Arguments: * * wszMountPoint - The mount point of this volume * * Return Value: * * Pointer to a newly created DEVICE_INFO. NULL on error. * * History: * * 11/06/2000 Original Version * \**************************************************************************/ DEVICE_INFO* CreateDevInfoForFSDriver(WCHAR *wszMountPoint) { HRESULT hr = E_OUTOFMEMORY; DEVICE_INFO *pDeviceInfo = NULL; BOOL bFatalError = FALSE; DWORD dwMajorType = StiDeviceTypeDigitalCamera; DWORD dwMinorType = 1;
WCHAR wszDevId[STI_MAX_INTERNAL_NAME_LENGTH]; WCHAR wszLabel[MAX_PATH];
pDeviceInfo = new DEVICE_INFO; if (!pDeviceInfo) { DBG_WRN(("CWiaDevMan::CreateDevInfoForFSDriver, Out of memory")); return NULL; } memset(pDeviceInfo, 0, sizeof(DEVICE_INFO)); memset(wszDevId, 0, sizeof(wszDevId));
//
// Grab the friendly name of the FS device
//
hr = GetMountPointLabel(wszMountPoint, wszLabel, sizeof(wszLabel) / sizeof(wszLabel[0])); if (FAILED(hr)) { DBG_WRN(("CWiaDevMan::CreateDevInfoForFSDriver, GetMountPointLabel failed - could not get display name - using mount point instead")); lstrcpynW(wszLabel, wszMountPoint, sizeof(wszLabel) / sizeof(wszLabel[0])); }
pDeviceInfo->bValid = FALSE; pDeviceInfo->dwDeviceState = 0;
pDeviceInfo->wszAlternateID = AllocCopyString(wszMountPoint); if (!pDeviceInfo->wszAlternateID) { DBG_WRN(("::CreateDevInfoForFSDriver, out of memory allocating wszAlternateID")); bFatalError = TRUE; }
//
// Construct Device ID. Device ID looks like:
// {MountPoint}
// e.g. {e:\}
//
lstrcpyW(wszDevId, L"{"); //
// We don't want to overrun our internal name length constarint, so we first check
// to see whether the string length of wszMountPoint is short enough to allow concatenation
// of {, }, wszMountPoint and NULL terminator, and still fit all this into a string of
// length STI_MAX_INTERNAL_NAME_LENGTH.
// Note the space after the brackets in sizeof(L"{} ").
//
if (lstrlenW(wszMountPoint) > (STI_MAX_INTERNAL_NAME_LENGTH - (sizeof(L"{} ") / sizeof(WCHAR)))) { //
// The name is too long, so we just insert our own name instead
//
lstrcatW(wszDevId, L"NameTooLong"); } else { lstrcatW(wszDevId, wszMountPoint); } lstrcatW(wszDevId, L"}");
pDeviceInfo->wszDeviceInternalName = AllocCopyString(wszDevId); if (!pDeviceInfo->wszAlternateID) { DBG_WRN(("::CreateDevInfoForFSDriver, out of memory allocating wszDeviceInternalName")); bFatalError = TRUE; } pDeviceInfo->wszDeviceRemoteName = AllocCopyString(wszDevId); if (!pDeviceInfo->wszDeviceRemoteName) { DBG_WRN(("::CreateDevInfoForFSDriver, out of memory allocating wszDeviceRemoteName")); bFatalError = TRUE; } pDeviceInfo->wszPortName = AllocCopyString(wszMountPoint); if (!pDeviceInfo->wszPortName) { DBG_WRN(("::CreateDevInfoForFSDriver, out of memory allocating wszPortName")); bFatalError = TRUE; } pDeviceInfo->wszUSDClassId = AllocCopyString(FS_USD_CLSID); if (!pDeviceInfo->wszUSDClassId) { DBG_WRN(("::CreateDevInfoForFSDriver, out of memory allocating wszUSDClassId")); bFatalError = TRUE; }
//
// We can't get the manufacturer string for these devices, so
// load our standard Manufacturer resource string
// (something like "(Not available)").
//
WCHAR wszManufacturer[32];
INT iRet = LoadStringW(g_hInst, IDS_MSC_MANUFACTURER_STR, wszManufacturer, sizeof(wszManufacturer)/sizeof(wszManufacturer[0])); if (iRet) { pDeviceInfo->wszVendorDescription = AllocCopyString(wszManufacturer); } else { //
// Can't load it, so give it an empty string
//
pDeviceInfo->wszVendorDescription = AllocCopyString(L""); } pDeviceInfo->wszDeviceDescription = AllocCopyString(wszLabel); pDeviceInfo->wszLocalName = AllocCopyString(wszLabel); pDeviceInfo->wszServer = AllocCopyString(LOCAL_DEVICE_STR); pDeviceInfo->wszBaudRate = NULL; pDeviceInfo->wszUIClassId = AllocCopyString(FS_UI_CLSID);
pDeviceInfo->dwDeviceState = DEV_STATE_ACTIVE; pDeviceInfo->DeviceType = MAKELONG(dwMinorType,dwMajorType); pDeviceInfo->dwLockHoldingTime = 0; pDeviceInfo->dwPollTimeout = 0; pDeviceInfo->dwDisableNotifications = 0; pDeviceInfo->DeviceCapabilities.dwVersion = STI_VERSION_REAL; pDeviceInfo->DeviceCapabilities.dwGenericCaps = STI_GENCAP_WIA; pDeviceInfo->dwHardwareConfiguration = HEL_DEVICE_TYPE_WDM; pDeviceInfo->dwInternalType = INTERNAL_DEV_TYPE_WIA | INTERNAL_DEV_TYPE_LOCAL; //
// Check whther this volume is really a camera device representing
// itself as a volume...
//
if (IsMassStorageCamera(wszMountPoint)) { pDeviceInfo->dwInternalType |= INTERNAL_DEV_TYPE_MSC_CAMERA;
//
// Here is a good time to set up the Device's registry entries. We'll call
// g_pDevMan->GetHKeyFromMountPoint(..), since this has the effect of creating
// the keys if the don't exist.
//
HKEY hKeyDev = g_pDevMan->GetHKeyFromMountPoint(wszMountPoint); if (hKeyDev) { RegCloseKey(hKeyDev); } } else { pDeviceInfo->dwInternalType |= INTERNAL_DEV_TYPE_VOL; }
if (!bFatalError) { pDeviceInfo->bValid = TRUE; } else { pDeviceInfo->bValid = FALSE; }
return pDeviceInfo; }
/**************************************************************************\
* CreateDevInfoForRemoteDevice * * Create a device info struct containing all the relevant info for our * remote devices. * * Arguments: * * hKeyDev - Device registry key * * Return Value: * * Pointer to a newly created DEVICE_INFO. NULL on error. * * History: * * 15/02/2001 Original Version * \**************************************************************************/ DEVICE_INFO* CreateDevInfoForRemoteDevice( HKEY hKeyDev) { HRESULT hr = E_OUTOFMEMORY; DEVICE_INFO *pDeviceInfo = NULL; BOOL bFatalError = FALSE;
DWORD dwTemp; WCHAR *wszTemp = NULL;
pDeviceInfo = new DEVICE_INFO; if (!pDeviceInfo) { DBG_WRN(("::CreateDevInfoForRemoteDevice, Out of memory")); return NULL; } memset(pDeviceInfo, 0, sizeof(DEVICE_INFO)); pDeviceInfo->bValid = FALSE;
//
// Always assume remote devices are ACTIVE
//
pDeviceInfo->dwDeviceState = DEV_STATE_ACTIVE;
//
// NOTE: To avoid any alignment faults, we read into &wszTemp, then assign wszTemp to
// the appropriate structure member.
//
hr = AllocReadRegistryString(hKeyDev, WIA_DIP_SERVER_NAME_STR, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for device (%ws)", WIA_DIP_SERVER_NAME_STR, pDeviceInfo->wszServer)); bFatalError = TRUE; } else { pDeviceInfo->wszServer = wszTemp; } hr = AllocReadRegistryString(hKeyDev, WIA_DIP_REMOTE_DEV_ID_STR, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, fatal for device (%ws)", WIA_DIP_REMOTE_DEV_ID_STR, pDeviceInfo->wszDeviceRemoteName)); bFatalError = TRUE; } else { pDeviceInfo->wszDeviceRemoteName = wszTemp; } pDeviceInfo->wszDeviceInternalName = AllocCatString(pDeviceInfo->wszServer, pDeviceInfo->wszDeviceRemoteName); if (!pDeviceInfo->wszDeviceInternalName) { DBG_TRC(("::CreateDevInfoFromHKey, Failed allocate memory for Device Name, fatal for device (%ws)", pDeviceInfo->wszDeviceInternalName)); bFatalError = TRUE; } hr = AllocReadRegistryString(hKeyDev, WIA_DIP_VEND_DESC_STR, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_VEND_DESC_STR, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszVendorDescription = wszTemp; } hr = AllocReadRegistryString(hKeyDev, WIA_DIP_DEV_NAME_STR, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_DEV_NAME_STR, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszLocalName = wszTemp; } hr = AllocReadRegistryString(hKeyDev, WIA_DIP_DEV_DESC_STR, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_DEV_DESC_STR, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszDeviceDescription = wszTemp; } hr = AllocReadRegistryString(hKeyDev, WIA_DIP_PORT_NAME_STR, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_PORT_NAME_STR, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszPortName = wszTemp; } hr = AllocReadRegistryString(hKeyDev, WIA_DIP_UI_CLSID_STR, &wszTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_UI_CLSID_STR, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->wszUIClassId = wszTemp; } hr = ReadRegistryDWORD(hKeyDev, WIA_DIP_DEV_TYPE_STR, &dwTemp); if (FAILED(hr)) { DBG_TRC(("::CreateDevInfoFromHKey, Failed to read %ws, non-fatal for device (%ws)", WIA_DIP_DEV_TYPE_STR, pDeviceInfo->wszDeviceInternalName)); } else { pDeviceInfo->DeviceType = dwTemp; } pDeviceInfo->DeviceCapabilities.dwGenericCaps = STI_GENCAP_WIA;
//
// Set the Internal Device type
//
pDeviceInfo->dwInternalType = INTERNAL_DEV_TYPE_REAL | INTERNAL_DEV_TYPE_WIA;
if (!bFatalError) { pDeviceInfo->bValid = TRUE; } else {
//
// If it's not valid, free the memory
// TDB: Remove the bValid field
//
DestroyDevInfo(pDeviceInfo); pDeviceInfo = NULL; }
return pDeviceInfo; }
/**************************************************************************\
* DestroyDevInfo * * Frees up any resources help by the DEVICE_INFO struct (like strings). * It will then delete the structure itsself. * * Arguments: * * pInfo - Pointer to DEVICE_INFO struct * * Return Value: * * None. * * History: * * 11/06/2000 Original Version * \**************************************************************************/ VOID DestroyDevInfo(DEVICE_INFO *pInfo) { if (pInfo) {
//
// Free struct members first
//
if (pInfo->wszAlternateID) { delete [] pInfo->wszAlternateID; pInfo->wszAlternateID = NULL; } if (pInfo->wszUSDClassId) { delete [] pInfo->wszUSDClassId; pInfo->wszUSDClassId = NULL; } if (pInfo->wszDeviceInternalName) { delete [] pInfo->wszDeviceInternalName; pInfo->wszDeviceInternalName = NULL; } if (pInfo->wszDeviceRemoteName) { delete [] pInfo->wszDeviceRemoteName; pInfo->wszDeviceRemoteName = NULL; } if (pInfo->wszVendorDescription) { delete [] pInfo->wszVendorDescription; pInfo->wszVendorDescription = NULL; } if (pInfo->wszDeviceDescription) { delete [] pInfo->wszDeviceDescription; pInfo->wszDeviceDescription = NULL; } if (pInfo->wszPortName) { delete [] pInfo->wszPortName; pInfo->wszPortName = NULL; } if (pInfo->wszPropProvider) { delete [] pInfo->wszPropProvider; pInfo->wszPropProvider = NULL; } if (pInfo->wszLocalName) { delete [] pInfo->wszLocalName; pInfo->wszLocalName = NULL; } if (pInfo->wszServer) { delete [] pInfo->wszServer; pInfo->wszServer = NULL; } if (pInfo->wszBaudRate) { delete [] pInfo->wszBaudRate; pInfo->wszBaudRate = NULL; } if (pInfo->wszUIClassId) { delete [] pInfo->wszUIClassId; pInfo->wszUIClassId = NULL; }
//
// Now free the struct itsself. NOTE: The caller must
// not attempt to use this pointer again!
//
delete pInfo;
} }
/**************************************************************************\
* DumpDevInfo * * Used for debugging, this dumps a few members of the DEVICE_INFO struct. * * Arguments: * * pInfo - Pointer to DEVICE_INFO struct * * Return Value: * * None. * * History: * * 11/06/2000 Original Version * \**************************************************************************/ VOID DumpDevInfo(DEVICE_INFO *pInfo) { if (pInfo) { DBG_PRT(("------------------------------------------------", pInfo)); DBG_PRT(("::DumpDevInfo (0x%08X)", pInfo)); //
// Output field values we're interested in
//
DBG_PRT(("\t\t bValid (%d)", pInfo->bValid)); DBG_PRT(("\t\t wszLocalName \t(%ws)", pInfo->wszLocalName)); DBG_PRT(("\t\t wszInternalName \t(%ws)", pInfo->wszDeviceInternalName)); DBG_PRT(("\t\t wszRemoteName \t(%ws)", pInfo->wszDeviceRemoteName)); DBG_PRT(("\t\t wszAlternateID \t(%ws)", pInfo->wszAlternateID)); DBG_PRT(("\t\t wszPortName \t(%ws)", pInfo->wszPortName)); DBG_PRT(("\t\t dwInternalType \t(%d)", pInfo->dwInternalType)); DBG_PRT(("------------------------------------------------", pInfo)); } }
/**************************************************************************\
* CreateDevInfoStg * * This helper method takes a DEVICE_INFO struct and creates an * IWiaPropertyStorage filled with the appropriate entries. * * Arguments: * * pInfo - Pointer to DEVICE_INFO struct * * Return Value: * * Pointer to IWiaPropertyStorage. Will be NULL on error. * * History: * * 11/06/2000 Original Version * \**************************************************************************/ IWiaPropertyStorage* CreateDevInfoStg(DEVICE_INFO *pInfo) { CWIADevInfo *pWiaDevInfo = NULL; HRESULT hr = E_FAIL; ULONG ulIndex = 0; WCHAR *wszTmp = NULL; PROPID propid = 0; PROPSPEC propspec[WIA_NUM_DIP]; PROPVARIANT propvar[WIA_NUM_DIP]; WCHAR wszVer[MAX_PATH];
IWiaPropertyStorage *pIWiaPropStg = NULL;
//
// Create the CWIADevInfo class
//
pWiaDevInfo = new CWIADevInfo(); if (!pWiaDevInfo) { return NULL; }
hr = pWiaDevInfo->Initialize(); if (SUCCEEDED(hr)) { //
// Insert the properties
//
// Set the property specifications and data. Order must match DEVMANGR.IDL
memset(propspec, 0, sizeof(PROPSPEC) * WIA_NUM_DIP); memset(propvar, 0, sizeof(VARIANT) * WIA_NUM_DIP); memset(wszVer ,0, sizeof(wszVer));
for (ulIndex = 0; ulIndex < WIA_NUM_DIP; ulIndex++) {
propid = g_piDeviceInfo[ulIndex]; wszTmp = NULL;
// Setup property specification.
propspec[ulIndex].ulKind = PRSPEC_PROPID; propspec[ulIndex].propid = propid;
propvar[ulIndex].vt = VT_BSTR; propvar[ulIndex].bstrVal = NULL;
switch (propid) {
case WIA_DIP_DEV_ID: wszTmp = pInfo->wszDeviceInternalName; break;
case WIA_DIP_REMOTE_DEV_ID: wszTmp = pInfo->wszDeviceRemoteName; break;
case WIA_DIP_SERVER_NAME: wszTmp = pInfo->wszServer; break;
case WIA_DIP_VEND_DESC: wszTmp = pInfo->wszVendorDescription; break;
case WIA_DIP_DEV_DESC: wszTmp = pInfo->wszDeviceDescription; break;
case WIA_DIP_DEV_TYPE: propvar[ulIndex].vt = VT_I4; propvar[ulIndex].lVal = (LONG) pInfo->DeviceType; break;
case WIA_DIP_PORT_NAME: wszTmp = pInfo->wszPortName; break;
case WIA_DIP_DEV_NAME: wszTmp = pInfo->wszLocalName; break;
case WIA_DIP_UI_CLSID: wszTmp = pInfo->wszUIClassId; break;
case WIA_DIP_HW_CONFIG: propvar[ulIndex].vt = VT_I4; propvar[ulIndex].lVal = (LONG) pInfo->dwHardwareConfiguration; break;
case WIA_DIP_BAUDRATE: wszTmp = pInfo->wszBaudRate; break;
case WIA_DIP_STI_GEN_CAPABILITIES: propvar[ulIndex].vt = VT_I4; propvar[ulIndex].lVal = (LONG) pInfo->DeviceCapabilities.dwGenericCaps; break;
case WIA_DIP_WIA_VERSION: wsprintf(wszVer,L"%d.%d",LOWORD(STI_VERSION_REAL),HIWORD(STI_VERSION_REAL)); wszTmp = wszVer; break;
case WIA_DIP_DRIVER_VERSION: if(FALSE == GetDriverDLLVersion(pInfo,wszVer,sizeof(wszVer))){ DBG_WRN(("GetDriverDLLVersion, unable to alloc get driver version resource information, defaulting to 0.0.0.0")); lstrcpyW(wszVer,L"0.0.0.0"); } wszTmp = wszVer; break;
default: hr = E_FAIL; DBG_ERR(("CreateDevInfoStg, Unknown device property")); DBG_ERR((" propid = %li",propid)); }
// Allocate and assign BSTR's.
if (propvar[ulIndex].vt == VT_BSTR) { if (wszTmp) { propvar[ulIndex].bstrVal = SysAllocString(wszTmp); if (!propvar[ulIndex].bstrVal) { DBG_WRN(("CreateDevInfoStg, unable to alloc dev info strings")); } } else { DBG_TRC(("CreateDevInfoStg, NULL device property string")); DBG_TRC((" propid = %li",propid)); propvar[ulIndex].bstrVal = SysAllocString(L"Empty"); } } }
IPropertyStorage *pIPropStg = pWiaDevInfo->m_pIPropStg;
if (pIPropStg) { // Set the device information properties.
hr = pIPropStg->WriteMultiple(WIA_NUM_DIP, propspec, propvar, WIA_DIP_FIRST); // Write the property names.
if (SUCCEEDED(hr)) { hr = pIPropStg->WritePropertyNames(WIA_NUM_DIP, g_piDeviceInfo, g_pszDeviceInfo); if (SUCCEEDED(hr)) { hr = pWiaDevInfo->QueryInterface(IID_IWiaPropertyStorage, (void**) &pIWiaPropStg); } else { DBG_WRN(("CreateDevInfoStg, WritePropertyNames Failed (0x%X)", hr)); } } else { ReportReadWriteMultipleError(hr, "CreateDevInfoStg", NULL, FALSE, WIA_NUM_DIP, propspec); } } else { DBG_WRN(("CreateDevInfoStg, IPropertyStorage is NULL")); hr = E_UNEXPECTED; }
// Free the allocated BSTR's.
FreePropVariantArray(WIA_NUM_DIP, propvar); }
//
// On failure, delete pWiaDevInfo
//
if (FAILED(hr)) { if (pWiaDevInfo) { delete pWiaDevInfo; pWiaDevInfo = NULL; pIWiaPropStg = NULL; } } return pIWiaPropStg; }
/**************************************************************************\
* _CoCreateInstanceInConsoleSession * * This helper function acts the same as CoCreateInstance, but will launch * a out-of-process COM server on the correct user's desktop, taking * fast user switching into account. (Normal CoCreateInstance will * launch it on the first logged on user's desktop, instead of the currently * logged on one). * * This code was taken with permission from the Shell's Hardware * Notification service, on behalf of StephStm. * * Arguments: * * rclsid, // Class identifier (CLSID) of the object
* pUnkOuter, // Pointer to controlling IUnknown
* dwClsContext // Context for running executable code
* riid, // Reference to the identifier of the interface
* ppv // Address of output variable that receives
* // the interface pointer requested in riid
* * Return Value: * * Status * * History: * * 03/01/2001 Original Version * \**************************************************************************/
HRESULT _CoCreateInstanceInConsoleSession(REFCLSID rclsid, IUnknown* punkOuter, DWORD dwClsContext, REFIID riid, void** ppv) { IBindCtx *pbc = NULL; HRESULT hr = CreateBindCtx(0, &pbc); // Create a bind context for use with Moniker
//
// Set the return
//
*ppv = NULL;
if (SUCCEEDED(hr)) { WCHAR wszCLSID[39];
//
// Convert the riid to GUID string for use in binding to moniker
//
if (StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0]))) { ULONG ulEaten = 0; IMoniker* pmoniker = NULL; WCHAR wszDisplayName[sizeof(SESSION_MONIKER)/sizeof(WCHAR) + sizeof(wszCLSID)/sizeof(wszCLSID[0]) + 2] = SESSION_MONIKER;
//
// We want something like: "Session:Console!clsid:760befd0-5b0b-44d7-957e-969af35ce954"
// Notice that we don't want the leading and trailing brackets {..} around the GUID.
// So, first get rid of trailing bracket by overwriting it with termintaing '\0'
//
wszCLSID[lstrlenW(wszCLSID) - 1] = L'\0';
//
// Form display name string. To get rid of the leading bracket, we pass in the
// address of the next character as the start of the string.
//
if (lstrcatW(wszDisplayName, &(wszCLSID[1]))) {
//
// Parse the name and get a moniker:
//
hr = MkParseDisplayName(pbc, wszDisplayName, &ulEaten, &pmoniker); if (SUCCEEDED(hr)) { IClassFactory *pcf = NULL;
//
// Attempt to get the class factory
//
hr = pmoniker->BindToObject(pbc, NULL, IID_IClassFactory, (void**)&pcf); if (SUCCEEDED(hr)) { //
// Attempt to create the object
//
hr = pcf->CreateInstance(punkOuter, riid, ppv);
DBG_TRC(("_CoCreateInstanceInConsoleSession, pcf->CreateInstance returned: hr = 0x%08X", hr)); pcf->Release(); } else {
DBG_WRN(("_CoCreateInstanceInConsoleSession, pmoniker->BindToObject returned: hr = 0x%08X", hr)); } pmoniker->Release(); } else { DBG_WRN(("_CoCreateInstanceInConsoleSession, MkParseDisplayName returned: hr = 0x%08X", hr)); } } else { DBG_WRN(("_CoCreateInstanceInConsoleSession, string concatenation failed")); hr = E_INVALIDARG; } } else { DBG_WRN(("_CoCreateInstanceInConsoleSession, StringFromGUID2 failed")); hr = E_INVALIDARG; }
pbc->Release(); } else { DBG_WRN(("_CoCreateInstanceInConsoleSession, CreateBindCtxt returned: hr = 0x%08X", hr)); }
return hr; }
/**************************************************************************\
* GetUserTokenForConsoleSession * * This helper function will grab the currently logged on interactive * user's token, which can be used in a call to CreateProcessAsUser. * Caller is responsible for closing this Token handle. * * It first grabs the impersontaed token from the current session (our * service runs in session 0, but with Fast User Switching, the currently * active user may be in a different session). It then creates a * primary token from the impersonated one. * * Arguments: * * None * * Return Value: * * HANDLE to Token for logged on user in the currently active session. * NULL otherwise. * * History: * * 03/05/2001 Original Version * \**************************************************************************/
HANDLE GetUserTokenForConsoleSession() { HANDLE hImpersonationToken = NULL; HANDLE hTokenUser = NULL;
//
// Get interactive user's token
//
if (GetWinStationUserToken(GetCurrentSessionID(), &hImpersonationToken)) {
//
// Maybe nobody is logged on, so do a check first.
//
if (hImpersonationToken) {
//
// We duplicate the token, since the returned token is an
// impersonated one, and we need it to be primary for
// use in CreateProcessAsUser.
//
if (!DuplicateTokenEx(hImpersonationToken, 0, NULL, SecurityImpersonation, TokenPrimary, &hTokenUser)) { DBG_WRN(("CEventNotifier::StartCallbackProgram, DuplicateTokenEx failed! GetLastError() = 0x%08X", GetLastError())); } } else { DBG_PRT(("CEventNotifier::StartCallbackProgram, No user appears to be logged on...")); }
} else { DBG_WRN(("CEventNotifier::StartCallbackProgram, GetWinStationUserToken failed! GetLastError() = 0x%08X", GetLastError())); }
//
// Close the impersonated token, since we no longer need it.
//
if (hImpersonationToken) { CloseHandle(hImpersonationToken); }
return hTokenUser; }
/**************************************************************************\
* IsMassStorageCamera * * This helper function will use the shell's CustomDeviceProperty API * to check whether a given volume device (represented by it's mount point) * reports itsself as a digital camera. * * Arguments: * * wszMountPoint - The mount point for a specified volume. * * Return Value: * * TRUE - The custom device property says this device is really a camera * FALSE - This device is not reported as a camera * * History: * * 03/08/2001 Original Version * \**************************************************************************/
BOOL IsMassStorageCamera( WCHAR *wszMountPoint) { HRESULT hr = E_FAIL; IHWDeviceCustomProperties *pIHWDeviceCustomProperties = NULL; BOOL bIsCamera = FALSE;
//
// CoCreate the CLSID_HWDeviceCustomProperties and grab the
// IHWDeviceCustomProperties interface.
//
hr = CoCreateInstance(CLSID_HWDeviceCustomProperties, NULL, CLSCTX_LOCAL_SERVER, IID_IHWDeviceCustomProperties, (VOID**)&pIHWDeviceCustomProperties); if (SUCCEEDED(hr)) {
//
// Make sure we initialize the device property interface, so it
// will know which device we're talking about.
//
hr = pIHWDeviceCustomProperties->InitFromDeviceID(wszMountPoint, HWDEVCUSTOMPROP_USEVOLUMEPROCESSING); if (SUCCEEDED(hr)) {
//
// Check whether this mass storage device is really a camera
//
DWORD dwVal = 0;
hr = pIHWDeviceCustomProperties->GetDWORDProperty(IS_DIGITAL_CAMERA_STR, &dwVal); if (SUCCEEDED(hr) && (dwVal == IS_DIGITAL_CAMERA_VAL)) { bIsCamera = TRUE; } } else { DBG_WRN(("IsMassStorageCamera, Initialize failed with (0x%08X)", hr)); }
pIHWDeviceCustomProperties->Release(); } else { DBG_WRN(("IsMassStorageCamera, CoCreateInstance failed with (0x%08X)", hr)); }
//
// Log whether we think this device is a camera or not
//
DBG_PRT(("IsMassStorageCamera, Returning %ws for drive (%ws)", bIsCamera ? L"TRUE" : L"FALSE", wszMountPoint));
return bIsCamera; }
/**************************************************************************\
* GetMountPointLabel * * This helper function is a replacement for SHGetFileInfoW. It will * fill in the label string of the specified mountpoint. * * Arguments: * * wszMountPoint - The mount point for a specified volume. * pszLabel - Pointer to a caller allocated buffer * cchLabel - Number of characters available in pszLabel * * Return Value: * * Status * * History: * * 03/08/2001 Original Version * \**************************************************************************/
HRESULT GetMountPointLabel(WCHAR* wszMountPoint, LPTSTR pszLabel, DWORD cchLabel) { HRESULT hr = S_OK; BOOL fFoundIt = FALSE; UINT uDriveType = GetDriveTypeW(wszMountPoint);
if (!wszMountPoint) { DBG_WRN(("GetMountPointLabel, called with NULL string")); return E_INVALIDARG; }
if (!fFoundIt) { //
// Grab "Label" property, if it exists
//
//
// CoCreate the CLSID_HWDeviceCustomProperties and grab the
// IHWDeviceCustomProperties interface.
//
IHWDeviceCustomProperties *pIHWDeviceCustomProperties = NULL; hr = CoCreateInstance(CLSID_HWDeviceCustomProperties, NULL, CLSCTX_LOCAL_SERVER, IID_IHWDeviceCustomProperties, (VOID**)&pIHWDeviceCustomProperties); if (SUCCEEDED(hr)) {
//
// Make sure we initialize the device property interface, so it
// will know which device we're talking about.
//
hr = pIHWDeviceCustomProperties->InitFromDeviceID(wszMountPoint, HWDEVCUSTOMPROP_USEVOLUMEPROCESSING); if (SUCCEEDED(hr)) {
//
// Check whether this mass storage device is really a camera
//
LPWSTR pwszLabel = NULL;
hr = pIHWDeviceCustomProperties->GetStringProperty(L"Label", &pwszLabel); if (SUCCEEDED(hr)) { lstrcpynW(pszLabel, pwszLabel, cchLabel); CoTaskMemFree(pwszLabel);
fFoundIt = TRUE; } } else { DBG_WRN(("GetMountPointLabel, Initialize failed with (0x%08X)", hr)); }
pIHWDeviceCustomProperties->Release(); } else { DBG_WRN(("GetMountPointLabel, CoCreateInstance failed with (0x%08X)", hr)); }
//
// Make sure to set hr to S_OK, since it is not a problem if we can't get the
// custom label (one might not exist).
//
hr = S_OK; }
if (!fFoundIt) { //
// If the drive is REMOVABLE, and the mountpoint begins with 'A' or 'B', then it is considered
// a floppy drive. We only want to call GetVolumeInformationW(..) if it is NOT a floppy...
//
if (!((uDriveType == DRIVE_REMOVABLE) && ((towupper(wszMountPoint[0]) == L'A') || (towupper(wszMountPoint[0]) == L'B')))) {
//
// This is not a floppy, so find out its volume info.
//
if (!GetVolumeInformationW(wszMountPoint, pszLabel, cchLabel, NULL, NULL, NULL, NULL, 0)) { //
// Failure case
//
*pszLabel = 0; } else { fFoundIt = TRUE; } } }
if (!fFoundIt) { UINT uResId = 0; INT iRet = 0;
switch (uDriveType) { case DRIVE_REMOVABLE: uResId = IDS_DRIVES_REMOVABLE_STR; break; case DRIVE_CDROM: uResId = IDS_DRIVES_CDROM_STR; break; case DRIVE_FIXED: default: uResId = IDS_DRIVES_FIXED_STR; break; } iRet = LoadString(g_hInst, uResId, pszLabel, cchLabel); if (iRet) {
fFoundIt = TRUE; } else { hr = E_FAIL; } }
if (fFoundIt) {
int iLabelLen = lstrlenW(pszLabel); if ((iLabelLen + (sizeof(L" ()") / sizeof(WCHAR)) + lstrlenW(wszMountPoint)) < cchLabel) { int iLenToChopOff = 1;
lstrcatW(pszLabel, L" ("); lstrcatW(pszLabel, wszMountPoint); lstrcpy(&pszLabel[lstrlenW(pszLabel) - iLenToChopOff], L")"); } } return hr; }
/**************************************************************************\
* GetDriverDLLVersion * * This helper function is for reading a DLL version resource * fill in the label string of the specified mountpoint. * * Arguments: * * wszMountPoint - The mount point for a specified volume. * pszLabel - Pointer to a caller allocated buffer * cchLabel - Number of characters available in pszLabel * * Return Value: * * TRUE - The custom device property says this device is really a camera * FALSE - This device is not reported as a camera * * History: * * 03/08/2001 Original Version * \**************************************************************************/ BOOL GetDriverDLLVersion(DEVICE_INFO *pDeviceInfo, WCHAR *wszVersion, UINT uiSize) { BOOL bSuccess = FALSE; if((NULL == wszVersion)||(NULL == pDeviceInfo)){ return bSuccess; }
//
// clear the version string buffer
//
memset(wszVersion,0,uiSize);
//
// get COM DLL path from registry
//
CLSID clsid; memset(&clsid,0,sizeof(clsid));
if (SUCCEEDED(CLSIDFromString(pDeviceInfo->wszUSDClassId, &clsid))) {
HKEY hk = NULL; LONG lRet = 0; WCHAR wszKey[MAX_PATH + 40];
//
// Look up the CLSID in HKEY_CLASSES_ROOT.
//
swprintf(wszKey, L"CLSID\\%s\\InProcServer32", pDeviceInfo->wszUSDClassId);
lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszKey, 0, KEY_QUERY_VALUE, &hk); if (lRet == ERROR_SUCCESS) {
WCHAR wszDll[MAX_PATH]; memset(wszDll,0,sizeof(wszDll));
LONG cb = 0;
cb = cbX(wszDll); lRet = RegQueryValueW(hk, 0, wszDll, &cb);
if (lRet == ERROR_SUCCESS) {
//
// get version information size
//
DWORD dwFileInfoVersionSize = GetFileVersionInfoSizeW(wszDll,NULL); if (dwFileInfoVersionSize > 0) {
//
// allocate version information buffer
//
void *pFileVersionData = LocalAlloc(LPTR,dwFileInfoVersionSize); if (pFileVersionData) { memset(pFileVersionData,0,(dwFileInfoVersionSize));
//
// fill version information buffer
//
if (GetFileVersionInfoW(wszDll,NULL,dwFileInfoVersionSize, pFileVersionData)) { VS_FIXEDFILEINFO *pFileVersionInfo = NULL; UINT uLen = 0;
//
// extract file version from version information buffer
//
if (VerQueryValue(pFileVersionData,TEXT("\\"),(LPVOID*)&pFileVersionInfo, &uLen)) {
//
// write the dll version resource into the string buffer
//
wsprintf(wszVersion,L"%d.%d.%d.%d", HIWORD(pFileVersionInfo->dwFileVersionMS), LOWORD(pFileVersionInfo->dwFileVersionMS), HIWORD(pFileVersionInfo->dwFileVersionLS), LOWORD(pFileVersionInfo->dwFileVersionLS)); bSuccess = TRUE; } else { DBG_WRN(("GetDriverDLLVersion, VerQueryValue Failed")); } } else { DBG_WRN(("GetDriverDLLVersion, GetFileVersionInfoW Failed")); }
//
// free allocated memory
//
LocalFree(pFileVersionData); pFileVersionData = NULL; } else { DBG_WRN(("GetDriverDLLVersion, Could not allocate memory for file version information")); } } else { DBG_WRN(("GetDriverDLLVersion, File Version Information Size is < 0 (File may be missing version resource)")); } } else { DBG_WRN(("GetDriverDLLVersion, No InprocServer32")); }
//
// close registry KEY
//
RegCloseKey(hk);
} else { DBG_WRN(("GetDriverDLLVersion, CLSID not registered")); } } else { DBG_WRN(("GetDriverDLLVersion, Invalid CLSID string")); }
return bSuccess; }
/**************************************************************************\
* CreateMSCRegEntries * * This helper function creates the registry sub-keys and value entries for * an MSC Camera device. * * Arguments: * * hDevRegKey - The relevent key under MSCDevList, which specifies * which device key we're initializing. * wszMountPoint - The mount point for a specified volume. * * Return Value: * * Status * * History: * * 04/07/2001 Original Version * \**************************************************************************/
HRESULT CreateMSCRegEntries( HKEY hDevRegKey, WCHAR *wszMountPoint) { HRESULT hr = S_OK;
if (hDevRegKey && wszMountPoint) { DWORD dwError = 0; DWORD dwDisposition = 0; HKEY hKey = NULL;
//
// Write the DeviceID. This is used to retsore event handlers for this device.
//
WCHAR wszInternalName[STI_MAX_INTERNAL_NAME_LENGTH];
//
// Make sure that there is enough space to enclose the mount point in {}.
//
if (lstrlenW(wszMountPoint) < (STI_MAX_INTERNAL_NAME_LENGTH - lstrlenW(L"{}"))) { wsprintf(wszInternalName, L"{%ws}", wszMountPoint);
dwError = RegSetValueEx(hDevRegKey, REGSTR_VAL_DEVICE_ID_W, 0, REG_SZ, (BYTE*)wszInternalName, sizeof(wszInternalName)); }
//
// Create the DeviceData sub-key
//
dwError = RegCreateKeyExW(hDevRegKey, REGSTR_VAL_DATA_W, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition); if (dwError == ERROR_SUCCESS) { //
// We created the DeviceData sub-key. We need to add
// color profile entry
//
WCHAR wszSRGB[MAX_PATH]; DWORD dwSize = 0;
//
// We insert sRGB as the color profile. We don't hardcode the
// name, so call the API to get it... Notice
// that the entry is a double NULL terminated list, so we
// set the size parameter to exclude the last 2 characters,
// so we're guaranteed to have 2 NULLs at the end.
//
memset(wszSRGB, 0, sizeof(wszSRGB)); dwSize = sizeof(wszSRGB) - sizeof(L"\0\0"); if (GetStandardColorSpaceProfileW(NULL, LCS_sRGB, wszSRGB, &dwSize)) { //
// We must calculate the number of bytes in this string,
// remembering to include the size for two terminating NULLs.
//
dwSize = (lstrlenW(wszSRGB) * sizeof(wszSRGB[0])) + sizeof("\0\0");
//
// Let's write the color profile entry.
//
dwError = RegSetValueEx(hKey, NULL, 0, REG_BINARY, (BYTE*)wszSRGB, dwSize); } else { DBG_WRN(("CreateMSCRegEntries, GetStandardColorSpaceProfile failed!")); }
//
// Nothing left to do with this key, so close it.
//
RegCloseKey(hKey); hKey = NULL; dwDisposition = 0; }
//
// Create the Events sub-key
//
dwError = RegCreateKeyExW(hDevRegKey, EVENTS, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition); if (dwError == ERROR_SUCCESS) {
//
// We created the Events sub-key. Let's fill in some event info
//
WCHAR wszCLSID[39]; // {GUID} is 38 characters long, 39 including NULL
HKEY hKeyTemp = NULL;
if (StringFromGUID2(WIA_EVENT_DEVICE_CONNECTED, wszCLSID, sizeof(wszCLSID) / sizeof(wszCLSID[0]))) {
//
// Create the entry for WIA_EVENT_DEVICE_CONNECTED
//
dwError = RegCreateKeyExW(hKey, WIA_EVENT_DEVICE_CONNECTED_STR, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyTemp, &dwDisposition); if (dwError == ERROR_SUCCESS) {
//
// Fill in the values for the sub-key.
// The result is as follows:
// [Device connected]
// Default: "Device connected"
// GUID: "{a28bbade-x64b6-11d2-a231-00c0-4fa31809}"
// LaunchApplications: "*"
//
// Note that we don't care about error returns.
//
dwError = RegSetValueEx(hKeyTemp, NULL, 0, REG_SZ, (BYTE*)WIA_EVENT_DEVICE_CONNECTED_STR, sizeof(WIA_EVENT_DEVICE_CONNECTED_STR)); dwError = RegSetValueEx(hKeyTemp, REGSTR_VAL_GUID_W, 0, REG_SZ, (BYTE*)wszCLSID, sizeof(wszCLSID)); dwError = RegSetValueEx(hKeyTemp, REGSTR_VAL_LAUNCH_APPS_W, 0, REG_SZ, (BYTE*)L"*", sizeof(L"*")); RegCloseKey(hKeyTemp); hKeyTemp = NULL; } } else { DBG_WRN(("::CreateMSCRegEntries, StringFromGUID2 for WIA_EVENT_DEVICE_CONNECTED failed!")); }
RegCloseKey(hKey); hKey = NULL; dwDisposition = 0; } } else { DBG_WRN(("::CreateMSCRegEntries, Can't have NULL parameters!")); }
return hr; }
|