Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1667 lines
46 KiB

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