How Asynchronous Binding and Storage Work

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

  1. The browser calls the MkParseDisplayName function, passing the link's URL.
  2. MkParseDisplayName parses the URL, creates a corresponding aynchronous 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 non-blocking 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 temp 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 whether the download is synchronous or asynchronous, the moniker returns from IMoniker::BindToObject, and the browser receives the initialized object it asked for.
  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 only enough to display something useful, in which case downloading continues in the background.)