-- v2: shell32: Implement Paste in the item menu. shell32: Respect the parent PIDL when pasting from CFSTR_SHELLIDLIST. shell32: Reimplement pasting from CF_DROP directly. shell32: Add a get_data_format() helper. shell32: Move DoPaste() up. shell32: Remove useless and commented out code. shell32/tests: Add tests for context menu copy/paste.
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/shell32/tests/shlfolder.c | 299 +++++++++++++++++++++++++++++++++ include/shlobj.h | 1 + 2 files changed, 300 insertions(+)
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c index 29785793355..9da28f570df 100644 --- a/dlls/shell32/tests/shlfolder.c +++ b/dlls/shell32/tests/shlfolder.c @@ -5604,6 +5604,304 @@ static void test_SHBindToFolderIDListParent(void) ok(pidl_last == NULL, "got %p\n", pidl_last); }
+static void test_copy_paste(void) +{ + CMINVOKECOMMANDINFO invoke_info = {.cbSize = sizeof(invoke_info)}; + WCHAR cwd[MAX_PATH], temp_path[MAX_PATH], path[MAX_PATH]; + ITEMIDLIST *pidl, *src_pidl, *dst_pidl, *pidls[2]; + IShellFolder *tmp_folder, *dst_folder; + IContextMenu *src_menu, *dst_menu; + const DROPFILES *dropfiles; + const WCHAR *filenameW; + IDataObject *data_obj; + const CIDA *cida; + STGMEDIUM medium; + FORMATETC format; + DWORD *effect; + HRESULT hr; + BOOL ret; + + format.dwAspect = DVASPECT_CONTENT; + format.ptd = NULL; + format.tymed = TYMED_HGLOBAL; + format.lindex = -1; + + GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd); + GetTempPathW(ARRAY_SIZE(temp_path), temp_path); + SetCurrentDirectoryW(temp_path); + + ret = CreateDirectoryW(L"testcopy_src", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + + ret = CreateDirectoryW(L"testcopy_dst", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + + hr = SHParseDisplayName(temp_path, NULL, &pidl, 0, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = SHBindToObject(NULL, pidl, NULL, &IID_IShellFolder, (void **)&tmp_folder); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ILFree(pidl); + + hr = IShellFolder_ParseDisplayName(tmp_folder, NULL, NULL, (WCHAR *)L"testcopy_src", NULL, &src_pidl, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IShellFolder_ParseDisplayName(tmp_folder, NULL, NULL, (WCHAR *)L"testcopy_dst", NULL, &dst_pidl, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IShellFolder_BindToObject(tmp_folder, dst_pidl, NULL, &IID_IShellFolder, (void **)&dst_folder); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IShellFolder_GetUIObjectOf(tmp_folder, NULL, 1, (const ITEMIDLIST **)&src_pidl, + &IID_IContextMenu, NULL, (void **)&src_menu); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = OleSetClipboard(NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + /* Cut. */ + + invoke_info.lpVerb = "cut"; + hr = IContextMenu_InvokeCommand(src_menu, &invoke_info); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = OleGetClipboard(&data_obj); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + trace("%p ole %p shell %p\n", data_obj->lpVtbl->SetData, GetModuleHandleW(L"ole32"), GetModuleHandleW(L"shell32")); + + format.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); + hr = IDataObject_GetData(data_obj, &format, &medium); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ReleaseStgMedium(&medium); + format.cfFormat = CF_HDROP; + hr = IDataObject_GetData(data_obj, &format, &medium); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ReleaseStgMedium(&medium); + format.cfFormat = RegisterClipboardFormatA(CFSTR_FILENAMEA); + hr = IDataObject_GetData(data_obj, &format, &medium); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ReleaseStgMedium(&medium); + format.cfFormat = RegisterClipboardFormatW(CFSTR_FILENAMEW); + hr = IDataObject_GetData(data_obj, &format, &medium); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ReleaseStgMedium(&medium); + + format.cfFormat = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECTW); + hr = IDataObject_GetData(data_obj, &format, &medium); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr == S_OK) + { + effect = GlobalLock(medium.hGlobal); + ok(*effect == DROPEFFECT_MOVE, "Got effect %#lx.\n", *effect); + GlobalUnlock(medium.hGlobal); + ReleaseStgMedium(&medium); + } + + IDataObject_Release(data_obj); + + ret = GetFileAttributesW(L"testcopy_src"); + ok(ret != INVALID_FILE_ATTRIBUTES, "Got %#x.\n", ret); + + hr = IShellFolder_GetUIObjectOf(tmp_folder, NULL, 1, (const ITEMIDLIST **)&dst_pidl, + &IID_IContextMenu, NULL, (void **)&dst_menu); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + invoke_info.lpVerb = "paste"; + hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ret = MoveFileExW(L"testcopy_dst/testcopy_src", L"testcopy_src", 0); + todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + + /* Copy. */ + + invoke_info.lpVerb = "copy"; + hr = IContextMenu_InvokeCommand(src_menu, &invoke_info); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = OleGetClipboard(&data_obj); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + format.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); + hr = IDataObject_GetData(data_obj, &format, &medium); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ReleaseStgMedium(&medium); + + format.cfFormat = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECTW); + hr = IDataObject_GetData(data_obj, &format, &medium); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr == S_OK) + { + effect = GlobalLock(medium.hGlobal); + ok(*effect == (DROPEFFECT_COPY | DROPEFFECT_LINK), "Got effect %#lx.\n", *effect); + GlobalUnlock(medium.hGlobal); + ReleaseStgMedium(&medium); + } + + IDataObject_Release(data_obj); + + ret = GetFileAttributesW(L"testcopy_src"); + ok(ret != INVALID_FILE_ATTRIBUTES, "Got %#x.\n", ret); + + hr = IShellFolder_GetUIObjectOf(tmp_folder, NULL, 1, (const ITEMIDLIST **)&dst_pidl, + &IID_IContextMenu, NULL, (void **)&dst_menu); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + invoke_info.lpVerb = "paste"; + hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ret = GetFileAttributesW(L"testcopy_src"); + ok(ret != INVALID_FILE_ATTRIBUTES, "Got %#x.\n", ret); + + ret = RemoveDirectoryW(L"testcopy_dst/testcopy_src"); + todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + + /* Manually change the drop effect back to "cut". */ + + hr = OleGetClipboard(&data_obj); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + format.cfFormat = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECTW); + medium.tymed = TYMED_HGLOBAL; + medium.hGlobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(DWORD)); + effect = GlobalLock(medium.hGlobal); + *effect = DROPEFFECT_MOVE; + GlobalUnlock(medium.hGlobal); + hr = IDataObject_SetData(data_obj, &format, &medium, TRUE); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IDataObject_Release(data_obj); + + invoke_info.lpVerb = "paste"; + hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ret = MoveFileExW(L"testcopy_dst/testcopy_src", L"testcopy_src", 0); + todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + + /* Paste into a background menu. */ + + IContextMenu_Release(dst_menu); + + invoke_info.lpVerb = "copy"; + hr = IContextMenu_InvokeCommand(src_menu, &invoke_info); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IShellFolder_CreateViewObject(dst_folder, NULL, &IID_IContextMenu, (void **)&dst_menu); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + invoke_info.lpVerb = "paste"; + hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ret = GetFileAttributesW(L"testcopy_src"); + ok(ret != INVALID_FILE_ATTRIBUTES, "Got %#x.\n", ret); + + ret = RemoveDirectoryW(L"testcopy_dst/testcopy_src"); + todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + + /* Paste into a selection comprising multiple directories. In this case the + * first directory is used, and the second is just ignored. + * This same behaviour can of course be observed when using the UI. */ + + IContextMenu_Release(dst_menu); + + ret = CreateDirectoryW(L"testcopy_dst2", NULL); + ok(ret, "Got error %lu.\n", GetLastError()); + + hr = IShellFolder_ParseDisplayName(tmp_folder, NULL, NULL, (WCHAR *)L"testcopy_dst2", NULL, &pidls[0], NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + pidls[1] = dst_pidl; + + hr = IShellFolder_GetUIObjectOf(tmp_folder, NULL, 2, (const ITEMIDLIST **)pidls, + &IID_IContextMenu, NULL, (void **)&dst_menu); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + invoke_info.lpVerb = "paste"; + hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ret = RemoveDirectoryW(L"testcopy_dst2/testcopy_src"); + todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + ret = GetFileAttributesW(L"testcopy_dst/testcopy_src"); + ok(ret == INVALID_FILE_ATTRIBUTES, "Got %#x.\n", ret); + + /* Cut multiple files, and test the clipboard contents. */ + + invoke_info.lpVerb = "cut"; + hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = OleGetClipboard(&data_obj); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + format.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); + hr = IDataObject_GetData(data_obj, &format, &medium); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + cida = GlobalLock(medium.hGlobal); + ok(cida->cidl == 2, "Got count %u.\n", cida->cidl); + GlobalUnlock(medium.hGlobal); + ReleaseStgMedium(&medium); + + format.cfFormat = CF_HDROP; + hr = IDataObject_GetData(data_obj, &format, &medium); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + dropfiles = GlobalLock(medium.hGlobal); + ok(dropfiles->pFiles == sizeof(DROPFILES), "Got offset %lu.\n", dropfiles->pFiles); + ok(dropfiles->fWide == TRUE, "Got wide %u.\n", dropfiles->fWide); + filenameW = (const WCHAR *)((const char *)dropfiles + dropfiles->pFiles); + swprintf(path, ARRAY_SIZE(path), L"%stestcopy_dst2", temp_path); + ok(!wcscmp(filenameW, path), "Got path %s.\n", debugstr_w(filenameW)); + filenameW += wcslen(filenameW) + 1; + swprintf(path, ARRAY_SIZE(path), L"%stestcopy_dst", temp_path); + ok(!wcscmp(filenameW, path), "Got path %s.\n", debugstr_w(filenameW)); + filenameW += wcslen(filenameW) + 1; + ok(!filenameW[0], "Got path %s.\n", debugstr_w(filenameW)); + GlobalUnlock(medium.hGlobal); + ReleaseStgMedium(&medium); + + format.cfFormat = RegisterClipboardFormatA(CFSTR_FILENAMEA); + hr = IDataObject_GetData(data_obj, &format, &medium); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ReleaseStgMedium(&medium); + + format.cfFormat = RegisterClipboardFormatW(CFSTR_FILENAMEW); + hr = IDataObject_GetData(data_obj, &format, &medium); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + filenameW = GlobalLock(medium.hGlobal); + swprintf(path, ARRAY_SIZE(path), L"%stestcopy_dst2", temp_path); + ok(!wcscmp(filenameW, path), "Got path %s.\n", debugstr_w(filenameW)); + GlobalUnlock(medium.hGlobal); + ReleaseStgMedium(&medium); + + IDataObject_Release(data_obj); + + ILFree(pidls[0]); + + /* Paste with nothing in the clipboard. */ + + hr = OleSetClipboard(NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + invoke_info.lpVerb = "paste"; + hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); + todo_wine ok(hr == S_OK || hr == S_FALSE /* win10 < 1809 */, "Got hr %#lx.\n", hr); + + ret = RemoveDirectoryW(L"testcopy_src"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = RemoveDirectoryW(L"testcopy_dst"); + ok(ret, "Got error %lu.\n", GetLastError()); + ret = RemoveDirectoryW(L"testcopy_dst2"); + ok(ret, "Got error %lu.\n", GetLastError()); + + IContextMenu_Release(src_menu); + IContextMenu_Release(dst_menu); + ILFree(src_pidl); + ILFree(dst_pidl); + IShellFolder_Release(dst_folder); + IShellFolder_Release(tmp_folder); + SetCurrentDirectoryW(cwd); +} + START_TEST(shlfolder) { init_function_pointers(); @@ -5651,6 +5949,7 @@ START_TEST(shlfolder) test_SHLimitInputEdit(); test_SHGetSetFolderCustomSettings(); test_SHOpenFolderAndSelectItems(); + test_copy_paste();
OleUninitialize(); } diff --git a/include/shlobj.h b/include/shlobj.h index f4376e1c338..327ab981648 100644 --- a/include/shlobj.h +++ b/include/shlobj.h @@ -77,6 +77,7 @@ typedef int GPFIDL_FLAGS; WINSHELLAPI void WINAPI SHFree(void*); WINSHELLAPI UINT WINAPI SHAddFromPropSheetExtArray(HPSXA,LPFNADDPROPSHEETPAGE,LPARAM); WINSHELLAPI void* WINAPI SHAlloc(ULONG) __WINE_ALLOC_SIZE(1) __WINE_DEALLOC(SHFree) __WINE_MALLOC; +WINSHELLAPI HRESULT WINAPI SHBindToObject(IShellFolder *, const ITEMIDLIST *, IBindCtx *, REFIID, void **); WINSHELLAPI HRESULT WINAPI SHCoCreateInstance(LPCWSTR,const CLSID*,IUnknown*,REFIID,LPVOID*); WINSHELLAPI HPSXA WINAPI SHCreatePropSheetExtArray(HKEY,LPCWSTR,UINT); WINSHELLAPI HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY,LPCWSTR,UINT,IDataObject*);
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/shell32/shlview_cmenu.c | 24 ------------------------ 1 file changed, 24 deletions(-)
diff --git a/dlls/shell32/shlview_cmenu.c b/dlls/shell32/shlview_cmenu.c index 4df296ec042..eef089f4812 100644 --- a/dlls/shell32/shlview_cmenu.c +++ b/dlls/shell32/shlview_cmenu.c @@ -1341,30 +1341,6 @@ static HRESULT DoPaste(ContextMenu *This)
IDataObject_Release(pda); } -#if 0 - HGLOBAL hMem; - - OpenClipboard(NULL); - hMem = GetClipboardData(CF_HDROP); - - if(hMem) - { - char * pDropFiles = GlobalLock(hMem); - if(pDropFiles) - { - int len, offset = sizeof(DROPFILESTRUCT); - - while( pDropFiles[offset] != 0) - { - len = strlen(pDropFiles + offset); - TRACE("%s\n", pDropFiles + offset); - offset += len+1; - } - } - GlobalUnlock(hMem); - } - CloseClipboard(); -#endif return hr; }
From: Zebediah Figura zfigura@codeweavers.com
And simplify the control flow a bit while we're at it. --- dlls/shell32/shlview_cmenu.c | 275 +++++++++++++++++------------------ 1 file changed, 134 insertions(+), 141 deletions(-)
diff --git a/dlls/shell32/shlview_cmenu.c b/dlls/shell32/shlview_cmenu.c index eef089f4812..e00306ee2a9 100644 --- a/dlls/shell32/shlview_cmenu.c +++ b/dlls/shell32/shlview_cmenu.c @@ -311,6 +311,138 @@ static void DoCopyOrCut(ContextMenu *This, HWND hwnd, BOOL cut) } }
+static HRESULT paste_pidls(ContextMenu *menu, ITEMIDLIST **pidls, unsigned int count) +{ + IShellFolder *desktop_folder; + HRESULT hr = S_OK; + + if (FAILED(hr = SHGetDesktopFolder(&desktop_folder))) + return hr; + + for (unsigned int i = 0; SUCCEEDED(hr) && i < count; i++) + { + IShellFolder *folder = NULL; + ITEMIDLIST *pidl_dir; + ITEMIDLIST *pidl_item; + + pidl_dir = ILClone(pidls[i]); + ILRemoveLastID(pidl_dir); + pidl_item = ILFindLastID(pidls[i]); + hr = IShellFolder_BindToObject(desktop_folder, pidl_dir, NULL, &IID_IShellFolder, (void **)&folder); + + if (folder) + { + ISFHelper *psfhlpdst = NULL, *psfhlpsrc = NULL; + + hr = IShellFolder_QueryInterface(menu->parent, &IID_ISFHelper, (void **)&psfhlpdst); + if (SUCCEEDED(hr)) + hr = IShellFolder_QueryInterface(folder, &IID_ISFHelper, (void **)&psfhlpsrc); + + if (psfhlpdst && psfhlpsrc) + { + hr = ISFHelper_CopyItems(psfhlpdst, folder, 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(folder); + } + ILFree(pidl_dir); + } + + IShellFolder_Release(desktop_folder); + return hr; +} + +static HRESULT do_paste(ContextMenu *menu) +{ + IDataObject *data; + HRESULT hr; + STGMEDIUM medium; + FORMATETC formatetc; + HRESULT format_hr; + + if (FAILED(hr = OleGetClipboard(&data))) + return hr; + + InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), TYMED_HGLOBAL); + format_hr = IDataObject_GetData(data, &formatetc, &medium); + if (SUCCEEDED(format_hr)) + { + CIDA *cida = GlobalLock(medium.hGlobal); + ITEMIDLIST **pidls; + ITEMIDLIST *pidl; + + if (cida) + { + pidls = _ILCopyCidaToaPidl(&pidl, cida); + if (pidls) + { + hr = paste_pidls(menu, pidls, cida->cidl); + _ILFreeaPidl(pidls, cida->cidl); + SHFree(pidl); + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + GlobalUnlock(medium.hGlobal); + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + ReleaseStgMedium(&medium); + } + else + { + InitFormatEtc(formatetc, CF_HDROP, TYMED_HGLOBAL); + format_hr = IDataObject_GetData(data, &formatetc, &medium); + if (SUCCEEDED(format_hr)) + { + WCHAR path[MAX_PATH]; + ITEMIDLIST **pidls; + UINT count; + + count = DragQueryFileW(medium.hGlobal, -1, NULL, 0); + pidls = SHAlloc(count * sizeof(ITEMIDLIST*)); + if (pidls) + { + for (unsigned int i = 0; i < count; i++) + { + DragQueryFileW(medium.hGlobal, i, path, ARRAY_SIZE(path)); + if (!(pidls[i] = ILCreateFromPathW(path))) + { + hr = E_FAIL; + break; + } + } + if (SUCCEEDED(hr)) + hr = paste_pidls(menu, pidls, count); + _ILFreeaPidl(pidls, count); + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + ReleaseStgMedium(&medium); + } + } + + if (FAILED(format_hr)) + { + ERR("Cannot paste any clipboard formats.\n"); + hr = format_hr; + } + + IDataObject_Release(data); + return hr; +} + /************************************************************************** * Properties_AddPropSheetCallback * @@ -1205,145 +1337,6 @@ 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 = NULL, *psfhlpsrc = NULL; - 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); - } - ILFree(pidl_dir); - } - - IShellFolder_Release(psfDesktop); - return hr; -} - -static HRESULT DoPaste(ContextMenu *This) -{ - IDataObject * pda; - HRESULT hr; - - TRACE("\n"); - - 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 */ - format_hr = IDataObject_GetData(pda,&formatetc,&medium); - if(SUCCEEDED(format_hr)) - { - LPITEMIDLIST * apidl; - LPITEMIDLIST pidl; - - LPIDA lpcida = GlobalLock(medium.hGlobal); - TRACE("cida=%p\n", lpcida); - if(lpcida) - { - apidl = _ILCopyCidaToaPidl(&pidl, lpcida); - if (apidl) - { - hr = paste_pidls(This, apidl, lpcida->cidl); - _ILFreeaPidl(apidl, lpcida->cidl); - SHFree(pidl); - } - else - hr = HRESULT_FROM_WIN32(GetLastError()); - GlobalUnlock(medium.hGlobal); - } - else - hr = HRESULT_FROM_WIN32(GetLastError()); - ReleaseStgMedium(&medium); - } - - 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.hGlobal); - count = DragQueryFileW(medium.hGlobal, -1, NULL, 0); - pidls = SHAlloc(count*sizeof(ITEMIDLIST*)); - if (pidls) - { - for (i = 0; i < count; i++) - { - DragQueryFileW(medium.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); - } - } - - if (FAILED(format_hr)) - { - ERR("there are no supported and retrievable clipboard formats\n"); - hr = format_hr; - } - - IDataObject_Release(pda); - } - return hr; -} - static HRESULT WINAPI BackgroundMenu_InvokeCommand( IContextMenu3 *iface, LPCMINVOKECOMMANDINFO lpcmi) @@ -1380,7 +1373,7 @@ static HRESULT WINAPI BackgroundMenu_InvokeCommand( } else if (!strcmp(lpcmi->lpVerb, "paste")) { - DoPaste(This); + do_paste(This); } else { @@ -1400,7 +1393,7 @@ static HRESULT WINAPI BackgroundMenu_InvokeCommand( break;
case FCIDM_SHVIEW_INSERT: - DoPaste(This); + do_paste(This); break;
case FCIDM_SHVIEW_PROPERTIES:
From: Zebediah Figura zfigura@codeweavers.com
Make the logic in do_paste() a bit more idiomatic. --- dlls/shell32/shlview_cmenu.c | 66 +++++++++++++++++------------------- 1 file changed, 32 insertions(+), 34 deletions(-)
diff --git a/dlls/shell32/shlview_cmenu.c b/dlls/shell32/shlview_cmenu.c index e00306ee2a9..6951bbd4216 100644 --- a/dlls/shell32/shlview_cmenu.c +++ b/dlls/shell32/shlview_cmenu.c @@ -358,20 +358,24 @@ static HRESULT paste_pidls(ContextMenu *menu, ITEMIDLIST **pidls, unsigned int c return hr; }
+static HRESULT get_data_format(IDataObject *data, UINT cf, STGMEDIUM *medium) +{ + FORMATETC format; + + InitFormatEtc(format, cf, TYMED_HGLOBAL); + return IDataObject_GetData(data, &format, medium); +} + static HRESULT do_paste(ContextMenu *menu) { IDataObject *data; HRESULT hr; STGMEDIUM medium; - FORMATETC formatetc; - HRESULT format_hr;
if (FAILED(hr = OleGetClipboard(&data))) return hr;
- InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), TYMED_HGLOBAL); - format_hr = IDataObject_GetData(data, &formatetc, &medium); - if (SUCCEEDED(format_hr)) + if (SUCCEEDED(get_data_format(data, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), &medium))) { CIDA *cida = GlobalLock(medium.hGlobal); ITEMIDLIST **pidls; @@ -398,45 +402,39 @@ static HRESULT do_paste(ContextMenu *menu) } ReleaseStgMedium(&medium); } - else + else if (SUCCEEDED(get_data_format(data, CF_HDROP, &medium))) { - InitFormatEtc(formatetc, CF_HDROP, TYMED_HGLOBAL); - format_hr = IDataObject_GetData(data, &formatetc, &medium); - if (SUCCEEDED(format_hr)) - { - WCHAR path[MAX_PATH]; - ITEMIDLIST **pidls; - UINT count; + WCHAR path[MAX_PATH]; + ITEMIDLIST **pidls; + UINT count;
- count = DragQueryFileW(medium.hGlobal, -1, NULL, 0); - pidls = SHAlloc(count * sizeof(ITEMIDLIST*)); - if (pidls) + count = DragQueryFileW(medium.hGlobal, -1, NULL, 0); + pidls = SHAlloc(count * sizeof(ITEMIDLIST*)); + if (pidls) + { + for (unsigned int i = 0; i < count; i++) { - for (unsigned int i = 0; i < count; i++) + DragQueryFileW(medium.hGlobal, i, path, ARRAY_SIZE(path)); + if (!(pidls[i] = ILCreateFromPathW(path))) { - DragQueryFileW(medium.hGlobal, i, path, ARRAY_SIZE(path)); - if (!(pidls[i] = ILCreateFromPathW(path))) - { - hr = E_FAIL; - break; - } + hr = E_FAIL; + break; } - if (SUCCEEDED(hr)) - hr = paste_pidls(menu, pidls, count); - _ILFreeaPidl(pidls, count); } - else - { - hr = HRESULT_FROM_WIN32(GetLastError()); - } - ReleaseStgMedium(&medium); + if (SUCCEEDED(hr)) + hr = paste_pidls(menu, pidls, count); + _ILFreeaPidl(pidls, count); + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); } + ReleaseStgMedium(&medium); } - - if (FAILED(format_hr)) + else { ERR("Cannot paste any clipboard formats.\n"); - hr = format_hr; + hr = E_FAIL; }
IDataObject_Release(data);
From: Zebediah Figura zfigura@codeweavers.com
Don't convert the source to PIDLs just to convert it back to paths. --- dlls/shell32/shlview_cmenu.c | 64 +++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 23 deletions(-)
diff --git a/dlls/shell32/shlview_cmenu.c b/dlls/shell32/shlview_cmenu.c index 6951bbd4216..aa89e14346e 100644 --- a/dlls/shell32/shlview_cmenu.c +++ b/dlls/shell32/shlview_cmenu.c @@ -366,7 +366,7 @@ static HRESULT get_data_format(IDataObject *data, UINT cf, STGMEDIUM *medium) return IDataObject_GetData(data, &format, medium); }
-static HRESULT do_paste(ContextMenu *menu) +static HRESULT do_paste(ContextMenu *menu, HWND hwnd) { IDataObject *data; HRESULT hr; @@ -404,31 +404,49 @@ static HRESULT do_paste(ContextMenu *menu) } else if (SUCCEEDED(get_data_format(data, CF_HDROP, &medium))) { - WCHAR path[MAX_PATH]; - ITEMIDLIST **pidls; - UINT count; + const DROPFILES *dropfiles = GlobalLock(medium.hGlobal); + IPersistFolder2 *dst_persist; + SHFILEOPSTRUCTW op = {0}; + WCHAR dst_path[MAX_PATH]; + ITEMIDLIST *dst_pidl; + int ret; + + if (FAILED(hr = IShellFolder_QueryInterface(menu->parent, &IID_IPersistFolder2, (void **)&dst_persist))) + { + WARN("Failed to get IPersistFolder2, hr %#lx.\n", hr); + IDataObject_Release(data); + return hr; + }
- count = DragQueryFileW(medium.hGlobal, -1, NULL, 0); - pidls = SHAlloc(count * sizeof(ITEMIDLIST*)); - if (pidls) + hr = IPersistFolder2_GetCurFolder(dst_persist, &dst_pidl); + IPersistFolder2_Release(dst_persist); + if (FAILED(hr)) { - for (unsigned int i = 0; i < count; i++) - { - DragQueryFileW(medium.hGlobal, i, path, ARRAY_SIZE(path)); - if (!(pidls[i] = ILCreateFromPathW(path))) - { - hr = E_FAIL; - break; - } - } - if (SUCCEEDED(hr)) - hr = paste_pidls(menu, pidls, count); - _ILFreeaPidl(pidls, count); + ERR("Failed to get dst folder pidl, hr %#lx.\n", hr); + IDataObject_Release(data); + return hr; } - else + + if (!SHGetPathFromIDListW(dst_pidl, dst_path)) { - hr = HRESULT_FROM_WIN32(GetLastError()); + ERR("Failed to get path, hr %#lx.\n", hr); + ILFree(dst_pidl); + IDataObject_Release(data); + return E_FAIL; } + + op.hwnd = hwnd; + op.wFunc = FO_COPY; + op.pFrom = (const WCHAR *)((const char *)dropfiles + dropfiles->pFiles); + op.pTo = dst_path; + op.fFlags = FOF_ALLOWUNDO; + if ((ret = SHFileOperationW(&op))) + { + WARN("Failed to copy, ret %d.\n", ret); + hr = E_FAIL; + } + + GlobalUnlock(medium.hGlobal); ReleaseStgMedium(&medium); } else @@ -1371,7 +1389,7 @@ static HRESULT WINAPI BackgroundMenu_InvokeCommand( } else if (!strcmp(lpcmi->lpVerb, "paste")) { - do_paste(This); + do_paste(This, lpcmi->hwnd); } else { @@ -1391,7 +1409,7 @@ static HRESULT WINAPI BackgroundMenu_InvokeCommand( break;
case FCIDM_SHVIEW_INSERT: - do_paste(This); + do_paste(This, lpcmi->hwnd); break;
case FCIDM_SHVIEW_PROPERTIES:
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/shell32/shlview_cmenu.c | 53 ++++++++++++++-------------------- dlls/shell32/tests/shlfolder.c | 2 +- 2 files changed, 22 insertions(+), 33 deletions(-)
diff --git a/dlls/shell32/shlview_cmenu.c b/dlls/shell32/shlview_cmenu.c index aa89e14346e..729f543ef51 100644 --- a/dlls/shell32/shlview_cmenu.c +++ b/dlls/shell32/shlview_cmenu.c @@ -311,50 +311,39 @@ static void DoCopyOrCut(ContextMenu *This, HWND hwnd, BOOL cut) } }
-static HRESULT paste_pidls(ContextMenu *menu, ITEMIDLIST **pidls, unsigned int count) +static HRESULT paste_pidls(ContextMenu *menu, const ITEMIDLIST *src_parent, ITEMIDLIST **pidls, unsigned int count) { - IShellFolder *desktop_folder; + IShellFolder *src_folder; HRESULT hr = S_OK;
- if (FAILED(hr = SHGetDesktopFolder(&desktop_folder))) + if (FAILED(hr = SHBindToObject(NULL, src_parent, NULL, &IID_IShellFolder, (void **)&src_folder))) + { + ERR("Failed to get folder from source PIDL, hr %#lx.\n", hr); return hr; + }
for (unsigned int i = 0; SUCCEEDED(hr) && i < count; i++) { - IShellFolder *folder = NULL; - ITEMIDLIST *pidl_dir; - ITEMIDLIST *pidl_item; + ISFHelper *psfhlpdst = NULL, *psfhlpsrc = NULL;
- pidl_dir = ILClone(pidls[i]); - ILRemoveLastID(pidl_dir); - pidl_item = ILFindLastID(pidls[i]); - hr = IShellFolder_BindToObject(desktop_folder, pidl_dir, NULL, &IID_IShellFolder, (void **)&folder); + hr = IShellFolder_QueryInterface(menu->parent, &IID_ISFHelper, (void **)&psfhlpdst); + if (SUCCEEDED(hr)) + hr = IShellFolder_QueryInterface(src_folder, &IID_ISFHelper, (void **)&psfhlpsrc);
- if (folder) + if (psfhlpdst && psfhlpsrc) { - ISFHelper *psfhlpdst = NULL, *psfhlpsrc = NULL; - - hr = IShellFolder_QueryInterface(menu->parent, &IID_ISFHelper, (void **)&psfhlpdst); - if (SUCCEEDED(hr)) - hr = IShellFolder_QueryInterface(folder, &IID_ISFHelper, (void **)&psfhlpsrc); - - if (psfhlpdst && psfhlpsrc) - { - hr = ISFHelper_CopyItems(psfhlpdst, folder, 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(folder); + hr = ISFHelper_CopyItems(psfhlpdst, src_folder, 1, (LPCITEMIDLIST *)&pidls[i]); + /* FIXME handle move + ISFHelper_DeleteItems(psfhlpsrc, 1, &pidl_item); + */ } - ILFree(pidl_dir); + if (psfhlpdst) + ISFHelper_Release(psfhlpdst); + if (psfhlpsrc) + ISFHelper_Release(psfhlpsrc); }
- IShellFolder_Release(desktop_folder); + IShellFolder_Release(src_folder); return hr; }
@@ -386,7 +375,7 @@ static HRESULT do_paste(ContextMenu *menu, HWND hwnd) pidls = _ILCopyCidaToaPidl(&pidl, cida); if (pidls) { - hr = paste_pidls(menu, pidls, cida->cidl); + hr = paste_pidls(menu, pidl, pidls, cida->cidl); _ILFreeaPidl(pidls, cida->cidl); SHFree(pidl); } diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c index 9da28f570df..d310cd80cbe 100644 --- a/dlls/shell32/tests/shlfolder.c +++ b/dlls/shell32/tests/shlfolder.c @@ -5797,7 +5797,7 @@ static void test_copy_paste(void) ok(ret != INVALID_FILE_ATTRIBUTES, "Got %#x.\n", ret);
ret = RemoveDirectoryW(L"testcopy_dst/testcopy_src"); - todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + ok(ret, "Got error %lu.\n", GetLastError());
/* Paste into a selection comprising multiple directories. In this case the * first directory is used, and the second is just ignored.
From: Zebediah Figura zfigura@codeweavers.com
Based on a patch by Michael Müller.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=34319 --- dlls/shell32/shell32.rc | 1 + dlls/shell32/shlview_cmenu.c | 67 ++++++++++++++++++++++++++++++++-- dlls/shell32/tests/shlfolder.c | 18 +++++---- 3 files changed, 75 insertions(+), 11 deletions(-)
diff --git a/dlls/shell32/shell32.rc b/dlls/shell32/shell32.rc index f47698524bb..970bd9a59c6 100644 --- a/dlls/shell32/shell32.rc +++ b/dlls/shell32/shell32.rc @@ -95,6 +95,7 @@ BEGIN BEGIN MENUITEM "C&ut", FCIDM_SHVIEW_CUT MENUITEM "&Copy", FCIDM_SHVIEW_COPY + MENUITEM "&Paste", FCIDM_SHVIEW_INSERT MENUITEM SEPARATOR MENUITEM "Create &Link", FCIDM_SHVIEW_CREATELINK MENUITEM "&Delete", FCIDM_SHVIEW_DELETE diff --git a/dlls/shell32/shlview_cmenu.c b/dlls/shell32/shlview_cmenu.c index 729f543ef51..cb7ce331897 100644 --- a/dlls/shell32/shlview_cmenu.c +++ b/dlls/shell32/shlview_cmenu.c @@ -157,6 +157,35 @@ static ULONG WINAPI ContextMenu_Release(IContextMenu3 *iface) return ref; }
+static BOOL can_paste(const ITEMIDLIST *dst_pidl) +{ + IDataObject *data; + FORMATETC format; + + if (!(_ILIsFolder(dst_pidl) || _ILIsDrive(dst_pidl))) + return FALSE; + + if (FAILED(OleGetClipboard(&data))) + return FALSE; + + InitFormatEtc(format, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), TYMED_HGLOBAL); + if (SUCCEEDED(IDataObject_QueryGetData(data, &format))) + { + IDataObject_Release(data); + return TRUE; + } + + InitFormatEtc(format, CF_HDROP, TYMED_HGLOBAL); + if (SUCCEEDED(IDataObject_QueryGetData(data, &format))) + { + IDataObject_Release(data); + return TRUE; + } + + IDataObject_Release(data); + return FALSE; +} + static UINT max_menu_id(HMENU hmenu, UINT offset, UINT last) { int i; @@ -252,6 +281,11 @@ static HRESULT WINAPI ItemMenu_QueryContextMenu( EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME - FCIDM_BASE + idCmdFirst, enable); }
+ /* It's legal to paste into more than one pidl at once. In that case + * the first is used and the rest are ignored. */ + if (!can_paste(This->apidl[0])) + RemoveMenu(hmenu, FCIDM_SHVIEW_INSERT - FCIDM_BASE + idCmdFirst, MF_BYCOMMAND); + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, uIDMax-idCmdFirst); } return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0); @@ -311,7 +345,8 @@ static void DoCopyOrCut(ContextMenu *This, HWND hwnd, BOOL cut) } }
-static HRESULT paste_pidls(ContextMenu *menu, const ITEMIDLIST *src_parent, ITEMIDLIST **pidls, unsigned int count) +static HRESULT paste_pidls(IShellFolder *dst_folder, + const ITEMIDLIST *src_parent, ITEMIDLIST **pidls, unsigned int count) { IShellFolder *src_folder; HRESULT hr = S_OK; @@ -326,7 +361,7 @@ static HRESULT paste_pidls(ContextMenu *menu, const ITEMIDLIST *src_parent, ITEM { ISFHelper *psfhlpdst = NULL, *psfhlpsrc = NULL;
- hr = IShellFolder_QueryInterface(menu->parent, &IID_ISFHelper, (void **)&psfhlpdst); + hr = IShellFolder_QueryInterface(dst_folder, &IID_ISFHelper, (void **)&psfhlpdst); if (SUCCEEDED(hr)) hr = IShellFolder_QueryInterface(src_folder, &IID_ISFHelper, (void **)&psfhlpsrc);
@@ -357,6 +392,7 @@ static HRESULT get_data_format(IDataObject *data, UINT cf, STGMEDIUM *medium)
static HRESULT do_paste(ContextMenu *menu, HWND hwnd) { + IShellFolder *dst_folder; IDataObject *data; HRESULT hr; STGMEDIUM medium; @@ -364,6 +400,21 @@ static HRESULT do_paste(ContextMenu *menu, HWND hwnd) if (FAILED(hr = OleGetClipboard(&data))) return hr;
+ if (menu->cidl) + { + if (FAILED(hr = IShellFolder_BindToObject(menu->parent, menu->apidl[0], + NULL, &IID_IShellFolder, (void **)&dst_folder))) + { + WARN("Failed to get destination folder, hr %#lx.\n", hr); + return hr; + } + } + else + { + dst_folder = menu->parent; + IShellFolder_AddRef(dst_folder); + } + if (SUCCEEDED(get_data_format(data, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), &medium))) { CIDA *cida = GlobalLock(medium.hGlobal); @@ -375,7 +426,7 @@ static HRESULT do_paste(ContextMenu *menu, HWND hwnd) pidls = _ILCopyCidaToaPidl(&pidl, cida); if (pidls) { - hr = paste_pidls(menu, pidl, pidls, cida->cidl); + hr = paste_pidls(dst_folder, pidl, pidls, cida->cidl); _ILFreeaPidl(pidls, cida->cidl); SHFree(pidl); } @@ -400,7 +451,7 @@ static HRESULT do_paste(ContextMenu *menu, HWND hwnd) ITEMIDLIST *dst_pidl; int ret;
- if (FAILED(hr = IShellFolder_QueryInterface(menu->parent, &IID_IPersistFolder2, (void **)&dst_persist))) + if (FAILED(hr = IShellFolder_QueryInterface(dst_folder, &IID_IPersistFolder2, (void **)&dst_persist))) { WARN("Failed to get IPersistFolder2, hr %#lx.\n", hr); IDataObject_Release(data); @@ -928,6 +979,9 @@ static HRESULT WINAPI ItemMenu_InvokeCommand( TRACE("Verb FCIDM_SHVIEW_CUT\n"); DoCopyOrCut(This, lpcmi->hwnd, TRUE); break; + case FCIDM_SHVIEW_INSERT: + do_paste(This, lpcmi->hwnd); + break; case FCIDM_SHVIEW_PROPERTIES: TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n"); DoOpenProperties(This, lpcmi->hwnd); @@ -946,6 +1000,8 @@ static HRESULT WINAPI ItemMenu_InvokeCommand( DoCopyOrCut(This, lpcmi->hwnd, FALSE); else if (strcmp(lpcmi->lpVerb,"cut")==0) DoCopyOrCut(This, lpcmi->hwnd, TRUE); + else if (!strcmp(lpcmi->lpVerb, "paste")) + do_paste(This, lpcmi->hwnd); else if (strcmp(lpcmi->lpVerb,"properties")==0) DoOpenProperties(This, lpcmi->hwnd); else { @@ -988,6 +1044,9 @@ static HRESULT WINAPI ItemMenu_GetCommandString(IContextMenu3 *iface, UINT_PTR c case FCIDM_SHVIEW_DELETE: cmdW = L"delete"; break; + case FCIDM_SHVIEW_INSERT: + cmdW = L"paste"; + break; case FCIDM_SHVIEW_PROPERTIES: cmdW = L"properties"; break; diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c index d310cd80cbe..55ee8235f73 100644 --- a/dlls/shell32/tests/shlfolder.c +++ b/dlls/shell32/tests/shlfolder.c @@ -5706,10 +5706,12 @@ static void test_copy_paste(void)
invoke_info.lpVerb = "paste"; hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = MoveFileExW(L"testcopy_dst/testcopy_src", L"testcopy_src", 0); todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + if (!ret && GetLastError() == ERROR_ALREADY_EXISTS) + RemoveDirectoryW(L"testcopy_dst/testcopy_src");
/* Copy. */
@@ -5747,13 +5749,13 @@ static void test_copy_paste(void)
invoke_info.lpVerb = "paste"; hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = GetFileAttributesW(L"testcopy_src"); ok(ret != INVALID_FILE_ATTRIBUTES, "Got %#x.\n", ret);
ret = RemoveDirectoryW(L"testcopy_dst/testcopy_src"); - todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + ok(ret, "Got error %lu.\n", GetLastError());
/* Manually change the drop effect back to "cut". */
@@ -5773,10 +5775,12 @@ static void test_copy_paste(void)
invoke_info.lpVerb = "paste"; hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = MoveFileExW(L"testcopy_dst/testcopy_src", L"testcopy_src", 0); todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + if (!ret && GetLastError() == ERROR_ALREADY_EXISTS) + RemoveDirectoryW(L"testcopy_dst/testcopy_src");
/* Paste into a background menu. */
@@ -5818,10 +5822,10 @@ static void test_copy_paste(void)
invoke_info.lpVerb = "paste"; hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr);
ret = RemoveDirectoryW(L"testcopy_dst2/testcopy_src"); - todo_wine ok(ret, "Got error %lu.\n", GetLastError()); + ok(ret, "Got error %lu.\n", GetLastError()); ret = GetFileAttributesW(L"testcopy_dst/testcopy_src"); ok(ret == INVALID_FILE_ATTRIBUTES, "Got %#x.\n", ret);
@@ -5884,7 +5888,7 @@ static void test_copy_paste(void)
invoke_info.lpVerb = "paste"; hr = IContextMenu_InvokeCommand(dst_menu, &invoke_info); - todo_wine ok(hr == S_OK || hr == S_FALSE /* win10 < 1809 */, "Got hr %#lx.\n", hr); + ok(hr == S_OK || hr == S_FALSE /* win10 < 1809 */, "Got hr %#lx.\n", hr);
ret = RemoveDirectoryW(L"testcopy_src"); ok(ret, "Got error %lu.\n", GetLastError());
Unrelated Windows test failure in shell32:systray, and Wine failures in ddraw and dinput.