MDAC 2.5 SDK - OLE DB Programmer's Reference
Chapter 7: BLOBs and COM Objects


 

Getting and Setting IPersist* Objects

The following sections explain how consumers get and set IPersist* objects and how these objects are stored by providers.

Getting IPersist* Objects

To get an IPersist* object from a column, a consumer performs the following actions:

  1. 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.

  2. Calls IRowset::GetData, IRowsetRefresh::GetLastVisibleData, or IRowsetUpdate::GetOriginalData.

If the object is not currently loaded, the provider will perform the following actions:

  1. Create an instance of the IPersist* object and obtain an IPersistStorage, IPersistStreamInit, or IPersistStream pointer on it.

    For example, the provider 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.

  2. Create 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.

  3. Load the IPersist* object: that is, call Load on the IPersist* interface on the object and pass the interface pointer obtained in step 2.

  4. Perform 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.

  5. Return 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 will return 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 IRowset::GetData, IRowsetRefresh::GetLastVisibleData, or IRowsetUpdate::GetOriginalData returns.

Setting IPersist* Objects

To set an IPersist* object in a column, a consumer uses one of two procedures. The first 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 that the rowset will not be able to later create an instance of.

In this first procedure, the consumer will perform the following actions:

  1. Call 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 IRowset::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.

  2. Call Save on the IPersist* interface of the IPersist* object and pass it the storage interface pointer retrieved in step 1.

  3. Call 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.

The second 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. In this second procedure, the consumer will call IRowsetChange::SetData or IRowsetChange::InsertRow and pass a pointer to an interface on the IPersist* object.

In turn, the provider will perform the following actions:

  1. Create a new storage object for the column and retrieve a storage interface pointer on that object.

    If there is an existing storage object on the column that the provider cannot release, IRowsetChange::SetData or IRowsetChange::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 might return a status of DBSTATUS_E_CANTCREATE for the column.

  2. (Optional) Call IPersist::GetClassID on the IPersist* object to verify that the specified IPersist* object is of a type that can be stored in the column.

  3. Call Save on the IPersist* interface of the IPersist* object and pass 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.

  4. Call IPersistStorage::SaveCompleted on the IPersist* object if IPersistStorage is used. The provider sets the pStgNew argument to a null pointer.

  5. Perform the operations required to enable future calls to IRowset::GetData, IRowsetRefresh::GetLastVisibleData, or IRowsetUpdate::GetOriginalData to detect whether the object is loaded and to return a pointer on the loaded object.

    After IRowsetChange::SetData or IRowsetChange::InsertRow returns, the rowset does not hold any reference counts on the IPersist* object.