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
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
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 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 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)
Comments are closed. |
I may be missing the obvious but doesn’t outlook use structured storage when dragging messages around.
Mr. Chen,
Thank you for this series. It has been one of the most fun so far.
JamesNT
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?)
god dammit it’s so boring, what’s the purpose raymond?
@gb When you need it, you’ll be able to use it.
@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.
@Anon
I am a computer science student and I wonder if it still a good idea to learn COM!
What do you think?
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… ;)
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.
I see from msdn online this works on XP and later systems. oops.