|
|
/*******************************************************************************
* * (C) COPYRIGHT MICROSOFT CORP., 1998 * * TITLE: DevInfo.Cpp * * VERSION: 2.0 * * AUTHOR: ReedB * * DATE: 9 Jan, 1998 * * DESCRIPTION: * Implementation for WIA device enumeration and information interface. * *******************************************************************************/ #include "precomp.h"
#include "stiexe.h"
#include "wiamindr.h"
#include "wia.h"
#include "devmgr.h"
#include "devinfo.h"
#include "helpers.h"
#define REGSTR_PATH_STICONTROL_DEVLIST_W L"System\\CurrentControlSet\\Control\\StillImage\\DevList"
#define REGSTR_PATH_STI_CLASS_W L"{6BDD1FC6-810F-11D0-BEC7-08002BE2092F}"
typedef struct _WIA_REMOTE_DEVICE { HKEY hKeyDevice; WCHAR wszDevName[MAX_PATH]; }WIA_REMOTE_DEVICE,*PWIA_REMOTE_DEVICE;
/**************************************************************************\
* GetPropID * * This method takes in a PROPSPEC and returns a PROPSPEC with the * whose ulKind field is always PRSPEC_PROPID. So if the input PROPSPEC * is a PropID, then it is simply copied to the output parameter, else * if it is identified by a name, then the name is looked up and the * corresponding PropId is returned in the output parameter. * * Arguments: * * pWiaPropStg - The property storage to work from * pPropSpecIn - A pointer to the input PROPSPEC containing the * property name. * pPropSpecOut - A pointer to a PROPSPEC where the corresponding * PropID will be put. * * Return Value: * * Status - An E_INVALIDARG will be returned if the property * is not found. If it is, then S_OK will be returned. * If an error occurs getting the enumerator from the * property storage, then that error is returned. * * History: * * 27/4/1998 Original Version * \**************************************************************************/
HRESULT GetPropID( IWiaPropertyStorage *pWiaPropStg, PROPSPEC *pPropSpecIn, PROPSPEC *pPropSpecOut) { HRESULT hr; IEnumSTATPROPSTG *pIEnum;
if (!pWiaPropStg) { DBG_ERR(("::GetPropIDFromName, property storage argument is NULL!")); return E_INVALIDARG; }
//
// If pPropSpecIn is a PropID, simply copy to pPropSpecOut
//
if (pPropSpecIn->ulKind == PRSPEC_PROPID) { pPropSpecOut->ulKind = PRSPEC_PROPID; pPropSpecOut->propid = pPropSpecIn->propid; return S_OK; }
hr = pWiaPropStg->Enum(&pIEnum); if (FAILED(hr)) { DBG_ERR(("::GetPropIDFromName, error getting IEnumSTATPROPSTG!")); return hr; }
//
// Go through properties
//
STATPROPSTG statProp; ULONG celtFetched;
statProp.lpwstrName = NULL; for (celtFetched = 1; celtFetched > 0; pIEnum->Next(1, &statProp, &celtFetched)) { if (statProp.lpwstrName) { if ((wcscmp(statProp.lpwstrName, pPropSpecIn->lpwstr)) == 0) {
//
// Found the right one, so get it's PropID
//
pPropSpecOut->ulKind = PRSPEC_PROPID; pPropSpecOut->propid = statProp.propid;
pIEnum->Release(); CoTaskMemFree(statProp.lpwstrName); return S_OK; }
//
// Free the property name
//
CoTaskMemFree(statProp.lpwstrName); statProp.lpwstrName = NULL; }
}
pIEnum->Release();
//
// Property not found
//
return E_INVALIDARG; }
/**************************************************************************\
* EnumRemoteDevices * * * * Arguments: * * * * Return Value: * * Status * * History: * * 1/4/1999 Original Version * \**************************************************************************/
HRESULT EnumRemoteDevices(DWORD *pnDevices,WIA_REMOTE_DEVICE **ppRemDev) { DBG_FN(::EnumRemoteDevices); *pnDevices = 0;
DWORD numDev = 0; HRESULT hr = S_OK;
//
// find remote device entry in registry
//
LPWSTR szKeyName = REGSTR_PATH_STICONTROL_DEVLIST_W;
HKEY hKeySetup,hKeyDevice; LONG lResult;
if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ | KEY_WRITE, &hKeySetup) == ERROR_SUCCESS) {
//
// look for machine names
//
WCHAR wszTemp[MAX_PATH+1];
LONG MachineIndex = 0;
//
// go through once to find number
//
do {
lResult = RegEnumKeyW(hKeySetup,MachineIndex++,wszTemp,MAX_PATH+1);
if (lResult == ERROR_SUCCESS) { numDev++; }
} while (lResult == ERROR_SUCCESS);
//
// allocate array for return values
//
PWIA_REMOTE_DEVICE pRemDev = (PWIA_REMOTE_DEVICE)LocalAlloc(LPTR,numDev * sizeof(WIA_REMOTE_DEVICE)); *ppRemDev = pRemDev;
if (pRemDev == NULL) { RegCloseKey(hKeySetup); DBG_ERR(("EnumRemoteDevices: failed to allcate memory for Remote device")); return E_OUTOFMEMORY; }
//
// go through enumeration again, open key and copy name and key to buffer
//
MachineIndex = 0;
do {
lResult = RegEnumKeyW(hKeySetup,MachineIndex,wszTemp,MAX_PATH+1);
if (lResult == ERROR_SUCCESS) {
lResult = RegOpenKeyExW (hKeySetup, wszTemp, 0, KEY_READ | KEY_WRITE, &hKeyDevice);
if (lResult == ERROR_SUCCESS) {
(*pnDevices)++;
lstrcpyW(pRemDev[MachineIndex].wszDevName,wszTemp);
pRemDev[MachineIndex].hKeyDevice = hKeyDevice;
MachineIndex++;
} else { DBG_ERR(("EnumRemoteDevices: failed RegOpenKeyExW, status = %lx",lResult)); }
}
} while (lResult == ERROR_SUCCESS);
} return hr; }
/**************************************************************************\
* SetWIARemoteDevInfoProperties * * Create a property storage on given stream and then write WIA and * STI device information into the device info properties. * * Arguments: * * pSti - sti object * pStm - return stream * pSdi - sti information on current device * * Return Value: * * status * * History: * * 9/2/1998 Original Version * \**************************************************************************/
HRESULT SetWIARemoteDevInfoProperties( LPSTREAM pStm, PWIA_REMOTE_DEVICE pRemoteDevice) { DBG_FN(::SetWIARemoteDevInfoProperties); UINT i; HRESULT hr; LONG lResult; IPropertyStorage *pPropStg = NULL; PROPSPEC propspec[WIA_NUM_DIP]; PROPVARIANT propvar[WIA_NUM_DIP];
//
// Create an IPropertyStorage on the stream.
//
hr = StgCreatePropStg(pStm, FMTID_NULL, &CLSID_NULL, PROPSETFLAG_DEFAULT, 0, &pPropStg);
if (SUCCEEDED(hr)) {
//
// Set the property specifications and data. Order must match
// the property order in devmangr.idl and wia.h.
//
memset(propspec, 0, sizeof(PROPSPEC) * WIA_NUM_DIP); memset(propvar, 0, sizeof(VARIANT) * WIA_NUM_DIP);
DWORD dwType; DWORD dwSize;
for (i = 0; i < WIA_NUM_DIP; i++) {
PROPID propid = g_piDeviceInfo[i];
propspec[i].ulKind = PRSPEC_PROPID; propspec[i].propid = propid;
propvar[i].vt = VT_BSTR;
switch (propid) {
case WIA_DIP_DEV_ID: case WIA_DIP_SERVER_NAME: case WIA_DIP_VEND_DESC: case WIA_DIP_DEV_DESC: case WIA_DIP_PORT_NAME: case WIA_DIP_DEV_NAME: case WIA_DIP_REMOTE_DEV_ID: case WIA_DIP_UI_CLSID: case WIA_DIP_BAUDRATE:
WCHAR szTemp[MAX_PATH];
dwType = REG_SZ; dwSize = MAX_PATH;
lResult = RegQueryValueExW(pRemoteDevice->hKeyDevice, g_pszDeviceInfo[i], 0, &dwType, (LPBYTE)szTemp, &dwSize);
if (lResult == ERROR_SUCCESS) { propvar[i].bstrVal = SysAllocString(szTemp);
if (!propvar[i].bstrVal) { DBG_ERR(("SetWIARemoteDevInfoProperties, unable to alloc dev info strings")); } } else { DBG_ERR(("SetWIARemoteDevInfoProperties, RegQueryValueExW failed")); DBG_ERR((" error: %d, propid = %li", lResult, propid));
hr = HRESULT_FROM_WIN32(lResult); propvar[i].bstrVal = NULL; } break;
case WIA_DIP_DEV_TYPE: { DWORD dwValue; dwType = REG_DWORD; dwSize = sizeof(DWORD);
lResult = RegQueryValueExW(pRemoteDevice->hKeyDevice, g_pszDeviceInfo[i], 0, &dwType, (LPBYTE)&dwValue, &dwSize);
if (lResult == ERROR_SUCCESS) { propvar[i].vt = VT_I4; propvar[i].lVal = (LONG)dwValue; } else { DBG_ERR(("SetWIARemoteDevInfoProperties, RegQueryValueExW failed")); DBG_ERR((" error: %d, propid = %li", lResult, propid)); hr = HRESULT_FROM_WIN32(lResult); } } break;
case WIA_DIP_HW_CONFIG: { DWORD dwValue; dwType = REG_DWORD; dwSize = sizeof(DWORD);
lResult = RegQueryValueExW(pRemoteDevice->hKeyDevice, REGSTR_VAL_HARDWARE_W, 0, &dwType, (LPBYTE)&dwValue, &dwSize);
if (lResult == ERROR_SUCCESS) { propvar[i].vt = VT_I4; propvar[i].lVal = (LONG)dwValue; } else { DBG_ERR(("SetWIARemoteDevInfoProperties, RegQueryValueExW failed")); DBG_ERR((" error: %d, propid = %li", lResult, propid)); hr = HRESULT_FROM_WIN32(lResult); } } break; case WIA_DIP_STI_GEN_CAPABILITIES: { DWORD dwValue; dwType = REG_DWORD; dwSize = sizeof(DWORD);
lResult = RegQueryValueExW(pRemoteDevice->hKeyDevice, REGSTR_VAL_GENERIC_CAPS_W, 0, &dwType, (LPBYTE)&dwValue, &dwSize);
if (lResult == ERROR_SUCCESS) { propvar[i].vt = VT_I4; propvar[i].lVal = (LONG)dwValue; } else { DBG_ERR(("SetWIARemoteDevInfoProperties, RegQueryValueExW failed")); DBG_ERR((" error: %d, propid = %li", lResult, propid)); hr = HRESULT_FROM_WIN32(lResult); } } break;
default: hr = E_FAIL; DBG_ERR(("SetWIARemoteDevInfoProperties, Unknown device property")); DBG_ERR((" propid = %li",propid)); } }
//
// Set the properties for a device
//
if (SUCCEEDED(hr)) { hr = pPropStg->WriteMultiple(WIA_NUM_DIP, propspec, propvar, WIA_DIP_FIRST);
//
// write property names
//
if (SUCCEEDED(hr)) {
hr = pPropStg->WritePropertyNames(WIA_NUM_DIP, g_piDeviceInfo, g_pszDeviceInfo); if (FAILED(hr)) { DBG_ERR(("SetWIARemoteDevInfoProperties, WritePropertyNames failed (0x%X)", hr)); } } else { ReportReadWriteMultipleError(hr, "SetWIARemoteDevInfoProperties", NULL, FALSE, WIA_NUM_DIP, propspec); } }
// Free the allocated BSTR's.
FreePropVariantArray(WIA_NUM_DIP, propvar);
pPropStg->Release(); } else { DBG_ERR(("SetWIARemoteDevInfoProperties, StgCreatePropStg Failed")); } return hr; }
/**************************************************************************\
* * QueryInterface * AddRef * Release * * Arguments: * * standard * * Return Value: * * status * * History: * * 9/2/1998 original version * \**************************************************************************/
HRESULT _stdcall CEnumWIADevInfo::QueryInterface(const IID& iid, void** ppv) { *ppv = NULL;
if (iid == IID_IUnknown || iid == IID_IEnumWIA_DEV_INFO) { *ppv = (IEnumWIA_DEV_INFO*) this; } else { return E_NOINTERFACE; } AddRef(); return S_OK; }
ULONG _stdcall CEnumWIADevInfo::AddRef() { InterlockedIncrement((long*) &m_cRef); return m_cRef; }
ULONG _stdcall CEnumWIADevInfo::Release() { ULONG ulRefCount = m_cRef - 1;
if (InterlockedDecrement((long*) &m_cRef) == 0) { delete this; return 0; } return ulRefCount; }
/**************************************************************************\
* CEnumWIADevInfo::CEnumWIADevInfo * * Init basic class info * * Arguments: * * none * * Return Value: * * none * * History: * * 9/2/1998 * \**************************************************************************/
CEnumWIADevInfo::CEnumWIADevInfo() { m_cRef = 0; m_lType = 0; m_pIWiaPropStg = NULL; m_cDevices = 0; m_ulIndex = 0;
//
// We're creating a component that exposes interfaces to clients, so
// inform service to make sure service wont shutdown prematurely.
//
CWiaSvc::AddRef(); }
/**************************************************************************\
* CEnumWIADevInfo::Initialize * * Get list of all devices from sti, then creat a stream for each device. * Write all the device info properties for each device into each stream. * * Arguments: * * lType - type of device this enumerator is being created for * pSti - sti object * * Return Value: * * status * * History: * * 9/2/1998 initial version * 07/06/1999 Changed to intialize entrie array of Dev. Info. storages * \**************************************************************************/
HRESULT CEnumWIADevInfo::Initialize( LONG lType) {
DBG_FN(CEnumWIADevInfo::Initialize);
HRESULT hr = E_FAIL; DWORD cDevices = 0;
hr = g_pDevMan->GetDevInfoStgs(lType, &m_cDevices, &m_pIWiaPropStg); // TBD: What about remote devices?
return hr; }
/**************************************************************************\
* CEnumWIADevInfo::~CEnumWIADevInfo * * Release and free the backing property streams for each device * * Arguments: * * none * * Return Value: * * none * * History: * * 9/2/1998 * \**************************************************************************/
CEnumWIADevInfo::~CEnumWIADevInfo() { DBG_FN(CEnumWIADevInfo::~CEnumWIADevInfo);
if (m_pIWiaPropStg) { for (ULONG index = 0; index < m_cDevices; index++) { if (m_pIWiaPropStg[index]) { m_pIWiaPropStg[index]->Release(); m_pIWiaPropStg[index] = NULL; } }
delete[] m_pIWiaPropStg; m_pIWiaPropStg = NULL; }
//
// Component is destroyed, so no more interfaces are exposed from here.
// Inform server by decrementing it's reference count. This will allow
// it to shutdown if it's no longer needed.
//
CWiaSvc::Release(); }
/**************************************************************************\
* CEnumWIADevInfo::Next * * Get the next propstg(s) in the enumerator and return. * Next_Proxy ensures that last parameter is non-NULL. * * Arguments: * * celt - number of property storages requested * rgelt - return propstg array * pceltFetched - number of property storages returned * * Return Value: * * status * * History: * * 9/2/1998 * \**************************************************************************/
HRESULT __stdcall CEnumWIADevInfo::Next( ULONG celt, IWiaPropertyStorage **rgelt, ULONG *pceltFetched) { DBG_FN(CEnumWIADevInfo::Next); HRESULT hr = S_FALSE; ULONG ulCount;
DBG_TRC(("CEnumWIADevInfo::Next, celt=%d ", celt));
*pceltFetched = 0;
//
// Validate parameters
//
if (celt == 0) { return(S_OK); }
//
// Check whether any more elements exist to enumerate through.
//
if ((m_ulIndex >= m_cDevices)) { return S_FALSE; }
//
// Check that the requested number of elements exist. If not,
// set ulCount to the remaining number of elements.
//
if (celt > (m_cDevices - m_ulIndex)) { ulCount = m_cDevices - m_ulIndex; } else { ulCount = celt; }
memset(rgelt, 0, sizeof(IWiaPropertyStorage*) * celt);
//
// Return the requested elements
//
for (ULONG index = 0; index < ulCount; index++) { hr = m_pIWiaPropStg[m_ulIndex]->QueryInterface(IID_IWiaPropertyStorage, (void**) &rgelt[index]); if (FAILED(hr)) { DBG_ERR(("CEnumWIADevInfo::Next, QI for IPropertyStorage failed")); break; } m_ulIndex++; }
if (FAILED(hr)) { for (ULONG index = 0; index < ulCount; index++) { if (rgelt[index]) { rgelt[index]->Release(); rgelt[index] = NULL; } } }
*pceltFetched = ulCount;
DBG_TRC(("CEnumWIADevInfo::Next exiting ulCount=%d *pceltFetched=%d hr=0x%X rgelt[0]=0x%lX", ulCount,*pceltFetched,hr,rgelt[0]));
//
// Return S_FALSE if we returned less elements than requested
//
if (ulCount < celt) { hr = S_FALSE; } return hr; }
/**************************************************************************\
* CEnumWIADevInfo::Skip * * Skip a number of entries in the enumerator * * Arguments: * * celt - number to skip * * Return Value: * * status * * History: * * 9/2/1998 * \**************************************************************************/
HRESULT __stdcall CEnumWIADevInfo::Skip(ULONG celt) { DBG_FN(CEnumWIADevInfo::Skip); //
// Check that we actually have a device list and that we don't
// exceed the number of elements
//
if((m_pIWiaPropStg) && ((m_ulIndex + celt) < m_cDevices)) { m_ulIndex += celt; return S_OK; } return S_FALSE; }
/**************************************************************************\
* CEnumWIADevInfo::Reset * * reset enumerator to first item * * Arguments: * * none * * Return Value: * * status * * History: * * 9/2/1998 Original Version * \**************************************************************************/
HRESULT __stdcall CEnumWIADevInfo::Reset(void) { DBG_FN(CEnumWIADevInfo::Reset); m_ulIndex = 0; return S_OK; }
/**************************************************************************\
* CEnumWIADevInfo::Clone * * Create a new enumerator and start it at the same location * this enumerator is running * * Arguments: * * ppenum return new enumerator interface * * Return Value: * * status * * History: * * 9/2/1998 Original Version * \**************************************************************************/
HRESULT __stdcall CEnumWIADevInfo::Clone(IEnumWIA_DEV_INFO **ppenum) { DBG_FN(CEnumWIADevInfo::Clone); HRESULT hr = S_OK; CEnumWIADevInfo* pClone=NULL;
pClone = new CEnumWIADevInfo();
if (!pClone) { return E_OUTOFMEMORY; }
hr = pClone->Initialize(m_lType); if (FAILED(hr)) { delete pClone; return hr; }
pClone->m_ulIndex = m_ulIndex; hr = pClone->QueryInterface(IID_IEnumWIA_DEV_INFO, (void**) ppenum); if (FAILED(hr)) { delete pClone; DBG_ERR(("CEnumWIADevInfo::Clone, QI for IWiaPropertyStorage failed")); return hr; } return S_OK; }
/**************************************************************************\
* GetCount * * Returns the number of elements stored in this enumerator. * * Arguments: * * pcelt - address of ULONG where to put the number of elements. * * Return Value: * * Status - S_OK if successful * E_FAIL if failed * * History: * * 05/07/99 Original Version * \**************************************************************************/ HRESULT _stdcall CEnumWIADevInfo::GetCount(ULONG *pcelt) { DBG_FN(CEnumWIADevInfo::GetCount); if (IsBadWritePtr(pcelt, sizeof(ULONG))) { return E_POINTER; } else { *pcelt = 0; }
//
// Check that we actually have a list and that the count
// has a non-zero value.
//
if(m_cDevices && m_pIWiaPropStg) {
*pcelt = m_cDevices; } return S_OK; }
/**************************************************************************\
* * QueryInterface * AddRef * Release * * Arguments: * * * * Return Value: * * * * History: * * 9/2/1998 Original Version * \**************************************************************************/
HRESULT _stdcall CWIADevInfo::QueryInterface(const IID& iid, void** ppv) { *ppv = NULL;
if (iid == IID_IUnknown || iid == IID_IWiaPropertyStorage) { *ppv = (IWiaPropertyStorage*) this; } else if (iid == IID_IPropertyStorage) { *ppv = (IPropertyStorage*) this; } else { return E_NOINTERFACE; } AddRef(); return S_OK; }
ULONG _stdcall CWIADevInfo::AddRef() { InterlockedIncrement((long*) &m_cRef); return m_cRef; }
ULONG _stdcall CWIADevInfo::Release() { ULONG ulRefCount = m_cRef - 1;
if (InterlockedDecrement((long*) &m_cRef) == 0) { delete this; return 0; } return ulRefCount; }
/**************************************************************************\
* CWIADevInfo::CWIADevInfo * * init empty object * * Arguments: * * none * * Return Value: * * none * * History: * * 9/2/1998 Original Version * \**************************************************************************/
CWIADevInfo::CWIADevInfo() { m_cRef = 0; m_pITypeInfo = NULL; m_pIPropStg = NULL; m_pIStm = NULL;
//
// We're creating a component that exposes interfaces to clients, so
// inform service to make sure service wont shutdown prematurely.
//
CWiaSvc::AddRef(); }
/**************************************************************************\
* CopyItemProp * * This helper method copies a single property from source to destination. * * Arguments: * * pIPropStgSrc - The IPropertyStorage that contains the property to * copy. * pIPropStgDst - The IPropertyStorage where the value is copied to. * pps - The PROPSPEC which specifies the source property. * pszErr - A string that will be printed out when an error * occurs. * Return Value: * * Status - Returns HRESULT from ReadMultiple and WriteMultiple. * * History: * * 28/04/1999 Original Version * \**************************************************************************/
HRESULT CopyItemProp( IPropertyStorage *pIPropStgSrc, IPropertyStorage *pIPropStgDst, PROPSPEC *pps, LPSTR pszErr) { DBG_FN(::CopyItemProp); PROPVARIANT pv[1];
HRESULT hr = pIPropStgSrc->ReadMultiple(1, pps, pv); if (SUCCEEDED(hr)) {
hr = pIPropStgDst->WriteMultiple(1, pps, pv, WIA_DIP_FIRST); if (FAILED(hr)) { ReportReadWriteMultipleError(hr, "CopyItemProp", pszErr, FALSE, 1, pps); } PropVariantClear(pv); } else { ReportReadWriteMultipleError(hr, "CopyItemProp", pszErr, TRUE, 1, pps); } return hr; }
/**************************************************************************\
* CWIADevInfo::Initialize * * Initialize DevInfo object with a stream, the stream must already be * filled out with device information properties * * Arguments: * * pIStream - data stream for the device * * Return Value: * * status * * History: * * 9/2/1998 Original Version * \**************************************************************************/
HRESULT CWIADevInfo::Initialize() { DBG_FN(CWIADevInfo::Initialize); HRESULT hr;
hr = CreateStreamOnHGlobal(NULL, TRUE, &m_pIStm); if (SUCCEEDED(hr)) {
//
// Open a property storage on the stream.
//
hr = StgCreatePropStg(m_pIStm, FMTID_NULL, &CLSID_NULL, PROPSETFLAG_DEFAULT, 0, &m_pIPropStg);
if (FAILED(hr)) { DBG_ERR(("CWIADevInfo::Initialize, StgOpenPropStg failed (0x%X)", hr)); } } else { DBG_ERR(("CWIADevInfo::Initialize, CreateStreamOnHGlobal failed (0x%X)", hr)); }
return hr; }
/**************************************************************************\
* CWIADevInfo::~CWIADevInfo * * release references to stream and typeInfo * * Arguments: * * none * * Return Value: * * none * * History: * * 9/2/1998 Original Version * \**************************************************************************/
CWIADevInfo::~CWIADevInfo() { DBG_FN(CWIADevInfo::~CWIADevInfo);
if (m_pIPropStg) { m_pIPropStg->Release(); m_pIPropStg = NULL; }
if (m_pIStm) { m_pIStm->Release(); m_pIStm = NULL; }
if (m_pITypeInfo) { m_pITypeInfo->Release(); }
//
// Component is destroyed, so no more interfaces are exposed from here.
// Inform server by decrementing it's reference count. This will allow
// it to shutdown if it's no longer needed.
//
CWiaSvc::Release(); }
/**************************************************************************\
* UpdateDeviceProperties * * Helper function for CWIADevInfo::WriteMultiple. It is used to change * the Device properties which are stored in the registry. * * Arguments: * * cpspec - count of properties to write. * rgpspec - PROPSPEC identifying the properties to write. Caller * ensures that these are of type PRSPEC_PROPID. * rgpropvar - PROPVARIANT array containing the values to write. * * Return Value: * * Status * * History: * * 26/08/1999 Original Version * \**************************************************************************/
HRESULT CWIADevInfo::UpdateDeviceProperties( ULONG cpspec, const PROPSPEC *rgpspec, const PROPVARIANT *rgpropvar) { DBG_FN(CWIADevInfo::UpdateDeviceProperties); ACTIVE_DEVICE *pActiveDevice = NULL; DEVICE_INFO *pDeviceInfo = NULL; PROPSPEC ps[1] = {{PRSPEC_PROPID, WIA_DIP_DEV_ID}}; PROPVARIANT pvDevID[1]; PSTI pSti; HRESULT hr = S_OK;
WCHAR *wszSavedLocalName = NULL; WCHAR *wszSavedPortName = NULL; WCHAR *wszSavedBaudRate = NULL;
//
// Get the DeviceID
//
PropVariantInit(pvDevID); hr = ReadMultiple(1, ps, pvDevID); if (hr == S_OK) {
//
// Use the DeviceID to get the corresponding ACTIVE_DEVICE
//
pActiveDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_DEV_ID, pvDevID->bstrVal); if (pActiveDevice) { TAKE_ACTIVE_DEVICE t(pActiveDevice);
pDeviceInfo = pActiveDevice->m_DrvWrapper.getDevInfo(); if (pDeviceInfo) {
//
// Update the pDevInfo struct values to the new values from
// rgpropvar. Inside this loop is where we update pDevInfo
// with all the fields we recognize. So far, these are:
// WIA_DIP_DEV_NAME
// WIA_DIP_PORT_NAME
// WIA_DIP_BAUDRATE
//
for (ULONG index = 0; index < cpspec; index++) {
//
// If the FriendlyName is being changed,
// then set the local name in pDevInfo.
// Make sure to free the old one before allocating the new one.
//
if (rgpspec[index].propid == WIA_DIP_DEV_NAME) {
//
// Check the the friendly name is not blank or null
//
//
// NOTE: The Shell should check for blank names, not us.
// However, it is safest to do it here...
//
if (rgpropvar[index].bstrVal) {
if (wcslen(rgpropvar[index].bstrVal) > 0) {
//
// Set the new local name. Save the old value, in case the
// update fails and we need to roll back.
//
wszSavedLocalName = pDeviceInfo->wszLocalName;
pDeviceInfo->wszLocalName = AllocCopyString(rgpropvar[index].bstrVal); if (!pDeviceInfo->wszLocalName) { DBG_ERR(("CWIADevInfo::UpdateDeviceProperties, Out of memory")); hr = E_OUTOFMEMORY; } } else { DBG_ERR(("CWIADevInfo::UpdateDeviceProperties, WIA_DIP_DEV_NAME is blank")); hr = E_INVALIDARG; break; } } else { DBG_ERR(("CWIADevInfo::UpdateDeviceProperties, WIA_DIP_DEV_NAME is NULL")); hr = E_INVALIDARG; break; } }
//
// If the port name is being changed, set it in pDeviceInfo.
//
if (rgpspec[index].propid == WIA_DIP_PORT_NAME) {
//
// Set the new port name. Save the old value, in case the
// update fails and we need to roll back.
//
wszSavedPortName = pDeviceInfo->wszPortName; pDeviceInfo->wszPortName = AllocCopyString(rgpropvar[index].bstrVal); if (!pDeviceInfo->wszPortName) { DBG_ERR(("CWIADevInfo::UpdateDeviceProperties, Out of memory")); hr = E_OUTOFMEMORY; } }
//
// If the baudrate is being changed, set it in pDeviceInfo.
//
if (rgpspec[index].propid == WIA_DIP_BAUDRATE) { //
// Set the new baudrate. Save the old value, in case the
// update fails and we need to roll back.
//
wszSavedBaudRate = pDeviceInfo->wszBaudRate; pDeviceInfo->wszBaudRate = AllocCopyString(rgpropvar[index].bstrVal); if (!pDeviceInfo->wszBaudRate) { DBG_ERR(("CWIADevInfo::UpdateDeviceProperties, Out of memory")); hr = E_OUTOFMEMORY; } } }
}
if (SUCCEEDED(hr)) {
//
// Write the changes to the registry
//
hr = g_pDevMan->UpdateDeviceRegistry(pDeviceInfo); }
//
// Release the ACTIVE_DEVICE since it was AddRef'd by IsInList(...)
//
pActiveDevice->Release(); }
//
// Free the propvariant data
//
PropVariantClear(pvDevID); } else { DBG_ERR(("CWIADevInfo::UpdateDeviceProperties, could not read the DeviceID (0x%X)", hr)); }
//
// Do cleanup
//
if (SUCCEEDED(hr)) { //
// On success, we need to free the old, saved values
//
if (wszSavedLocalName) { delete [] wszSavedLocalName; wszSavedLocalName = NULL; } if (wszSavedPortName) { delete [] wszSavedPortName; wszSavedPortName = NULL; } if (wszSavedBaudRate) { delete [] wszSavedBaudRate; wszSavedBaudRate = NULL; } } else { //
// On failure, we need to roll back to the old values.
//
if (wszSavedLocalName) { if (pDeviceInfo->wszLocalName) { delete [] pDeviceInfo->wszLocalName; } pDeviceInfo->wszLocalName = wszSavedLocalName; } if (wszSavedPortName) { if (pDeviceInfo->wszPortName) { delete [] pDeviceInfo->wszPortName; } pDeviceInfo->wszPortName = wszSavedLocalName; } if (wszSavedBaudRate) { if (pDeviceInfo->wszBaudRate) { delete [] pDeviceInfo->wszBaudRate; } pDeviceInfo->wszBaudRate = wszSavedLocalName; } }
return hr; }
/*******************************************************************************
* * ReadMultiple * WriteMultiple * DeleteMultiple * ReadPropertyNames * WritePropertyNames * DeletePropertyNames * Commit * Revert * Enum * SetTimes * SetClass * Stat * * Pass-through implementation to IPropStg * * Arguments: * * * * Return Value: * * * * History: * * 9/2/1998 Original Version * \**************************************************************************/
HRESULT _stdcall CWIADevInfo::ReadMultiple( ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgpropvar) { DBG_FN(CWIADevInfo::ReadMultiple); HRESULT hr = m_pIPropStg->ReadMultiple(cpspec, rgpspec, rgpropvar);
if (FAILED(hr)) { ReportReadWriteMultipleError(hr, "CWIADevInfo::ReadMultiple", NULL, TRUE, cpspec, rgpspec); } return hr; }
HRESULT _stdcall CWIADevInfo::WriteMultiple( ULONG cpspec, const PROPSPEC *rgpspec, const PROPVARIANT *rgpropvar, PROPID propidNameFirst) { DBG_FN(CWIADevInfo::WriteMultiple); BOOL bInvalidProp; PROPSPEC *pPropSpec; HRESULT hr = S_OK;
//
// Attempt to impersonate the client. We need it since LocalService does not have sufficient permissions
// to modify the registry where the DIP values are stored - only ADMINs have rights to this key.
//
hr = CoImpersonateClient(); if (SUCCEEDED(hr)) { //
// Attempt to update any properties to which access is allowed.
// Currently, only the FriendlyName may be changed, anything
// else returns E_INVALIDARG.
//
pPropSpec = (PROPSPEC*) LocalAlloc(LPTR, sizeof(PROPSPEC) * cpspec); if (pPropSpec) { //
// First, make a copy of the incoming PROPSPEC array, and convert
// any property names to PROPIDs. While doing the conversion,
// make sure that access to those properties are allowed.
// This ensures that UpdateDeviceProperties receives only valid
// properties indicated by PROPIDs.
//
for (ULONG index = 0; index < cpspec; index++) { bInvalidProp = TRUE; pPropSpec[index].ulKind = PRSPEC_PROPID; if (SUCCEEDED(GetPropID(this, (PROPSPEC*)&rgpspec[index], &pPropSpec[index]))) { //
// Look for PropID matches here. So far, we only recognize:
// WIA_DIP_DEV_NAME
// WIA_DIP_PORT_NAME
// WIA_DIP_BAUDRATE
//
switch (rgpspec[index].propid) { case WIA_DIP_DEV_NAME : case WIA_DIP_PORT_NAME : case WIA_DIP_BAUDRATE : bInvalidProp = FALSE; break; default: bInvalidProp = TRUE; } } if (bInvalidProp) { DBG_ERR(("CWIADevInfo::WriteMultiple, property not allowed to be written")); hr = E_ACCESSDENIED; break; } } if (SUCCEEDED(hr)) { //
// Update the device properties stored in the registry
//
hr = UpdateDeviceProperties(cpspec, pPropSpec, rgpropvar); if (SUCCEEDED(hr)) { //
// Registry updated, so update the PropertyStorage to reflect
// the change.
//
hr = m_pIPropStg->WriteMultiple(cpspec, pPropSpec, rgpropvar, WIA_DIP_FIRST); if (FAILED(hr)) { DBG_ERR(("CWIADevInfo::WriteMultiple, updated registry, but failed to update property storage")); } } } //
// Free our PropSpec array
//
LocalFree(pPropSpec); } else { DBG_ERR(("CWIADevInfo::WriteMultiple, out of memory")); hr = E_OUTOFMEMORY; } HRESULT hrRevert = CoRevertToSelf(); if (FAILED(hrRevert)) { DBG_ERR(("CWIADevInfo::WriteMultiple, could not revert to self, hr = %08X", hr)); // TBD: What do we do now? Terminate?
} } else { DBG_ERR(("Error attempting to update device settings, could not impersonate client, therefore we do not have sufficient credentials to write to the registry")); } return hr; }
HRESULT _stdcall CWIADevInfo::ReadPropertyNames( ULONG cpropid, const PROPID *rgpropid, LPOLESTR *rglpwstrName) { DBG_FN(CWIADevInfo::ReadPropertyNames); return m_pIPropStg->ReadPropertyNames(cpropid,rgpropid,rglpwstrName); }
HRESULT _stdcall CWIADevInfo::WritePropertyNames( ULONG cpropid, const PROPID *rgpropid, const LPOLESTR *rglpwstrName) { DBG_FN(CWIADevInfo::WritePropertyNames); return(E_ACCESSDENIED); }
HRESULT _stdcall CWIADevInfo::Enum( IEnumSTATPROPSTG **ppenum) { DBG_FN(CWIADevInfo::Enum); return m_pIPropStg->Enum(ppenum); }
HRESULT _stdcall CWIADevInfo::GetPropertyAttributes( ULONG cPropSpec, PROPSPEC *pPropSpec, ULONG *pulAccessFlags, PROPVARIANT *ppvValidValues) { DBG_FN(CWIADevInfo::GetPropertyAttributes); return E_ACCESSDENIED; }
HRESULT _stdcall CWIADevInfo::GetCount( ULONG* pulPropCount) { DBG_FN(CWIADevInfo::GetCount); IEnumSTATPROPSTG *pIEnum; STATPROPSTG stg; ULONG ulCount; HRESULT hr = S_OK;
stg.lpwstrName = NULL;
hr = m_pIPropStg->Enum(&pIEnum); if (SUCCEEDED(hr)) { for (ulCount = 0; hr == S_OK; hr = pIEnum->Next(1, &stg, NULL)) { ulCount++;
if(stg.lpwstrName) { CoTaskMemFree(stg.lpwstrName); } } if (SUCCEEDED(hr)) { hr = S_OK; *pulPropCount = ulCount; } else { DBG_ERR(("CWIADevInfo::GetCount, pIEnum->Next failed (0x%X)", hr)); } pIEnum->Release(); } else { DBG_ERR(("CWIADevInfo::GetCount, Enum failed")); } return hr; }
HRESULT _stdcall CWIADevInfo::GetPropertyStream(GUID *pCompatibilityId, LPSTREAM *ppstmProp) { DBG_FN(CWIADevInfo::GetPropertyStream); return E_NOTIMPL; }
HRESULT _stdcall CWIADevInfo::SetPropertyStream(GUID *pCompatibilityId, LPSTREAM pstmProp) { DBG_FN(CWIADevInfo::SetPropertyStream); return E_ACCESSDENIED; }
/**************************************************************************\
* * Methods of IPropertyStorage not directly off IWiaPropertySTorage * * DeleteMultiple * DeletePropertyNames * Commit * Revert * SetTimes * SetClass * Stat * * 9/3/1998 Original Version * \**************************************************************************/
HRESULT _stdcall CWIADevInfo::DeleteMultiple( ULONG cpspec, const PROPSPEC __RPC_FAR rgpspec[]) { DBG_FN(CWIADevInfo::DeleteMultiple); return E_ACCESSDENIED; }
HRESULT _stdcall CWIADevInfo::DeletePropertyNames( ULONG cpropid, const PROPID __RPC_FAR rgpropid[]) { DBG_FN(CWIADevInfo::DeletePropertyNames); return E_ACCESSDENIED; }
HRESULT _stdcall CWIADevInfo::Commit(DWORD grfCommitFlags) { DBG_FN(CWIADevInfo::Commit);
return m_pIPropStg->Commit(grfCommitFlags); }
HRESULT _stdcall CWIADevInfo::Revert(void) { DBG_FN(CWIADevInfo::Revert); return m_pIPropStg->Revert(); }
HRESULT _stdcall CWIADevInfo::SetTimes( const FILETIME __RPC_FAR *pctime, const FILETIME __RPC_FAR *patime, const FILETIME __RPC_FAR *pmtime) { DBG_FN(CWIADevInfo::SetTimes); return m_pIPropStg->SetTimes(pctime,patime,pmtime); }
HRESULT _stdcall CWIADevInfo::SetClass(REFCLSID clsid) { DBG_FN(CWIADevInfo::SetClass); return E_ACCESSDENIED; }
HRESULT _stdcall CWIADevInfo::Stat(STATPROPSETSTG *pstatpsstg) { DBG_FN(CWIADevInfo::Stat); return m_pIPropStg->Stat(pstatpsstg); }
|