从我的应用程序的ListView拖放到外部应用程序(例如Windows资源管理器)

时间:2017-07-12 10:14:32

标签: c++ listview winapi drag-and-drop shell-extensions

我有一个包含文件列表的ListView

hList = CreateWindowEx(0, WC_LISTVIEW, L"", WS_CHILD | WS_VISIBLE | LVS_REPORT, 0, 0, 500, 400, hWnd, (HMENU)ID_LISTVIEW, hInst, NULL);

我们说它包含一行c:\temp\hello.txt

如何启用此文件从我的应用程序的ListView拖放到外部应用程序(例如Windows资源管理器)作为"复制"?

enter image description here

问题的GUI部分可能很明显(or not?)来自:

case WM_NOTIFY:
{
    ...
    case LVN_BEGINDRAG:

但是这里的问题是关于将文件实际发送到外部应用程序,例如Windows资源管理器。怎么做?

2 个答案:

答案 0 :(得分:1)

实施IDropSourceIDropSourceNotify(可选)和IDataObject并致电DoDragDrop

  

如果您正在开发可以充当OLE拖放操作的数据源的应用程序,则必须在检测到用户已启动OLE拖放操作时调用DoDragDrop。

     

DoDragDrop函数进入一个循环,在其中调用IDropSource和IDropTarget接口中的各种方法。 (对于成功的拖放操作,充当数据源的应用程序也必须实现IDropSource,而目标应用程序必须实现IDropTarget。)

SHCreateDataObject可以为您提供IDataObject个实例,但您最终必须code your own,因为shell提供的实现是not perfect

IDragSourceHelper可以帮助您获得精美的拖动图像。

另见:

答案 1 :(得分:0)

这是一些代码,它实现了执行此类ListView文件拖放所需的所有操作。首先是一些包括:

#define CINTERFACE
#define COBJMACROS
#include "ShObjIdl.h"
#include "ShlObj.h"
#include "oleidl.h"

然后在WinMain函数中,初始化OLE操作。

OleInitialize(NULL);
InitCommonControls();

然后,IDropSource部分:

typedef struct __DSV_TDropSource {
    IDropSource     This;
    IDropSourceVtbl Func;
    ULONG           RefCnt;
} __DSV_TDropSource;

HRESULT WINAPI __DSV_QueryInterface(IDropSource *This, REFIID riid, void **ppvObject)
{
    IUnknown *punk = NULL;

    if (riid == IID_IUnknown)
    {
        punk = (IUnknown*)This;
    }
    else if (riid == IID_IDropSource)
    {
        punk = (IUnknown*)This;
    }

    *ppvObject = punk;

    if (punk)
    {
        IUnknown_AddRef(punk);
        return S_OK;
    }
    else {
        return E_NOINTERFACE;
    }
}

ULONG WINAPI __DSV_AddRef(IDropSource *This)
{
    __DSV_TDropSource *pThis = (__DSV_TDropSource*)This;
    return pThis->RefCnt++;
}

ULONG WINAPI __DSV_Release(IDropSource *This)
{
    __DSV_TDropSource *pThis = (__DSV_TDropSource*)This;

    LONG iRes = (LONG)pThis->RefCnt - 1;
    if (iRes < 1) { iRes = 0; }
    pThis->RefCnt = iRes;

    if (iRes == 0) { free(pThis); }
    return iRes;
}

HRESULT WINAPI __DSV_QueryContinueDrag(IDropSource *This, BOOL fEscapePressed, DWORD grfKeyState)
{
    if (fEscapePressed) { return DRAGDROP_S_CANCEL; }

    if (!(grfKeyState & (MK_LBUTTON | MK_RBUTTON))) { return DRAGDROP_S_DROP; }

    return S_OK;
}

HRESULT WINAPI __DSV_GiveFeedback(IDropSource *This, DWORD dwEffect)
{
    return DRAGDROP_S_USEDEFAULTCURSORS;
}

IDropSource* CreateDropSource()
{
    __DSV_TDropSource *pResu = (__DSV_TDropSource*)malloc(sizeof(__DSV_TDropSource));
    if (!pResu) { return 0; }

    pResu->This.lpVtbl = &(pResu->Func);
    pResu->Func.QueryInterface = __DSV_QueryInterface;
    pResu->Func.AddRef = __DSV_AddRef;
    pResu->Func.Release = __DSV_Release;
    pResu->Func.QueryContinueDrag = __DSV_QueryContinueDrag;
    pResu->Func.GiveFeedback = __DSV_GiveFeedback;

    pResu->RefCnt = 1;
    return (IDropSource*)pResu;
}


void** GetFileUiObject(TCHAR *ptFile, REFIID riid)
{

    void** pInterfaceResu = 0;
    IShellFolder *pFolder;
    PIDLIST_RELATIVE pFile;
    PIDLIST_ABSOLUTE pITEMDLIST_File;
    HRESULT iResu;

    pITEMDLIST_File = ILCreateFromPath(ptFile);
    if (!pITEMDLIST_File)
        return 0;

    iResu = SHBindToParent(pITEMDLIST_File, IID_IShellFolder, (void**)&pFolder, (PCUITEMID_CHILD*)&pFile);
    if (iResu != S_OK)
        return 0;

    const ITEMIDLIST* pArray[1] = { pFile };
    iResu = IShellFolder_GetUIObjectOf(pFolder, NULL, 1, pArray, riid, NULL, (void**)&pInterfaceResu);
    if (iResu != S_OK)
        return 0;

    IShellFolder_Release(pFolder);

    return pInterfaceResu;
}

最后,这应该在消息循环中执行:

case WM_NOTIFY:
        pdi = (NMLVDISPINFO*) lParam;
        nmlv = (NMLISTVIEW*) lParam;
        switch (pdi->hdr.code)
        {

        case LVN_BEGINDRAG:
            wstring fName = L"C:\\test.txt";
            IDataObject *pObj;
            IDropSource *pSrc;
            pObj = (IDataObject*)GetFileUiObject(LPWSTR(fName.c_str()), IID_IDataObject);
            if (!pObj)
                break;

            pSrc = CreateDropSource();
            if (!pSrc)
            {
                IDataObject_Release(pObj);
                break;
            }

            DWORD dwEffect;
            DoDragDrop(pObj, pSrc, DROPEFFECT_COPY | DROPEFFECT_LINK, &dwEffect);

            IDropSource_Release(pSrc);
            IDataObject_Release(pObj);
            break;