How to get Explorer-like drag images?
Hi,
On Vista, Windows Explorer uses some new kind of drag images. It consists of a quadratic (with rounded corners) bluish background with a large (48x48 I guess) icon on it. At the bottom of the drag image there's some blue text explaining what will happen if you drop the item.
What do I have to do if I want such drag-images in my app?
I've a listview window which is the source of the drag operation. I call SHDoDragDrop() instead of DoDragDrop(), so that I don't have to fiddle around with IDragSourceHelper to get any drag images. However, I only get old-style drag images.
I noticed that I get an empty quadratic (with rounded corners) bluish drag image WITHOUT icon if I intercept the DI_GETDRAGIMAGE message and simply return FALSE. So how do I get the listview item's icon onto this rounded square? And how do I make the blue text display?
Thanks in advance
TiKu
[896 byte] By [
TiKu] at [2007-12-24]
Thanks Microsoft for such incredible good documentation. :] I finally found it out myself.
As I wrote, you'll get the bluish drag-image without any content if you intercept DI_GETDRAGIMAGE and return FALSE. To get some content, simply draw the image like you would do if you'd return TRUE instead of FALSE.
To get the textual drop-effect description at the bottom-right corner of the drag-image, all you have to do is call SHDoDragDrop() passing NULL as drag source object. Don't ask me how I found this one out. :)
There're still two things I'd like to know:
- How do I customize the textual drop-effect description? I know it has to do with the DROPDESCRIPTION struct, but as usual there's not much documentation...
- Is drawing a drag-image in DI_GETDRAGIMAGE and returning FALSE really the right way to fill this bluish thing?
TiKu
*push*
As using the shell's default IDropSource implementation sometimes isn't what I want, I'd like to know how to get Vista-style drag images with my own IDropSource implementation.
So far, I've this:
// DI_GETDRAGIMAGE message handler
LPSHDRAGIMAGE pDragImage = (LPSHDRAGIMAGE) lParam;
pDragImage->sizeDragImage.cx = 100;
pDragImage->sizeDragImage.cy = 100;
// create a 100x100 bitmap compatible to the screen and draw into this bitmap
// then set pDragImage->hbmpDragImage to this bitmap's handle
return FALSE;
My implementation of IDropSource::GiveFeedback(DWORD dwEffect) includes this code:
FORMATETC format = {(CLIPFORMAT) ::RegisterClipboardFormat(CFSTR_DROPDESCRIPTION), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM storageMedium = {0};
storageMedium.tymed = TYMED_HGLOBAL;
storageMedium.hGlobal = ::GlobalAlloc(GHND, sizeof(DROPDESCRIPTION));
if(storageMedium.hGlobal) {
DROPDESCRIPTION* pDD = (DROPDESCRIPTION*) ::GlobalLock(storageMedium.hGlobal);
pDD->type = (DROPIMAGETYPE) dwEffect;
lstrcpyn(pDD->szMessage, L"Move to %1", MAX_PATH);
lstrcpyn(pDD->szInsert, L"Test", MAX_PATH);
::GlobalUnlock(storageMedium.hGlobal);
pDataObject->SetData(&format, &storageMedium, TRUE);
}
return S_OK;
And this is how I'm starting the drag operation:
IDragSourceHelper* pDragSourceHelper = NULL;
IDragSourceHelper2* pDragSourceHelper2 = NULL;
::CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_ALL, IID_IDragSourceHelper, reinterpret_cast<void**>(&pDragSourceHelper));
if(pDragSourceHelper) {
pDragSourceHelper->QueryInterface(IID_IDragSourceHelper2, reinterpret_cast<void**>(&pDragSourceHelper2));
if(pDragSourceHelper2) {
pDragSourceHelper2->SetFlags(DSH_ALLOWDROPDESCRIPTIONTEXT);
pDragSourceHelper2->InitializeFromWindow(hWnd, &mousePosition, pDataObject);
DoDragDrop(pDataObject, pDragSource/*this*/, supportedEffects, &performedEffects);
}
}
But this doesn't really work. The description text is missing and the effect doesn't seem to be updated if I press the modifier keys.
How do I make the description text being displayed?
TiKu