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

问题描述:

我有一个包含文件列表的ListView拖放从我的应用程序的ListView的外部应用程序(如Windows资源管理器)

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资源管理器。这个怎么做?

+1

的可能的复制[拖放支持为Win32 GUI( https://*.com/questions/12345435/drag-and-drop-support-for-win32-gui) – VTT

+0

没有@VTT这是相反的(从浏览器到我的应用程序)!这里我想要的是相反的:从我的应用程序到外部应用程序。 – Basj

+1

这种情况也在该线程讨论。只是看第二个解释“IDropSource”的答案,然后看第三个链接。 – VTT

下面是一些代码,实现所有需要执行这样一个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; 

实施IDropSourceIDropSourceNotify(可选)和IDataObject,并呼吁DoDragDrop

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

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

SHCreateDataObject可以为你提供一个IDataObject实例,但你经常结束由于shell提供的实现是not perfect,因此不得不。

IDragSourceHelper可以帮助您获得一个奇特的拖动图像。

参见:

+0

谢谢安德斯。 “不完美”的链接不起作用,你还有吗?另外为什么IDropSourceNotify是可选的?如果我不使用它会发生什么? – Basj

+0

链接工作正常,基本上你不能使用CFSTR_FILECONTENTS,因为数据对象只支持索引-1。也许https://archive.is/xVH4X对你更好。通知是可选的,因为您可能不关心用户正在放入的窗口类型。 – Anders