【问题标题】:Drag and drop from my app's ListView to external apps (such as Windows Explorer)从我的应用的 ListView 拖放到外部应用(例如 Windows 资源管理器)
【发布时间】:2017-07-18 06:24:28
【问题描述】:

我有一个包含文件列表的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 资源管理器)作为“复制”?

问题的 GUI 部分可能很明显 (or not?),通过:

case WM_NOTIFY:
{
    ...
    case LVN_BEGINDRAG:

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

【问题讨论】:

  • No @VTT 恰恰相反(从浏览器到我的应用程序)!在这里我想要相反:从我的应用程序到外部应用程序。
  • 该线程也讨论了这种情况。只看第二个答案解释IDropSource 和第三个链接。
  • 所谓的重复问题清楚地说明了反向请求@VTT,而您提到的答案只是2个链接(应该是cmets),因此我认为这个实际问题可能仍然是相关的,出于这两个原因,你能重新考虑一下,你怎么看?
  • 为什么不搜索网页?这已经被问过很多次了。你以为你是第一个来这里问的?

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


【解决方案1】:

实现IDropSourceIDropSourceNotify(可选)和IDataObject并调用DoDragDrop

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

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

SHCreateDataObject 可以为您提供IDataObject 实例,但您通常最终不得不code your own,因为shell 提供的实现是not perfect

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

另见:

【讨论】:

  • 谢谢安德斯。 “不完美”的链接失效了,你还有吗?另外为什么 IDropSourceNotify 是可选的?如果我不使用它会怎样?
  • 链接工作正常,基本上你不能使用CFSTR_FILECONTENTS,因为数据对象只支持索引-1。也许archive.is/xVH4X 更适合你。通知是可选的,因为您可能不关心用户正在进入的窗口类型。
【解决方案2】:

这里有一些代码实现了执行此类 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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-29
    • 2011-04-02
    • 2011-04-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    • 2011-02-22
    相关资源
    最近更新 更多