Damjan Jovanovic : shell32: Support the CF_HDROP format too when pasting from the context menu.

Alexandre Julliard julliard at winehq.org
Wed May 26 15:46:27 CDT 2021


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

Author: Damjan Jovanovic <damjan.jov at gmail.com>
Date:   Tue May 25 07:53:28 2021 +0200

shell32: Support the CF_HDROP format too when pasting from the context menu.

Signed-off-by: Damjan Jovanovic <damjan.jov at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/shell32/shlview_cmenu.c   | 95 +++++++++++++++++++++++++++++++++++++++++-
 dlls/shell32/tests/shlfolder.c | 10 +++++
 2 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/dlls/shell32/shlview_cmenu.c b/dlls/shell32/shlview_cmenu.c
index 3d79f82a92e..dd03c64e654 100644
--- a/dlls/shell32/shlview_cmenu.c
+++ b/dlls/shell32/shlview_cmenu.c
@@ -1134,10 +1134,59 @@ static void DoNewFolder(ContextMenu *This, IShellView *view)
     }
 }
 
+static HRESULT paste_pidls(ContextMenu *This, ITEMIDLIST **pidls, UINT count)
+{
+    IShellFolder *psfDesktop;
+    UINT i;
+    HRESULT hr = S_OK;
+
+    /* bind to the source shellfolder */
+    hr = SHGetDesktopFolder(&psfDesktop);
+    if (FAILED(hr))
+        return hr;
+
+    for (i = 0; SUCCEEDED(hr) && i < count; i++) {
+        ITEMIDLIST *pidl_dir = NULL;
+        ITEMIDLIST *pidl_item;
+        IShellFolder *psfFrom = NULL;
+
+        pidl_dir = ILClone(pidls[i]);
+        ILRemoveLastID(pidl_dir);
+        pidl_item = ILFindLastID(pidls[i]);
+        hr = IShellFolder_BindToObject(psfDesktop, pidl_dir, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom);
+
+        if (psfFrom)
+        {
+            /* get source and destination shellfolder */
+            ISFHelper *psfhlpdst, *psfhlpsrc;
+            hr = IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&psfhlpdst);
+            if (SUCCEEDED(hr))
+                hr = IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (void**)&psfhlpsrc);
+
+            /* do the copy/move */
+            if (psfhlpdst && psfhlpsrc)
+            {
+                hr = ISFHelper_CopyItems(psfhlpdst, psfFrom, 1, (LPCITEMIDLIST*)&pidl_item);
+                /* FIXME handle move
+                ISFHelper_DeleteItems(psfhlpsrc, 1, &pidl_item);
+                */
+            }
+            if(psfhlpdst) ISFHelper_Release(psfhlpdst);
+            if(psfhlpsrc) ISFHelper_Release(psfhlpsrc);
+            IShellFolder_Release(psfFrom);
+        }
+        SHFree(pidl_dir);
+    }
+
+    IShellFolder_Release(psfDesktop);
+    return hr;
+}
+
 static BOOL DoPaste(ContextMenu *This)
 {
 	BOOL bSuccess = TRUE;
 	IDataObject * pda;
+	HRESULT hr;
 
 	TRACE("\n");
 
@@ -1145,6 +1194,7 @@ static BOOL DoPaste(ContextMenu *This)
 	{
 	  STGMEDIUM medium;
 	  FORMATETC formatetc;
+	  HRESULT format_hr;
 
 	  TRACE("pda=%p\n", pda);
 
@@ -1152,7 +1202,8 @@ static BOOL DoPaste(ContextMenu *This)
 	  InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), TYMED_HGLOBAL);
 
 	  /* Get the pidls from IDataObject */
-	  if(SUCCEEDED(IDataObject_GetData(pda,&formatetc,&medium)))
+	  format_hr = IDataObject_GetData(pda,&formatetc,&medium);
+	  if(SUCCEEDED(format_hr))
           {
 	    LPITEMIDLIST * apidl;
 	    LPITEMIDLIST pidl;
@@ -1215,6 +1266,48 @@ static BOOL DoPaste(ContextMenu *This)
 	  }
 	  else
 	    bSuccess = FALSE;
+
+	  if(FAILED(format_hr))
+	  {
+	    InitFormatEtc(formatetc, CF_HDROP, TYMED_HGLOBAL);
+	    format_hr = IDataObject_GetData(pda,&formatetc,&medium);
+	    if(SUCCEEDED(format_hr))
+	    {
+	      WCHAR path[MAX_PATH];
+	      UINT i, count;
+	      ITEMIDLIST **pidls;
+
+	      TRACE("CF_HDROP=%p\n", medium.u.hGlobal);
+	      count = DragQueryFileW(medium.u.hGlobal, -1, NULL, 0);
+	      pidls = SHAlloc(count*sizeof(ITEMIDLIST**));
+	      if (pidls)
+	      {
+	        for (i = 0; i < count; i++)
+	        {
+	          DragQueryFileW(medium.u.hGlobal, i, path, ARRAY_SIZE(path));
+	          if ((pidls[i] = ILCreateFromPathW(path)) == NULL)
+	          {
+	            hr = E_FAIL;
+	            break;
+	          }
+	        }
+	        if (SUCCEEDED(hr))
+	          hr = paste_pidls(This, pidls, count);
+	        _ILFreeaPidl(pidls, count);
+	      }
+	      else
+	        hr = HRESULT_FROM_WIN32(GetLastError());
+	      ReleaseStgMedium(&medium);
+	      bSuccess = SUCCEEDED(hr);
+	    }
+	  }
+
+	  if (FAILED(format_hr))
+	  {
+	    ERR("there are no supported and retrievable clipboard formats\n");
+	    bSuccess = FALSE;
+	  }
+
 	  IDataObject_Release(pda);
 	}
 	else
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index 8e92a0896b5..29fcd0b7754 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -4387,7 +4387,17 @@ static void test_contextmenu(IContextMenu *menu, BOOL background)
             {
                 trace("Got ID %d, verb %s, string %s.\n", mii.wID, debugstr_a(buf), debugstr_a(mii.dwTypeData));
                 if (!strcmp(buf, "copy"))
+                {
+                    CMINVOKECOMMANDINFO cmi;
                     ok(mii.wID == 64 - 0x7000 + FCIDM_SHVIEW_COPY, "wrong menu wID %d\n", mii.wID);
+                    memset(&cmi, 0, sizeof(CMINVOKECOMMANDINFO));
+                    cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
+                    cmi.lpVerb = "copy";
+                    hr = IContextMenu_InvokeCommand(menu, &cmi);
+                    ok(hr == S_OK, "got 0x%08x\n", hr);
+                    ok(IsClipboardFormatAvailable(RegisterClipboardFormatA(CFSTR_SHELLIDLISTA)), "CFSTR_SHELLIDLISTA not available\n");
+                    ok(IsClipboardFormatAvailable(CF_HDROP), "CF_HDROP not available\n");
+                }
                 else if (!strcmp(buf, "paste"))
                     ok(mii.wID == 64 - 0x7000 + FCIDM_SHVIEW_INSERT, "wrong menu wID %d\n", mii.wID);
                 else if (!strcmp(buf, "properties"))




More information about the wine-cvs mailing list