Getting and Setting IPersist* Objects
The following sections explain how to get and set IPersist* objects.
Getting IPersist* Objects
To get an IPersist* object from a column, a consumer performs the following actions:
-
Creates an accessor that includes a binding to the column. It sets the wType element of the DBBINDING structure to DBTYPE_IUNKNOWN and sets the iid element of the DBOBJECT structure in the binding to the needed interface.
-
Calls IRowset::GetData, IRowsetRefresh::GetLastVisibleData, or IRowsetUpdate::GetOriginalData.
If the object is not currently loaded, the provider, in turn:
-
Creates an instance of the IPersist* object and obtains an IPersistStorage, IPersistStreamInit, or IPersistStream pointer on it. For example, it might call CoCreateInstance with rclsid set to the class ID of the object and riid set to IID_IPersistStorage. How the provider determines the class ID of the object is provider-specific. For more information, see "IPersist* Objects," earlier in this chapter.
-
Creates an IStream or IStorage instance over the data in the column. If there is no data in the column, as is the case for a newly created row, the provider then calls InitNew on either IPersistStorage or IPersistStreamInit.
If the provider supports only a single open storage object at a time and another storage object is open, the method returns a status of DBSTATUS_E_CANTCREATE for the column.
-
Loads the IPersist* object by calling Load on the IPersist* interface on the object and passing the interface pointer obtained in step 2.
-
Performs the operations required to enable future calls to the method to detect that the object has already been loaded (for example, using a moniker to the object) and to return a pointer on the loaded object.
-
Returns a pointer to the requested interface to the consumer. If the object does not support the requested interface, the method returns E_NOINTERFACE. After the method returns, the rowset does not hold any reference counts on the object.
If the object is currently loaded—which the provider can determine by virtue of the operations performed in step 4 in the preceding procedure—the provider performs the following action:
-
Returns a pointer to the requested interface to the consumer.
-
If the object does not support this interface, the method returns E_NOINTERFACE.
If any errors occur during these procedures, the provider ensures that no objects remain instantiated when GetData, GetLastVisibleData, or GetOriginalData returns.
Setting IPersist* Objects
To set an IPersist* object in a column, a consumer uses one of two procedures. In the first procedure, the consumer performs the following actions:
-
Calls IRowset::GetData to retrieve an IStorage or IStream pointer over the object's data. It does this in the same way it retrieves an IStorage or IStream pointer over BLOB data. The provider does not load the object, as is the case when the consumer calls GetData and requests a different interface, such as IPersistStorage. If the provider supports only one open storage object at a time and another storage object is open, the method returns a status of DBSTATUS_E_CANTCREATE for the column.
-
Calls Save on the IPersist* interface of the IPersist* object and passes it the storage interface pointer retrieved in step 1.
-
Calls IPersistStorage::SaveCompleted on the IPersist* object if IPersistStorage is used. The consumer should be careful if it sets the pStgNew parameter to a non-null pointer, because the provider does not dissociate the column's storage object from the IPersist* object.
This procedure should be used only by consumers that know what kind of IPersist* objects should be stored in a column. Because the storage object, which is implemented by the rowset, does not have a pointer to the IPersist* object, the rowset cannot determine whether the IPersist* object uses a class ID that matches the class ID used by the objects in the column. The possibility therefore arises that the consumer could store an object in the column of a type of which the rowset will not be able to create an instance later.
-
In the second procedure, the consumer performs the following action. Note that this procedure can be used by any consumer. It should be used by consumers that do not know what kind of IPersist* objects can be stored in the column because the provider can check the class ID of the object before storing it.Calls IRowsetChange::SetData or IRowsetChange::InsertRow and passes a pointer to an interface on the IPersist* object.
The provider performs the following actions, in turn:
-
Creates a new storage object for the column and retrieves a storage interface pointer on that object.
If there is an existing storage object on the column that the provider cannot release, SetData or InsertRow returns a status of DBSTATUS_E_CANTCREATE for the column. For example, this occurs if there is an IPersist* object loaded on the column. If the provider supports only one open storage object at a time and a storage object is open over another column or row, the method returns a status of DBSTATUS_E_CANTCREATE for the column.
-
(Optional) Calls IPersist::GetClassID on the IPersist* object to verify that the specified IPersist* object is of a type that can be stored in the column.
-
Calls Save on the IPersist* interface of the IPersist* object and passes it the storage interface pointer retrieved in step 1.
If the provider calls IPersistStorage::Save, it sets the fSameAsLoad argument to FALSE; if the provider calls IPersistStream::Save or IPersistStreamInit::Save, it sets the fClearDirty flag to TRUE.
-
Calls IPersistStorage::SaveCompleted on the IPersist* object if IPersistStorage is used. The provider sets the pStgNew argument to a null pointer.
-
Performs the operations required to enable future calls to GetData, GetLastVisibleData, or GetOriginalData to detect whether the object is loaded and to return a pointer on the loaded object.
After SetData or InsertRow returns, the rowset does not hold any reference counts on the IPersist* object.