[PATCH v2] shell32: support the CF_HDROP format too when pasting from the context menu
Damjan Jovanovic
damjan.jov at gmail.com
Wed May 5 22:20:48 CDT 2021
Try 2 fixes lock and STDMEDIUM leaks, improves error handling, and removes
the old commented out debugging code.
Signed-off-by: Damjan Jovanovic <damjan.jov at gmail.com>
---
dlls/shell32/shlview_cmenu.c | 186 +++++++++++++++++++--------------
dlls/shell32/tests/shlfolder.c | 10 ++
2 files changed, 119 insertions(+), 77 deletions(-)
-------------- next part --------------
diff --git a/dlls/shell32/shlview_cmenu.c b/dlls/shell32/shlview_cmenu.c
index 67f5ac80d84..29406bcb2ae 100644
--- a/dlls/shell32/shlview_cmenu.c
+++ b/dlls/shell32/shlview_cmenu.c
@@ -1134,115 +1134,147 @@ static void DoNewFolder(ContextMenu *This, IShellView *view)
}
}
-static BOOL DoPaste(ContextMenu *This)
+static HRESULT paste_pidls(ContextMenu *This, ITEMIDLIST **pidls, UINT count)
{
- BOOL bSuccess = TRUE;
- IDataObject * pda;
+ 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;
+}
- TRACE("\n");
+static HRESULT DoPaste(ContextMenu *This)
+{
+ IDataObject * pda;
+ HRESULT hr;
- if(SUCCEEDED(OleGetClipboard(&pda)))
+ TRACE("(%p)\n", This);
+ hr = OleGetClipboard(&pda);
+ if(SUCCEEDED(hr))
{
STGMEDIUM medium;
FORMATETC formatetc;
+ HRESULT format_hr;
TRACE("pda=%p\n", pda);
-
/* Set the FORMATETC structure*/
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;
- IShellFolder *psfFrom = NULL, *psfDesktop;
- int i;
LPIDA lpcida = GlobalLock(medium.u.hGlobal);
TRACE("cida=%p\n", lpcida);
-
- apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
-
- for (i = 0; bSuccess && i < lpcida->cidl; i++) {
- ITEMIDLIST *apidl_dir = NULL;
- ITEMIDLIST *apidl_item;
-
- psfFrom = NULL;
- /* bind to the source shellfolder */
- SHGetDesktopFolder(&psfDesktop);
- if(psfDesktop)
+ if (lpcida)
+ {
+ apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
+ if (apidl)
{
- apidl_dir = ILClone(apidl[i]);
- ILRemoveLastID(apidl_dir);
- apidl_item = ILFindLastID(apidl[i]);
- IShellFolder_BindToObject(psfDesktop, apidl_dir, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom);
- IShellFolder_Release(psfDesktop);
+ hr = paste_pidls(This, apidl, lpcida->cidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ SHFree(pidl);
}
+ else
+ hr = HRESULT_FROM_WIN32(hr);
+ }
+ else
+ hr = HRESULT_FROM_WIN32(hr);
+ ReleaseStgMedium(&medium);
+ }
- if (psfFrom)
+ if(FAILED(format_hr))
+ {
+ InitFormatEtc(formatetc, CF_HDROP, TYMED_HGLOBAL);
+ format_hr = IDataObject_GetData(pda,&formatetc,&medium);
+ if(SUCCEEDED(format_hr))
+ {
+ DROPFILES *dropfiles = GlobalLock(medium.u.hGlobal);
+ TRACE("CF_HDROP=%p\n", dropfiles);
+ if (dropfiles)
{
- /* get source and destination shellfolder */
- ISFHelper *psfhlpdst, *psfhlpsrc;
- IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&psfhlpdst);
- IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (void**)&psfhlpsrc);
+ WCHAR path[MAX_PATH];
+ UINT i, count;
+ ITEMIDLIST **pidls;
- /* do the copy/move */
- if (psfhlpdst && psfhlpsrc)
+ count = DragQueryFileW(medium.u.hGlobal, -1, NULL, 0);
+ pidls = SHAlloc(count*sizeof(ITEMIDLIST**));
+ if (pidls)
{
- HRESULT hr = ISFHelper_CopyItems(psfhlpdst, psfFrom, 1, (LPCITEMIDLIST*)&apidl_item);
- if (FAILED(hr))
- bSuccess = FALSE;
- /* FIXME handle move
- ISFHelper_DeleteItems(psfhlpsrc, 1, &apidl_item);
- */
+ 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);
}
- if(psfhlpdst) ISFHelper_Release(psfhlpdst);
- if(psfhlpsrc) ISFHelper_Release(psfhlpsrc);
- IShellFolder_Release(psfFrom);
+ else
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ GlobalUnlock(medium.u.hGlobal);
}
else
- bSuccess = FALSE;
- SHFree(apidl_dir);
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ ReleaseStgMedium(&medium);
}
-
- _ILFreeaPidl(apidl, lpcida->cidl);
- SHFree(pidl);
-
- /* release the medium*/
- ReleaseStgMedium(&medium);
}
- else
- bSuccess = FALSE;
- IDataObject_Release(pda);
- }
- else
- bSuccess = FALSE;
-#if 0
- HGLOBAL hMem;
- OpenClipboard(NULL);
- hMem = GetClipboardData(CF_HDROP);
-
- if(hMem)
- {
- char * pDropFiles = GlobalLock(hMem);
- if(pDropFiles)
+ if (FAILED(format_hr))
{
- int len, offset = sizeof(DROPFILESTRUCT);
-
- while( pDropFiles[offset] != 0)
- {
- len = strlen(pDropFiles + offset);
- TRACE("%s\n", pDropFiles + offset);
- offset += len+1;
- }
+ ERR("there are no supported and retrievable clipboard formats\n");
+ hr = format_hr;
}
- GlobalUnlock(hMem);
+ IDataObject_Release(pda);
}
- CloseClipboard();
-#endif
- return bSuccess;
+
+ return hr;
}
static HRESULT WINAPI BackgroundMenu_InvokeCommand(
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-devel
mailing list