Saving Run-Time Information

The QueryPersistenceInterface and SaveRuntimeState methods allow the host to find and use the persistence interface for the run-time object. (These methods apply to the run-time object only. Persistent data for the visual designer are handled directly through IPersist and its derived interfaces.)

Calls to QueryPersistenceInterface pass the interface identifier (IID) of one of the persistence interfaces (IPersistStreamInit, IPersistStream, or IPersistStorage). If the ActiveX designer supports the specified interface, it returns S_OK; if not, it returns S_FALSE, as in the following example:

STDMETHODIMP CMyDesigner::QueryPersistenceInterface
(
  REFIID riid
)
{
    if (riid == IID_IPersistStreamInit)
      return S_OK;
    else if (riid == IID_IPersistStorage)
      return S_OK;
    else if (riid == IID_IPersistStream)
      return S_OK;
      else 
   return S_FALSE;
} 

The example shows a designer that supports all three persistence interfaces for the run-time object.

After the host queries for a persistence interface, it opens a stream or storage object, as appropriate, and calls SaveRuntimeState to save data for the run-time object. Input parameters to SaveRuntimeState are the IID of the persistence interface, the IID of the stream or storage object, and a pointer to the stream or storage object.

The following example checks to see what type of interface the host has passed and sets up the pointer appropriately. For storage persistence, it opens a stream within the storage object and writes the data to the stream.

STDMETHODIMP CMyDesigner::SaveRuntimeState
(
  REFIID riidItf,
   REFIID riidObj,
  void  *pMedium
)
{
  IStream *pStream;
  long   l;
  HRESULT  hr;
  LPWSTR pwsz;

  // Get an IStream.
  
  if (riidObj == IID_IStream) {
    pStream = (IStream *)pMedium;
    pStream->AddRef();
    }
  else if (riidObj == IID_IStorage) {
    // Save to the CONTENTS stream.
    
    hr = ((IStorage *)pMedium)->
            CreateStream(s_wszRuntimeSaveStream, 
               STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 
               0, 0, &pStream);
    RETURN_ON_FAILURE(hr);
         }
   else {
   FAIL("Unsupported persistence interface!");
    }

  // Save some standard state information. The Load
  // routine will look for it in the stream.
  
  hr = SaveStandardState(pStream);
  RETURN_ON_FAILURE(hr);

  // Save property.
  
  if (m_bstrMyString) {
    pwsz = m_bstrMyString;
    l = SysStringLen(m_bstrMyString) + 1;
  } else {
    pwsz = L"";
    l = 1;
  }

  hr = pStream->Write(&l, sizeof(l), NULL);
  RETURN_ON_FAILURE(hr);
  hr = pStream->Write(pwsz, l * sizeof(WCHAR), NULL);

  pStream->Release();
  return hr;
}

The example saves two kinds of persistent data: some standard data that is the same for all objects of this class, and a local property that the end user can change. After writing the data to the stream, the sample code releases the stream pointer and returns.

Your requirements will vary depending on the nature and complexity of your ActiveX designer. You should make sure the persistent data includes all the information needed to create an instance of the run-time object. This might include type information, properties, and global variables such as time-out values that may have been set at design time.

When you implement the Load method of the persistence interfaces, you write code to load the saved information into the run-time object. The host calls the Load method when it creates an instance of the run-time object.