65.9K
CodeProject 正在变化。 阅读更多。
Home

DragSourceHelper MFC

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.38/5 (7投票s)

2003 年 1 月 20 日

2分钟阅读

viewsIcon

99154

downloadIcon

1474

使用 IDragSourceHelper 接口与 MFC

Sample Image - DropSourceHelperMFC.jpg

引言

从 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();

问题

不幸的是,这段代码无法工作,因为 COleDataSourceIDataObject 接口实现存在限制。原因是,在调用 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 混合的拖放操作。

© . All rights reserved.