What a drag: Dragging a virtual file (IStorage edition)

Date:March 20, 2008 / year-entry #91
Tags:code;what-a-drag
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20080320-00/?p=23063
Comments:    10
Summary: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...

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.


Comments (10)
  1. Steve Thresher says:

    I may be missing the obvious but doesn’t outlook use structured storage when dragging messages around.

  2. JamesNT says:

    Mr. Chen,

    Thank you for this series.  It has been one of the most fun so far.

    JamesNT

  3. Dan says:

    Steve: Are you nitpicking?  I don’t think those are virtual files (or real files; doesn’t outlook use one large file for all your e-mail?)

  4. gb says:

    god dammit it’s so boring, what’s the purpose raymond?

  5. @gb When you need it, you’ll be able to use it.

  6. Anon says:

    @gb

    You can’t fool me. I’ve seen lots of movies where esoteric computer knowledge saves the world. When the aliens attack, a knowledge of COM and OLE may save the world. It’s certainly more likely than them using Macs like the aliens in Independence Day. Watch the skys but make sure you read Dale Rogerson!

    More to the point, I could hack up an explorer style application with a treeview/splitter/listview/menu bar that lets me drag and drop files from my PTP device. Or anything else for that matter.

  7. Rivari says:

    @Anon

    I am a computer science student and I wonder if it still a good idea to learn COM!

    What do you think?

  8. Matt Green says:

    If you want to integrate with Windows, you will probably have to learn it. If you’re not aiming to do that, then learn the concepts behind it and why it developed the way it did.

    I know the basics and how to use it in a pinch, but I probably couldn’t write a COM component easily, and I consider myself a fairly competent Windows developer. Maybe I’m not if I try to avoid COM… ;)

  9. Anthony Wieser says:

    Now all I need to do is figure out how to implement the other end of the drop target so that I can register file associations.

    MSDN says this:

    On Microsoft Windows XP systems, enhanced support is added for applications that implement drag-and-drop features and expose their IDropTarget interface. With this method, the Shell communicates with the application through the Component Object Model (COM) subsystem. This method offers a significant performance gain over both the command line method and DDE. To use this method, add a DropTarget subkey under a verb’s key. Under the DropTarget, add a registry string named Clsid, and set the value of this string to a valid CLSID Key.

    MSDN online also adds this helpful advice:

    Implementations of IDropTarget::Drop need to return quickly to the caller avoid causing an unresponsive state. There are two ways to accomplish this:

    Marshall the input IDropTarget to a new thread.

    Take a reference to the data object, set a short timer, and process the drop against that timer. If you use this method, you must ensure that you do not begin processing a second drop while the first is still being processed.

    http://msdn2.microsoft.com/en-us/library/bb776883.aspx

    What it doesn’t say is: Does this work on Vista?

    I assume all I need to do is expose on object on my exe with the specified CLSID that supports an IDropTarget interface.

  10. Anthony Wieser says:

    I see from msdn online this works on XP and later systems.  oops.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index