第一部分:OLE Drag&Drop 介绍

1.基本概念


    拖放,是指用鼠标拖动的方法,在不同程序的窗口之间、同一程序的不同窗口之间或同一程序同一窗体的不同控件之间,进行移动、复制、粘贴数据等操作的技术。拖放操作是依靠操作系统来完成的,被拖动的对象首先向操作系统注册一种它所使用数据的格式,并且按照这种格式来提供数据,拖放结束时,目标窗口提取出数据,并根据提取的数据生成相应的对象。

    拖放方式有两种,一种是OLE拖放(这个比较复杂)和文件管理器拖放。它们利用了不同的机制。

2.文件管理器拖放


    只能处理文件名,比如,你可以在资源管理器中选择一个或多个文件,拖到应用程序上面(这个程序的dwExStyle要加上WS_EX_ACCEPTFILES),那么这个窗体就会收到一个WM_DROPFILES消息。它主要用到下面几个API函数:DragQueryFile、DragQueryPoint、DragFinish。函数原型如下:

    a)UINT DragQueryFile(HDROP hDrop, UINT iFile, LPTSTR lpszFile, UINT cch)
    b)BOOL DragQueryPoint(HDROP hDrop, LPPOINT lppt)
    c)void DragFinish(HDROP hDrop)
       一般用法如下:
    void CListCtrlEx::OnDropFiles(HDROP hDrop)
    {
        char   szFilePathName[_MAX_PATH+1] = {0};
        UINT  nNumOfFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); //得到文件个数
        for (UINT nIndex=0 ; nIndex< nFileCount; ++nIndex)
        {
            DragQueryFile(hDrop, nIndex, szFilePathName, _MAX_PATH);  //得到文件名
        }
        DragFinish(hDrop);
    }

       由于这里不重点讲这种方式的拖放,所以具体的用法讲参考MSDN,上面都有详细说明。

3.OLE拖放原理

       拖放是用来描述用鼠标装数据从一个地方传输到另一个地方,OLE拖放比文件管理拖放更加通用得多,能在不同的应用程序中交互任务类型的数据(先要向系统注册该类型)。每一个拖放操作都须包含三个元素,当然,这些都是COM对象,需要我们去实现这些接口。

    1)IDropSource,表示拖放操作的源,它包含了拖放目标要使用的数据(IDataObject),它能在拖放的过程生成一些可视化的反馈,如设置鼠标样式等。
    2)IDropTarget,表示拖放操作的目标,它决定拖放的效果、接收任何合法数据、给拖放源一些反馈等。
    3)IDataObject,表示拖放源与目标之间传输的数据。

    注意了,一个应用程序不需要支持所有的COM接口。如果你的程序想做为一个拖放目标,那么你就实现IDropTarget接口,同样的,如果你需要支持作为数据源的程序,那么就应该实现IDropSource和IDataObject接口。当然,程序也可以同时实现这三个接口,从而可以在同一程序中支持拖放操作。


上面的图描述了拖放操作中所需要的关键组件。左边的表示拖放操作的源,它已经包含了两个对象,一个是IDropSource,另一个是IDataObject,最终是通过API函数DoDragDrop来发现拖放操作。

    右边描述了拖放操作的目标,它需要实现IDropTarget接口。这个目标中,它能接收IDataObject对象。当鼠标拖动到目标窗体时,OLE传递一个IDataObject接口到目标对象上面,这是源传给目标的数据,它不能以任何方式得到一个副本。这目标这边它可以根据IDataObject得到该数据格式,从而判断这种格式是不是目标能识别的,如果不能识别,就不接收。它本质上需要调用RegisterDragDrop来把当前目标窗体注册成一个拖放目标。

    注意,上面的图所示,源和目标可以是同一进程,也可以是不同进程。在使用之前,需要调用COM和OLE的初始化,使用完后,再调用其反初始化。

    WINOLEAPI OleInitialize(LPVOID pvReserved);
    WINOLEAPI OleUninitialize();

4.开始拖放

    上面也提到了,DoDragDrop函数,它用来开始拖放操作,原型如下:
    WINOLEAPI DoDragDrop(
        IDataObject  * pDataObject,   // Pointer to the data object
        IDropSource  * pDropSource,   // Pointer to the source
        DWORD          dwOKEffect,    // Effects allowed by the source
        DWORD        * pdwEffect      // Pointer to effects on the source
        );

       在调用这个方法时,就要把你实现的源(IDragSource)和数据(IDataObject)传给他,至于如何创建源和数据的对象,在后面介绍。
       当调用DoDragDrop时,它会进入一个模态的消息循环,用来监视鼠标和简单的消息,它是会阻塞住的。

5.注册目标

    要想一个窗体成为一个拖放的接收方,它必须调用RegisterDragDrop函数来注册。其原型如下:
    WINOLEAPI RegisterDragDrop(
        HWND           hwnd,          // Handle to a window that can accept drops
        IDropTarget  * pDropTarget // Pointer to object that is to be target of drop
        );

       它的第一个参数就是目标窗体的句柄。
       与它作用相反的函数是RevokeDragDrop函数,释放注册时用到的IDropTarget接口对象。这个函数在窗体销毁时应该调用。
    WINOLEAPI RevokeDragDrop(
        HWND    hwnd                  // Handle to a window that can accept drops
        );

你可能感兴趣的:(COM)