从我的应用程序的 ListView 拖放到外部应用程序(例如 Windows Explorer)
Drag and drop from my app's ListView to external apps (such as Windows Explorer)
我有一个 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 Explorer),如 "Copy"?
问题的 GUI 部分可能很明显 (or not?) 通过:
case WM_NOTIFY:
{
...
case LVN_BEGINDRAG:
但这里的问题是关于将文件实际发送到外部应用程序,例如 Windows Explorer。如何做到这一点?
实施 IDropSource
、IDropSourceNotify
(可选)和 IDataObject
并调用 DoDragDrop
:
If you are developing an application that can act as a data source for an OLE drag-and-drop operation, you must call DoDragDrop when you detect that the user has started an OLE drag-and-drop operation.
The DoDragDrop function enters a loop in which it calls various methods in the IDropSource and IDropTarget interfaces. (For a successful drag-and-drop operation, the application acting as the data source must also implement IDropSource, while the target application must implement IDropTarget.)
SHCreateDataObject
can provide a IDataObject
instance for you but you often end up having to code your own because the shell provided implementation is not perfect.
IDragSourceHelper
可以帮助您获得精美的拖动图像。
另请参阅:
下面是一些实现执行此类 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;
我有一个 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 Explorer),如 "Copy"?
问题的 GUI 部分可能很明显 (or not?) 通过:
case WM_NOTIFY:
{
...
case LVN_BEGINDRAG:
但这里的问题是关于将文件实际发送到外部应用程序,例如 Windows Explorer。如何做到这一点?
实施 IDropSource
、IDropSourceNotify
(可选)和 IDataObject
并调用 DoDragDrop
:
If you are developing an application that can act as a data source for an OLE drag-and-drop operation, you must call DoDragDrop when you detect that the user has started an OLE drag-and-drop operation.
The DoDragDrop function enters a loop in which it calls various methods in the IDropSource and IDropTarget interfaces. (For a successful drag-and-drop operation, the application acting as the data source must also implement IDropSource, while the target application must implement IDropTarget.)
SHCreateDataObject
can provide a IDataObject
instance for you but you often end up having to code your own because the shell provided implementation is not perfect.
IDragSourceHelper
可以帮助您获得精美的拖动图像。
另请参阅:
下面是一些实现执行此类 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;