There are three storage media that can be used for virtual file transfer. We've already seen HGLOBAL and IStream; the last one is IStorage. I doubt anybody will ever need to do virtual file transfer with structured storage, but here it is anyway. Remember that the theme of this series is "It's the least you can do", so I'm going to try to get away with as little as possible.

Starting with our stream-based sample from last time, we need only make a few changes. First, of course, we have to declare that we provide an IStorage as our file contents.

CTinyDataObject::CTinyDataObject() : m_cRef(1)
{
  SetFORMATETC(&m_rgfe[DATA_FILEGROUPDESCRIPTOR],
               RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR));
  SetFORMATETC(&m_rgfe[DATA_FILECONTENTS],
               RegisterClipboardFormat(CFSTR_FILECONTENTS),
               TYMED_ISTORAGE, /* lindex */ 0);
}

Next, we need to produce that storage in our IDataObject::GetData handler:

HRESULT CTinyDataObject::GetData(FORMATETC *pfe, STGMEDIUM *pmed)
{
  ZeroMemory(pmed, sizeof(*pmed));

  switch (GetDataIndex(pfe)) {
  case DATA_FILEGROUPDESCRIPTOR:
  {
    FILEGROUPDESCRIPTOR fgd;
    ZeroMemory(&fgd, sizeof(fgd));
    fgd.cItems = 1;
    StringCchCopy(fgd.fgd[0].cFileName,
                  ARRAYSIZE(fgd.fgd[0].cFileName),
                  TEXT("Dummy"));
    pmed->tymed = TYMED_HGLOBAL;
    return CreateHGlobalFromBlob(&fgd, sizeof(fgd),
                              GMEM_MOVEABLE, &pmed->hGlobal);
  }

  case DATA_FILECONTENTS: //  Create an empty storage
  {
    pmed->tymed = TYMED_ISTORAGE;
    ILockBytes *plb;
    HRESULT hr = CreateILockBytesOnHGlobal(NULL, TRUE, &plb);
    if (SUCCEEDED(hr)) {
        hr = StgCreateDocfileOnILockBytes(plb,
                STGM_READWRITE | STGM_SHARE_EXCLUSIVE |
                STGM_CREATE | STGM_DIRECT,
                0, &pmed->pstg);
        plb->Release();
    }
    return hr;
  }

  return DV_E_FORMATETC;
}

The hardest part was creating the empty storage object! The bookkeeping you're by now well-familiar with. and, as noted when we made the HGLOBAL-based data object, there are additional attributes you can set in the FILEGROUPDESCRIPTOR to make the experience a bit smoother.

That pretty much covers "The least you can do" for virtual file transfer in the shell. You can think of these little sample programs as "scratch data objects"—you can use them as the basis for more complicated virtual file transfer scenarios. We'll see more about this in future articles.