Writes a specified group of properties to the current property set. If a property with a specified name already exists, it is replaced, even when the old and new types for the property value are different. If a property of a given name or property identifier does not exist, it is created.
HRESULT WriteMultiple(
ULONG cpspec, //The number of properties being set
PROPSPEC const rgpspec[], //Property specifiers
PROPVARIANT const rgvar[], //Array of PROPVARIANT values
PROPID propidNameFirst //Minimum value for property identifiers
//when they must be allocated
);
This method supports the standard return value E_UNEXPECTED, as well as the following:
If a specified property already exists, it's value is replaced with the new one, even when the old and new types for the property value are different. If you specify a property identifier that does not exist, that property is created. If a string name is supplied for a property which does not exist, the method will allocate a property identifier for that property, and the name will be added to the dictionary.
When allocating a property identifier, the implementation can choose any value not currently in use in the property set for a property identifier, as long as it is not 0 or 1 or greater than 0x80000000, all of which are reserved values. The propidNameFirst parameter establishes a minimum value for property identifiers within the set, and must be greater than 1 and less than 0x80000000.
If there is an attempt to write a property that already exists with an invalid parameter, the method should return STG_E_INVALIDPARAMETER; if the property does not exist, it should not be created. This behavior facilitates the use of a ReadMultiple – update – WriteMultiple sequence to update a group of properties without requiring that the calling code ensure that all the requested properties in the call to ReadMultiple were retrieved.
It is recommended that property sets be created as Unicode, by not setting the PROPSETFLAG_ANSI flag in the grfFlags parameter of IPropertySetStorage::Create. It is also recommended that you avoid using VT_LPSTR values, and use VT_LPWSTR values instead. When the property set code page is Unicode, VT_LPSTR string values are converted to Unicode when stored, and back to multibyte string values when retrieved. When the code page of the property set is not Unicode, property names, VT_BSTR strings, and non-simple property values are converted to multibyte strings when stored, and converted back to Unicode when retrieved, all using the current system ANSI code page.
To create stream or storage object as a property in a nonsimple property set, call IPropertyStorage::WriteMultiple. While you would also call this method to update simple properties, it is not an efficient way to update stream and storage objects in a property set. This is because updating one of these properties through a call to WriteMultiple creates in the property storage object a copy of the passed-in data, and the IStorage or IStream pointers are not retained beyond the duration of this call. It is usually more efficient to update stream or storage objects by first calling IPropertyStorage::ReadMultiple to get the interface pointer to the stream or storage, then writing data through 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 is still likely to be a transaction on the property set as a whole. Further, a property-based stream or storage is opened in read-write mode, if possible, given the mode on the property set; otherwise, read mode is used.
When the copy is made, the underlying CopyTo operation on VT_STREAM properties operates on the current seek position of the source. The seek position is destroyed on failure, but on success it is at EOF.
If a stream or storage property does not exist, passing an IStream or IStorage pointer with a value of NULL creates an empty stream or storage property value. If a stream or storage property is already open from a call to ReadMultiple, a NULL value must cause the WriteMultiple operation to truncate it and return S_OK, placing the previously returned stream- and storage-valued pointers into the reverted state (as happens in the compound file implementation.)
Storage- and stream-valued properties always manifest themselves to downlevel clients as sibling streams or storages to the stream containing the main contents of the property set—they are never stored directly in-line in the property set. This allows smooth interoperability and control when down-level clients interact with up-level clients. Thus, from a downlevel perspective, property sets containing IStream or IStorage valued properties are always stored in a storage object, not a stream. The specific name of the sibling used is completely under the control of the IPropertyStorage implementation, as long as the name is from the non-reserved part of the IStorage name space. See Appendix C of the OLE Programmer's Guide for a discussion of the serialized property set format for further details. As is described there, the string name is stored in the same format as a VT_BSTR. Refer also to the earlier discussion in this method of multibyte to Unicode conversions for property names.
If the WriteMultiple method returns an error when writing stream- or storage-valued properties (indirect properties), the amount of data actually written is undefined. If the caller requires consistency of the property set and its indirect properties when writing stream- and/or storage-valued properties, use of transacted mode is advised.
If an implicit deletion of a stream- or storage-valued property occurs while that property is open, (as, for example, when a VT_I4 is written over a VT_STREAM), the deletion will succeed and place the previously returned IStream pointer in the reverted state.
Windows NT: Use version 4.0 or later.
Windows: Use Windows 95 or later. Available as a redistributable for Windows 95.
Windows CE: Unsupported.
Header: Declared in objidl.h.
IPropertySetStorage::Create, IPropertyStorage::ReadMultiple