DragSourceHelper MFC






4.38/5 (7 votes)
Jan 20, 2003
2 min read

98022

1474
Making use of the IDragSourceHelper interface with MFC
Introduction
Beginning with Window2000 the shell exposes helper COM-objects that allow an application to specify an image that is displayed during a drag&drop operation. This image will automatically be alpha-blended to fit the current OS's look&feel. That's great news for a developer. The bad news is that it does not work with MFC's default implementation of the OLE data source without modification.
Background
The shell (version 5 or higher) exposes the DragSourceHelper object
(CLSID_DragDropHelper
) with the interface IDragSourceHelper
.
HRESULT InitializeFromBitmap( LPSHDRAGIMAGE pshdi, IDataObject *pDataObject );
HRESULT InitializeFromWindow( HWND hwnd, POINT *ppt, IDataObject *pDataObject );
The purpose of the object is to give visual feedback during a drag&drop operation. Before issuing the ::DoDragDrop
call, you need to instantiate the object and transfer the bitmap you would like to see while the object is dragged around. That's all. In MFC that procedure reads like this:
The Data Source
Instantiate and initialize the data source:
COleDataSource source;
// add some content to the source
The Helper Object
Instantiate the helper object using standard COM techniques. Obtain a bitmap handle and initialize the SHDRAGIMAGE
structure. Now initialize the helper with the bitmap and the data object. Please note that this code also works under systems that do not expose the helper object (Windows 95,98,ME and NT), it simply does not display a drag image.
CComPtr<IDragSourceHelper> pHelper; HRESULT hr = CoCreateInstance(CLSID_DragDropHelper,NULL, CLSCTX_ALL,IID_IDragSourceHelper,(LPVOID*)&pHelper); if SUCCEEDED(hr) { // load a testbitmap CBitmap bmp; GetBitmap(bmp); // prepare the SHDRAGIMAGE structure BITMAP bmpInfo; bmp.GetBitmap(&bmpInfo); // fill the drag&drop structure SHDRAGIMAGE info; info.sizeDragImage.cx = bmpInfo.bmWidth; info.sizeDragImage.cy = bmpInfo.bmHeight; info.ptOffset.x = 0; info.ptOffset.y = 0; info.hbmpDragImage = (HBITMAP)bmp.Detach(); info.crColorKey = GetSysColor(COLOR_WINDOW); // this call assures that the bitmap will be dragged around hr = pHelper->InitializeFromBitmap( // drag&drop settings &info, // a pointer to the data object, the helper will store // a reference to itself into this object (IDataObject*)source.GetInterface(&IID_IDataObject) ); // in case of an error we need to destroy the image, // else the helper object takes ownership if FAILED(hr) DeleteObject(info.hbmpDragImage); }
Starting the Drag&Drop operation
Perform standard drag&drop.source.DoDragDrop();
The Problem
Unfortunately this piece of code does not work because of a limitation of COleDataSource
's implementation of the IDataObject
interface. The reason is that in the call to InitializeFromBitmap
the helper calls IDataObject::SetData
with a custom clipboard format to keep a pointer to itself within the data object. The data object must satisfy this call. The default implementation of COleDataSource
however does not accept unknown clipboard formats, so we need to override the IDataObject::SetData
method.
The Solution
If we override theIDataObject::SetData
method and allow an arbitrary format to be stored in the data object, everything works fine. Class COleDataSourceEx : public COleDataSource { public: // helper methods to fix IDropSourceHelper DECLARE_INTERFACE_MAP() // handle name events BEGIN_INTERFACE_PART(DataObj, IDataObject) INIT_INTERFACE_PART(COleDataSourceEx, DataObject) // IDataObject … STDMETHOD(SetData)(LPFORMATETC, LPSTGMEDIUM, BOOL); END_INTERFACE_PART(DataObj) };
STDMETHODIMP COleDataSourceEx::XDataObj::SetData(LPFORMATETC pFormatetc, LPSTGMEDIUM pmedium, BOOL fRelease) { METHOD_PROLOGUE(COleDataSourceEx, DataObj) // normal processing HRESULT hr = pThis->m_xDataObject.SetData(pFormatetc,pmedium,fRelease); if (hr==DATA_E_FORMATETC) { // cache the data explicitly pThis->CacheData(pFormatetc->cfFormat,pmedium,pFormatetc); return S_OK; } // normal error return hr; }
Conclusion
The Windows2000 DragSourceHelper
object provides a cool way to do alpha blended drag&drop with only very few lines of code.