IPropertyStorage-Compound File Implementation
The COM implementation of the Structured Storage architecture is called compound files. Storage objects as implemented in compound files include an implementation of both IPropertyStorage, the interface that manages a single persistent property set, and IPropertySetStorage, the interface that manages groups of persistent property sets. For more information about the IPropertyStorage interface, see IPropertyStorage and Property Storage Considerations.
To get a pointer to the compound file implementation of IPropertyStorage, call StgCreateStorageEx to create a new compound file object or StgOpenStorageEx to open a previously created compound file object. In the case of StgCreateStorageEx, the stgfmt parameter should be set to STGFMT_STORAGE. In the case of StgOpenStorageEx, the stgfmt parameter should be set to STGFMT_STORAGE or STGFMT_ANY. In both cases, the riid parameter should be set to IID_IPropertySetStorage. Both functions supply a pointer to the object IPropertySetStorage interface. By calling either the Create or Open method of that interface, you will get a pointer to the IPropertyStorage interface, which you can use to call any of its methods.
An alternative way to get a pointer to the compound file implementation of IPropertySetStorage is to call the older StgCreateDocfile and StgOpenStorage functions, or to specify an riid parameter of IID_IStorage to the StgCreateStorageEx or StgOpenStorageEx function. In either case, a pointer to the object's IStorage interface is returned. With persistent property sets, call QueryInterface for the IPropertySetStorage interface, specifying the header-defined name for the interface identifier (IID) IID_IPropertySetStorage.
When to Use
Use IPropertyStorage to manage properties within a single property set. Its methods support reading, writing, and deleting both properties and the optional string names that can be associated with property identifiers. Other methods support the standard commit and revert storage operations. There is also a method that enables you to set times associated with the property storage, and another that permits the assignment of a CLSID that can be used to associate other code, such as user interface code, with the property set. Calling the Enum method supplies a pointer to the compound file implementation of IEnumSTATPROPSTG, which allows you to enumerate the properties in the set.
If you obtain a pointer to IPropertyStorage by calling StgCreateDocfile, StgCreateStorageEx, StgOpenStorage or StgOpenStorageEx on a simple-mode property set storage, the IPropertyStorage methods adhere to the rules of simple-mode streams. The property set storage is simple mode if it was obtained for a file that was created or opened with the STGM_SIMPLE flag. In this case, it is not always possible to make the underlying stream larger and it is not possible to replace existing properties with larger properties. For more information, see IPropertySetStorage-Compound File Implementation.
IPropertyStorage and Caching
The compound file implementation of IPropertyStorage caches open property sets in memory in order to improve performance. As a result, changes to a property set are not written to the compound file until the Commit or Release (last reference) methods are called.
Simple Mode Property Sets
A property storage object is in simple mode if it is created from a simple mode property set storage object. For example, a property set storage object would be in simple mode if it were obtained from the StgOpenStorageEx function, with the STGM_SIMPLE flag set in the grfMode parameter. Note that "simple mode" is unrelated to "simple property sets". A property set is simple if it is created by calling IPropertySetStorage::Create with the PROPSETFLAG_NONSIMPLE flag set in the grfFlags parameter. For more information about simple and nonsimple property sets, see Storage and Stream Objects for a Property Set.
When a simple mode property storage object is created, there are no restrictions on its use. When an existing simple-mode property storage object is opened, the underlying stream object that stores the property set cannot be grown. Consequently, it is not always possible to modify such a property storage object if the change requires a larger stream.
Property Set Formats
The compound file implementation of IPropertyStorage supports both the version 0 and the version 1 property set serialization formats. The version 1 format is supported on computers running on Windows 2000. For more information, see Property Set Serialization. Property sets are created in version 0 format and remain in that format unless new features are requested. When that occurs, the format is updated to version 1.
For example, if a property set is created with the PROPSETFLAG_DEFAULT flag, its format is version 0. As long as property types that conform to the version 0 format are written to and read from that property set, the property set remains in version 0 format. If a version 1 property type is written to the property set, the property set is automatically updated to version 1. Subsequently, that property set can no longer be read by implementations that recognize only version 0.
IPropertyStorage and Variant Types
The compound file implementation of IPropertyStorage does not support the variant types VT_UNKNOWN or VT_DISPATCH in the vt member of the PROPVARIANT structure.
The following table lists variant types that are supported within a SafeArray; that is, these values can be combined with VT_ARRAY in the vt member of the PROPVARIANT structure.
Variant types supported within SafeArray by compound file implementation of IPropertyStorage
When VT_VARIANT is combined with VT_ARRAY, the SafeArray itself holds PROPVARIANT structures. However, the types of these elements must be taken from the preceding list, cannot be VT_VARIANT, and cannot include the VT_VECTOR, VT_ARRAY, or VT_BYREF indicators.
The compound file implementation of IPropertyStorage supports the following methods:
Reads the properties specified in the rgpspec array and supplies the values of all valid properties in the rgvar array of PROPVARIANTs. In the COM compound file implementation, duplicate property identifiers that refer to stream or storage types result in multiple calls to IStorage::OpenStream or IStorage::OpenStorage and the success or failure of ReadMultiple depends on the underlying storage implementation's ability to share opening operations. Because in a compound file STGM_SHARE_EXCLUSIVE is forced, multiple open attempts will fail. Opening the same storage object more than once from the same parent storage is not supported. The STGM_SHARE_EXCLUSIVE flag must be specified.
In addition, to ensure thread-safe operation if the same stream- or storage-valued property is requested several times through the same IPropertyStorage pointer in the COM compound file implementation, the open operation will succeed or fail depending on whether the property is already open and whether the underlying file system handles multiple openings of a stream or storage. Thus, the ReadMultiple operation on a stream- or storage-valued property always results in a call to IStorage::OpenStream, or IStorage::OpenStorage, which passes the access (STGM_READWRITE, and so forth) and share flags (STGM_SHARE_EXCLUSIVE, and so on) specified when the original property set was opened or created.
If the method fails, the values written to rgvar are undefined. If some stream- or storage-valued properties are opened successfully but an error occurs before execution is complete, these should be released before the method returns.
Writes the properties specified in the rgpspec array, assigning them the PROPVARIANT tags and values specified in rgvar. Properties that already exist are assigned the specified PROPVARIANT values. Properties that do not currently exist are created.
Deletes the properties specified in the rgpspec.
Reads existing string names associated with the property IDs specified in the rgpropid array.
Assigns string names specified in the rglpwstrName array to property IDs specified in the rgpropid array.
Deletes property names for the properties specified in the rgpropid array.
Sets the CLSID of the property set stream. In the compound file implementation, setting the CLSID on a nonsimple property set (one that can legally contain storage- or stream-valued properties, as described in IPropertySetStorage::Create) also sets the CLSID on the underlying substorage so that it can be obtained through a call to IStorage::Stat.
For both simple and nonsimple property sets, flushes the property set memory image to the underlying storage. In addition, for nonsimple transacted-mode property sets, this method performs a commit (as in IStorage::Commit) on the storage which contains the property set.
For nonsimple property sets only, calls the Revert method of the underlying storage and reopens the 'contents' stream. For simple property sets, this interface always returns S_OK. Nonsimple property sets are those which were created using the PROPSETFLAG_NONSIMPLE flag in the IPropertySetStorage::Create method. For more information, see Storage and Stream Objects for a Property Set .
Constructs an instance of IEnumSTATPROPSTG, the methods of which can be called to enumerate the STATPROPSTG structures that provide information about each of the properties in the set. This implementation creates an array into which the entire property set is read and which can be shared when IEnumSTATPROPSTG::Clone is called. Changes to the property set are not reflected in an open IEnumSTATPROPSTG instance. To see such changes, a new instance of this enumerator must be constructed.
Fills in the members of a STATPROPSETSTG structure, which contains data about the property set as a whole. On return, supplies a pointer to the structure. For nonsimple storage sets, this implementation calls IStorage::Stat (or IStream::Stat) to get the times from the underlying storage or stream. For simple storage sets, no times are maintained.
For nonsimple property sets only, sets the times supported by the underlying storage. The compound file storage implementation supports all three: modification, access, and creation. This implementation of SetTimes calls the IStorage::SetElementTimes method of the underlying storage to retrieve these times.