Skip to content

Commit

Permalink
[SHELL32] CFSDropTarget: Initial implementation of right click drag menu
Browse files Browse the repository at this point in the history
  • Loading branch information
yagoulas committed Feb 17, 2018
1 parent 8f8ab05 commit 6d91269
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 4 deletions.
114 changes: 111 additions & 3 deletions dll/win32/shell32/droptargets/CFSDropTarget.cpp
Expand Up @@ -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;

Expand All @@ -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)
{
}

Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -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;

Expand All @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 12 additions & 1 deletion dll/win32/shell32/droptargets/CFSDropTarget.h
Expand Up @@ -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();
Expand All @@ -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()

};
Expand Down

0 comments on commit 6d91269

Please sign in to comment.