# IPropertyStorage::ReadMultiple

Reads specified properties from the current property set.

HRESULT ReadMultiple(

ULONG cpspec, | //Count of properties being read.
PROPSPEC const rgpspec[], | //Array of the properties to be read
PROPVARIANT rgvar[] | //Array of PROPVARIANTs containing the property values on return
); |

Parameters

cpspec
  [in] Count of properties specified in the rgpspec array. May legally be zero, though this is a no-op, reading no properties.
rgpspec[]
  [in] The properties to be read in the PROPSPEC structures. Properties can be specified either by property identifier or by optional string name. It is not necessary to specify properties in any particular order in the array. The array can contain duplicate properties, resulting in duplicate property values on return for simple properties. Non-simple properties should return access denied on an attempt to open them a second time. The array can contain a mixture of property identifiers and string identifiers.
rgvar[]
  [in, out] Caller-allocated array of PROPVARIANTs that, on return, contains the values of the properties specified by rgpspec. The array must be able to receive at least cpspec PROPVARIANTs. The caller does not need to initialize these PROPVARIANTs in any particular way; the implementation must fill in all field members correctly on return. If there is no other appropriate value, the implementation must set the vt member of each PROPVARIANT to VT_EMPTY.

Return Values

This method supports the standard return value E_UNEXPECTED, as well as the following:

S_OK
  Success. At least some of the requested properties were retrieved.
S_FALSE
  All the property names or identifiers had valid syntax, but none of them exist in this property set. Accordingly, no properties were retrieved., and each PROPVARIANT structure is set to VT_EMPTY.
STG_E_ACCESSDENIED
  The requested access to the property set has been denied, or, when one or more of the properties is a stream or storage object, access to that substorage or substream has been denied. (The storage or stream may already be open). No properties were retrieved.
STG_E_INSUFFICIENTMEMORY
  There is not sufficient memory to perform this operation. No properties were retrieved.
STG_E_INVALIDPARAMETER
  At least one of the parameters is invalid, such as when one of the PROPSPECs contains an illegal ulKind value. No properties were retrieved.
STG_E_INVALIDPOINTER
  At least one of the pointers passed in is invalid. No properties were retrieved.
HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION)
  There was a failed attempt to translate a Unicode string to or from Ansi.

Remarks

IPropertyStorage::ReadMultiple reads as many of the properties specified in the rgpspec array as are found in the property set. As long as any of the properties requested is read, a request to retrieve a property that does not exist is not an error. Instead, this must cause VT_EMPTY to be written for that property to the rgvar[] array on return. When none of the requested properties exist, the method should return S_FALSE, and set VT_EMPTY in each PROPVARIANT. If any other error is returned, no property values are retrieved, and the caller need not worry about releasing them.

The rgpspec parameter is an array of PROPSPEC structures, which specify for each property either its property identifier or, if one is assigned, a string identifier. You can map a string to a property identifier by calling IPropertyStorage:: WritePropertyNames. The use of property identifiers is, however, likely to be significantly more efficient than the use of strings.

Properties that are requested by string name (PRSPEC_LPWSTR) are mapped case-insensitively to property identifiers as they are specified in the current property set (and according to the current system locale).

All propvariants, except for those that are pointers to streams and storages, are called simple propvariants. These simple propvariants receive data by value, so a call to IPropertyStorage::ReadMultiple supplies a copy of the data that the caller then owns. To create or update these properties, call IPropertyStorage::WriteMultiple.

In contrast, the variant types VT_STREAM, VT_STREAMEDOBJECT, VT_STORAGE, and VT_STOREDOBJECT are non-simple properties, because rather than supplying a value, the method retrieves a pointer to the indicated interface, from which the data can then be read. These types permit the storage of large amounts of information through a single property. There are several issues that arise in using non-simple properties.

To create these properties, as for the other properties, call IPropertyStorage::WriteMultiple. Rather than calling the same method to update, however, it is more efficient to first call IPropertyStorage::ReadMultiple to get the interface pointer to the stream or storage, then write data using the IStream or IStorage methods. A stream or storage opened through a property is always opened in direct mode, so an additional level of nested transaction is not introduced. There may, however, still be a transaction on the property set as a whole, depending on how it was opened or created through IPropertySetStorage. Further, the access and share mode tags specified when the property set is opened or created, are passed to property-based streams or storages.

The lifetimes of property-based stream or storage pointers, although theoretically independent of their associated IPropertyStorage and IPropertySetStorage pointers, in fact, effectively depend on them. The data visible through the stream or storage is related to the transaction on the property storage object from which it is retrieved, just as for a storage object (supporting IStorage) with contained stream and storage sub-objects. If the transaction on the parent object is aborted, existing IStream and IStorage pointers subordinate to that object enter a “zombie” state. Because IPropertyStorage is the only interface on the property storage object, the useful lifetime of the contained IStream and IStorage pointers is bounded by the lifetime of the IPropertyStorage interface.

The implementation must also deal with the situation where the same stream- or storage-valued property is requested multiple times through the same IPropertyStorage interface instance. For example, in the OLE compound file implementation, the open will succeed or fail depending on whether or not the property is already open.

Another issue is multiple opens in transacted mode. The result depends on the isolation level that was specified through a call to IPropertySetStorage methods, (either the Open or Create method, through the STGM flags) at the time that the property storage was opened .

If the call to open the property set specifies read-write access, IStorage- and IStream-valued properties are always opened with read-write access. Data can then be written through these interfaces, changing the value of the property, which is the most efficient way to update these properties. The property value itself does not have an additional level of transaction nesting, so changes are scoped under the transaction (if any) on the property storage object.

See Also

IPropertySetStorage, IPropertyStorage::WriteMultiple, IPropertyStorage::WritePropertyNames