DragSourceHelper MFC






4.38/5 (7投票s)
2003 年 1 月 20 日
2分钟阅读

99154

1474
使用 IDragSourceHelper 接口与 MFC
引言
从 Windows2000 开始,Shell 暴露了辅助 COM 对象,允许应用程序指定在拖放操作期间显示的图像。该图像将自动与当前操作系统的外观和感觉进行 Alpha 混合。这对开发者来说是个好消息。坏消息是,在不进行修改的情况下,它无法与 MFC 的 OLE 数据源的默认实现一起工作。
背景
Shell(版本 5 或更高版本)暴露了 DragSourceHelper 对象
(CLSID_DragDropHelper
) 并带有接口 IDragSourceHelper
。
HRESULT InitializeFromBitmap( LPSHDRAGIMAGE pshdi, IDataObject *pDataObject );
HRESULT InitializeFromWindow( HWND hwnd, POINT *ppt, IDataObject *pDataObject );
该对象的目的是在拖放操作期间提供视觉反馈。在发出 ::DoDragDrop
调用之前,您需要实例化该对象并将您希望在拖动对象时看到的位图传递给它。就这些了。在 MFC 中,该过程如下所示
数据源
实例化并初始化数据源
COleDataSource source;
// add some content to the source
辅助对象
使用标准的 COM 技术实例化辅助对象。获取位图句柄并初始化 SHDRAGIMAGE
结构。现在使用位图和数据对象初始化辅助对象。请注意,这段代码也适用于不暴露辅助对象的系统(Windows 95、98、ME 和 NT),它只是不会显示拖放图像。
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); }
开始拖放操作
执行标准的拖放操作。source.DoDragDrop();
问题
不幸的是,这段代码无法工作,因为 COleDataSource
的 IDataObject
接口实现存在限制。原因是,在调用 InitializeFromBitmap
时,辅助对象使用自定义剪贴板格式调用 IDataObject::SetData
,以便在数据对象中保留指向自身的指针。数据对象必须满足此调用。但是,COleDataSource
的默认实现不接受未知的剪贴板格式,因此我们需要重写 IDataObject::SetData
方法。
解决方案
如果我们重写IDataObject::SetData
方法并允许将任意格式存储在数据对象中,那么一切都会正常工作。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; }
结论
Windows2000 DragSourceHelper
对象提供了一种很棒的方式,只需几行代码即可实现 Alpha 混合的拖放操作。