How Asynchronous Binding and Storage Work

Asynchronous storage enhances the COM structured storage specification to support downloading of storage objects on high-latency, slow-link networks such as the Internet. Asynchronous storage works together with asynchronous monikers to provide complete asynchronous binding behavior.

Document object embedded in a Web page

When a user clicks a link representing a document embedded in a Web page, the following events occur:

  1. The browser calls the MkParseDisplayName function, passing the link URL.

  2. MkParseDisplayName parses the URL, creates a corresponding asynchronous moniker, and returns a pointer to the moniker's IMoniker interface.

  3. The browser calls IsAsyncMoniker to determine if the moniker is asynchronous, creates a bind context, registers the IBindStatusCallback interface with the bind context, only if the moniker is asynchronous, and calls IMoniker::BindToObject, passing the bind context.

  4. The moniker binds to the object and queries it for the IPersistMoniker interface, which indicates whether the object supports asynchronous binding and storage. If the object returns a pointer to IPersistMoniker:

    1. The URL moniker calls IPersistMoniker::Load, passing its own IMoniker pointer to the object.
    2. The object modifies the bind context, chooses whether it wants a blocking or nonblocking storage, registers its own IBindStatusCallback and calls IMoniker::BindToStorage on the pointer it received through IPersistMoniker::Load.
    3. The moniker creates an asynchronous storage, keeps a reference to the wrapper object's IFillLockBytes interface, registers the IProgressNotify interface on the root storage, and calls IPersistStorage::Load, passing the asynchronous storage's IStorage pointer. As data arrives (on a background thread) the moniker calls IFillLockBytes to fill the ILockBytes on the temp file.
    4. The object reads data from the storage and returns from IPersistMoniker::Load when it has received sufficient data to consider itself initialized. If the object attempts to read data that has not yet been downloaded, the downloader receives a notification on IProgressNotify. Inside the IProgressNotify::OnProgress method, the downloading thread either blocks in a modal message loop, or causes the asynchronous storage to return E_PENDING, depending on whether the object has requested a blocking or nonblocking storage.
  5. If the object does not implement IPersistMoniker, the moniker queries for IPersistStorage, which indicates that the object's persistent state is stored in a storage object. If the object returns a pointer to IPersistStorage:

    1. The Moniker calls IMoniker::BindToStorage on itself, requesting a blocking IStorage (because the object is not asynchronous-aware), creates an asynchronous storage, keeps a reference to the wrapper object's IFillLockBytes interface, registers the IProgressNotify interface on the root storage, and calls IPersistStorage::Load, passing the asynchronous storage's IStorage pointer. As data arrives (on a background thread) the moniker calls IFillLockBytes to fill the ILockBytes on the temporary file.
    2. The object reads data from storage and returns from IPersistStorage::Load when it has received sufficient data to consider itself initialized. If the object attempts to read data that has not yet been downloaded, it receives a notification on IProgressNotify. Inside the IProgressNotify::OnProgress method, the downloading thread always blocks in a modal message loop.
  6. Regardless of whether the download is synchronous or asynchronous, the moniker returns from IMoniker::BindToObject, and the browser receives the initialized object it requested.

  7. The browser queries for IOleObject and hosts the object as a Document Object. (At this point the object may not be initialized completely, but enough to display something useful, in which case downloading continues in the background.)