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.
 
 
 
 
 
 

1635 lines
44 KiB

/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORP., 1999
*
* TITLE: wiapsc.cpp
*
* VERSION: 1.0
*
* AUTHOR: ByronC
*
* DATE: 2 June, 1999
*
* DESCRIPTION:
* Implementation for the WIA Property Storage class.
*
*******************************************************************************/
#include "precomp.h"
#include "stiexe.h"
#include <wiamindr.h>
#include "helpers.h"
#include "wiapsc.h"
/**************************************************************************\
* CurStg
*
* Returns the IPropertyStorage used to store the current property values.
*
* Arguments:
*
*
* Return Value:
*
* IPropertyStorage for current values.
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
IPropertyStorage* _stdcall CWiaPropStg::CurStg()
{
return m_pIPropStg[WIA_CUR_STG];
}
/**************************************************************************\
* CurStm
*
* Returns the IStream used to store the current property values.
*
* Arguments:
*
*
* Return Value:
*
* IStream for current values.
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
IStream* _stdcall CWiaPropStg::CurStm()
{
return m_pIStream[WIA_CUR_STG];
}
/**************************************************************************\
* OldStg
*
* Returns the IPropertyStorage used to store the old property values.
*
* Arguments:
*
*
* Return Value:
*
* IPropertyStorage for old values.
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
IPropertyStorage* _stdcall CWiaPropStg::OldStg()
{
return m_pIPropStg[WIA_OLD_STG];
}
/**************************************************************************\
* OldStm
*
* Returns the IStream used to store the old property values.
*
* Arguments:
*
*
* Return Value:
*
* IStream for old values.
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
IStream* _stdcall CWiaPropStg::OldStm()
{
return m_pIStream[WIA_OLD_STG];
}
/**************************************************************************\
* ValidStg
*
* Returns the IPropertyStorage used to store the valid values.
*
* Arguments:
*
*
* Return Value:
*
* IPropertyStorage for valid values.
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
IPropertyStorage* _stdcall CWiaPropStg::ValidStg()
{
return m_pIPropStg[WIA_VALID_STG];
}
/**************************************************************************\
* ValidStm
*
* Returns the IStream used to store the current property values.
*
* Arguments:
*
*
* Return Value:
*
* IStream for valid values.
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
IStream* _stdcall CWiaPropStg::ValidStm()
{
return m_pIStream[WIA_VALID_STG];
}
/**************************************************************************\
* AccessStg
*
* Returns the IPropertyStorage used to store the access flags.
*
* Arguments:
*
*
* Return Value:
*
* IPropertyStorage for access values.
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
IPropertyStorage* _stdcall CWiaPropStg::AccessStg()
{
return m_pIPropStg[WIA_ACCESS_STG];
}
/**************************************************************************\
* AccessStm
*
* Returns the IStream used to store the access flag values.
*
* Arguments:
*
*
* Return Value:
*
* IStream for access values.
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
IStream* _stdcall CWiaPropStg::AccessStm()
{
return m_pIStream[WIA_ACCESS_STG];
}
/**************************************************************************\
* Backup
*
* This sets the backup storages and sets the old value storage. The
* backup storages are created here, but are released when either
* Undo() or Save() are called (since they're no longer needed until the
* next call to Backup()).
*
* Arguments:
*
*
* Return Value:
*
* Status - S_OK if successful
* - Error returns are those returned by CreateStorage
* and CopyProps
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaPropStg::Backup()
{
HRESULT hr = S_OK;
ULONG ulIndexOfBackup;
for (int lIndex = 0; lIndex < NUM_BACKUP_STG; lIndex++) {
//
// The normal storage indexes run from top to bottom, while their
// corresponding backup storage indexes run from bottom to top -
// this is to simplify the implementation of Backup()
//
ulIndexOfBackup = NUM_PROP_STG - (lIndex + 1);
//
// Create the corresponding backup storage.
//
hr = CreateStorage(ulIndexOfBackup);
if (SUCCEEDED(hr)) {
//
// Make the backup copy.
//
hr = CopyProps(m_pIPropStg[lIndex],
m_pIPropStg[ulIndexOfBackup]);
if (FAILED(hr)) {
DBG_ERR(("CWiaPropStg::Backup, CopyProps failed"));
break;
}
} else {
break;
}
}
if (SUCCEEDED(hr)) {
//
// Backups worked, so set the old property values to the
// current property values.
//
hr = CopyProps(CurStg(), OldStg());
if (FAILED(hr)) {
DBG_ERR(("CWiaPropStg::Backup, Could not set old values"));
}
}
if (FAILED(hr)) {
//
// There was a failure, so clean up
//
ReleaseBackups();
}
return hr;
}
/**************************************************************************\
* Undo
*
* This method is called if the properties fail validation and need to be
* restored to their previous values. The backup storages are then
* released.
*
* Arguments:
*
*
* Return Value:
*
* Status -
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaPropStg::Undo()
{
HRESULT hr = S_OK;
ULONG ulIndexOfBackup;
for (int lIndex = 0; lIndex < NUM_BACKUP_STG; lIndex++) {
//
// Restore the backup copy.
//
ulIndexOfBackup = NUM_PROP_STG - (lIndex + 1);
hr = CopyProps(m_pIPropStg[ulIndexOfBackup],
m_pIPropStg[lIndex]);
if (FAILED(hr)) {
DBG_ERR(("CWiaPropStg::Undo, CopyProps failed"));
break;
}
}
ReleaseBackups();
return hr;
}
/**************************************************************************\
* Initialize
*
* This method is called to set up the property streams and storages.
* If the any of the creation fails, CleanUp() is called.
*
* Arguments:
*
*
* Return Value:
*
* Status - S_OK if successful
* - E_OUTOFMEMORY if not enough memory
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaPropStg::Initialize()
{
HRESULT hr = S_OK;
for (int lIndex = 0; lIndex < (NUM_PROP_STG - NUM_BACKUP_STG); lIndex++) {
hr = CreateStorage(lIndex);
if (FAILED(hr)) {
break;
}
}
return hr;
}
/**************************************************************************\
* ReleaseBackups
*
* This frees all resources used by the backup storages.
*
* Arguments:
*
*
* Return Value:
*
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaPropStg::ReleaseBackups()
{
LONG lIndex;
//
// Release the property storages and property streams. Start at the
// last element in the array, and work up until the number of
// backup storages has been reached.
// The normal storage indexes run from top to bottom, while their
// corresponding backup storage indexes run from bottom to top
//
for (int count = 1; count <= NUM_BACKUP_STG; count++) {
lIndex = NUM_PROP_STG - count;
if(m_pIPropStg[lIndex]) {
m_pIPropStg[lIndex]->Release();
m_pIPropStg[lIndex] = NULL;
}
if(m_pIStream[lIndex]) {
m_pIStream[lIndex]->Release();
m_pIStream[lIndex] = NULL;
}
}
return S_OK;
}
/**************************************************************************\
* CheckPropertyAccess
*
* This method checks the access flags for specified properties, and
* fails if the access flags allow READ only access. Application
* written properties will have no access flags and so are assumed
* OK.
*
* Arguments:
*
* bShowErrors - specifies whether debug output should be shown when
* an error occurs. This flag exists so that some methods
* can skip over properties which don't have the correct
* access flags set.
* rgpspec - array of PROPSPECs specifying the properties.
* cpspec - number of elements in rgpspec.
*
* Return Value:
*
* Status - S_OK if the access flags do not prohibit WRITEs.
* E_POINTER if rgpspec is a bad read pointer.
* E_ACCESSDENIED if any access does not allow WRITE
* access.
*
* History:
*
* 28/04/1999 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaPropStg::CheckPropertyAccess(
BOOL bShowErrors,
LONG cpspec,
PROPSPEC *rgpspec)
{
PROPVARIANT *ppvAccess;
HRESULT hr;
//
// PROPSPEC pointer has not been checked yet, so check that it is valid.
//
if (IsBadWritePtr(rgpspec, sizeof(PROPSPEC) * cpspec)) {
DBG_ERR(("CWiaPropStg::CheckPropertyAccess, PROPSPEC array is invalid"));
return E_POINTER;
}
ppvAccess = (PROPVARIANT*) LocalAlloc(LPTR, sizeof(PROPVARIANT) * cpspec);
if (ppvAccess) {
hr = (AccessStg())->ReadMultiple(cpspec,
rgpspec,
ppvAccess);
if (hr == S_OK) {
for (LONG i = 0; i < cpspec; i++) {
if (ppvAccess[i].vt == VT_EMPTY) {
//
// This is an application written property
//
hr = S_OK;
} else if (!(ppvAccess[i].ulVal & WIA_PROP_WRITE)) {
if (!bShowErrors) {
hr = E_ACCESSDENIED;
break;
}
#ifdef WIA_DEBUG
if (rgpspec[i].ulKind == PRSPEC_PROPID) {
DBG_ERR(("CWiaPropStg::CheckPropertyAccess, no write access on prop ID: %d (%ws)",
rgpspec[i].propid,
GetNameFromWiaPropId(rgpspec[i].propid)));
}
else if (rgpspec[i].ulKind == PRSPEC_LPWSTR) {
DBG_ERR(("CWiaPropStg::CheckPropertyAccess, no write access prop ID: %ls", rgpspec[i].lpwstr));
}
else {
DBG_ERR(("CWiaPropStg::CheckPropertyAccess, bad property specification"));
hr = E_INVALIDARG;
break;
}
#endif
hr = E_ACCESSDENIED;
}
if (FAILED(hr)) {
break;
}
}
} else {
//
// ??? What about the application written property case?
// If return is S_FALSE then all the specified properties are
// application written properties so return OK.
//
if (hr == S_FALSE) {
hr = S_OK;
} else {
ReportReadWriteMultipleError(hr, "CWiaPropStg:CheckPropertyAccess", "access flags", TRUE, cpspec, rgpspec);
DBG_ERR(("CWiaPropStg:CheckPropertyAccess, unable to read access rights for some properties"));
}
}
LocalFree(ppvAccess);
}
else {
DBG_ERR(("CWiaPropStg:CheckPropertyAccess, unable to allocate access propvar, count: %d", cpspec));
hr = E_OUTOFMEMORY;
}
return hr;
}
/**************************************************************************\
* CheckPropertyType
*
* This method checks that the new property value type matches the current
* property type for all properties being written.
*
* Arguments:
*
* pIPropStg - the property storage to check against
* cpspec - number of elements in rgpspec.
* rgpspec - array of PROPSPECs specifying the properties.
* rgpvar - array of PROPVARIANTS holding
*
* Return Value:
*
* Status - S_OK if the access flags allow WRITEs.
* E_INVALIDARG if property type is invalid
* E_POINTER if rgpvar is a bad read pointer.
* E_OUTOFMEMORY if temporary storage could not be
* allocated.
*
* History:
*
* 13/05/1999 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaPropStg::CheckPropertyType(
IPropertyStorage *pIPropStg,
LONG cpspec,
PROPSPEC *rgpspec,
PROPVARIANT *rgpvar)
{
PROPVARIANT *ppvCurrent;
HRESULT hr;
//
// PROPVARIANT pointer has not been checked yet, so check it now.
//
if (IsBadWritePtr(rgpvar, sizeof(PROPSPEC) * cpspec)) {
DBG_ERR(("CWiaPropStg::CheckPropertyType, PROPVARIANT array is invalid"));
return E_POINTER;
}
ppvCurrent = (PROPVARIANT*) LocalAlloc(LPTR, sizeof(PROPVARIANT) * cpspec);
if (ppvCurrent) {
//
// Get the current values
//
hr = pIPropStg->ReadMultiple(cpspec,
rgpspec,
ppvCurrent);
if (SUCCEEDED(hr)) {
//
// Check that the PROPVARIANT types match. If VT is VT_EMPTY,
// then it's an application written property so skip check.
//
for (LONG i = 0; i < cpspec; i++) {
if ((rgpvar[i].vt != ppvCurrent[i].vt) && (ppvCurrent[i].vt != VT_EMPTY)) {
hr = E_INVALIDARG;
break;
}
}
FreePropVariantArray(cpspec, ppvCurrent);
} else {
ReportReadWriteMultipleError(hr,
"CWiaPropStg::CheckPropertyType",
"Reading current values",
TRUE,
1,
rgpspec);
}
LocalFree(ppvCurrent);
}
else {
DBG_ERR(("CWiaPropStg::CheckPropertyType, unable to allocate PropVar, count: %d", cpspec));
hr = E_OUTOFMEMORY;
}
return hr;
}
/**************************************************************************\
* GetPropIDFromName
*
* This method takes in a PROPSPEC that identifies a property by its name
* and returns a PROPSPEC with the corresponding PropID. It checks against
* the current value storage.
*
* Arguments:
*
* 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 _stdcall CWiaPropStg::GetPropIDFromName(
PROPSPEC *pPropSpecIn,
PROPSPEC *pPropSpecOut)
{
HRESULT hr;
IEnumSTATPROPSTG *pIEnum;
hr = (CurStg())->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;
CoTaskMemFree(statProp.lpwstrName);
pIEnum->Release();
return S_OK;
}
//
// Free the property name
//
CoTaskMemFree(statProp.lpwstrName);
statProp.lpwstrName = NULL;
}
}
pIEnum->Release();
//
// Property not found
//
return E_INVALIDARG;
}
/**************************************************************************\
* NamesToPropIDs
*
* This method takes in an array of PROPSPECs, and outputs an array
* of PROPSPECs which contain only PropIDs. This function should
* be called by methods which only want to deal with PropIDs, and not
* property names.
*
* If none of the PropSpecs have to be converted, then the returned
* PROPSPEC is NULL, else a new PropSpec array is allocated and
* returned. Users of this method must use LocalFree to free
* up the returned array.
*
* Arguments:
*
* pPropSpecIn - A pointer to the input PROPSPEC containing the
* property name.
* ppPropSpecOut - A pointer to a PROPSPEC where the corresponding
* PropID will be put.
* celt - Number of PROPSPECS
*
* Return Value:
*
* Status - An E_INVALIDARG will be returned if the property
* is not found. If it is, then S_OK will be returned
* E_OUTOFMEMORY will be returned if the new PROPSPEC
* array could not be allocated.
*
* History:
*
* 27/4/1998 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaPropStg::NamesToPropIDs(
LONG celt,
PROPSPEC *pPropSpecIn,
PROPSPEC **ppPropSpecOut)
{
HRESULT hr;
*ppPropSpecOut = NULL;
if (celt < 1) {
return S_OK;
}
//
// Check whether conversion needs to be done.
//
for (int i = 0; i < celt; i++) {
if (pPropSpecIn[i].ulKind == PRSPEC_LPWSTR) {
//
// Found a Name, so we need to convert the whole thing
//
PROPSPEC *pOut;
pOut = (PROPSPEC*) LocalAlloc(LPTR, sizeof(PROPSPEC) * celt);
if (!pOut) {
DBG_ERR(("NamesToPropIDs, out of memory"));
return E_OUTOFMEMORY;
}
for (int j = 0; j < celt; j++) {
if (pPropSpecIn[j].ulKind == PRSPEC_LPWSTR) {
hr = GetPropIDFromName(&pPropSpecIn[j], &pOut[j]);
if (FAILED(hr)) {
LocalFree(pOut);
return hr;
}
}
else {
pOut[j].ulKind = PRSPEC_PROPID;
pOut[j].propid = pPropSpecIn[j].propid;
}
}
//
// Everything converted, so return
//
*ppPropSpecOut = pOut;
return S_OK;
}
}
//
// Nothing to convert
//
return S_OK;
}
/**************************************************************************\
* CopyItemProp
*
* This 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 CWiaPropStg::CopyItemProp(
IPropertyStorage *pIPropStgSrc,
IPropertyStorage *pIPropStgDst,
PROPSPEC *pps,
LPSTR pszErr)
{
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;
}
/*******************************************************************************
*
* CopyProps
*
* This is a helper function used to copy the property values from one
* property storage into another.
*
* Parameters:
*
* pSrc - the source property storage
* pDest - the destination property storage
*
* Return:
*
* Status - S_OK if successful.
* Error returns are those returned by WriteMultiple
*
* History
*
* 06/05/1999 Original Version
*
*******************************************************************************/
HRESULT CWiaPropStg::CopyProps(
IPropertyStorage *pSrc,
IPropertyStorage *pDest)
{
IEnumSTATPROPSTG *pIEnum;
STATPROPSTG StatPropStg;
PROPSPEC ps[1];
HRESULT hr;
hr = pSrc->Enum(&pIEnum);
if (SUCCEEDED(hr)) {
ULONG ulFetched;
ps[0].ulKind = PRSPEC_PROPID;
while (pIEnum->Next(1, &StatPropStg, &ulFetched) == S_OK) {
PROPID pi[1];
LPWSTR psz[1];
pi[0] = StatPropStg.propid;
psz[0] = StatPropStg.lpwstrName;
if (StatPropStg.lpwstrName) {
//
// Copy the property name
//
hr = pDest->WritePropertyNames(1, pi, psz);
if (FAILED(hr)) {
CoTaskMemFree(StatPropStg.lpwstrName);
break;
}
}
ps[0].propid = StatPropStg.propid;
//
// Copy the property value
//
hr = CopyItemProp(pSrc,
pDest,
ps,
"CopyProps");
CoTaskMemFree(StatPropStg.lpwstrName);
if (FAILED(hr)) {
break; hr;
}
}
pIEnum->Release();
} else {
return hr;
}
return hr;
}
/**************************************************************************\
* WriteItemPropNames
*
* Write property names to all internal property storages (except the
* storages used for backups).
*
* Arguments:
*
*
*
* Return Value:
*
* Status
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaPropStg::WriteItemPropNames(
LONG cItemProps,
PROPID *ppId,
LPOLESTR *ppszNames)
{
HRESULT hr = S_OK;
for(LONG lIndex = 0; lIndex < (NUM_PROP_STG - NUM_BACKUP_STG); lIndex++) {
if (m_pIPropStg[lIndex]) {
hr = m_pIPropStg[lIndex]->WritePropertyNames(cItemProps,
ppId,
ppszNames);
if (FAILED(hr)) {
DBG_ERR(("CWiaPropStg::WriteItemPropNames, WritePropertyNames failed 0x%X", hr));
return hr;
}
}
}
return hr;
}
/*******************************************************************************
*
* CreateStorage
*
* This is a helper function used to create streams and property storage.
* The ulIndex argument indicates where the pointers are stored in the
* streams and propertystorage arrays.
*
* Parameters:
*
* ulIndex - the index of the IPropertyStorage
*
* Return:
*
* Status - S_OK if successful.
* - Error returns are those returned by CreateStreamOnHGlobal
* and StgCreatePropStg
*
* History
*
* 06/05/1999 Original Version
*
*******************************************************************************/
HRESULT CWiaPropStg::CreateStorage(
ULONG ulIndex)
{
HRESULT hr;
//
// Create stream and property storage.
//
hr = CreateStreamOnHGlobal(NULL, TRUE, &m_pIStream[ulIndex]);
if (SUCCEEDED(hr)) {
hr = StgCreatePropStg(m_pIStream[ulIndex],
FMTID_NULL,
&CLSID_NULL,
PROPSETFLAG_DEFAULT,
0,
&m_pIPropStg[ulIndex]);
if (FAILED(hr)) {
DBG_ERR(("CWiaPropStg::CreateStorage, StgCreatePropStg failed 0x%X", hr));
}
} else {
DBG_ERR(("CWiaPropStg::CreateStorage, CreateStreamOnHGlobal failed 0x%X", hr));
}
return hr;
}
/**************************************************************************\
* CopyRWStreamProps
*
* Copies properties from source stream to destination stream. Only copies
* properties that the app. has read/write access to.
*
* Arguments:
*
* pstmPropSrc - Pointer to source property stream.
* pstmPropDst - Pointer to returned destination property stream.
* pCompatibilityId - Address of GUID to receive the property
* stream CompatibilityId.
*
* Return Value:
*
* Status
*
* History:
*
* 9/3/1998 Original Version
* 06/04/1999 Moved from CWiaItem to CWiaPropStg
*
\**************************************************************************/
HRESULT CWiaPropStg::CopyRWStreamProps(
LPSTREAM pstmPropSrc,
LPSTREAM pstmPropDst,
GUID *pCompatibilityId)
{
IPropertyStorage *pSrc;
IPropertyStorage *pDst;
IEnumSTATPROPSTG *pIEnum;
STATPROPSTG StatPropStg;
LONG lNumProps = 0;
HRESULT hr;
PROPSPEC ps[1] = {{PRSPEC_PROPID, WIA_IPA_PROP_STREAM_COMPAT_ID}};
PROPVARIANT pv[1];
//
// Open a storage on the source stream.
//
hr = StgOpenPropStg(pstmPropSrc,
FMTID_NULL,
PROPSETFLAG_DEFAULT,
0,
&pSrc);
if (SUCCEEDED(hr)) {
//
// Get the compatibility ID. If stream doesn't contain a
// compatibility ID then assume GUID_NULL.
//
PropVariantInit(pv);
hr = pSrc->ReadMultiple(1, ps, pv);
if (hr == S_OK) {
*pCompatibilityId = *(pv[0].puuid);
} else {
*pCompatibilityId = GUID_NULL;
}
PropVariantClear(pv);
//
// Create a storage on the destination stream.
//
hr = StgCreatePropStg(pstmPropDst,
FMTID_NULL,
&CLSID_NULL,
PROPSETFLAG_DEFAULT,
0,
&pDst);
if (SUCCEEDED(hr)) {
hr = pSrc->Enum(&pIEnum);
if (SUCCEEDED(hr)) {
ULONG ulFetched;
ps[0].ulKind = PRSPEC_PROPID;
//
// Enumerate through the properties in the stream
//
while (pIEnum->Next(1, &StatPropStg, &ulFetched) == S_OK) {
PROPID pi[1];
LPWSTR psz[1];
pi[0] = StatPropStg.propid;
psz[0] = StatPropStg.lpwstrName;
ps[0].propid = StatPropStg.propid;
//
// Check whether property has read/write access. Skip
// property write if this check fails
//
hr = CheckPropertyAccess(FALSE, 1, ps);
if (hr != S_OK) {
hr = S_OK;
if (StatPropStg.lpwstrName) {
CoTaskMemFree(StatPropStg.lpwstrName);
}
continue;
}
//
// Copy the property name (if it has one), and value
//
if (StatPropStg.lpwstrName) {
hr = pDst->WritePropertyNames(1, pi, psz);
if (FAILED(hr)) {
DBG_ERR(("CWiaPropStg::CopyRWStreamProps WritePropertyNames failed"));
break;
}
CoTaskMemFree(StatPropStg.lpwstrName);
}
hr = CopyItemProp(pSrc,
pDst,
ps,
"CWiaPropStg::CopyRWStreamProps");
if (FAILED(hr)) {
break;
}
//
// Increase the property count
//
lNumProps++;
}
pIEnum->Release();
} else {
DBG_ERR(("CWiaPropStg::CopyRWStreamProps, Enum failed 0x%X", hr));
}
if (SUCCEEDED(hr)) {
//
// Write the number of properties to stream
//
ps[0].propid = WIA_NUM_PROPS_ID;
pv[0].vt = VT_I4;
pv[0].lVal = lNumProps;
hr = pDst->WriteMultiple(1, ps, pv, WIA_IPA_FIRST);
if (FAILED(hr)) {
DBG_ERR(("CWiaPropStg::CopyRWStreamProps, Error writing number of properties"));
}
}
pDst->Release();
} else {
DBG_ERR(("CWiaPropStg::CopyRWStreamProps, creating Dst storage failed 0x%X", hr));
}
pSrc->Release();
} else {
DBG_ERR(("CWiaPropStg::CopyRWStreamProps, StgCreatePropStg for pSrc failed 0x%X", hr));
}
return hr;
}
/**************************************************************************\
* GetPropertyStream
*
* Get a copy of an items property stream. Caller must free returned
* property stream.
*
* Arguments:
*
* pCompatibilityId - Address of GUID to receive the property
* stream CompatibilityId.
* ppstmProp - Pointer to returned property stream.
*
* Return Value:
*
* Status
*
* History:
*
* 9/3/1998 Original Version
* 06/04/1999 Updated and moved from CWiaItem to CWiaPropStg
* 12/12/1999 Modified to use CompatibilityId
*
\**************************************************************************/
HRESULT _stdcall CWiaPropStg::GetPropertyStream(
GUID *pCompatibilityId,
LPSTREAM *ppstmProp)
{
IStream *pStm;
*ppstmProp = NULL;
//
// Commit any pending transactions.
//
HRESULT hr = m_pIPropStg[WIA_CUR_STG]->Commit(STGC_DEFAULT);
if (FAILED(hr)) {
DBG_ERR(("CWiaPropStg::GetPropertyStream, Commit failed"));
return hr;
}
//
// Create a stream
//
hr = CreateStreamOnHGlobal(NULL, TRUE, ppstmProp);
if (SUCCEEDED(hr)) {
//
// Copy the RW properties from one stream to another.
//
hr = CopyRWStreamProps(m_pIStream[WIA_CUR_STG], *ppstmProp, pCompatibilityId);
if (FAILED(hr)) {
(*ppstmProp)->Release();
*ppstmProp = NULL;
}
} else {
DBG_ERR(("CWiaPropStg::GetPropertyStream, CreateStreamOnHGlobal failed"));
}
return hr;
}
/**************************************************************************\
* GetPropsFromStorage
*
* Gets the properties contained in a storage which was opened on a stream
* returned by GetPropertyStream. The property values are returned in
* ppVar, and the propID's are returned in ppPSpec.
*
* Arguments:
*
* pSrc - pointer to the IProperty storage
* pPSpec - address where the number of properties is returned
* ppPSpec - address of a pointer to hold PROPSPECs
* ppVar - address of pointer to hold PROPVARIANTs
*
* Return Value:
*
* Status
*
* History:
*
* 07/04/1999 Original Version
*
\**************************************************************************/
HRESULT CWiaPropStg::GetPropsFromStorage(
IPropertyStorage *pSrc,
ULONG *cPSpec,
PROPSPEC **ppPSpec,
PROPVARIANT **ppVar)
{
IEnumSTATPROPSTG *pIEnum = NULL;
STATPROPSTG StatPropStg;
PROPSPEC *ps = NULL;
PROPVARIANT *pv = NULL;
LONG lIndex = 0;
//
// Read the number of properties
//
PROPSPEC psNumProps[1];
PROPVARIANT pvNumProps[1];
psNumProps[0].ulKind = PRSPEC_PROPID;
psNumProps[0].propid = WIA_NUM_PROPS_ID;
PropVariantInit(pvNumProps);
HRESULT hr = pSrc->ReadMultiple(1, psNumProps, pvNumProps);
if (hr == S_OK) {
//
// Get the memory for the values
//
ps = (PROPSPEC*) LocalAlloc(LPTR, sizeof(PROPSPEC) * pvNumProps[0].lVal);
pv = (PROPVARIANT*) LocalAlloc(LPTR, sizeof(PROPVARIANT) * pvNumProps[0].lVal);
if (!pv || !ps) {
DBG_ERR(("CWiaPropStg::GetPropsFromStream, out of memory"));
hr = E_OUTOFMEMORY;
}
} else {
DBG_ERR(("CWiaPropStg::GetPropsFromStream, reading WIA_NUM_PROPS_ID failed"));
hr = E_INVALIDARG;
}
if (SUCCEEDED(hr)) {
hr = pSrc->Enum(&pIEnum);
if (SUCCEEDED(hr)) {
//
// Enumerate through the properties in the stream
//
for (lIndex = 0; lIndex < pvNumProps[0].lVal; lIndex++) {
hr = pIEnum->Next(1, &StatPropStg, NULL);
//
// Ignore the WIA_NUM_PROPS_ID property
//
if (StatPropStg.propid == WIA_NUM_PROPS_ID) {
hr = pIEnum->Next(1, &StatPropStg, NULL);
}
if (hr != S_OK) {
DBG_ERR(("CWiaPropStg::GetPropsFromStream, error enumerating properties"));
hr = E_INVALIDARG;
if(StatPropStg.lpwstrName) {
CoTaskMemFree(StatPropStg.lpwstrName);
}
break;
}
ps[lIndex].ulKind = PRSPEC_PROPID;
ps[lIndex].propid = StatPropStg.propid;
if(StatPropStg.lpwstrName) {
CoTaskMemFree(StatPropStg.lpwstrName);
}
}
if (SUCCEEDED(hr)) {
hr = pSrc->ReadMultiple(pvNumProps[0].lVal, ps, pv);
if (hr != S_OK) {
DBG_ERR(("CWiaPropStg::GetPropsFromStream, read multiple failed"));
if (hr == S_FALSE) {
hr = E_INVALIDARG;
}
}
}
pIEnum->Release();
} else {
DBG_ERR(("CWiaPropStg::GetPropsFromStream, Enum failed"));
}
}
if (FAILED(hr)) {
if (ps) {
LocalFree(ps);
ps = NULL;
}
if (pv) {
LocalFree(pv);
pv = NULL;
}
}
//
// Set return values
//
*cPSpec = pvNumProps[0].lVal;
PropVariantClear(pvNumProps);
*ppPSpec = ps;
*ppVar = pv;
return hr;
}
/**************************************************************************\
* SetPropertyStream
*
* Sets the current value properties to the values contained in the argument
* stream. The properties are written to the corresponding WiaItem.
*
* Arguments:
*
* pCompatibilityId - Pointer to a GUID representing the property
* stream CompatibilityId.
* pItem - Pointer to the WiaItem.
* pstmProp - Pointer to property stream.
*
* Return Value:
*
* Status
*
* History:
*
* 07/06/1999 Original Version
* 12/12/1999 Modified to use CompatibilityId
*
\**************************************************************************/
HRESULT _stdcall CWiaPropStg::SetPropertyStream(
GUID *pCompatibilityId,
IWiaItem *pItem,
LPSTREAM pstmProp)
{
IPropertyStorage *pSrc = NULL;
PROPSPEC *ps = NULL;
PROPVARIANT *pv = NULL;
PROPSPEC psCompatId[1] = {{PRSPEC_PROPID, WIA_IPA_PROP_STREAM_COMPAT_ID}};
PROPVARIANT pvCompatId[1];
ULONG celt = 0;
HRESULT hr = S_OK;
//
// Write the compatibility ID. This way the driver will validate the
// ID before we attempt to write all the properties in this stream.
// Skip this step if pCompatibilityId is GUID_NULL.
//
if (*pCompatibilityId != GUID_NULL) {
pvCompatId[0].vt = VT_CLSID;
pvCompatId[0].puuid = pCompatibilityId;
hr = ((CWiaItem*) pItem)->WriteMultiple(1,
psCompatId,
pvCompatId,
WIA_IPA_FIRST);
if (FAILED(hr)) {
DBG_ERR(("CWiaPropStg::SetPropertyStream, Writing Compatibility ID failed!"));
return hr;
}
}
//
// If the stream is NULL, return here. The stream will be NULL if the
// application simply wants to check whether the CompatibilityId is
// valid.
//
if (pstmProp == NULL) {
return S_OK;
}
//
// We need to impersonate the client to be able to access the
// properties in the stream
//
BOOL bImpersonating = FALSE;
_try
{
hr = CoImpersonateClient();
if (SUCCEEDED(hr))
{
bImpersonating = TRUE;
//
// Create a storage on the incoming stream
//
hr = StgOpenPropStg(pstmProp,
FMTID_NULL,
PROPSETFLAG_DEFAULT,
0,
&pSrc);
if (SUCCEEDED(hr)) {
//
// Get the properties from the stream
//
hr = GetPropsFromStorage(pSrc, &celt, &ps, &pv);
//
// Release the property stream - we no longer need it
//
if (pSrc)
{
pSrc->Release();
pSrc = NULL;
}
} else {
DBG_ERR(("CWiaPropStg::SetPropertyStream, open storage failed 0x%X", hr));
pSrc = NULL;
}
}
}
_finally
{
if (bImpersonating)
{
HRESULT hres = CoRevertToSelf();
}
}
//
// If everything is still successful, we now have ps and pv arrays
// allocated and filled with properties
//
if (SUCCEEDED(hr)) {
//
// Write the properties to the item
//
hr = ((CWiaItem*) pItem)->WriteMultiple(celt, ps, pv, WIA_IPA_FIRST);
if (FAILED(hr)) {
DBG_ERR(("CWiaPropStg::SetPropertyStream, WriteMultiple failed"));
}
}
//
// Cleanup
//
if (ps)
{
LocalFree(ps);
ps = NULL;
}
if (pv)
{
for (ULONG i = 0; i < celt; i++)
{
PropVariantClear(&pv[i]);
}
LocalFree(pv);
pv = NULL;
}
return hr;
}
/**************************************************************************\
* CWiaPropStg
*
* Constructor for CWiaPropStg.
*
* Arguments:
*
*
* Return Value:
*
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
CWiaPropStg::CWiaPropStg()
{
//
// Set the property storage and property stream pointers to NULL
//
for (int lIndex = 0; lIndex < NUM_PROP_STG; lIndex++) {
m_pIPropStg[lIndex] = NULL;
m_pIStream[lIndex] = NULL;
}
}
/**************************************************************************\
* ~CWiaPropStg
*
* Destructor for CWiaPropStg. Calls CleanUp to free resources.
*
* Arguments:
*
*
* Return Value:
*
*
* History:
*
* 06/03/1999 Original Version
*
\**************************************************************************/
CWiaPropStg::~CWiaPropStg()
{
//
// Release the property storages and property streams
//
for (int lIndex = 0; lIndex < NUM_PROP_STG; lIndex++) {
if(m_pIPropStg[lIndex]) {
m_pIPropStg[lIndex]->Release();
m_pIPropStg[lIndex] = NULL;
}
if(m_pIStream[lIndex]) {
m_pIStream[lIndex]->Release();
m_pIStream[lIndex] = NULL;
}
}
}