拖放从我的应用程序的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资源管理器)作为“复制”?
问题的GUI部分可能通过很明显(or not?):
case WM_NOTIFY:
{
...
case LVN_BEGINDRAG:
但这里有个问题是关于实际发送文件到外部应用程序,如Windows资源管理器。这个怎么做?
答
下面是一些代码,实现所有需要执行这样一个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;
答
实施IDropSource
,IDropSourceNotify
(可选)和IDataObject
,并呼吁DoDragDrop
:
如果您正在开发可以作为一个OLE拖放和拖放操作的数据源作用的应用程序,你必须调用的DoDragDrop当您检测到用户已启动OLE拖放操作时。
DoDragDrop函数进入一个循环,在该循环中它调用IDropSource和IDropTarget接口中的各种方法。 (对于一个成功的拖和拖放操作,作为数据源的应用程序还必须实现IDropSource,而目标应用程序必须实现下降目标。)
SHCreateDataObject
可以为你提供一个IDataObject
实例,但你经常结束由于shell提供的实现是not perfect,因此不得不。
IDragSourceHelper
可以帮助您获得一个奇特的拖动图像。
参见:
的可能的复制[拖放支持为Win32 GUI( https://stackoverflow.com/questions/12345435/drag-and-drop-support-for-win32-gui) – VTT
没有@VTT这是相反的(从浏览器到我的应用程序)!这里我想要的是相反的:从我的应用程序到外部应用程序。 – Basj
这种情况也在该线程讨论。只是看第二个解释“IDropSource”的答案,然后看第三个链接。 – VTT