Alexandre Julliard : shell32: Merge the drag & drop implementation from the Unix shell folder.

Alexandre Julliard julliard at winehq.org
Fri Sep 10 15:29:45 CDT 2021


Module: wine
Branch: master
Commit: df9c67d19695dddf5ee63d64a84244649748f94c
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=df9c67d19695dddf5ee63d64a84244649748f94c

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri Sep 10 18:52:37 2021 +0200

shell32: Merge the drag & drop implementation from the Unix shell folder.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/shell32/shfldr_fs.c | 134 +++++++++++++++++++++++++++++++++++------------
 1 file changed, 100 insertions(+), 34 deletions(-)

diff --git a/dlls/shell32/shfldr_fs.c b/dlls/shell32/shfldr_fs.c
index 52bdccd6c38..55d380ffb1d 100644
--- a/dlls/shell32/shfldr_fs.c
+++ b/dlls/shell32/shfldr_fs.c
@@ -72,11 +72,11 @@ typedef struct {
     LPWSTR sPathTarget;     /* complete path to target used for enumeration and ChangeNotify */
 
     LPITEMIDLIST pidlRoot; /* absolute pidl */
-
-    UINT cfShellIDList;    /* clipboardformat for IDropTarget */
-    BOOL fAcceptFmt;       /* flag for pending Drop */
+    DWORD drop_effects_mask;
 } IGenericSFImpl;
 
+static UINT cfShellIDList;
+
 static inline IGenericSFImpl *impl_from_IUnknown(IUnknown *iface)
 {
     return CONTAINING_RECORD(iface, IGenericSFImpl, IUnknown_inner);
@@ -102,18 +102,6 @@ static inline IGenericSFImpl *impl_from_ISFHelper(ISFHelper *iface)
     return CONTAINING_RECORD(iface, IGenericSFImpl, ISFHelper_iface);
 }
 
-/**************************************************************************
-* registers clipboardformat once
-*/
-static void SF_RegisterClipFmt (IGenericSFImpl * This)
-{
-    TRACE ("(%p)\n", This);
-
-    if (!This->cfShellIDList) {
-        This->cfShellIDList = RegisterClipboardFormatW (CFSTR_SHELLIDLISTW);
-    }
-}
-
 /**************************************************************************
 * inner IUnknown
 */
@@ -136,7 +124,7 @@ static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown *iface, REFIID riid, vo
         *ppvObj = &This->ISFHelper_iface;
     else if (IsEqualIID (riid, &IID_IDropTarget)) {
         *ppvObj = &This->IDropTarget_iface;
-        SF_RegisterClipFmt(This);
+        if (!cfShellIDList) cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
     }
 
     if (*ppvObj) {
@@ -1543,22 +1531,42 @@ static ULONG WINAPI ISFDropTarget_Release(IDropTarget *iface)
     return IUnknown_Release(This->outer_unk);
 }
 
+#define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
+#define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
+
 static HRESULT WINAPI
 ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject,
                          DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
 {
-    FORMATETC fmt;
-
     IGenericSFImpl *This = impl_from_IDropTarget(iface);
+    FORMATETC format;
+    STGMEDIUM medium;
 
-    TRACE ("(%p)->(DataObject=%p)\n", This, pDataObject);
+    TRACE("(%p)->(%p 0x%08x {.x=%d, .y=%d} %p)\n", This, pDataObject, dwKeyState, pt.x, pt.y, pdwEffect);
 
-    InitFormatEtc (fmt, This->cfShellIDList, TYMED_HGLOBAL);
-    This->fAcceptFmt = IDataObject_QueryGetData (pDataObject, &fmt) == S_OK;
-    if (This->fAcceptFmt)
-        *pdwEffect = KeyStateToDropEffect(dwKeyState);
-    else
-        *pdwEffect = DROPEFFECT_NONE;
+    if (!pdwEffect || !pDataObject)
+        return E_INVALIDARG;
+
+    /* Compute a mask of supported drop-effects for this shellfolder object and the given data
+     * object. Dropping is only supported on folders, which represent filesystem locations. One
+     * can't drop on file objects. And the 'move' drop effect is only supported, if the source
+     * folder is not identical to the target folder. */
+    This->drop_effects_mask = DROPEFFECT_NONE;
+    InitFormatEtc(format, cfShellIDList, TYMED_HGLOBAL);
+    if (_ILIsFolder(ILFindLastID(This->pidlRoot)) && /* Only drop to folders, not to files */
+        SUCCEEDED(IDataObject_GetData(pDataObject, &format, &medium))) /* Only ShellIDList format */
+    {
+        LPIDA pidaShellIDList = GlobalLock(medium.u.hGlobal);
+        This->drop_effects_mask |= DROPEFFECT_COPY|DROPEFFECT_LINK;
+
+        if (pidaShellIDList) { /* Files can only be moved between two different folders */
+            if (!ILIsEqual(HIDA_GetPIDLFolder(pidaShellIDList), This->pidlRoot))
+                This->drop_effects_mask |= DROPEFFECT_MOVE;
+            GlobalUnlock(medium.u.hGlobal);
+        }
+    }
+
+    *pdwEffect = KeyStateToDropEffect(dwKeyState) & This->drop_effects_mask;
 
     return S_OK;
 }
@@ -1569,15 +1577,12 @@ ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt,
 {
     IGenericSFImpl *This = impl_from_IDropTarget(iface);
 
-    TRACE ("(%p)\n", This);
+    TRACE("(%p)->(0x%08x {.x=%d, .y=%d} %p)\n", This, dwKeyState, pt.x, pt.y, pdwEffect);
 
     if (!pdwEffect)
         return E_INVALIDARG;
 
-    if (This->fAcceptFmt)
-        *pdwEffect = KeyStateToDropEffect(dwKeyState);
-    else
-        *pdwEffect = DROPEFFECT_NONE;
+    *pdwEffect = KeyStateToDropEffect(dwKeyState) & This->drop_effects_mask;
 
     return S_OK;
 }
@@ -1586,10 +1591,9 @@ static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface)
 {
     IGenericSFImpl *This = impl_from_IDropTarget(iface);
 
-    TRACE ("(%p)\n", This);
-
-    This->fAcceptFmt = FALSE;
+    TRACE("(%p)\n", This);
 
+    This->drop_effects_mask = DROPEFFECT_NONE;
     return S_OK;
 }
 
@@ -1598,8 +1602,70 @@ ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject,
                     DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
 {
     IGenericSFImpl *This = impl_from_IDropTarget(iface);
+    FORMATETC format;
+    STGMEDIUM medium;
+    HRESULT hr;
+
+    TRACE("(%p)->(%p %d {.x=%d, .y=%d} %p) semi-stub\n",
+        This, pDataObject, dwKeyState, pt.x, pt.y, pdwEffect);
+
+    InitFormatEtc(format, cfShellIDList, TYMED_HGLOBAL);
+    hr = IDataObject_GetData(pDataObject, &format, &medium);
+    if (FAILED(hr))
+        return hr;
+
+    if (medium.tymed == TYMED_HGLOBAL) {
+        IShellFolder *psfSourceFolder, *psfDesktopFolder;
+        LPIDA pidaShellIDList = GlobalLock(medium.u.hGlobal);
+        STRRET strret;
+        UINT i;
+
+        if (!pidaShellIDList)
+            return HRESULT_FROM_WIN32(GetLastError());
+
+        hr = SHGetDesktopFolder(&psfDesktopFolder);
+        if (FAILED(hr)) {
+            GlobalUnlock(medium.u.hGlobal);
+            return hr;
+        }
+
+        hr = IShellFolder_BindToObject(psfDesktopFolder, HIDA_GetPIDLFolder(pidaShellIDList), NULL,
+                                       &IID_IShellFolder, (LPVOID*)&psfSourceFolder);
+        IShellFolder_Release(psfDesktopFolder);
+        if (FAILED(hr)) {
+            GlobalUnlock(medium.u.hGlobal);
+            return hr;
+        }
 
-    FIXME ("(%p) object dropped\n", This);
+        for (i = 0; i < pidaShellIDList->cidl; i++) {
+            WCHAR wszSourcePath[MAX_PATH];
+
+            hr = IShellFolder_GetDisplayNameOf(psfSourceFolder, HIDA_GetPIDLItem(pidaShellIDList, i),
+                                               SHGDN_FORPARSING, &strret);
+            if (FAILED(hr))
+                break;
+
+            hr = StrRetToBufW(&strret, NULL, wszSourcePath, MAX_PATH);
+            if (FAILED(hr))
+                break;
+
+            switch (*pdwEffect) {
+                case DROPEFFECT_MOVE:
+                    FIXME("Move %s to %s!\n", debugstr_w(wszSourcePath), debugstr_w(This->sPathTarget));
+                    break;
+                case DROPEFFECT_COPY:
+                    FIXME("Copy %s to %s!\n", debugstr_w(wszSourcePath), debugstr_w(This->sPathTarget));
+                    break;
+                case DROPEFFECT_LINK:
+                    FIXME("Link %s from %s!\n", debugstr_w(wszSourcePath), debugstr_w(This->sPathTarget));
+                    break;
+            }
+        }
+
+        IShellFolder_Release(psfSourceFolder);
+        GlobalUnlock(medium.u.hGlobal);
+        return hr;
+    }
 
     return E_NOTIMPL;
 }




More information about the wine-cvs mailing list