Commit 08219c02 authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

shell32/tests: Add tests for context menu copy/paste.

parent 366398cc
...@@ -5604,6 +5604,304 @@ static void test_SHBindToFolderIDListParent(void) ...@@ -5604,6 +5604,304 @@ static void test_SHBindToFolderIDListParent(void)
ok(pidl_last == NULL, "got %p\n", pidl_last); 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) START_TEST(shlfolder)
{ {
init_function_pointers(); init_function_pointers();
...@@ -5651,6 +5949,7 @@ START_TEST(shlfolder) ...@@ -5651,6 +5949,7 @@ START_TEST(shlfolder)
test_SHLimitInputEdit(); test_SHLimitInputEdit();
test_SHGetSetFolderCustomSettings(); test_SHGetSetFolderCustomSettings();
test_SHOpenFolderAndSelectItems(); test_SHOpenFolderAndSelectItems();
test_copy_paste();
OleUninitialize(); OleUninitialize();
} }
...@@ -77,6 +77,7 @@ typedef int GPFIDL_FLAGS; ...@@ -77,6 +77,7 @@ typedef int GPFIDL_FLAGS;
WINSHELLAPI void WINAPI SHFree(void*); WINSHELLAPI void WINAPI SHFree(void*);
WINSHELLAPI UINT WINAPI SHAddFromPropSheetExtArray(HPSXA,LPFNADDPROPSHEETPAGE,LPARAM); WINSHELLAPI UINT WINAPI SHAddFromPropSheetExtArray(HPSXA,LPFNADDPROPSHEETPAGE,LPARAM);
WINSHELLAPI void* WINAPI SHAlloc(ULONG) __WINE_ALLOC_SIZE(1) __WINE_DEALLOC(SHFree) __WINE_MALLOC; 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 HRESULT WINAPI SHCoCreateInstance(LPCWSTR,const CLSID*,IUnknown*,REFIID,LPVOID*);
WINSHELLAPI HPSXA WINAPI SHCreatePropSheetExtArray(HKEY,LPCWSTR,UINT); WINSHELLAPI HPSXA WINAPI SHCreatePropSheetExtArray(HKEY,LPCWSTR,UINT);
WINSHELLAPI HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY,LPCWSTR,UINT,IDataObject*); WINSHELLAPI HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY,LPCWSTR,UINT,IDataObject*);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment