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