使用IDropTarget接口同时支持文本和文件拖放(一)

 
使用IDropTarget接口同时支持文本和文件拖放(一)
2008-01-12 07:46

最近在写Shell Extension方面的东西,看到了这篇文章,抄在这里。
原文地址http://blog.csdn.net/vcbear/archive/2002/01/25/5990.aspx
同时也找到了一个与Drag and Drop有关的例子,地址:http://www.codeproject.com/useritems/NSExtDragDrop.asp

vcbear

关于

Windows 的外壳扩展编程,拖放是比较简单的一种,在网上可以找到不少介绍这个技巧的文章。大部分是介绍使用 MFC COleDropTarget 实现的,我觉得一般使用 COleDropTarget 已经很好了,但是我习惯在一些程序模块中,完全的不使用 MFC, 比如纯 SDK 编程 , 还有用在 ATL 的时候 ,MFC 是相当累赘的。所以 COleDropTarget 在这个意义上讲不够完美。

参考了

MSDN 以及 www.CodeProject.com 的相关文章和代码( by Thomas Blenkers )之后,我发现拖放实际上主要使用了 IDropTarget 的接口方法,非常简单,不妨直接面对原始 IDropTarget 实现自己的拖放类。

作为学习笔记,就有了这么一篇文字,以抛砖引玉:

IDropTarget

是系统留给支持拖放的客户程序的一个纯虚接口,事先没有对接口的任何函数进行实现,而是让用户通过实现接口函数来接管拖放的结果。IDropTarget 接口有以下成员函数:
  • 基本
COM 成员函数

QueryInterface

AddRef

Release

    • 接管拖放事件的成员函数:
    • 随时跟踪鼠标和键盘的状态,根据状态决定调用其
    • 从这些接口获取客户程序的返回值,根据这些值和用户界面以及数据源进行交互。

      可以说

    • DragEnter

      DragEnter

      DragOver

      DragLeave

      Drop

      也就是说,要在客户程序里实现以上

      7个函数的实体。

      系统在检测到拖放发生的时候,会在合适的时候依次调用客户程序里实现的

      IDropTarget接口相应函数,检查用户在这些函数里返回的标志,决定鼠标外观表现和拖放结果。

      实现

      IDropTarget接口

      为此建立一个基类为IDropTarget的类:

      class CDropTargetEx : public IDropTarget

      IDropTarget接口在OLEIDL.h里定义,为纯虚接口。

      CDropTargetEx里依次声明接口所包含的7个函数,原形为:

      HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject);

      ULONG STDMETHODCALLTYPE AddRef(void);

      ULONG STDMETHODCALLTYPE Release(void);

      HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState,

      POINTL pt,

      DWORD *pdwEffect);

      HRESULT STDMETHODCALLTYPE DragEnter(IDataObject * pDataObject,

      DWORD grfKeyState, POINTL pt,

      DWORD * pdwEffect);

      HRESULT STDMETHODCALLTYPE DragLeave(void);

      HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj,

      DWORD grfKeyState,

      POINTL pt,

      DWORD __RPC_FAR *pdwEffect);

      (为了实现Addref计数,还有一个ULONG tb_RefCount成员变量是必须的。QueryInterfaceAddRef,Release3个函数的实现是COM知识中最基本的,请参见附例)

      在讲解

      IDropTarget其他函数的具体实现之前,有必要介绍一下一个你可能永远不会直接调用但是确实存在的函数:DoDragDrop函数.此函数在某数据源的数据被拖动的时候就被调用,它负责
      • 检测目标窗口是否支持拖放,发现目标窗口的
      IDropTarget接口

      DrageEnter,DragMove,DropDragLeave接口

      DoDragDrop控制拖放的整个过程,我们要做的,只是将这个过程里发生的事件,接管下来并得到相应的信息,和DoDragDrop进行交互而已。了解了这一点有助于我们理解为什么通过区区一个接口4个函数就可以实现了拖放的效果,因为系统为我们已经做了很多。

      另一个非常重要的

      APIRegisterDragDrop,这个函数的原形是这样的:

      WINOLEAPI RegisterDragDrop(

      HWND hwnd,

      IDropTarget * pDropTarget

      );

      不用被

      WINOLEAPI吓到,这是一个宏:

      #define STDAPI EXTERN_C HRESULT STDAPICALLTYPE

      也就是表示一个标准的

      WIN API函数,返回一个HRESULT的值。

      函数

      RegisterDragDrop的作用是告诉系统:某个窗口(hwnd参数指定)可以接受拖放,接管拖放的接口是pDropTarget

      记住在调用

      RegisterDragDrop之前,一定要先调用OleInitialize初始化OLE环境。

      在类

      CDropTargetEx里设计了一个函数

      BOOL CDropTargetEx::DragDropRegister(HWND hWnd,

      DWORD AcceptKeyState=|MK_LBUTTON)

      {

      if(!IsWindow(hWnd))return false;

      HRESULT s = ::RegisterDragDrop (hWnd,this);

      if(SUCCEEDED(s))

      {

      m_hTargetWnd = hWnd;

      m_AcceptKeyState = AcceptKeyState;

      return true;

      }

      else { return false; }

      }

      在这个函数里调用

      RegisterDragDrop,this指针传入,表示本类实现了IDropTarget.,由本类接管拖放事件。另外顺便定义了一下拖放鼠标和键盘特性常数,对这个类来说,我希望默认的只接受鼠标左键的拖放,所以,默认的AcceptKeyState值是MK_LBUTTON。相关的键盘鼠标常数还有MK_SHIFT,MK_ALT,MK_RBOTTON,MK_MBUTTON,MK_BOTTON等几个,我想这个几个常数从字面上就可以理解它的意思了。这些常数可以用“位与”的操作组合。

      以下具体讨论

      IDropTarget的拖放相关接口函数(4个),这里的拖放对象以文本和文件为主。

        当你用鼠标选中了某一个文件或一段文本,并且将鼠标移到某个可以接受拖放(已经调用过

        RegisterDragDrop)的窗口里,DragEnter将第一时间被调用。再看一下其原形:

        HRESULT DragEnter( IDataObject * pDataObject,

           DWORD grfKeyState,

            POINTL pt,

              DWORD * pdwEffect   )

        pDataobject

        是从拖放的原数据中传递过来的一个IDataObject接口实例,包含数据对象的一些相关方法,可以通过此接口获得数据。

        grfKeyState

        DragEnter被调用时当前的键盘和鼠标的状态,包含上面介绍过的键盘鼠标状态常数。

        pt

        表示鼠标所在的点。是以整个屏幕为参考坐标的。

        pdwEffect

        DoDragDrop提供的一个DWORD指针,客户程序通过这个指针给DoDragDrop返回特定的状态。有效的状态包括:

        DROPEFFECT_NONE=0 表示此窗口不能接受拖放。

        DROPEFFECT_MOVE=1 表示拖放的结果将使源对象被删除

        DROPEFFECT_COPY=2 表示拖放将引起源对象的复制。

        DROPEFFECT_LINK =4 表示拖放源对象创建了一个对自己的连接

        DROPEFFECT_SCROLL=0x80000000表示拖放目标窗口正在或将要进行卷滚。此标志可以和其他几个合用

        对于拖放对象来说,一般只要使用DROPEFFECT_NONEDROPEFFECT_COPY即可。

        DragEnter里要做什么呢?主要是告知拖放已经进入窗口区域,并判断是否支持某具体类型的拖放。

        首先,要判断键盘的状态。在调用DragDropRegister时我传入了一个AcceptKeyState并将其保存在m_AcceptKeyState成员变量里,现在可以拿它跟这里得到的grfKeyState比较:

        if(grfKeyState!=m_AcceptKeyState )

        {

        *pdwEffect = DROPEFFECT_NONE;

        return S_OK;

        }

        如果键盘和鼠标的状态和我期望的不一样,那么

        pdwEffect里返回DROPEFFECT_NONE表示不接受拖放。

        然后

        ,判断拖放过来的IDataObject对象里有没有我感兴趣的数据。

        这里要介绍的是两个关键的结构体

        FORMATETC和STDMEDIUM

        FORMATETC

        OLE数据交换的一个关键结构,对某种设备,数据,和相关媒体做了格式上的描述。

        其定义为

        typedef struct tagFORMATETC

        {

        CLIPFORMAT cfFormat;

        DVTARGETDEVICE *ptd;

        DWORD dwAspect;

        LONG lindex;

        DWORD tymed;

        }

        FORMATETC, *LPFORMATETC;
      评论 1
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值