[SHELL32] CFSDropTarget: Initial implementation of right click drag menu

This commit is contained in:
Giannis Adamopoulos 2018-02-16 20:33:44 +02:00
parent 8f8ab050db
commit 6d91269eda
2 changed files with 123 additions and 4 deletions

View file

@ -83,7 +83,7 @@ HRESULT WINAPI CFSDropTarget::CopyItems(IShellFolder * pSFFrom, UINT cidl,
SHFILEOPSTRUCTW op = {0};
op.pFrom = pszSrcList;
op.pTo = wszTargetPath;
op.hwnd = GetActiveWindow();
op.hwnd = m_hwndSite;
op.wFunc = bCopy ? FO_COPY : FO_MOVE;
op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
@ -100,7 +100,9 @@ HRESULT WINAPI CFSDropTarget::CopyItems(IShellFolder * pSFFrom, UINT cidl,
CFSDropTarget::CFSDropTarget():
cfShellIDList(0),
fAcceptFmt(FALSE),
sPathTarget(NULL)
sPathTarget(NULL),
m_hwndSite(NULL),
m_grfKeyState(0)
{
}
@ -180,6 +182,70 @@ BOOL CFSDropTarget::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
return FALSE;
}
HRESULT CFSDropTarget::_GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, DWORD *pdwEffect)
{
HMENU hmenu = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(IDM_DRAGFILE));
if (!hmenu)
return E_OUTOFMEMORY;
/* FIXME: We need to support shell extensions here */
UINT uCommand = TrackPopupMenu(GetSubMenu(hmenu, 0),
TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
pt.x, pt.y, 0, m_hwndSite, NULL);
if (uCommand == 0)
return S_FALSE;
else if (uCommand == IDM_COPYHERE)
*pdwEffect = DROPEFFECT_COPY;
else if (uCommand == IDM_MOVEHERE)
*pdwEffect = DROPEFFECT_MOVE;
else if (uCommand == IDM_LINKHERE)
*pdwEffect = DROPEFFECT_LINK;
return S_OK;
}
HRESULT CFSDropTarget::_RepositionItems(IShellFolderView *psfv, IDataObject *pdtobj, POINTL pt)
{
CComPtr<IFolderView> pfv;
POINT ptDrag;
HRESULT hr = psfv->QueryInterface(IID_PPV_ARG(IFolderView, &pfv));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
hr = psfv->GetDragPoint(&ptDrag);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
PIDLIST_ABSOLUTE pidlFolder;
PUITEMID_CHILD *apidl;
UINT cidl;
hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
CComHeapPtr<POINT> apt;
if (!apt.Allocate(cidl))
{
SHFree(pidlFolder);
_ILFreeaPidl(apidl, cidl);
return E_OUTOFMEMORY;
}
for (UINT i = 0; i<cidl; i++)
{
pfv->GetItemPosition(apidl[i], &apt[i]);
apt[i].x += pt.x - ptDrag.x;
apt[i].y += pt.y - ptDrag.y;
}
pfv->SelectAndPositionItems(cidl, apidl, apt, SVSI_SELECT);
SHFree(pidlFolder);
_ILFreeaPidl(apidl, cidl);
return S_OK;
}
HRESULT WINAPI CFSDropTarget::DragEnter(IDataObject *pDataObject,
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
{
@ -196,6 +262,8 @@ HRESULT WINAPI CFSDropTarget::DragEnter(IDataObject *pDataObject,
else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
fAcceptFmt = TRUE;
m_grfKeyState = dwKeyState;
QueryDrop(dwKeyState, pdwEffect);
return S_OK;
}
@ -208,6 +276,8 @@ HRESULT WINAPI CFSDropTarget::DragOver(DWORD dwKeyState, POINTL pt,
if (!pdwEffect)
return E_INVALIDARG;
m_grfKeyState = dwKeyState;
QueryDrop(dwKeyState, pdwEffect);
return S_OK;
@ -230,8 +300,28 @@ HRESULT WINAPI CFSDropTarget::Drop(IDataObject *pDataObject,
if (!pdwEffect)
return E_INVALIDARG;
IUnknown_GetWindow(m_site, &m_hwndSite);
QueryDrop(dwKeyState, pdwEffect);
if (m_grfKeyState & MK_RBUTTON)
{
HRESULT hr = _GetEffectFromMenu(pDataObject, pt, pdwEffect);
if (FAILED_UNEXPECTEDLY(hr) || hr == S_FALSE)
return hr;
}
if (*pdwEffect == DROPEFFECT_MOVE && m_site)
{
CComPtr<IShellFolderView> psfv;
HRESULT hr = IUnknown_QueryService(m_site, SID_IFolderView, IID_PPV_ARG(IShellFolderView, &psfv));
if (SUCCEEDED(hr) && psfv->IsDropOnSource(this) == S_OK)
{
_RepositionItems(psfv, pDataObject, pt);
return S_OK;
}
}
BOOL fIsOpAsync = FALSE;
CComPtr<IAsyncOperation> pAsyncOperation;
@ -257,6 +347,24 @@ HRESULT WINAPI CFSDropTarget::Drop(IDataObject *pDataObject,
return this->_DoDrop(pDataObject, dwKeyState, pt, pdwEffect);
}
HRESULT
WINAPI
CFSDropTarget::SetSite(IUnknown *pUnkSite)
{
m_site = pUnkSite;
return S_OK;
}
HRESULT
WINAPI
CFSDropTarget::GetSite(REFIID riid, void **ppvSite)
{
if (!m_site)
return E_FAIL;
return m_site->QueryInterface(riid, ppvSite);
}
HRESULT WINAPI CFSDropTarget::_DoDrop(IDataObject *pDataObject,
DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
{
@ -474,7 +582,7 @@ HRESULT WINAPI CFSDropTarget::_DoDrop(IDataObject *pDataObject,
ZeroMemory(&op, sizeof(op));
op.pFrom = pszSrcList;
op.pTo = wszTargetPath;
op.hwnd = GetActiveWindow();
op.hwnd = m_hwndSite;
op.wFunc = bCopy ? FO_COPY : FO_MOVE;
op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
hr = SHFileOperationW(&op);

View file

@ -25,18 +25,24 @@
class CFSDropTarget :
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IDropTarget
public IDropTarget,
public IObjectWithSite
{
private:
UINT cfShellIDList; /* clipboardformat for IDropTarget */
BOOL fAcceptFmt; /* flag for pending Drop */
LPWSTR sPathTarget;
HWND m_hwndSite;
DWORD m_grfKeyState;
CComPtr<IUnknown> m_site;
BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
virtual HRESULT WINAPI _DoDrop(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect);
virtual HRESULT WINAPI CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl, BOOL bCopy);
BOOL GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut);
static DWORD WINAPI _DoDropThreadProc(LPVOID lpParameter);
HRESULT _GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, DWORD *pdwEffect);
HRESULT _RepositionItems(IShellFolderView *psfv, IDataObject *pDataObject, POINTL pt);
public:
CFSDropTarget();
@ -49,12 +55,17 @@ class CFSDropTarget :
virtual HRESULT WINAPI DragLeave();
virtual HRESULT WINAPI Drop(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect);
// IObjectWithSite
virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite);
virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, void **ppvSite);
DECLARE_NOT_AGGREGATABLE(CFSDropTarget)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CFSDropTarget)
COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
END_COM_MAP()
};