wine/dlls/shell32/tests/shlfileop.c

3117 lines
136 KiB
C

/*
* Unit test of the SHFileOperation function.
*
* Copyright 2002 Andriy Palamarchuk
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <stdio.h>
#define COBJMACROS
#include <windows.h>
#include "shellapi.h"
#include "shlwapi.h"
#include "shlobj.h"
#include "sherrors.h"
#include "commoncontrols.h"
#include "wine/test.h"
/* Error codes could be pre-Win32 */
#define DE_SAMEFILE 0x71
#define DE_MANYSRC1DEST 0x72
#define DE_DIFFDIR 0x73
#define DE_OPCANCELLED 0x75
#define DE_DESTSUBTREE 0x76
#define DE_INVALIDFILES 0x7C
#define DE_DESTSAMETREE 0x7D
#define DE_FLDDESTISFILE 0x7E
#define DE_FILEDESTISFLD 0x80
#define expect_retval(ret, ret_prewin32)\
ok(retval == ret ||\
broken(retval == ret_prewin32),\
"Expected %d, got %ld\n", ret, retval)
static BOOL old_shell32 = FALSE;
static CHAR CURR_DIR[MAX_PATH];
static const WCHAR UNICODE_PATH[] = L"c:\\\x00ae\0";
/* "c:\®" can be used in all codepages */
/* Double-null termination needed for pFrom field of SHFILEOPSTRUCT */
/* creates a file with the specified name for tests */
static void createTestFile(const CHAR *name)
{
HANDLE file;
DWORD written;
file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
WriteFile(file, name, strlen(name), &written, NULL);
WriteFile(file, "\n", strlen("\n"), &written, NULL);
CloseHandle(file);
}
static void createTestFileW(const WCHAR *name)
{
HANDLE file;
file = CreateFileW(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
ok(file != INVALID_HANDLE_VALUE, "Failure to open file\n");
CloseHandle(file);
}
static BOOL file_exists(const CHAR *name)
{
return GetFileAttributesA(name) != INVALID_FILE_ATTRIBUTES;
}
static BOOL dir_exists(const CHAR *name)
{
DWORD attr;
BOOL dir;
attr = GetFileAttributesA(name);
dir = ((attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
return ((attr != INVALID_FILE_ATTRIBUTES) && dir);
}
static BOOL file_existsW(LPCWSTR name)
{
return GetFileAttributesW(name) != INVALID_FILE_ATTRIBUTES;
}
static BOOL file_has_content(const CHAR *name, const CHAR *content)
{
CHAR buf[MAX_PATH];
HANDLE file;
DWORD read;
file = CreateFileA(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (file == INVALID_HANDLE_VALUE)
return FALSE;
ReadFile(file, buf, MAX_PATH - 1, &read, NULL);
buf[read] = 0;
CloseHandle(file);
return strcmp(buf, content)==0;
}
static void remove_directory(const WCHAR *name)
{
SHFILEOPSTRUCTW shfo;
WCHAR path[MAX_PATH];
memset(&shfo, 0, sizeof(shfo));
shfo.wFunc = FO_DELETE;
wcscpy(path, name);
path[wcslen(name) + 1] = 0;
shfo.pFrom = path;
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT;
SHFileOperationW(&shfo);
}
/* initializes the tests */
static void init_shfo_tests(void)
{
int len;
GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
len = lstrlenA(CURR_DIR);
if(len && (CURR_DIR[len-1] == '\\'))
CURR_DIR[len-1] = 0;
createTestFile("test1.txt");
createTestFile("test2.txt");
createTestFile("test3.txt");
createTestFile("test_5.txt");
CreateDirectoryA("test4.txt", NULL);
CreateDirectoryA("testdir2", NULL);
CreateDirectoryA("testdir2\\nested", NULL);
createTestFile("testdir2\\one.txt");
createTestFile("testdir2\\nested\\two.txt");
CreateDirectoryA("testdir4", NULL);
CreateDirectoryA("testdir4\\nested", NULL);
CreateDirectoryA("testdir4\\nested\\subnested", NULL);
createTestFile("testdir4\\nested\\2.txt");
createTestFile("testdir4\\nested\\subnested\\3.txt");
CreateDirectoryA("testdir6", NULL);
CreateDirectoryA("testdir6\\nested", NULL);
CreateDirectoryA("testdir8", NULL);
CreateDirectoryA("testdir8\\nested", NULL);
}
/* cleans after tests */
static void clean_after_shfo_tests(void)
{
DeleteFileA("test1.txt");
DeleteFileA("test2.txt");
DeleteFileA("test3.txt");
DeleteFileA("test_5.txt");
DeleteFileA("one.txt");
DeleteFileA("test4.txt\\test1.txt");
DeleteFileA("test4.txt\\test2.txt");
DeleteFileA("test4.txt\\test3.txt");
DeleteFileA("test4.txt\\one.txt");
DeleteFileA("test4.txt\\nested\\two.txt");
RemoveDirectoryA("test4.txt\\nested");
RemoveDirectoryA("test4.txt");
DeleteFileA("testdir2\\one.txt");
DeleteFileA("testdir2\\test1.txt");
DeleteFileA("testdir2\\test2.txt");
DeleteFileA("testdir2\\test3.txt");
DeleteFileA("testdir2\\test4.txt\\test1.txt");
DeleteFileA("testdir2\\nested\\two.txt");
RemoveDirectoryA("testdir2\\test4.txt");
RemoveDirectoryA("testdir2\\nested");
RemoveDirectoryA("testdir2");
DeleteFileA("testdir4\\nested\\subnested\\3.txt");
DeleteFileA("testdir4\\nested\\two.txt");
DeleteFileA("testdir4\\nested\\2.txt");
RemoveDirectoryA("testdir4\\nested\\subnested");
RemoveDirectoryA("testdir4\\nested");
RemoveDirectoryA("testdir4");
DeleteFileA("testdir6\\nested\\subnested\\3.txt");
DeleteFileA("testdir6\\nested\\two.txt");
DeleteFileA("testdir6\\nested\\2.txt");
DeleteFileA("testdir6\\one.txt");
DeleteFileA("testdir6\\two.txt");
RemoveDirectoryA("testdir6\\nested\\subnested");
RemoveDirectoryA("testdir6\\subnested");
RemoveDirectoryA("testdir6\\nested");
RemoveDirectoryA("testdir6");
DeleteFileA("testdir8\\nested\\subnested\\3.txt");
DeleteFileA("testdir8\\subnested\\3.txt");
DeleteFileA("testdir8\\nested\\2.txt");
DeleteFileA("testdir8\\2.txt");
RemoveDirectoryA("testdir8\\nested\\subnested");
RemoveDirectoryA("testdir8\\subnested");
RemoveDirectoryA("testdir8\\nested");
RemoveDirectoryA("testdir8");
RemoveDirectoryA("c:\\testdir3");
DeleteFileA("nonexistent\\notreal\\test2.txt");
RemoveDirectoryA("nonexistent\\notreal");
RemoveDirectoryA("nonexistent");
}
static void test_get_file_info(void)
{
DWORD rc, rc2;
SHFILEINFOA shfi, shfi2;
SHFILEINFOW shfiw;
char notepad[MAX_PATH];
HANDLE unset_icon;
/* Test whether fields of SHFILEINFOA are always cleared */
memset(&shfi, 0xcf, sizeof(shfi));
rc=SHGetFileInfoA("", 0, &shfi, sizeof(shfi), 0);
ok(rc == 1, "SHGetFileInfoA('' | 0) should return 1, got 0x%lx\n", rc);
todo_wine ok(shfi.hIcon == 0, "SHGetFileInfoA('' | 0) did not clear hIcon\n");
todo_wine ok(shfi.szDisplayName[0] == 0, "SHGetFileInfoA('' | 0) did not clear szDisplayName[0]\n");
todo_wine ok(shfi.szTypeName[0] == 0, "SHGetFileInfoA('' | 0) did not clear szTypeName[0]\n");
ok(shfi.iIcon == 0xcfcfcfcf ||
broken(shfi.iIcon != 0xcfcfcfcf), /* NT4 doesn't clear but sets this field */
"SHGetFileInfoA('' | 0) should not clear iIcon\n");
ok(shfi.dwAttributes == 0xcfcfcfcf ||
broken(shfi.dwAttributes != 0xcfcfcfcf), /* NT4 doesn't clear but sets this field */
"SHGetFileInfoA('' | 0) should not clear dwAttributes\n");
memset(&shfiw, 0xcf, sizeof(shfiw));
memset(&unset_icon, 0xcf, sizeof(unset_icon));
rc = SHGetFileInfoW(NULL, 0, &shfiw, sizeof(shfiw), 0);
ok(!rc, "SHGetFileInfoW(NULL | 0) should fail\n");
ok(shfiw.hIcon == unset_icon, "SHGetFileInfoW(NULL | 0) should not clear hIcon\n");
ok(shfiw.szDisplayName[0] == 0xcfcf, "SHGetFileInfoW(NULL | 0) should not clear szDisplayName[0]\n");
ok(shfiw.szTypeName[0] == 0xcfcf, "SHGetFileInfoW(NULL | 0) should not clear szTypeName[0]\n");
ok(shfiw.iIcon == 0xcfcfcfcf, "SHGetFileInfoW(NULL | 0) should not clear iIcon\n");
ok(shfiw.dwAttributes == 0xcfcfcfcf, "SHGetFileInfoW(NULL | 0) should not clear dwAttributes\n");
/* Test some flag combinations that MSDN claims are not allowed,
* but which work anyway
*/
memset(&shfi, 0xcf, sizeof(shfi));
rc=SHGetFileInfoA("c:\\nonexistent", FILE_ATTRIBUTE_DIRECTORY,
&shfi, sizeof(shfi),
SHGFI_ATTRIBUTES | SHGFI_USEFILEATTRIBUTES);
ok(rc == 1, "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) should return 1, got 0x%lx\n", rc);
if (rc)
ok(shfi.dwAttributes != 0xcfcfcfcf, "dwFileAttributes is not set\n");
todo_wine ok(shfi.hIcon == 0, "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) did not clear hIcon\n");
todo_wine ok(shfi.szDisplayName[0] == 0, "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) did not clear szDisplayName[0]\n");
todo_wine ok(shfi.szTypeName[0] == 0, "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) did not clear szTypeName[0]\n");
ok(shfi.iIcon == 0xcfcfcfcf ||
broken(shfi.iIcon != 0xcfcfcfcf), /* NT4 doesn't clear but sets this field */
"SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) should not clear iIcon\n");
rc=SHGetFileInfoA("c:\\nonexistent", FILE_ATTRIBUTE_DIRECTORY,
&shfi, sizeof(shfi),
SHGFI_EXETYPE | SHGFI_USEFILEATTRIBUTES);
todo_wine ok(rc == 1, "SHGetFileInfoA(c:\\nonexistent | SHGFI_EXETYPE) should return 1, got 0x%lx\n", rc);
/* Test SHGFI_USEFILEATTRIBUTES support */
strcpy(shfi.szDisplayName, "dummy");
shfi.iIcon=0xdeadbeef;
rc=SHGetFileInfoA("c:\\nonexistent", FILE_ATTRIBUTE_DIRECTORY,
&shfi, sizeof(shfi),
SHGFI_ICONLOCATION | SHGFI_USEFILEATTRIBUTES);
ok(rc == 1, "SHGetFileInfoA(c:\\nonexistent) should return 1, got 0x%lx\n", rc);
if (rc)
{
ok(strcmp(shfi.szDisplayName, "dummy"), "SHGetFileInfoA(c:\\nonexistent) displayname is not set\n");
ok(shfi.iIcon != 0xdeadbeef, "SHGetFileInfoA(c:\\nonexistent) iIcon is not set\n");
}
/* Wine does not have a default icon for text files, and Windows 98 fails
* if we give it an empty executable. So use notepad.exe as the test
*/
if (SearchPathA(NULL, "notepad.exe", NULL, sizeof(notepad), notepad, NULL))
{
strcpy(shfi.szDisplayName, "dummy");
shfi.iIcon=0xdeadbeef;
rc=SHGetFileInfoA(notepad, GetFileAttributesA(notepad),
&shfi, sizeof(shfi),
SHGFI_ICONLOCATION | SHGFI_USEFILEATTRIBUTES);
ok(rc == 1, "SHGetFileInfoA(%s, SHGFI_USEFILEATTRIBUTES) should return 1, got 0x%lx\n", notepad, rc);
strcpy(shfi2.szDisplayName, "dummy");
shfi2.iIcon=0xdeadbeef;
rc2=SHGetFileInfoA(notepad, 0,
&shfi2, sizeof(shfi2),
SHGFI_ICONLOCATION);
ok(rc2 == 1, "SHGetFileInfoA(%s) failed %lx\n", notepad, rc2);
if (rc && rc2)
{
ok(lstrcmpiA(shfi2.szDisplayName, shfi.szDisplayName) == 0, "wrong display name %s != %s\n", shfi.szDisplayName, shfi2.szDisplayName);
ok(shfi2.iIcon == shfi.iIcon, "wrong icon index %d != %d\n", shfi.iIcon, shfi2.iIcon);
}
}
/* with a directory now */
strcpy(shfi.szDisplayName, "dummy");
shfi.iIcon=0xdeadbeef;
rc=SHGetFileInfoA("test4.txt", GetFileAttributesA("test4.txt"),
&shfi, sizeof(shfi),
SHGFI_ICONLOCATION | SHGFI_USEFILEATTRIBUTES);
ok(rc == 1, "SHGetFileInfoA(test4.txt/, SHGFI_USEFILEATTRIBUTES) should return 1, got 0x%lx\n", rc);
strcpy(shfi2.szDisplayName, "dummy");
shfi2.iIcon=0xdeadbeef;
rc2=SHGetFileInfoA("test4.txt", 0,
&shfi2, sizeof(shfi2),
SHGFI_ICONLOCATION);
ok(rc2 == 1, "SHGetFileInfoA(test4.txt/) should return 1, got 0x%lx\n", rc2);
if (rc && rc2)
{
ok(lstrcmpiA(shfi2.szDisplayName, shfi.szDisplayName) == 0, "wrong display name %s != %s\n", shfi.szDisplayName, shfi2.szDisplayName);
ok(shfi2.iIcon == shfi.iIcon, "wrong icon index %d != %d\n", shfi.iIcon, shfi2.iIcon);
}
/* with drive root directory */
strcpy(shfi.szDisplayName, "dummy");
strcpy(shfi.szTypeName, "dummy");
shfi.hIcon=(HICON) 0xdeadbeef;
shfi.iIcon=0xdeadbeef;
shfi.dwAttributes=0xdeadbeef;
rc=SHGetFileInfoA("c:\\", 0, &shfi, sizeof(shfi),
SHGFI_TYPENAME | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_SMALLICON);
ok(rc == 1, "SHGetFileInfoA(c:\\) should return 1, got 0x%lx\n", rc);
ok(strcmp(shfi.szDisplayName, "dummy") != 0, "display name was expected to change\n");
ok(strcmp(shfi.szTypeName, "dummy") != 0, "type name was expected to change\n");
ok(shfi.hIcon != (HICON) 0xdeadbeef, "hIcon was expected to change\n");
ok(shfi.iIcon != 0xdeadbeef, "iIcon was expected to change\n");
}
static void check_icon_size( HICON icon, DWORD flags )
{
ICONINFO info;
BITMAP bm;
SIZE metrics_size;
int list_cx, list_cy;
IImageList *list;
GetIconInfo( icon, &info );
GetObjectW( info.hbmColor, sizeof(bm), &bm );
SHGetImageList( (flags & SHGFI_SMALLICON) ? SHIL_SMALL : SHIL_LARGE,
&IID_IImageList, (void **)&list );
IImageList_GetIconSize( list, &list_cx, &list_cy );
IImageList_Release( list );
metrics_size.cx = GetSystemMetrics( (flags & SHGFI_SMALLICON) ? SM_CXSMICON : SM_CXICON );
metrics_size.cy = GetSystemMetrics( (flags & SHGFI_SMALLICON) ? SM_CYSMICON : SM_CYICON );
if (flags & SHGFI_SHELLICONSIZE)
{
ok( bm.bmWidth == list_cx, "got %d expected %d\n", bm.bmWidth, list_cx );
ok( bm.bmHeight == list_cy, "got %d expected %d\n", bm.bmHeight, list_cy );
}
else
{
ok( bm.bmWidth == metrics_size.cx, "got %d expected %ld\n", bm.bmWidth, metrics_size.cx );
ok( bm.bmHeight == metrics_size.cy, "got %d expected %ld\n", bm.bmHeight, metrics_size.cy );
}
}
static void test_get_file_info_iconlist(void)
{
/* Test retrieving a handle to the system image list, and
* what that returns for hIcon
*/
HRESULT hr;
HIMAGELIST hSysImageList;
LPITEMIDLIST pidList;
SHFILEINFOA shInfoa;
SHFILEINFOW shInfow;
IImageList *small_list, *large_list;
ULONG start_refs, refs;
hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidList);
if (FAILED(hr)) {
skip("can't get desktop pidl\n");
return;
}
SHGetImageList( SHIL_LARGE, &IID_IImageList, (void **)&large_list );
SHGetImageList( SHIL_SMALL, &IID_IImageList, (void **)&small_list );
start_refs = IImageList_AddRef( small_list );
IImageList_Release( small_list );
memset(&shInfoa, 0xcf, sizeof(shInfoa));
hSysImageList = (HIMAGELIST) SHGetFileInfoA((const char *)pidList, 0,
&shInfoa, sizeof(shInfoa),
SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_PIDL);
ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
refs = IImageList_AddRef( small_list );
IImageList_Release( small_list );
ok( refs == start_refs + 1 ||
broken( refs == start_refs ), /* XP and 2003 */
"got %ld, start_refs %ld\n", refs, start_refs );
todo_wine ok(shInfoa.hIcon == 0, "SHGetFileInfoA(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) did not clear hIcon\n");
todo_wine ok(shInfoa.szTypeName[0] == 0, "SHGetFileInfoA(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) did not clear szTypeName[0]\n");
ok(shInfoa.iIcon != 0xcfcfcfcf, "SHGetFileInfoA(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) should set iIcon\n");
ok(shInfoa.dwAttributes == 0xcfcfcfcf ||
shInfoa.dwAttributes == 0 || /* Vista */
broken(shInfoa.dwAttributes != 0xcfcfcfcf), /* NT4 doesn't clear but sets this field */
"SHGetFileInfoA(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL), unexpected dwAttributes\n");
/* Don't release hSysImageList here (and in similar places below) because of the broken reference behaviour of XP and 2003. */
memset(&shInfow, 0xcf, sizeof(shInfow));
hSysImageList = (HIMAGELIST) SHGetFileInfoW((const WCHAR *)pidList, 0,
&shInfow, sizeof(shInfow), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_PIDL);
ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
todo_wine ok(shInfow.hIcon == 0, "SHGetFileInfoW(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) did not clear hIcon\n");
ok(shInfow.szTypeName[0] == 0, "SHGetFileInfoW(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) did not clear szTypeName[0]\n");
ok(shInfow.iIcon != 0xcfcfcfcf, "SHGetFileInfoW(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) should set iIcon\n");
ok(shInfow.dwAttributes == 0xcfcfcfcf ||
shInfoa.dwAttributes == 0, /* Vista */
"SHGetFileInfoW(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) unexpected dwAttributes\n");
/* Various suposidly invalid flag testing */
memset(&shInfow, 0xcf, sizeof(shInfow));
hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON);
ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
ok(shInfow.dwAttributes==0xcfcfcfcf ||
shInfoa.dwAttributes==0, /* Vista */
"unexpected dwAttributes\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON);
ok(hr != 0, " SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n");
ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
check_icon_size( shInfow.hIcon, SHGFI_SMALLICON );
DestroyIcon(shInfow.hIcon);
todo_wine ok(shInfow.dwAttributes==0,"dwAttributes not set\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_LARGEICON);
ok(hr != 0, "SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_LARGEICON Failed\n");
ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
check_icon_size( shInfow.hIcon, SHGFI_LARGEICON );
DestroyIcon( shInfow.hIcon );
todo_wine ok(shInfow.dwAttributes==0,"dwAttributes not set\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_LARGEICON);
ok(hSysImageList == (HIMAGELIST)large_list, "got %p expect %p\n", hSysImageList, small_list);
ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
ok(shInfow.dwAttributes==0xcfcfcfcf ||
shInfoa.dwAttributes==0, /* Vista */
"unexpected dwAttributes\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_OPENICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON);
ok(hr != 0, "SHGFI_OPENICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n");
todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON);
ok(hr != 0, "SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n");
todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON);
ok(hr != 0, "SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n");
todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|
SHGFI_ATTRIBUTES);
ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|
SHGFI_EXETYPE);
todo_wine ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
ok(shInfow.dwAttributes==0xcfcfcfcf ||
shInfoa.dwAttributes==0, /* Vista */
"unexpected dwAttributes\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_EXETYPE);
todo_wine ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_EXETYPE Failed\n");
todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_ATTRIBUTES);
ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_ATTRIBUTES Failed\n");
todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|
SHGFI_ATTRIBUTES);
ok(hSysImageList == (HIMAGELIST)large_list, "got %p expect %p\n", hSysImageList, large_list);
ok(hr != 0, "SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_ATTRIBUTES Failed\n");
ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_EXETYPE);
todo_wine ok(hSysImageList == (HIMAGELIST)large_list, "got %p expect %p\n", hSysImageList, large_list);
ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
ok(shInfow.dwAttributes==0xcfcfcfcf ||
shInfoa.dwAttributes==0, /* Vista */
"unexpected dwAttributes\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_EXETYPE);
todo_wine ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_EXETYPE Failed\n");
todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_ATTRIBUTES);
ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_ATTRIBUTES Failed\n");
todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n");
memset(&shInfow, 0xcf, sizeof(shInfow));
hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_SYSICONINDEX|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_SHELLICONSIZE|SHGFI_ICON);
ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
check_icon_size( shInfow.hIcon, SHGFI_SMALLICON | SHGFI_SHELLICONSIZE );
DestroyIcon( shInfow.hIcon );
memset(&shInfow, 0xcf, sizeof(shInfow));
hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
SHGFI_SYSICONINDEX|SHGFI_PIDL|SHGFI_SHELLICONSIZE|SHGFI_ICON);
ok(hSysImageList == (HIMAGELIST)large_list, "got %p expect %p\n", hSysImageList, small_list);
ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
check_icon_size( shInfow.hIcon, SHGFI_LARGEICON | SHGFI_SHELLICONSIZE );
DestroyIcon( shInfow.hIcon );
ILFree(pidList);
IImageList_Release( small_list );
IImageList_Release( large_list );
}
/*
puts into the specified buffer file names with current directory.
files - string with file names, separated by null characters. Ends on a double
null characters
*/
static void set_curr_dir_path(CHAR *buf, const CHAR* files)
{
buf[0] = 0;
while (files[0])
{
strcpy(buf, CURR_DIR);
buf += strlen(buf);
buf[0] = '\\';
buf++;
strcpy(buf, files);
buf += strlen(buf) + 1;
files += strlen(files) + 1;
}
buf[0] = 0;
}
#define check_file_operation(func, flags, from, to, expect_ret, expect_aborted, todo_ret, todo_aborted) \
check_file_operation_(__LINE__, func, flags, from, to, expect_ret, expect_aborted, todo_ret, todo_aborted)
void check_file_operation_(unsigned int line, UINT func, FILEOP_FLAGS flags, const char *from, const char *to,
DWORD expect_ret, BOOL expect_aborted, BOOL todo_ret, BOOL todo_aborted)
{
SHFILEOPSTRUCTA op;
DWORD ret;
memset(&op, 0, sizeof(op));
op.wFunc = func;
op.fFlags = flags;
op.pFrom = from;
op.pTo = to;
op.fAnyOperationsAborted = 0xdeadbeef;
ret = SHFileOperationA(&op);
todo_wine_if(todo_ret)
ok_(__FILE__, line)(ret == expect_ret, "SHFileOperationA returned %ld, expected %ld.\n", ret, expect_ret);
todo_wine_if(todo_aborted)
ok_(__FILE__, line)(op.fAnyOperationsAborted == expect_aborted,
"Unexpected fAnyOperationsAborted %d, expected %d.\n",
op.fAnyOperationsAborted, expect_aborted);
}
/* tests the FO_DELETE action */
static void test_delete(void)
{
char from[MAX_PATH * 5];
/* Wildcard source, with FOF_FILESONLY. */
set_curr_dir_path(from, "test?.txt\0");
check_file_operation(FO_DELETE, FOF_NO_UI | FOF_FILESONLY, from, NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(dir_exists("test4.txt"), "Directory should not have been removed\n");
ok(!file_exists("test1.txt"), "File should have been removed\n");
ok(!file_exists("test2.txt"), "File should have been removed\n");
ok(!file_exists("test3.txt"), "File should have been removed\n");
set_curr_dir_path(from, "test?.txt\0");
check_file_operation(FO_DELETE, FOF_NO_UI | FOF_FILESONLY, from, NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(dir_exists("test4.txt"), "Directory should not have been removed\n");
/* Wildcard source, no FOF_FILESONLY. */
set_curr_dir_path(from, "test?.txt\0");
check_file_operation(FO_DELETE, FOF_NO_UI, from, NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("test4.txt"), "Directory should have been removed\n");
/* Nonexistent wildcard source. */
set_curr_dir_path(from, "test?.txt\0");
check_file_operation(FO_DELETE, FOF_NO_UI, from, NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
/* Delete a dir with a file inside. */
init_shfo_tests();
set_curr_dir_path(from, "test4.txt\0");
ok(MoveFileA("test1.txt", "test4.txt\\test1.txt"), "Filling the subdirectory failed\n");
check_file_operation(FO_DELETE, FOF_NO_UI, from, NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("test4.txt"), "Directory is not removed\n");
/* Remove a dir and a file. */
init_shfo_tests();
check_file_operation(FO_DELETE, FOF_NO_UI, "test1.txt\0test4.txt\0", NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!file_exists("test1.txt"), "The file should have been removed\n");
ok(!dir_exists("test4.txt"), "Directory should have been removed\n");
ok(file_exists("test2.txt"), "This file should not have been removed\n");
/* Wildcard source, with FOF_FILESONLY. */
init_shfo_tests();
check_file_operation(FO_DELETE, FOF_NO_UI | FOF_FILESONLY, "*.txt\0", NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!file_exists("test1.txt"), "test1.txt should have been removed\n");
ok(!file_exists("test_5.txt"), "test_5.txt should have been removed\n");
ok(dir_exists("test4.txt"), "test4.txt should not have been removed\n");
/* Explicitly specify a dir, with FOF_FILESONLY. */
init_shfo_tests();
check_file_operation(FO_DELETE, FOF_NO_UI | FOF_FILESONLY, "test_?.txt\0test4.txt\0", NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("test4.txt"), "test4.txt should have been removed\n");
ok(!file_exists("test_5.txt"), "test_5.txt should have been removed\n");
ok(file_exists("test1.txt"), "test1.txt should not have been removed\n");
/* Empty filename. */
init_shfo_tests();
check_file_operation(FO_DELETE, FOF_NO_UI, "\0", NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
/* NULL filename. */
init_shfo_tests();
check_file_operation(FO_DELETE, FOF_NO_UI, NULL, NULL,
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
/* Invalid function. */
init_shfo_tests();
check_file_operation(0, FOF_NO_UI, "test1.txt\0", NULL,
ERROR_INVALID_PARAMETER, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
/* Empty filename, only one null terminator */
init_shfo_tests();
check_file_operation(FO_DELETE, FOF_NO_UI, "", NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
/* Nonexistent file. */
check_file_operation(FO_DELETE, FOF_NO_UI, "nonexistent.txt\0", NULL,
ERROR_FILE_NOT_FOUND, FALSE, FALSE, FALSE);
/* Delete a dir, and then a file inside the dir,
* same as deleting a nonexistent file. */
init_shfo_tests();
check_file_operation(FO_DELETE, FOF_NO_UI, "testdir2\0testdir2\\one.txt\0", NULL,
DE_INVALIDFILES, FALSE, TRUE, FALSE);
ok(!dir_exists("testdir2"), "Expected testdir2 to not exist\n");
ok(!file_exists("testdir2\\one.txt"), "Expected testdir2\\one.txt to not exist\n");
/* Delete an existent file and a nonexistent file. */
init_shfo_tests();
check_file_operation(FO_DELETE, FOF_NO_UI, "test1.txt\0nonexistent.txt\0test2.txt\0", NULL,
ERROR_FILE_NOT_FOUND, FALSE, FALSE, FALSE);
todo_wine
ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
ok(file_exists("test2.txt"), "Expected test2.txt to exist\n");
/* Delete a nonexistent file in an existent dir or a nonexistent dir. */
init_shfo_tests();
check_file_operation(FO_DELETE, FOF_NO_UI, "testdir2\\nonexistent.txt\0", NULL,
ERROR_FILE_NOT_FOUND, FALSE, FALSE, FALSE);
check_file_operation(FO_DELETE, FOF_NO_UI, "nonexistent\\one.txt\0", NULL,
DE_INVALIDFILES, FALSE, FALSE, FALSE);
/* With FOF_NORECURSION, subdirs are still deleted. */
init_shfo_tests();
check_file_operation(FO_DELETE, FOF_NO_UI | FOF_NORECURSION, "testdir2\0", NULL,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!file_exists("testdir2\\one.txt"), "Expected testdir2\\one.txt to not exist\n");
ok(!dir_exists("testdir2\\nested"), "Expected testdir2\\nested to not exist\n");
}
static BOOL is_below_windows8(void)
{
INT_PTR rc;
rc = (INT_PTR)ShellExecuteA(NULL, "averb", "shlproto://foo/bar", NULL, NULL, SW_HIDE);
return rc == SE_ERR_ACCESSDENIED;
}
/* tests the FO_RENAME action */
static void test_rename(void)
{
char from[5 * MAX_PATH], to[5 * MAX_PATH];
/* Rename a file to an existing dir. */
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test4.txt\0");
check_file_operation(FO_RENAME, FOF_NO_UI, from, to,
DE_FILEDESTISFLD, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "The file is renamed\n");
/* Rename a dir to an existing file. */
set_curr_dir_path(from, "test4.txt\0");
set_curr_dir_path(to, "test1.txt\0");
check_file_operation(FO_RENAME, FOF_NO_UI, from, to,
DE_FLDDESTISFILE, FALSE, FALSE, FALSE);
ok(dir_exists("test4.txt"), "The file is renamed\n");
/* Rename file to a different directory. */
set_curr_dir_path(from, "test3.txt\0");
set_curr_dir_path(to, "test4.txt\\test1.txt\0");
check_file_operation(FO_RENAME, FOF_NO_UI, from, to,
DE_DIFFDIR, FALSE, FALSE, FALSE);
ok(!file_exists("test4.txt\\test1.txt"), "The file is renamed\n");
/* Multiple sources and targets, no FOF_MULTIDESTFILES. */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
check_file_operation(FO_RENAME, FOF_NO_UI, from, to,
DE_MANYSRC1DEST, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "The file is renamed - many files are specified\n");
/* Multiple sources and targets, with FOF_MULTIDESTFILES. */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
check_file_operation(FO_RENAME, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
DE_MANYSRC1DEST, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "The file is not renamed - many files are specified\n");
/* Sources outnumber targets, with FOF_MULTIDESTFILES. */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0");
check_file_operation(FO_RENAME, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
DE_MANYSRC1DEST, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "The file is not renamed - many files are specified\n");
/* Rename a file. */
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test6.txt\0");
check_file_operation(FO_RENAME, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!file_exists("test1.txt"), "The file is not renamed\n");
ok(file_exists("test6.txt"), "The file is not renamed\n");
set_curr_dir_path(from, "test6.txt\0");
set_curr_dir_path(to, "test1.txt\0");
check_file_operation(FO_RENAME, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
/* Rename a dir. */
set_curr_dir_path(from, "test4.txt\0");
set_curr_dir_path(to, "test6.txt\0");
check_file_operation(FO_RENAME, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("test4.txt"), "The dir is not renamed\n");
ok(dir_exists("test6.txt"), "The dir is not renamed\n");
set_curr_dir_path(from, "test6.txt\0");
set_curr_dir_path(to, "test4.txt\0");
check_file_operation(FO_RENAME, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(dir_exists("test4.txt"), "The dir is not renamed\n");
/* Rename multiple files to a single file. */
check_file_operation(FO_RENAME, FOF_NO_UI,
"test1.txt\0test2.txt\0", "a.txt\0",
DE_MANYSRC1DEST, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
ok(file_exists("test2.txt"), "Expected test2.txt to exist\n");
ok(!file_exists("a.txt"), "Expected a.txt to not exist\n");
/* Rename a file to multiple files. */
check_file_operation(FO_RENAME, FOF_NO_UI,
"test1.txt\0", "a.txt\0b.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!file_exists("test1.txt"), "Expected test1.txt to not exist\n");
ok(DeleteFileA("a.txt"), "Expected a.txt to exist\n");
ok(!DeleteFileA("b.txt"), "Expected b.txt to not exist\n");
/* Rename a nonexistent file. */
check_file_operation(FO_RENAME, FOF_NO_UI,
"idontexist\0", "newfile\0",
ERROR_FILE_NOT_FOUND, FALSE, FALSE, FALSE);
ok(!file_exists("newfile"), "Expected newfile to not exist\n");
/* Target already exists. */
createTestFile("test1.txt");
check_file_operation(FO_RENAME, FOF_NO_UI,
"test1.txt\0", "test2.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
if (!is_below_windows8()) /* Hangs with Windows 7 */
{
check_file_operation(FO_RENAME, FOF_NO_UI,
"testdir2\0", "testdir4\0",
ERROR_SUCCESS, FALSE, TRUE, FALSE);
}
else
win_skip("Skip FO_RENAME with already existing target directory.\n");
/* Empty source or target. */
clean_after_shfo_tests();
init_shfo_tests();
check_file_operation(FO_RENAME, FOF_NO_UI,
"\0", "test1.txt\0",
DE_MANYSRC1DEST, FALSE, FALSE, FALSE);
check_file_operation(FO_RENAME, FOF_NO_UI,
"\0", "testdir2\0",
DE_MANYSRC1DEST, FALSE, FALSE, FALSE);
check_file_operation(FO_RENAME, FOF_NO_UI,
"\0", "nonexistence\0",
DE_MANYSRC1DEST, FALSE, FALSE, FALSE);
ok(!file_exists("nonexistence"), "Expected nonexistence to not exist\n");
check_file_operation(FO_RENAME, FOF_NO_UI,
"testdir2\0", "\0",
DE_DIFFDIR, FALSE, FALSE, FALSE);
ok(file_exists("testdir2"), "Expected testdir2 to exist\n");
check_file_operation(FO_RENAME, FOF_NO_UI,
"test1.txt\0", "\0",
DE_DIFFDIR, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "Expected test1.txt to exist\n");
check_file_operation(FO_RENAME, FOF_NO_UI,
"nonexistence\0", "\0",
ERROR_FILE_NOT_FOUND, FALSE, FALSE, FALSE);
check_file_operation(FO_RENAME, FOF_NO_UI,
"\0", "\0",
DE_MANYSRC1DEST, FALSE, FALSE, FALSE);
/* NULL source or target. */
clean_after_shfo_tests();
init_shfo_tests();
check_file_operation(FO_RENAME, FOF_NO_UI,
NULL, "test1.txt\0",
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
check_file_operation(FO_RENAME, FOF_NO_UI,
NULL, "testdir2\0",
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
check_file_operation(FO_RENAME, FOF_NO_UI,
NULL, "nonexistence\0",
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
check_file_operation(FO_RENAME, FOF_NO_UI,
"test1.txt\0", NULL,
ERROR_ACCESS_DENIED, FALSE, FALSE, FALSE);
check_file_operation(FO_RENAME, FOF_NO_UI,
"testdir2\0", NULL,
ERROR_ACCESS_DENIED, FALSE, FALSE, FALSE);
check_file_operation(FO_RENAME, FOF_NO_UI,
"nonexistence\0", NULL,
ERROR_ACCESS_DENIED, FALSE, FALSE, FALSE);
check_file_operation(FO_RENAME, FOF_NO_UI,
NULL, NULL,
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
/* Wildcard source or target. */
clean_after_shfo_tests();
init_shfo_tests();
check_file_operation(FO_RENAME, FOF_NO_UI,
"test?.txt\0", "test_target.txt\0",
DE_MANYSRC1DEST, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "Expected test1.txt to exist.\n");
ok(!DeleteFileA("test_target.txt"), "Expected test_target.txt to not exist.\n");
check_file_operation(FO_RENAME, FOF_NO_UI,
"t?st1.txt\0", "test_target.txt\0",
DE_MANYSRC1DEST, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "Expected test1.txt to exist.\n");
ok(!DeleteFileA("test_target.txt"), "Expected test_target.txt to not exist.\n");
check_file_operation(FO_RENAME, FOF_NO_UI,
"test1.txt\0", "test?.txt\0",
ERROR_INVALID_NAME, FALSE, FALSE, FALSE);
ok(file_exists("test1.txt"), "Expected test1.txt to exist.\n");
}
/* tests the FO_COPY action */
static void test_copy(void)
{
char from[5 * MAX_PATH], to[5 * MAX_PATH];
DWORD retval;
LPSTR ptr;
BOOL ret;
/* Sources and targets have the same number, no FOF_MULTIDESTFILES. */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
check_file_operation(FO_COPY, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("test6.txt\\test1.txt"), "test6.txt\\test1.txt is not copied.\n");
ok(DeleteFileA("test6.txt\\test2.txt"), "test6.txt\\test2.txt is not copied.\n");
RemoveDirectoryA("test6.txt\\test4.txt");
RemoveDirectoryA("test6.txt");
/* Sources and targets have the same number, with FOF_MULTIDESTFILES. */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("test6.txt"), "The file is not copied - many files are "
"specified as a target\n");
DeleteFileA("test6.txt");
DeleteFileA("test7.txt");
RemoveDirectoryA("test8.txt");
/* Sources outnumber targets, with FOF_MULTIDESTFILES. */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0");
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
DE_DESTSAMETREE, FALSE, FALSE, FALSE);
ok(DeleteFileA("test6.txt\\test1.txt"), "The file is not copied.\n");
RemoveDirectoryA("test6.txt");
ok(DeleteFileA("test7.txt\\test2.txt"), "The file is not copied.\n");
RemoveDirectoryA("test7.txt");
/* Wildcard source. */
createTestFile("test4.txt\\test1.txt");
set_curr_dir_path(from, "test?.txt\0");
set_curr_dir_path(to, "testdir2\0");
check_file_operation(FO_COPY, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("testdir2\\test1.txt"), "The file is copied\n");
ok(file_exists("testdir2\\test4.txt"), "The directory is copied\n");
ok(file_exists("testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is copied\n");
clean_after_shfo_tests();
/* Wildcard source, with FOF_FILESONLY. */
init_shfo_tests();
set_curr_dir_path(from, "test?.txt\0");
set_curr_dir_path(to, "testdir2\0");
check_file_operation(FO_COPY, FOF_NO_UI | FOF_FILESONLY, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("testdir2\\test1.txt"), "The file is copied\n");
ok(!file_exists("testdir2\\test4.txt"), "The directory is copied\n");
clean_after_shfo_tests();
/* Multiple sources, with FOF_FILESONLY. */
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0test2.txt\0");
set_curr_dir_path(to, "testdir2\0");
check_file_operation(FO_COPY, FOF_NO_UI | FOF_FILESONLY, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("testdir2\\test1.txt"), "The file is copied\n");
ok(file_exists("testdir2\\test2.txt"), "The file is copied\n");
clean_after_shfo_tests();
/* Multiple sources, one not existing. */
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0test10.txt\0test2.txt\0");
set_curr_dir_path(to, "testdir2\0");
check_file_operation(FO_COPY, FOF_NO_UI, from, to,
ERROR_FILE_NOT_FOUND, FALSE, FALSE, FALSE);
ok(!file_exists("testdir2\\test1.txt"), "The file is copied\n");
ok(!file_exists("testdir2\\test2.txt"), "The file is copied\n");
clean_after_shfo_tests();
/* Nonexistent target directory. */
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "nonexistent\\notreal\\test2.txt\0");
check_file_operation(FO_COPY, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("nonexistent"), "nonexistent not created\n");
ok(file_exists("nonexistent\\notreal"), "nonexistent\\notreal not created\n");
ok(file_exists("nonexistent\\notreal\\test2.txt"), "Directory not created\n");
ok(!file_exists("nonexistent\\notreal\\test1.txt"), "test1.txt should not exist\n");
clean_after_shfo_tests();
/* Relative path. */
init_shfo_tests();
check_file_operation(FO_COPY, FOF_NO_UI,"test1.txt\0test2.txt\0test3.txt\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("testdir2\\test1.txt"), "Expected testdir2\\test1 to exist\n");
clean_after_shfo_tests();
/* Overwrite an existing write protected file. */
init_shfo_tests();
ret = SetFileAttributesA("test2.txt", FILE_ATTRIBUTE_READONLY);
ok(ret, "Failure to set file attributes (error %lx)\n", GetLastError());
retval = CopyFileA("test1.txt", "test2.txt", FALSE);
ok(!retval && GetLastError() == ERROR_ACCESS_DENIED, "CopyFileA should have fail with ERROR_ACCESS_DENIED\n");
check_file_operation(FO_COPY, FOF_NO_UI,"test1.txt\0", "test2.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
/* Set back normal attributes to make the file deletion succeed */
ret = SetFileAttributesA("test2.txt", FILE_ATTRIBUTE_NORMAL);
ok(ret, "Failure to set file attributes (error %lx)\n", GetLastError());
clean_after_shfo_tests();
/* Copy files to a file */
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0test2.txt\0");
set_curr_dir_path(to, "test3.txt\0");
check_file_operation(FO_COPY, FOF_NO_UI, from, to,
DE_INVALIDFILES, FALSE, TRUE, FALSE);
ok(!file_exists("test3.txt\\test2.txt"), "Expected test3.txt\\test2.txt to not exist\n");
/* Copy many files to a nonexistent directory. */
set_curr_dir_path(from, "test1.txt\0test2.txt\0");
set_curr_dir_path(to, "test3.txt\0");
DeleteFileA(to);
check_file_operation(FO_COPY, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("test3.txt\\test1.txt"), "Expected test3.txt\\test1.txt to exist\n");
ok(DeleteFileA("test3.txt\\test2.txt"), "Expected test3.txt\\test1.txt to exist\n");
ok(RemoveDirectoryA(to), "Expected test3.txt to exist\n");
/* Targets outnumber sources, with FOF_MULTIDESTFILES. */
init_shfo_tests();
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"test1.txt\0test2.txt\0test3.txt\0",
"testdir2\\a.txt\0testdir2\\b.txt\0testdir2\\c.txt\0testdir2\\d.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("testdir2\\a.txt\\test1.txt"), "Expected testdir2\\a.txt\\test1.txt to exist\n");
RemoveDirectoryA("testdir2\\a.txt");
ok(DeleteFileA("testdir2\\b.txt\\test2.txt"), "Expected testdir2\\b.txt\\test2.txt to exist\n");
RemoveDirectoryA("testdir2\\b.txt");
ok(DeleteFileA("testdir2\\c.txt\\test3.txt"), "Expected testdir2\\c.txt\\test3.txt to exist\n");
RemoveDirectoryA("testdir2\\c.txt");
ok(!file_exists("testdir2\\d.txt"), "Expected testdir2\\d.txt to not exist\n");
/* Sources outnumber targets, with FOF_MULTIDESTFILES. */
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"test1.txt\0test2.txt\0test3.txt\0",
"e.txt\0f.txt\0",
DE_SAMEFILE, FALSE, FALSE, FALSE);
ok(DeleteFileA("e.txt\\test1.txt"), "Expected e.txt\\test1.txt to exist\n");
RemoveDirectoryA("e.txt");
ok(DeleteFileA("f.txt\\test2.txt"), "Expected f.txt\\test2.txt to exist\n");
RemoveDirectoryA("f.txt");
/* Sources and targets have the same number, with FOF_MULTIDESTFILES. */
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"test1.txt\0test2.txt\0test4.txt\0",
"testdir2\\a.txt\0testdir2\\b.txt\0testdir2\\c.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("testdir2\\a.txt"), "Expected testdir2\\a.txt to exist\n");
ok(DeleteFileA("testdir2\\b.txt"), "Expected testdir2\\b.txt to exist\n");
ok(RemoveDirectoryA("testdir2\\c.txt"), "Expected testdir2\\c.txt to exist\n");
/* Sources and targets have the same number, no FOF_MULTIDESTFILES. */
check_file_operation(FO_COPY, FOF_NO_UI,
"test1.txt\0test2.txt\0test3.txt\0",
"a.txt\0b.txt\0c.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("a.txt\\test1.txt"), "Expected a.txt\\test1.txt to exist\n");
ok(DeleteFileA("a.txt\\test2.txt"), "Expected a.txt\\test2.txt to exist\n");
ok(DeleteFileA("a.txt\\test3.txt"), "Expected a.txt\\test3.txt to exist\n");
ok(!dir_exists("b.txt"), "Expected b.txt directory to not exist.\n");
ok(!dir_exists("c.txt"), "Expected c.txt directory to not exist.\n");
RemoveDirectoryA("a.txt");
/* Sources outnumber targets, no FOF_MULTIDESTFILES. */
check_file_operation(FO_COPY, FOF_NO_UI,
"test1.txt\0test2.txt\0test3.txt\0",
"a.txt\0b.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("a.txt\\test1.txt"), "Expected a.txt\\test1.txt to exist\n");
ok(DeleteFileA("a.txt\\test2.txt"), "Expected a.txt\\test2.txt to exist\n");
ok(DeleteFileA("a.txt\\test3.txt"), "Expected a.txt\\test3.txt to exist\n");
ok(!dir_exists("b.txt"), "Expected b.txt directory to not exist.\n");
RemoveDirectoryA("a.txt");
/* Wildcard source. */
check_file_operation(FO_COPY, FOF_NO_UI, "test?.txt\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("testdir2\\test1.txt"), "Expected testdir2\\test1.txt to exist\n");
ok(dir_exists("testdir2\\test4.txt"), "Expected testdir2\\test4.txt to exist\n");
/* Wildcard source, with FOF_FILESONLY. */
clean_after_shfo_tests();
init_shfo_tests();
check_file_operation(FO_COPY, FOF_NO_UI | FOF_FILESONLY, "test?.txt\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("testdir2\\test1.txt"), "Expected testdir2\\test1.txt to exist\n");
ok(!dir_exists("testdir2\\test4.txt"), "Expected testdir2\\test4.txt to not exist\n");
/* Wildcard source, and same number of targets, with FOF_MULTIDESTFILES. */
clean_after_shfo_tests();
init_shfo_tests();
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"test?.txt\0", "testdir2\\a.txt\0testdir2\\b.txt\0testdir2\\c.txt\0testdir2\\d.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("testdir2\\a.txt\\test1.txt"), "Expected testdir2\\a.txt\\test1.txt to exist\n");
ok(DeleteFileA("testdir2\\a.txt\\test2.txt"), "Expected testdir2\\a.txt\\test2.txt to exist\n");
ok(DeleteFileA("testdir2\\a.txt\\test3.txt"), "Expected testdir2\\a.txt\\test3.txt to exist\n");
ok(RemoveDirectoryA("testdir2\\a.txt\\test4.txt"), "Expected testdir2\\a.txt\\test4.txt to exist\n");
RemoveDirectoryA("testdir2\\a.txt");
ok(!RemoveDirectoryA("b.txt"), "b.txt should not exist\n");
/* Copy one file to two others, second is ignored. */
clean_after_shfo_tests();
init_shfo_tests();
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"test1.txt\0", "b.txt\0c.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("b.txt"), "Expected b.txt to exist\n");
ok(!DeleteFileA("c.txt"), "Expected c.txt to not exist\n");
/* Copy two file to three others. */
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"test1.txt\0test2.txt\0", "b.txt\0c.txt\0d.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("b.txt\\test1.txt"), "Expected b.txt\\test1.txt to exist\n");
RemoveDirectoryA("b.txt");
ok(DeleteFileA("c.txt\\test2.txt"), "Expected c.txt\\test2.txt to exist\n");
RemoveDirectoryA("c.txt");
/* Copy one file and one directory to three others. */
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"test1.txt\0test4.txt\0", "b.txt\0c.txt\0d.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("b.txt\\test1.txt"), "Expected b.txt\\test1.txt to exist\n");
RemoveDirectoryA("b.txt");
ok(RemoveDirectoryA("c.txt\\test4.txt"), "Expected c.txt\\test4.txt to exist\n");
RemoveDirectoryA("c.txt");
/* Copy a file and a dir containing file to another dir. */
createTestFile("test4.txt\\a.txt");
check_file_operation(FO_COPY, FOF_NO_UI,
"test4.txt\0test1.txt\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("testdir2\\test1.txt"), "Expected testdir2\\test1.txt to exist\n");
ok(DeleteFileA("testdir2\\test4.txt\\a.txt"), "Expected a.txt to exist\n");
ok(RemoveDirectoryA("testdir2\\test4.txt"), "Expected testdir2\\test4.txt to exist\n");
/* Copy one dir and a file in that dir to another dir. */
check_file_operation(FO_COPY, FOF_NO_UI,
"test4.txt\\a.txt\0test4.txt\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("testdir2\\test4.txt\\a.txt"), "Expected a.txt to exist\n");
ok(DeleteFileA("testdir2\\a.txt"), "Expected testdir2\\a.txt to exist\n");
check_file_operation(FO_COPY, FOF_NO_UI,
"test4.txt\\a.txt\0test4.txt\0", "nonexistent\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("nonexistent\\test4.txt\\a.txt"), "Expected nonexistent\\test4.txt\\a.txt to exist\n");
RemoveDirectoryA("nonexistent\\test4.txt");
ok(DeleteFileA("nonexistent\\a.txt"), "Expected nonexistent\\a.txt to exist\n");
RemoveDirectoryA("nonexistent");
DeleteFileA("test4.txt\\a.txt");
/* Target file is same as source file. */
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"test1.txt\0test2.txt\0test3.txt\0", "b.txt\0test2.txt\0c.txt\0",
DE_SAMEFILE, FALSE, FALSE, FALSE);
ok(DeleteFileA("b.txt"), "Expected b.txt to exist\n");
ok(!file_exists("c.txt"), "Expected c.txt to not exist\n");
/* Target dir is same as source dir. */
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"test1.txt\0test4.txt\0test3.txt\0", "b.txt\0test4.txt\0c.txt\0",
DE_DESTSAMETREE, FALSE, FALSE, FALSE);
ok(DeleteFileA("b.txt"), "Expected b.txt to exist\n");
ok(!file_exists("c.txt"), "Expected c.txt to not exist\n");
/* Copy a dir into it's subdir. */
check_file_operation(FO_COPY, FOF_NO_UI,
"test4.txt\0", "test4.txt\\newdir\0",
DE_DESTSUBTREE, FALSE, FALSE, FALSE);
ok(!RemoveDirectoryA("test4.txt\\newdir"), "Expected test4.txt\\newdir to not exist\n");
/* Copy a dir into itself. */
check_file_operation(FO_COPY, FOF_NO_UI, "test4.txt\0", "test4.txt\0",
DE_DESTSUBTREE, FALSE, FALSE, FALSE);
/* Copy a file into a dir, and the dir into itself. */
check_file_operation(FO_COPY, FOF_NO_UI,
"test1.txt\0test4.txt\0", "test4.txt\0",
DE_DESTSUBTREE, FALSE, FALSE, FALSE);
ok(DeleteFileA("test4.txt\\test1.txt"), "Expected test4.txt\\test1.txt to exist\n");
/* Copy a file to a file, and the dir into it's subdir. */
check_file_operation(FO_COPY, FOF_NO_UI,
"test1.txt\0test4.txt\0", "test4.txt\\a.txt\0",
DE_DESTSUBTREE, FALSE, FALSE, FALSE);
ok(DeleteFileA("test4.txt\\a.txt\\test1.txt"), "Expected test4.txt\\a.txt\\test1.txt to exist\n");
RemoveDirectoryA("test4.txt\\a.txt");
/* Copy a nonexistent file to a nonexistent dir. */
check_file_operation(FO_COPY, FOF_NO_UI, "e.txt\0", "nonexistent\0",
ERROR_FILE_NOT_FOUND, FALSE, FALSE, FALSE);
ok(!file_exists("nonexistent\\e.txt"), "Expected nonexistent\\e.txt to not exist\n");
ok(!file_exists("nonexistent"), "Expected nonexistent to not exist\n");
/* Overwrite tests */
clean_after_shfo_tests();
init_shfo_tests();
/* Without FOF_NOCONFIRMATION the confirmation is Yes/No. */
check_file_operation(FO_COPY, FOF_NOCONFIRMATION, "test1.txt\0", "test2.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_has_content("test2.txt", "test1.txt\n"), "The file was not copied\n");
/* Without FOF_NOCONFIRMATION the confirmation is Yes/Yes to All/No/Cancel */
check_file_operation(FO_COPY, FOF_NOCONFIRMATION | FOF_MULTIDESTFILES,
"test3.txt\0test1.txt\0", "test2.txt\0one.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_has_content("test2.txt", "test3.txt\n"), "The file was not copied\n");
/* Without FOF_NOCONFIRMATION the confirmation is Yes/No */
check_file_operation(FO_COPY, FOF_NOCONFIRMATION, "one.txt\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_has_content("testdir2\\one.txt", "test1.txt\n"), "The file was not copied\n");
createTestFile("test4.txt\\test1.txt");
check_file_operation(FO_COPY, FOF_NOCONFIRMATION, "test4.txt\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
createTestFile("test4.txt\\.\\test1.txt"); /* Modify the content of the file. */
/* Without FOF_NOCONFIRMATION the confirmation is "This folder already contains a folder named ...". */
check_file_operation(FO_COPY, FOF_NOCONFIRMATION, "test4.txt\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_has_content("testdir2\\test4.txt\\test1.txt", "test4.txt\\.\\test1.txt\n"), "The file was not copied\n");
/* pFrom contains bogus 2nd name longer than MAX_PATH */
createTestFile("one.txt");
memset(from, 'a', MAX_PATH*2);
memset(from+MAX_PATH*2, 0, 2);
lstrcpyA(from, "one.txt");
check_file_operation(FO_COPY, FOF_NO_UI, from, "two.txt\0",
DE_INVALIDFILES, FALSE, TRUE, FALSE);
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
todo_wine
ok(RemoveDirectoryA("two.txt"), "Expected two.txt to exist\n");
/* pTo contains bogus 2nd name longer than MAX_PATH, no FOF_MULTIDESTFILES. */
createTestFile("one.txt");
memset(to, 'a', MAX_PATH*2);
memset(to+MAX_PATH*2, 0, 2);
lstrcpyA(to, "two.txt");
check_file_operation(FO_COPY, FOF_NO_UI, "one.txt\0", to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("two.txt"), "Expected file to exist\n");
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
/* Copy one file to two files, no FOF_MULTIDESTFILES. */
createTestFile("one.txt");
check_file_operation(FO_COPY, FOF_NO_UI,
"one.txt\0", "two.txt\0three.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("two.txt"), "Expected file to exist\n");
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
ok(!DeleteFileA("three.txt"), "Expected file to not exist.\n");
/* both pFrom and pTo contain bogus 2nd names longer than MAX_PATH */
createTestFile("one.txt");
memset(from, 'a', MAX_PATH*2);
memset(from+MAX_PATH*2, 0, 2);
memset(to, 'a', MAX_PATH*2);
memset(to+MAX_PATH*2, 0, 2);
lstrcpyA(from, "one.txt");
lstrcpyA(to, "two.txt");
check_file_operation(FO_COPY, FOF_NO_UI, from, to,
DE_INVALIDFILES, FALSE, TRUE, FALSE);
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
todo_wine
ok(RemoveDirectoryA("two.txt"), "Expected two.txt to exist\n");
/* pTo contains bogus 2nd name longer than MAX_PATH, with FOF_MULTIDESTFILES. */
createTestFile("one.txt");
memset(to, 'a', MAX_PATH*2);
memset(to+MAX_PATH*2, 0, 2);
lstrcpyA(to, "two.txt");
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES, "one.txt\0", to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("two.txt"), "Expected file to exist\n");
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
/* pTo contains bogus 2nd name longer than MAX_PATH,
* multiple source files, nonexistent target dir, no FOF_MULTIDESTFILES. */
createTestFile("one.txt");
createTestFile("two.txt");
memset(to, 'a', 2 * MAX_PATH);
memset(to+MAX_PATH*2, 0, 2);
lstrcpyA(to, "threedir");
check_file_operation(FO_COPY, FOF_NO_UI,
"one.txt\0two.txt\0", to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("threedir\\one.txt"), "Expected threedir\\one.txt to exist.\n");
ok(DeleteFileA("threedir\\two.txt"), "Expected threedir\\one.txt to exist.\n");
ok(RemoveDirectoryA("threedir"), "Expected threedir to exist.\n");
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
ok(DeleteFileA("two.txt"), "Expected file to exist\n");
/* pTo contains bogus 2nd name longer than MAX_PATH,
* multiple source files, target dir exists, no FOF_MULTIDESTFILES. */
createTestFile("one.txt");
createTestFile("two.txt");
CreateDirectoryA("threedir", NULL);
memset(to, 'a', 2 * MAX_PATH);
memset(to+MAX_PATH*2, 0, 2);
lstrcpyA(to, "threedir");
check_file_operation(FO_COPY, FOF_NO_UI,
"one.txt\0two.txt\0", to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("threedir\\one.txt"), "Expected file to exist\n");
ok(DeleteFileA("threedir\\two.txt"), "Expected file to exist\n");
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
ok(DeleteFileA("two.txt"), "Expected file to exist\n");
ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n");
/* pTo contains bogus 2nd name longer than MAX_PATH,
* multiple source files, nonexistent target dir, with FOF_MULTIDESTFILES. */
createTestFile("one.txt");
createTestFile("two.txt");
memset(to, 'a', 2 * MAX_PATH);
memset(to+MAX_PATH*2, 0, 2);
lstrcpyA(to, "threedir");
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"one.txt\0two.txt\0", to,
ERROR_ACCESS_DENIED, FALSE, TRUE, FALSE);
ok(!DeleteFileA("threedir\\one.txt"), "Expected file to not exist\n");
ok(!DeleteFileA("threedir\\two.txt"), "Expected file to not exist\n");
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
ok(DeleteFileA("two.txt"), "Expected file to exist\n");
todo_wine
ok(!DeleteFileA("threedir"), "Expected file to not exist\n");
/* pTo contains bogus 2nd name longer than MAX_PATH,
* multiple source files, target dir exists, with FOF_MULTIDESTFILES. */
createTestFile("one.txt");
createTestFile("two.txt");
CreateDirectoryA("threedir", NULL);
memset(to, 'a', 2 * MAX_PATH);
memset(to+MAX_PATH*2, 0, 2);
lstrcpyA(to, "threedir");
ptr = to + lstrlenA(to) + 1;
lstrcpyA(ptr, "fourdir");
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"one.txt\0two.txt\0", to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
ok(DeleteFileA("two.txt"), "Expected file to exist\n");
ok(DeleteFileA("threedir\\one.txt"), "Expected file to exist\n");
ok(!DeleteFileA("threedir\\two.txt"), "Expected file to not exist\n");
ok(DeleteFileA("fourdir\\two.txt"), "Expected file to exist\n");
RemoveDirectoryA("fourdir");
ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n");
/* Same number sources and targets, first target dir exists, with FOF_MULTIDESTFILES. */
createTestFile("one.txt");
createTestFile("two.txt");
CreateDirectoryA("threedir", NULL);
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"one.txt\0two.txt\0", "threedir\0fourdir\0",
DE_FILEDESTISFLD, FALSE, FALSE, FALSE);
ok(!DeleteFileA("threedir\\one.txt"), "Expected file to not exist\n");
ok(!DeleteFileA("threedir\\two.txt"), "Expected file to not exist\n");
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
ok(DeleteFileA("two.txt"), "Expected file to exist\n");
ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n");
ok(!DeleteFileA("fourdir"), "Expected file to not exist\n");
ok(!RemoveDirectoryA("fourdir"), "Expected dir to not exist\n");
/* Targets outnumber sources, first target dir exists, with FOF_MULTIDESTFILES. */
createTestFile("one.txt");
createTestFile("two.txt");
CreateDirectoryA("threedir", NULL);
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"one.txt\0two.txt\0", "threedir\0fourdir\0five\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
ok(DeleteFileA("two.txt"), "Expected file to exist\n");
ok(DeleteFileA("threedir\\one.txt"), "Expected file to exist\n");
ok(!DeleteFileA("threedir\\two.txt"), "Expected file to not exist\n");
ok(DeleteFileA("fourdir\\two.txt"), "Expected file to exist\n");
RemoveDirectoryA("fourdir");
ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n");
ok(!DeleteFileA("five"), "Expected file to not exist\n");
ok(!RemoveDirectoryA("five"), "Expected dir to not exist\n");
createTestFile("aa.txt");
createTestFile("ab.txt");
createTestFile("bb.txt");
CreateDirectoryA("one", NULL);
CreateDirectoryA("two", NULL);
/* Test with FOF_MULTIDESTFILES with a wildcard in pFrom and single output directory. */
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"a*.txt\0", "one\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("one\\aa.txt"), "Expected file to exist\n");
ok(DeleteFileA("one\\ab.txt"), "Expected file to exist\n");
/* pFrom has a glob, pTo has more than one dest, no FOF_MULTIDESTFILES. */
check_file_operation(FO_COPY, FOF_NO_UI,
"a*.txt\0", "one\0two\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("one\\aa.txt"), "Expected file to exist\n");
ok(DeleteFileA("one\\ab.txt"), "Expected file to exist\n");
ok(!DeleteFileA("two\\aa.txt"), "Expected file to not exist\n");
ok(!DeleteFileA("two\\ab.txt"), "Expected file to not exist\n");
/* pFrom has more than one glob, pTo has more than one dest, without FOF_MULTIDESTFILES. */
check_file_operation(FO_COPY, FOF_NO_UI,
"a*.txt\0*b.txt\0", "one\0two\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("one\\aa.txt"), "Expected file to exist\n");
ok(DeleteFileA("one\\ab.txt"), "Expected file to exist\n");
ok(DeleteFileA("one\\bb.txt"), "Expected file to exist\n");
ok(!DeleteFileA("two\\ab.txt"), "Expected file to exist\n");
ok(!DeleteFileA("two\\bb.txt"), "Expected file to exist\n");
/* pFrom has more than one glob, pTo has more than one dest, with FOF_MULTIDESTFILES. */
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"a*.txt\0*b.txt\0", "one\0two\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("one\\aa.txt"), "Expected file to exist\n");
ok(DeleteFileA("one\\ab.txt"), "Expected file to exist\n");
ok(DeleteFileA("two\\ab.txt"), "Expected file to exist\n");
ok(DeleteFileA("two\\bb.txt"), "Expected file to exist\n");
/* Wildcard target. */
check_file_operation(FO_COPY, FOF_NO_UI, "aa.txt\0", "tw?\0",
ERROR_INVALID_NAME, FALSE, FALSE, FALSE);
ok(!file_exists("two\\aa.txt"), "Expected file to not exist\n");
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"aa.txt\0", "one\0tw?\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("one\\aa.txt"), "Expected file to exist\n");
ok(!DeleteFileA("two\\aa.txt"), "Expected file to not exist\n");
check_file_operation(FO_COPY, FOF_NO_UI,
"aa.txt\0bb.txt\0", "one\0tw?\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("one\\aa.txt"), "Expected file to exist\n");
ok(DeleteFileA("one\\bb.txt"), "Expected file to exist\n");
ok(!DeleteFileA("two\\bb.txt"), "Expected file to not exist\n");
check_file_operation(FO_COPY, FOF_NO_UI | FOF_MULTIDESTFILES,
"aa.txt\0bb.txt\0", "one\0tw?\0",
ERROR_INVALID_NAME, FALSE, FALSE, FALSE);
ok(!DeleteFileA("one\\aa.txt"), "Expected file to not exist\n");
ok(!DeleteFileA("two\\bb.txt"), "Expected file to not exist\n");
ok(DeleteFileA("aa.txt"), "Expected file to exist\n");
ok(DeleteFileA("ab.txt"), "Expected file to exist\n");
ok(DeleteFileA("bb.txt"), "Expected file to exist\n");
ok(RemoveDirectoryA("one"), "Expected dir to exist\n");
ok(RemoveDirectoryA("two"), "Expected dir to exist\n");
/* Empty source or target. */
clean_after_shfo_tests();
init_shfo_tests();
check_file_operation(FO_COPY, FOF_NO_UI,
"testdir2\\one.txt\0", "\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("one.txt"), "Expected file to exist\n");
check_file_operation(FO_COPY, FOF_NO_UI,
"testdir2\\nested\0", "\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("nested\\two.txt"), "Expected file to exist\n");
ok(RemoveDirectoryA("nested"), "Expected dir to exist\n");
check_file_operation(FO_COPY, FOF_NO_UI,
"nonexistence\0", "\0",
ERROR_FILE_NOT_FOUND, FALSE, FALSE, FALSE);
check_file_operation(FO_COPY, FOF_NO_UI,
"\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
check_file_operation(FO_COPY, FOF_NO_UI,
"\0", "testfile.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
check_file_operation(FO_COPY, FOF_NO_UI,
"\0", "nonexistence\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
check_file_operation(FO_COPY, FOF_NO_UI,
"\0", "\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
/* NULL source or target. */
clean_after_shfo_tests();
init_shfo_tests();
check_file_operation(FO_COPY, FOF_NO_UI,
NULL, "test1.txt\0",
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
check_file_operation(FO_COPY, FOF_NO_UI,
NULL, "testdir2\0",
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
check_file_operation(FO_COPY, FOF_NO_UI,
NULL, "nonexistence\0",
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
check_file_operation(FO_COPY, FOF_NO_UI,
"test1.txt\0", NULL,
ERROR_ACCESS_DENIED, FALSE, FALSE, FALSE);
check_file_operation(FO_COPY, FOF_NO_UI,
"testdir2\0", NULL,
ERROR_ACCESS_DENIED, FALSE, FALSE, FALSE);
check_file_operation(FO_COPY, FOF_NO_UI,
"nonexistence\0", NULL,
ERROR_ACCESS_DENIED, FALSE, FALSE, FALSE);
check_file_operation(FO_COPY, FOF_NO_UI,
NULL, NULL,
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
/* Check last error after a successful file operation. */
clean_after_shfo_tests();
init_shfo_tests();
SetLastError(0xdeadbeef);
check_file_operation(FO_COPY, FOF_NO_UI, "test1.txt\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", GetLastError());
/* Check last error after a failed file operation. */
clean_after_shfo_tests();
init_shfo_tests();
SetLastError(0xdeadbeef);
check_file_operation(FO_COPY, FOF_NO_UI, "nonexistence\0", "testdir2\0",
ERROR_FILE_NOT_FOUND, FALSE, FALSE, FALSE);
ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", GetLastError());
/* test with / */
CreateDirectoryA("dir", NULL);
CreateDirectoryA("dir\\subdir", NULL);
createTestFile("dir\\subdir\\aa.txt");
check_file_operation(FO_COPY, FOF_NO_UI,
"dir/subdir/aa.txt\0", "dir\\destdir/aa.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("dir\\destdir\\aa.txt"), "Expected file to exist\n");
ok(RemoveDirectoryA("dir\\destdir"), "Expected dir to exist\n");
ok(DeleteFileA("dir\\subdir\\aa.txt"), "Expected file to exist\n");
ok(RemoveDirectoryA("dir\\subdir"), "Expected dir to exist\n");
ok(RemoveDirectoryA("dir"), "Expected dir to exist\n");
}
/* tests the FO_MOVE action */
static void test_move(void)
{
char from[MAX_PATH * 5], to[MAX_PATH * 5];
clean_after_shfo_tests();
init_shfo_tests();
set_curr_dir_path(from, "testdir2\\*.*\0");
set_curr_dir_path(to, "test4.txt\\*.*\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_INVALID_NAME, FALSE, FALSE, FALSE);
ok(file_exists("testdir2"), "dir should not be moved\n");
ok(file_exists("testdir2\\one.txt"), "file should not be moved\n");
ok(file_exists("testdir2\\nested"), "dir should not be moved\n");
ok(file_exists("testdir2\\nested\\two.txt"), "file should not be moved\n");
set_curr_dir_path(from, "testdir2\\*.*\0");
set_curr_dir_path(to, "test4.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("testdir2"), "dir should not be moved\n");
ok(!file_exists("testdir2\\one.txt"), "file should be moved\n");
ok(!file_exists("testdir2\\nested"), "dir should be moved\n");
ok(!file_exists("testdir2\\nested\\two.txt"), "file should be moved\n");
ok(file_exists("test4.txt"), "dir should exist\n");
ok(file_exists("test4.txt\\one.txt"), "file should exist\n");
ok(file_exists("test4.txt\\nested"), "dir should exist\n");
ok(file_exists("test4.txt\\nested\\two.txt"), "file should exist\n");
clean_after_shfo_tests();
init_shfo_tests();
/* same tests above, but with / */
set_curr_dir_path(from, "testdir2/*.*\0");
set_curr_dir_path(to, "test4.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(dir_exists("testdir2"), "dir should not be moved\n");
ok(!file_exists("testdir2\\one.txt"), "file should be moved\n");
ok(!dir_exists("testdir2\\nested"), "dir should be moved\n");
ok(!file_exists("testdir2\\nested\\two.txt"), "file should be moved\n");
ok(file_exists("test4.txt\\one.txt"), "file should exist\n");
ok(dir_exists("test4.txt\\nested"), "dir should exist\n");
ok(file_exists("test4.txt\\nested\\two.txt"), "file should exist\n");
clean_after_shfo_tests();
init_shfo_tests();
/* Prepare test to check how directories are moved recursively. */
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test4.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!file_exists("test1.txt"), "test1.txt should not exist\n");
ok(file_exists("test4.txt\\test1.txt"), "The file is not moved\n");
set_curr_dir_path(from, "test?.txt\0");
set_curr_dir_path(to, "testdir2\0");
ok(!file_exists("testdir2\\test2.txt"), "The file is not moved yet\n");
ok(!file_exists("testdir2\\test4.txt"), "The directory is not moved yet\n");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("testdir2\\test2.txt"), "The file is moved\n");
ok(file_exists("testdir2\\test4.txt"), "The directory is moved\n");
ok(file_exists("testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is moved\n");
clean_after_shfo_tests();
init_shfo_tests();
/* test moving dir to destination containing dir of the same name */
set_curr_dir_path(from, "testdir2\\nested\0");
set_curr_dir_path(to, "testdir4\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("testdir2\\nested"), "dir should be moved\n");
ok(!file_exists("testdir2\\nested\\two.txt"), "file should be moved\n");
ok(dir_exists("testdir4\\nested"), "dir should exist\n");
ok(file_exists("testdir4\\nested\\two.txt"), "file should exist\n");
ok(file_exists("testdir4\\nested\\2.txt"), "file should exist\n");
clean_after_shfo_tests();
init_shfo_tests();
/* test moving empty dir to destination containing dir of the same name */
DeleteFileA("testdir2\\nested\\two.txt");
set_curr_dir_path(from, "testdir2\\nested\0");
set_curr_dir_path(to, "testdir4\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("testdir2\\nested"), "dir should be moved\n");
ok(dir_exists("testdir4\\nested"), "dir should exist\n");
ok(file_exists("testdir4\\nested\\2.txt"), "file should exist\n");
clean_after_shfo_tests();
init_shfo_tests();
/* test moving multiple dirs to destination containing dir of the same name */
set_curr_dir_path(from, "testdir2\\nested\0testdir4\\nested\0");
set_curr_dir_path(to, "testdir6\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("testdir2\\nested"), "dir should be moved\n");
ok(!file_exists("testdir2\\nested\\two.txt"), "file should be moved\n");
ok(!dir_exists("testdir4\\nested"), "dir should be moved\n");
ok(!file_exists("testdir4\\nested\\2.txt"), "file should be moved\n");
ok(!dir_exists("testdir4\\nested\\subnested"), "dir should be moved\n");
ok(!file_exists("testdir4\\nested\\subnested\\3.txt"), "file should be moved\n");
ok(dir_exists("testdir6\\nested"), "dir should exist\n");
ok(file_exists("testdir6\\nested\\two.txt"), "file should exist\n");
ok(file_exists("testdir6\\nested\\2.txt"), "file should exist\n");
ok(dir_exists("testdir6\\nested\\subnested"), "dir should exist\n");
ok(file_exists("testdir6\\nested\\subnested\\3.txt"), "file should exist\n");
clean_after_shfo_tests();
init_shfo_tests();
/* test moving dir to destination containing dir of the same name with FOF_MULTIDESTFILES set */
set_curr_dir_path(from, "testdir2\\nested\0");
set_curr_dir_path(to, "testdir6\0");
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("testdir2\\nested"), "dir should be moved\n");
ok(!file_exists("testdir2\\nested\\two.txt"), "file should be moved\n");
ok(!file_exists("testdir6\\nested\\two.txt"), "file should not exist\n");
ok(dir_exists("testdir6\\nested"), "dir should exist\n");
ok(file_exists("testdir6\\two.txt"), "file should exist\n");
clean_after_shfo_tests();
init_shfo_tests();
/* same as above, without 'nested' in from path */
set_curr_dir_path(from, "testdir2\0");
set_curr_dir_path(to, "testdir6\0");
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("testdir2\\nested"), "dir should be moved\n");
ok(!file_exists("testdir2\\nested\\two.txt"), "file should be moved\n");
ok(!file_exists("testdir6\\two.txt"), "file should not exist\n");
ok(dir_exists("testdir6\\nested"), "dir should exist\n");
ok(file_exists("testdir6\\nested\\two.txt"), "file should exist\n");
clean_after_shfo_tests();
init_shfo_tests();
/* test moving multiple dirs to multiple destinations containing dir of the same name */
set_curr_dir_path(from, "testdir2\\nested\0testdir4\\nested\0");
set_curr_dir_path(to, "testdir6\0testdir8\0");
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("testdir2\\nested"), "dir should be moved\n");
ok(!file_exists("testdir2\\nested\\two.txt"), "file should be moved\n");
ok(!dir_exists("testdir4\\nested"), "dir should be moved\n");
ok(!file_exists("testdir4\\nested\\2.txt"), "file should be moved\n");
ok(!file_exists("testdir6\\nested\\two.txt"), "file should not exist\n");
ok(!file_exists("testdir6\\nested\\2.txt"), "file should not exist\n");
ok(dir_exists("testdir6\\nested"), "dir should exist\n");
ok(file_exists("testdir6\\two.txt"), "file should exist\n");
ok(!dir_exists("testdir8\\nested\\subnested"), "dir should not exist\n");
ok(!file_exists("testdir8\\nested\\subnested\\3.txt"), "file should not exist\n");
ok(!file_exists("testdir8\\nested\\two.txt"), "file should not exist\n");
ok(!file_exists("testdir8\\nested\\2.txt"), "file should not exist\n");
ok(dir_exists("testdir8\\nested"), "dir should exist\n");
ok(dir_exists("testdir8\\subnested"), "dir should exist\n");
ok(file_exists("testdir8\\subnested\\3.txt"), "file should exist\n");
ok(file_exists("testdir8\\2.txt"), "file should exist\n");
clean_after_shfo_tests();
init_shfo_tests();
/* same as above, but include subdir in destinations */
set_curr_dir_path(from, "testdir2\\nested\0testdir4\\nested\0");
set_curr_dir_path(to, "testdir6\\nested\0testdir8\\nested\0");
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("testdir2\\nested"), "dir should be moved\n");
ok(!file_exists("testdir2\\nested\\two.txt"), "file should be moved\n");
ok(!dir_exists("testdir4\\nested"), "dir should be moved\n");
ok(!file_exists("testdir4\\nested\\2.txt"), "file should be moved\n");
ok(dir_exists("testdir6\\nested"), "dir should exist\n");
ok(file_exists("testdir6\\nested\\two.txt"), "file should exist\n");
ok(!file_exists("testdir6\\nested\\2.txt"), "file should not exist\n");
ok(!file_exists("testdir6\\two.txt"), "file should not exist\n");
ok(!dir_exists("testdir8\\subnested"), "dir should not exist\n");
ok(!file_exists("testdir8\\2.txt"), "file should not exist\n");
ok(!file_exists("testdir8\\nested\\two.txt"), "file should not exist\n");
ok(dir_exists("testdir8\\nested"), "dir should exist\n");
ok(file_exists("testdir8\\nested\\2.txt"), "file should exist\n");
ok(dir_exists("testdir8\\nested\\subnested"), "dir should exist\n");
ok(file_exists("testdir8\\nested\\subnested\\3.txt"), "file should exist\n");
clean_after_shfo_tests();
init_shfo_tests();
/* Move many files. */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("test6.txt"), "The file is not moved - many files are "
"specified as a target\n");
ok(DeleteFileA("test7.txt"), "The file is not moved\n");
ok(RemoveDirectoryA("test8.txt"), "The directory is not moved\n");
init_shfo_tests();
/* Sources outnumber targets. */
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
DE_DESTSAMETREE, FALSE, FALSE, FALSE);
ok(DeleteFileA("test6.txt\\test1.txt"), "The file is not moved\n");
RemoveDirectoryA("test6.txt");
ok(DeleteFileA("test7.txt\\test2.txt"), "The file is not moved\n");
RemoveDirectoryA("test7.txt");
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0test2.txt\0test3.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
DE_SAMEFILE, FALSE, FALSE, FALSE);
ok(DeleteFileA("test6.txt\\test1.txt"), "The file is not moved\n");
RemoveDirectoryA("test6.txt");
ok(DeleteFileA("test7.txt\\test2.txt"), "The file is not moved\n");
RemoveDirectoryA("test7.txt");
ok(file_exists("test3.txt"), "File should not be moved\n");
/* Targets outnumber sources. */
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0test2.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("test6.txt\\test1.txt"),"The file is not moved\n");
ok(DeleteFileA("test7.txt\\test2.txt"),"The file is not moved\n");
ok(!dir_exists("test8.txt") && !file_exists("test8.txt"), "Directory should not be created\n");
RemoveDirectoryA("test6.txt");
RemoveDirectoryA("test7.txt");
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0test2.txt\0test3.txt\0");
set_curr_dir_path(to, "test4.txt\0test5.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES, from, to,
DE_SAMEFILE, FALSE, FALSE, FALSE);
ok(DeleteFileA("test4.txt\\test1.txt"),"The file is not moved\n");
ok(DeleteFileA("test5.txt\\test2.txt"),"The file is not moved\n");
ok(file_exists("test3.txt"), "The file is not moved\n");
RemoveDirectoryA("test4.txt");
RemoveDirectoryA("test5.txt");
/* Empty source or target. */
clean_after_shfo_tests();
init_shfo_tests();
check_file_operation(FO_MOVE, FOF_NO_UI,
"\0", "test1.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
"\0", "testdir2\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
"\0", "nonexistence\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!file_exists("nonexistence"), "Expected nonexistence to not exist.\n");
check_file_operation(FO_MOVE, FOF_NO_UI,
"test1.txt\0", "\0",
DE_SAMEFILE, FALSE, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
"testdir2\0", "\0",
DE_DESTSAMETREE, FALSE, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
"nonexistence\0", "\0",
ERROR_FILE_NOT_FOUND, FALSE, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
"\0", "\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
/* NULL source or target. */
clean_after_shfo_tests();
init_shfo_tests();
check_file_operation(FO_MOVE, FOF_NO_UI,
NULL, "test1.txt\0",
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
NULL, "testdir2\0",
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
NULL, "nonexistence\0",
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
"test1.txt\0", NULL,
ERROR_ACCESS_DENIED, FALSE, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
"testdir2\0", NULL,
ERROR_ACCESS_DENIED, FALSE, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
"nonexistent\0", NULL,
ERROR_ACCESS_DENIED, FALSE, FALSE, FALSE);
check_file_operation(FO_MOVE, FOF_NO_UI,
NULL, NULL,
ERROR_INVALID_PARAMETER, 0xdeadbeef, FALSE, FALSE);
clean_after_shfo_tests();
init_shfo_tests();
set_curr_dir_path(from, "test3.txt\0");
set_curr_dir_path(to, "test4.txt\\test1.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(file_exists("test4.txt\\test1.txt"), "The file is not moved\n");
set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("test6.txt\\test1.txt"), "The file is not moved. Many files are specified\n");
ok(DeleteFileA("test6.txt\\test2.txt"), "The file is not moved. Many files are specified\n");
ok(DeleteFileA("test6.txt\\test4.txt\\test1.txt"), "The file is not moved. Many files are specified\n");
ok(RemoveDirectoryA("test6.txt\\test4.txt"), "The directory is not moved. Many files are specified\n");
RemoveDirectoryA("test6.txt");
init_shfo_tests();
set_curr_dir_path(from, "test1.txt\0");
set_curr_dir_path(to, "test6.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!file_exists("test1.txt"), "The file is not moved\n");
ok(file_exists("test6.txt"), "The file is not moved\n");
set_curr_dir_path(from, "test6.txt\0");
set_curr_dir_path(to, "test1.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
set_curr_dir_path(from, "test4.txt\0");
set_curr_dir_path(to, "test6.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!dir_exists("test4.txt"), "The dir is not moved\n");
ok(dir_exists("test6.txt"), "The dir is moved\n");
set_curr_dir_path(from, "test6.txt\0");
set_curr_dir_path(to, "test4.txt\0");
check_file_operation(FO_MOVE, FOF_NO_UI, from, to,
ERROR_SUCCESS, FALSE, FALSE, FALSE);
/* move one file to two others */
init_shfo_tests();
check_file_operation(FO_MOVE, FOF_NO_UI,
"test1.txt\0", "a.txt\0b.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("a.txt"), "Expected a.txt to exist\n");
ok(!file_exists("test1.txt"), "Expected test1.txt to not exist\n");
ok(!file_exists("b.txt"), "Expected b.txt to not exist\n");
/* move two files to one other */
check_file_operation(FO_MOVE, FOF_NO_UI,
"test2.txt\0test3.txt\0", "test1.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("test1.txt\\test2.txt"), "Expected test1.txt\\test2.txt to exist\n");
ok(DeleteFileA("test1.txt\\test3.txt"), "Expected test1.txt\\test3.txt to exist\n");
RemoveDirectoryA("test1.txt");
createTestFile("test2.txt");
createTestFile("test3.txt");
/* move a directory into itself */
check_file_operation(FO_MOVE, FOF_NO_UI,
"test4.txt\0", "test4.txt\\b.txt\0",
DE_DESTSUBTREE, FALSE, FALSE, FALSE);
ok(!RemoveDirectoryA("test4.txt\\b.txt"), "Expected test4.txt\\b.txt to not exist\n");
ok(dir_exists("test4.txt"), "Expected test4.txt to exist\n");
/* move many files without FOF_MULTIDESTFILES */
check_file_operation(FO_MOVE, FOF_NO_UI,
"test2.txt\0test3.txt\0", "d.txt\0e.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("d.txt\\test2.txt"), "Expected d.txt\\test2.txt to exist\n");
ok(DeleteFileA("d.txt\\test3.txt"), "Expected d.txt\\test3.txt to exist\n");
RemoveDirectoryA("d.txt");
createTestFile("test2.txt");
createTestFile("test3.txt");
/* number of sources != number of targets */
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES,
"test2.txt\0test3.txt\0", "d.txt\0",
DE_SAMEFILE, FALSE, FALSE, FALSE);
ok(DeleteFileA("d.txt\\test2.txt"), "Expected d.txt\\test2.txt to exist\n");
ok(!file_exists("d.txt\\test3.txt"), "Expected d.txt\\test3.txt to not exist\n");
RemoveDirectoryA("d.txt");
createTestFile("test2.txt");
/* FO_MOVE does not create dest directories */
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES,
"test2.txt\0", "dir1\\dir2\\test2.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(DeleteFileA("dir1\\dir2\\test2.txt"), "Expected dir1\\dir2\\test2.txt to exist\n");
RemoveDirectoryA("dir1\\dir2");
RemoveDirectoryA("dir1");
createTestFile("test2.txt");
/* try to overwrite an existing file */
check_file_operation(FO_MOVE, FOF_NO_UI | FOF_MULTIDESTFILES,
"test2.txt\0", "test3.txt\0",
ERROR_SUCCESS, FALSE, FALSE, FALSE);
ok(!file_exists("test2.txt"), "Expected test2.txt to not exist\n");
ok(file_exists("test3.txt"), "Expected test3.txt to exist\n");
}
static void test_sh_create_dir(void)
{
CHAR path[MAX_PATH];
int ret;
set_curr_dir_path(path, "testdir2\\test4.txt\0");
ret = SHCreateDirectoryExA(NULL, path, NULL);
ok(ERROR_SUCCESS == ret, "SHCreateDirectoryEx failed to create directory recursively, ret = %d\n", ret);
ok(file_exists("testdir2"), "The first directory is not created\n");
ok(file_exists("testdir2\\test4.txt"), "The second directory is not created\n");
ret = SHCreateDirectoryExA(NULL, path, NULL);
ok(ERROR_ALREADY_EXISTS == ret, "SHCreateDirectoryEx should fail to create existing directory, ret = %d\n", ret);
ret = SHCreateDirectoryExA(NULL, "c:\\testdir3", NULL);
ok(ERROR_SUCCESS == ret, "SHCreateDirectoryEx failed to create directory, ret = %d\n", ret);
ok(file_exists("c:\\testdir3"), "The directory is not created\n");
}
static void test_sh_path_prepare(void)
{
HRESULT res;
CHAR path[MAX_PATH];
CHAR UNICODE_PATH_A[MAX_PATH];
BOOL UsedDefaultChar;
/* directory exists, SHPPFW_NONE */
set_curr_dir_path(path, "testdir2\0");
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
ok(res == S_OK, "res == 0x%08lx, expected S_OK\n", res);
/* directory exists, SHPPFW_IGNOREFILENAME */
set_curr_dir_path(path, "testdir2\\test4.txt\0");
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME);
ok(res == S_OK, "res == 0x%08lx, expected S_OK\n", res);
/* directory exists, SHPPFW_DIRCREATE */
set_curr_dir_path(path, "testdir2\0");
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_DIRCREATE);
ok(res == S_OK, "res == 0x%08lx, expected S_OK\n", res);
/* directory exists, SHPPFW_IGNOREFILENAME|SHPPFW_DIRCREATE */
set_curr_dir_path(path, "testdir2\\test4.txt\0");
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME|SHPPFW_DIRCREATE);
ok(res == S_OK, "res == 0x%08lx, expected S_OK\n", res);
ok(!file_exists("nonexistent\\"), "nonexistent\\ exists but shouldn't\n");
/* file exists, SHPPFW_NONE */
set_curr_dir_path(path, "test1.txt\0");
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY) ||
res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* WinMe */
res == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), /* Vista */
"Unexpected result : 0x%08lx\n", res);
/* file exists, SHPPFW_DIRCREATE */
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_DIRCREATE);
ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY) ||
res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* WinMe */
res == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), /* Vista */
"Unexpected result : 0x%08lx\n", res);
/* file exists, SHPPFW_NONE, trailing \ */
set_curr_dir_path(path, "test1.txt\\\0");
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY) ||
res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* WinMe */
res == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), /* Vista */
"Unexpected result : 0x%08lx\n", res);
/* relative path exists, SHPPFW_DIRCREATE */
res = SHPathPrepareForWriteA(0, 0, ".\\testdir2", SHPPFW_DIRCREATE);
ok(res == S_OK, "res == 0x%08lx, expected S_OK\n", res);
/* relative path doesn't exist, SHPPFW_DIRCREATE -- Windows does not create the directory in this case */
res = SHPathPrepareForWriteA(0, 0, ".\\testdir2\\test4.txt", SHPPFW_DIRCREATE);
ok(res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "res == 0x%08lx, expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)\n", res);
ok(!file_exists(".\\testdir2\\test4.txt\\"), ".\\testdir2\\test4.txt\\ exists but shouldn't\n");
/* directory doesn't exist, SHPPFW_NONE */
set_curr_dir_path(path, "nonexistent\0");
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
ok(res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "res == 0x%08lx, expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)\n", res);
/* directory doesn't exist, SHPPFW_IGNOREFILENAME */
set_curr_dir_path(path, "nonexistent\\notreal\0");
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME);
ok(res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "res == 0x%08lx, expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)\n", res);
ok(!file_exists("nonexistent\\notreal"), "nonexistent\\notreal exists but shouldn't\n");
ok(!file_exists("nonexistent\\"), "nonexistent\\ exists but shouldn't\n");
/* directory doesn't exist, SHPPFW_IGNOREFILENAME|SHPPFW_DIRCREATE */
set_curr_dir_path(path, "testdir2\\test4.txt\\\0");
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME|SHPPFW_DIRCREATE);
ok(res == S_OK, "res == 0x%08lx, expected S_OK\n", res);
ok(file_exists("testdir2\\test4.txt\\"), "testdir2\\test4.txt doesn't exist but should\n");
/* nested directory doesn't exist, SHPPFW_DIRCREATE */
set_curr_dir_path(path, "nonexistent\\notreal\0");
res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_DIRCREATE);
ok(res == S_OK, "res == 0x%08lx, expected S_OK\n", res);
ok(file_exists("nonexistent\\notreal"), "nonexistent\\notreal doesn't exist but should\n");
/* SHPPFW_ASKDIRCREATE, SHPPFW_NOWRITECHECK, and SHPPFW_MEDIACHECKONLY are untested */
SetLastError(0xdeadbeef);
UsedDefaultChar = FALSE;
if (WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, UNICODE_PATH, -1, UNICODE_PATH_A, sizeof(UNICODE_PATH_A), NULL, &UsedDefaultChar) == 0)
{
win_skip("Could not convert Unicode path name to multibyte (%ld)\n", GetLastError());
return;
}
if (UsedDefaultChar)
{
win_skip("Could not find unique multibyte representation for directory name using default codepage\n");
return;
}
/* unicode directory doesn't exist, SHPPFW_NONE */
RemoveDirectoryA(UNICODE_PATH_A);
res = SHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_NONE);
ok(res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "res == %08lx, expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)\n", res);
ok(!file_exists(UNICODE_PATH_A), "unicode path was created but shouldn't be\n");
RemoveDirectoryA(UNICODE_PATH_A);
/* unicode directory doesn't exist, SHPPFW_DIRCREATE */
res = SHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_DIRCREATE);
ok(res == S_OK, "res == %08lx, expected S_OK\n", res);
ok(file_exists(UNICODE_PATH_A), "unicode path should've been created\n");
/* unicode directory exists, SHPPFW_NONE */
res = SHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_NONE);
ok(res == S_OK, "ret == %08lx, expected S_OK\n", res);
/* unicode directory exists, SHPPFW_DIRCREATE */
res = SHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_DIRCREATE);
ok(res == S_OK, "ret == %08lx, expected S_OK\n", res);
RemoveDirectoryA(UNICODE_PATH_A);
}
static void test_sh_new_link_info(void)
{
BOOL ret, mustcopy=TRUE;
CHAR linkto[MAX_PATH];
CHAR destdir[MAX_PATH];
CHAR result[MAX_PATH];
CHAR result2[MAX_PATH];
/* source file does not exist */
set_curr_dir_path(linkto, "nosuchfile.txt\0");
set_curr_dir_path(destdir, "testdir2\0");
ret = SHGetNewLinkInfoA(linkto, destdir, result, &mustcopy, 0);
ok(ret == FALSE ||
broken(ret == lstrlenA(result) + 1), /* NT4 */
"SHGetNewLinkInfoA succeeded\n");
ok(mustcopy == FALSE, "mustcopy should be FALSE\n");
/* dest dir does not exist */
set_curr_dir_path(linkto, "test1.txt\0");
set_curr_dir_path(destdir, "nosuchdir\0");
ret = SHGetNewLinkInfoA(linkto, destdir, result, &mustcopy, 0);
ok(ret == TRUE ||
broken(ret == lstrlenA(result) + 1), /* NT4 */
"SHGetNewLinkInfoA failed, err=%li\n", GetLastError());
ok(mustcopy == FALSE, "mustcopy should be FALSE\n");
/* source file exists */
set_curr_dir_path(linkto, "test1.txt\0");
set_curr_dir_path(destdir, "testdir2\0");
ret = SHGetNewLinkInfoA(linkto, destdir, result, &mustcopy, 0);
ok(ret == TRUE ||
broken(ret == lstrlenA(result) + 1), /* NT4 */
"SHGetNewLinkInfoA failed, err=%li\n", GetLastError());
ok(mustcopy == FALSE, "mustcopy should be FALSE\n");
ok(CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, destdir,
lstrlenA(destdir), result, lstrlenA(destdir)) == CSTR_EQUAL,
"%s does not start with %s\n", result, destdir);
ok(lstrlenA(result) > 4 && lstrcmpiA(result+lstrlenA(result)-4, ".lnk") == 0,
"%s does not end with .lnk\n", result);
/* preferred target name already exists */
createTestFile(result);
ret = SHGetNewLinkInfoA(linkto, destdir, result2, &mustcopy, 0);
ok(ret == TRUE ||
broken(ret == lstrlenA(result2) + 1), /* NT4 */
"SHGetNewLinkInfoA failed, err=%li\n", GetLastError());
ok(mustcopy == FALSE, "mustcopy should be FALSE\n");
ok(CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, destdir,
lstrlenA(destdir), result2, lstrlenA(destdir)) == CSTR_EQUAL,
"%s does not start with %s\n", result2, destdir);
ok(lstrlenA(result2) > 4 && lstrcmpiA(result2+lstrlenA(result2)-4, ".lnk") == 0,
"%s does not end with .lnk\n", result2);
ok(lstrcmpiA(result, result2) != 0, "%s and %s are the same\n", result, result2);
DeleteFileA(result);
}
static void test_unicode(void)
{
SHFILEOPSTRUCTW shfoW;
int ret;
HANDLE file;
static const WCHAR UNICODE_PATH_TO[] = L"c:\\\x00ae\x00ae\0";
HWND hwnd;
shfoW.hwnd = NULL;
shfoW.wFunc = FO_DELETE;
shfoW.pFrom = UNICODE_PATH;
shfoW.pTo = NULL;
shfoW.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
shfoW.hNameMappings = NULL;
shfoW.lpszProgressTitle = NULL;
/* Clean up before start test */
DeleteFileW(UNICODE_PATH);
RemoveDirectoryW(UNICODE_PATH);
/* Make sure we are on a system that supports unicode */
SetLastError(0xdeadbeef);
file = CreateFileW(UNICODE_PATH, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
{
skip("Unicode tests skipped on non-unicode system\n");
return;
}
if (GetLastError()==ERROR_ACCESS_DENIED)
{
skip("test needs admin rights\n");
return;
}
CloseHandle(file);
/* Try to delete a file with unicode filename */
ok(file_existsW(UNICODE_PATH), "The file does not exist\n");
ret = SHFileOperationW(&shfoW);
ok(!ret, "File is not removed, ErrorCode: %d\n", ret);
ok(!file_existsW(UNICODE_PATH), "The file should have been removed\n");
/* Try to trash a file with unicode filename */
createTestFileW(UNICODE_PATH);
shfoW.fFlags |= FOF_ALLOWUNDO;
ok(file_existsW(UNICODE_PATH), "The file does not exist\n");
ret = SHFileOperationW(&shfoW);
ok(!ret, "File is not removed, ErrorCode: %d\n", ret);
ok(!file_existsW(UNICODE_PATH), "The file should have been removed\n");
/* Try to delete a directory with unicode filename */
ret = SHCreateDirectoryExW(NULL, UNICODE_PATH, NULL);
ok(!ret, "SHCreateDirectoryExW returned %d\n", ret);
ok(file_existsW(UNICODE_PATH), "The directory is not created\n");
shfoW.fFlags &= ~FOF_ALLOWUNDO;
ret = SHFileOperationW(&shfoW);
ok(!ret, "Directory is not removed, ErrorCode: %d\n", ret);
ok(!file_existsW(UNICODE_PATH), "The directory should have been removed\n");
/* Try to trash a directory with unicode filename */
ret = SHCreateDirectoryExW(NULL, UNICODE_PATH, NULL);
ok(!ret, "SHCreateDirectoryExW returned %d\n", ret);
ok(file_existsW(UNICODE_PATH), "The directory was not created\n");
shfoW.fFlags |= FOF_ALLOWUNDO;
ret = SHFileOperationW(&shfoW);
ok(!ret, "Directory is not removed, ErrorCode: %d\n", ret);
ok(!file_existsW(UNICODE_PATH), "The directory should have been removed\n");
shfoW.hwnd = NULL;
shfoW.wFunc = FO_COPY;
shfoW.pFrom = UNICODE_PATH;
shfoW.pTo = UNICODE_PATH_TO;
shfoW.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
shfoW.hNameMappings = NULL;
shfoW.lpszProgressTitle = NULL;
/* Check last error after a successful file operation. */
createTestFileW(UNICODE_PATH);
ok(file_existsW(UNICODE_PATH), "The file does not exist\n");
SetLastError(0xdeadbeef);
ret = SHFileOperationW(&shfoW);
ok(ret == ERROR_SUCCESS, "File copy failed with %d\n", ret);
ok(!shfoW.fAnyOperationsAborted, "Didn't expect aborted operations\n");
ok(GetLastError() == ERROR_SUCCESS ||
broken(GetLastError() == ERROR_INVALID_HANDLE), /* WinXp, win2k3 */
"Expected ERROR_SUCCESS, got %ld\n", GetLastError());
DeleteFileW(UNICODE_PATH_TO);
/* Check last error after a failed file operation. */
DeleteFileW(UNICODE_PATH);
ok(!file_existsW(UNICODE_PATH), "The file should have been removed\n");
SetLastError(0xdeadbeef);
ret = SHFileOperationW(&shfoW);
ok(ret != ERROR_SUCCESS, "Unexpected ERROR_SUCCESS\n");
ok(!shfoW.fAnyOperationsAborted, "Didn't expect aborted operations\n");
ok(GetLastError() == ERROR_SUCCESS ||
broken(GetLastError() == ERROR_INVALID_HANDLE), /* WinXp, win2k3 */
"Expected ERROR_SUCCESS, got %ld\n", GetLastError());
/* Check SHCreateDirectoryExW with a Hwnd
* returns ERROR_ALREADY_EXISTS where a directory already exists */
/* Get any window handle */
hwnd = FindWindowA(NULL, NULL);
ok(hwnd != 0, "FindWindowA failed to produce a hwnd\n");
ret = SHCreateDirectoryExW(hwnd, UNICODE_PATH, NULL);
ok(!ret, "SHCreateDirectoryExW returned %d\n", ret);
/* Create already-existing directory */
ok(file_existsW(UNICODE_PATH), "The directory was not created\n");
ret = SHCreateDirectoryExW(hwnd, UNICODE_PATH, NULL);
ok(ret == ERROR_ALREADY_EXISTS,
"Expected ERROR_ALREADY_EXISTS, got %d\n", ret);
RemoveDirectoryW(UNICODE_PATH);
}
static void
test_shlmenu(void) {
HRESULT hres;
HMENU src_menu, dst_menu;
int count;
MENUITEMINFOA item_info;
BOOL bres;
hres = Shell_MergeMenus (0, 0, 0x42, 0x4242, 0x424242, 0);
ok (hres == 0x4242, "expected 0x4242 but got %lx\n", hres);
hres = Shell_MergeMenus ((HMENU)42, 0, 0x42, 0x4242, 0x424242, 0);
ok (hres == 0x4242, "expected 0x4242 but got %lx\n", hres);
src_menu = CreatePopupMenu ();
ok (src_menu != NULL, "CreatePopupMenu() failed, error %ld\n", GetLastError ());
dst_menu = CreatePopupMenu ();
ok (dst_menu != NULL, "CreatePopupMenu() failed, error %ld\n", GetLastError ());
bres = InsertMenuA (src_menu, -1, MF_BYPOSITION | MF_STRING, 10, "item1");
ok (bres, "InsertMenuA failed, error %ld\n", GetLastError());
bres = InsertMenuA (src_menu, -1, MF_BYPOSITION | MF_STRING, 11, "item2");
ok (bres, "InsertMenuA failed, error %ld\n", GetLastError());
hres = Shell_MergeMenus (dst_menu, src_menu, 0, 123, 133, MM_SUBMENUSHAVEIDS);
ok (hres == 134, "got %ld\n", hres);
count = GetMenuItemCount (dst_menu);
ok (count == 1, "got %d\n", count);
memset (&item_info, 0, sizeof(item_info));
item_info.cbSize = sizeof(item_info);
item_info.fMask = MIIM_ID;
bres = GetMenuItemInfoA (dst_menu, 0, TRUE, &item_info);
ok (bres, "GetMenuItemInfoA failed, error %ld\n", GetLastError ());
ok (item_info.wID == 133, "got %d\n", item_info.wID);
DestroyMenu (dst_menu);
/* integer overflow: Shell_MergeMenus() return value is wrong, but items are still added */
dst_menu = CreatePopupMenu ();
ok (dst_menu != NULL, "CreatePopupMenu() failed, error %ld\n", GetLastError ());
hres = Shell_MergeMenus (dst_menu, src_menu, 0, -1, 133, MM_SUBMENUSHAVEIDS);
ok (hres == -1, "got %ld\n", hres);
count = GetMenuItemCount (dst_menu);
ok (count == 2, "got %d\n", count);
DestroyMenu (dst_menu);
DestroyMenu (src_menu);
}
/* Check for old shell32 (4.0.x) */
static BOOL is_old_shell32(void)
{
SHFILEOPSTRUCTA shfo;
CHAR from[5*MAX_PATH];
CHAR to[5*MAX_PATH];
DWORD retval;
shfo.hwnd = NULL;
shfo.wFunc = FO_COPY;
shfo.pFrom = from;
shfo.pTo = to;
/* FOF_NOCONFIRMMKDIR is needed for old shell32 */
shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI | FOF_MULTIDESTFILES | FOF_NOCONFIRMMKDIR;
shfo.hNameMappings = NULL;
shfo.lpszProgressTitle = NULL;
set_curr_dir_path(from, "test1.txt\0test2.txt\0test3.txt\0");
set_curr_dir_path(to, "test6.txt\0test7.txt\0");
retval = SHFileOperationA(&shfo);
/* Delete extra files on old shell32 and Vista+*/
DeleteFileA("test6.txt\\test1.txt");
/* Delete extra files on old shell32 */
DeleteFileA("test6.txt\\test2.txt");
DeleteFileA("test6.txt\\test3.txt");
/* Delete extra directory on old shell32 and Vista+ */
RemoveDirectoryA("test6.txt");
/* Delete extra files/directories on Vista+*/
DeleteFileA("test7.txt\\test2.txt");
RemoveDirectoryA("test7.txt");
if (retval == ERROR_SUCCESS)
return TRUE;
return FALSE;
}
struct progress_sink
{
IFileOperationProgressSink IFileOperationProgressSink_iface;
unsigned int instance_id;
LONG ref;
struct progress_expected_notifications *expected;
};
struct progress_expected_notification
{
const char *text;
DWORD tsf, tsf_broken;
HRESULT hres, hres_broken;
};
struct progress_expected_notifications
{
unsigned int index, count, line;
const WCHAR *dir_prefix;
const struct progress_expected_notification *expected;
};
static inline struct progress_sink *impl_from_IFileOperationProgressSink(IFileOperationProgressSink *iface)
{
return CONTAINING_RECORD(iface, struct progress_sink, IFileOperationProgressSink_iface);
}
#define progress_init_check_notifications(a, b, c, d, e) progress_init_check_notifications_(__LINE__, a, b, c, d, e)
static void progress_init_check_notifications_(unsigned int line, IFileOperationProgressSink *iface,
unsigned int count, const struct progress_expected_notification *expected, const WCHAR *dir_prefix,
struct progress_expected_notifications *n)
{
struct progress_sink *progress = impl_from_IFileOperationProgressSink(iface);
n->line = line;
n->index = 0;
n->count = count;
n->expected = expected;
n->dir_prefix = dir_prefix;
progress->expected = n;
}
static void progress_check_notification(struct progress_sink *progress, const char *text, DWORD tsf, HRESULT hres)
{
struct progress_expected_notifications *e = progress->expected;
char str[4096];
ok(!!e, "expected notifications are not set up.\n");
sprintf(str, "[%u] %s", progress->instance_id, text);
ok_(__FILE__, e->line)(e->index < e->count, "extra notification %s.\n", debugstr_a(str));
if (e->index < e->count)
{
ok_(__FILE__, e->line)(!strcmp(str, e->expected[e->index].text), "got notification %s, expected %s, index %u.\n",
debugstr_a(str), debugstr_a(e->expected[e->index].text), e->index);
ok_(__FILE__, e->line)(tsf == e->expected[e->index].tsf || broken(tsf == e->expected[e->index].tsf_broken),
"got tsf %#lx, expected %#lx, index %u (%s).\n", tsf, e->expected[e->index].tsf, e->index, debugstr_a(text));
ok_(__FILE__, e->line)(hres == e->expected[e->index].hres || broken(hres == e->expected[e->index].hres_broken),
"got hres %#lx, expected %#lx, index %u (%s).\n", hres, e->expected[e->index].hres, e->index, debugstr_a(text));
}
++e->index;
}
static void progress_end_check_notifications(IFileOperationProgressSink *iface)
{
struct progress_sink *progress = impl_from_IFileOperationProgressSink(iface);
struct progress_expected_notifications *e = progress->expected;
ok(!!e, "expected notifications are not set up.\n");
ok_(__FILE__, e->line)(e->index == e->count, "got notification count %u, expected %u.\n", e->index, e->count);
progress->expected = NULL;
}
static const char *shellitem_str(struct progress_sink *progress, IShellItem *item)
{
char str[MAX_PATH];
unsigned int len;
const char *ret;
WCHAR *path;
HRESULT hr;
if (!item)
return "<null>";
hr = IShellItem_GetDisplayName(item, SIGDN_FILESYSPATH, &path);
if (FAILED(hr))
return "<invalid>";
len = wcslen(progress->expected->dir_prefix);
if (progress->expected->dir_prefix[len - 1] == '\\')
--len;
if (wcsncmp(path, progress->expected->dir_prefix, len))
{
ret = debugstr_w(path);
}
else
{
sprintf(str, "<prefix>%s", debugstr_w(path + len) + 1);
ret = __wine_dbg_strdup(str);
}
CoTaskMemFree(path);
return ret;
}
static HRESULT WINAPI progress_QueryInterface(IFileOperationProgressSink *iface, REFIID riid, void **out)
{
struct progress_sink *operation = impl_from_IFileOperationProgressSink(iface);
if (IsEqualIID(&IID_IFileOperationProgressSink, riid) || IsEqualIID(&IID_IUnknown, riid))
*out = &operation->IFileOperationProgressSink_iface;
else
{
trace("not implemented for %s.\n", debugstr_guid(riid));
*out = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef((IUnknown *)*out);
return S_OK;
}
static ULONG WINAPI progress_AddRef(IFileOperationProgressSink *iface)
{
struct progress_sink *progress = impl_from_IFileOperationProgressSink(iface);
return InterlockedIncrement(&progress->ref);
}
static ULONG WINAPI progress_Release(IFileOperationProgressSink *iface)
{
struct progress_sink *progress = impl_from_IFileOperationProgressSink(iface);
LONG ref = InterlockedDecrement(&progress->ref);
if (!ref)
free(progress);
return ref;
}
static HRESULT WINAPI progress_StartOperations(IFileOperationProgressSink *iface)
{
progress_check_notification(impl_from_IFileOperationProgressSink(iface), "StartOperations", 0, 0);
return S_OK;
}
static HRESULT WINAPI progress_FinishOperations(IFileOperationProgressSink *iface, HRESULT result)
{
progress_check_notification(impl_from_IFileOperationProgressSink(iface), "FinishOperations", 0, result);
return S_OK;
}
static HRESULT WINAPI progress_PreRenameItem(IFileOperationProgressSink *iface, DWORD flags, IShellItem *item,
const WCHAR *new_name)
{
ok(0, ".\n");
return E_NOTIMPL;
}
static HRESULT WINAPI progress_PostRenameItem(IFileOperationProgressSink *iface, DWORD flags, IShellItem *item,
const WCHAR *new_name, HRESULT hrRename, IShellItem *newly_created)
{
ok(0, ".\n");
return E_NOTIMPL;
}
static HRESULT WINAPI progress_PreMoveItem(IFileOperationProgressSink *iface, DWORD flags, IShellItem *item,
IShellItem *dest_folder, const WCHAR *new_name)
{
struct progress_sink *progress = impl_from_IFileOperationProgressSink(iface);
char str[1024];
sprintf(str, "PreMoveItem %s, %s, %s", shellitem_str(progress, item),
shellitem_str(progress, dest_folder), debugstr_w(new_name) + 1);
progress_check_notification(progress, str, flags, 0);
return S_OK;
}
static HRESULT WINAPI progress_PostMoveItem(IFileOperationProgressSink *iface, DWORD flags, IShellItem *item,
IShellItem *dest_folder, const WCHAR *new_name, HRESULT result, IShellItem *newly_created)
{
struct progress_sink *progress = impl_from_IFileOperationProgressSink(iface);
char str[1024];
sprintf(str, "PostMoveItem %s, %s, %s -> %s", shellitem_str(progress, item),
shellitem_str(progress, dest_folder), debugstr_w(new_name) + 1, shellitem_str(progress, newly_created));
progress_check_notification(progress, str, flags, result);
return S_OK;
}
static HRESULT WINAPI progress_PreCopyItem(IFileOperationProgressSink *iface, DWORD flags, IShellItem *item,
IShellItem *dest_folder,LPCWSTR pszNewName)
{
ok(0, ".\n");
return E_NOTIMPL;
}
static HRESULT WINAPI progress_PostCopyItem(IFileOperationProgressSink *iface, DWORD flags, IShellItem *item,
IShellItem *dest_folder, const WCHAR *new_name, HRESULT result, IShellItem *newly_created)
{
ok(0, ".\n");
return E_NOTIMPL;
}
static HRESULT WINAPI progress_PreDeleteItem(IFileOperationProgressSink *iface, DWORD flags, IShellItem *item)
{
ok(0, ".\n");
return E_NOTIMPL;
}
static HRESULT WINAPI progress_PostDeleteItem(IFileOperationProgressSink *iface, DWORD flags, IShellItem *item,
HRESULT result, IShellItem *newly_created)
{
ok(0, ".\n");
return E_NOTIMPL;
}
static HRESULT WINAPI progress_PreNewItem(IFileOperationProgressSink *iface, DWORD flags,IShellItem *dest_folder,
const WCHAR *new_name)
{
ok(0, ".\n");
return E_NOTIMPL;
}
static HRESULT WINAPI progress_PostNewItem(IFileOperationProgressSink *iface, DWORD flags, IShellItem *dest_folder,
const WCHAR *new_name, const WCHAR *template_name, DWORD file_attrs, HRESULT result, IShellItem *newly_created)
{
ok(0, ".\n");
return E_NOTIMPL;
}
static HRESULT WINAPI progress_UpdateProgress(IFileOperationProgressSink *iface, UINT total, UINT sofar)
{
return S_OK;
}
static HRESULT WINAPI progress_ResetTimer(IFileOperationProgressSink *iface)
{
progress_check_notification(impl_from_IFileOperationProgressSink(iface), "ResetTimer", 0, 0);
return S_OK;
}
static HRESULT WINAPI progress_PauseTimer(IFileOperationProgressSink *iface)
{
ok(0, ".\n");
return E_NOTIMPL;
}
static HRESULT WINAPI progress_ResumeTimer(IFileOperationProgressSink *iface)
{
ok(0, ".\n");
return E_NOTIMPL;
}
static const IFileOperationProgressSinkVtbl progress_vtbl =
{
progress_QueryInterface,
progress_AddRef,
progress_Release,
progress_StartOperations,
progress_FinishOperations,
progress_PreRenameItem,
progress_PostRenameItem,
progress_PreMoveItem,
progress_PostMoveItem,
progress_PreCopyItem,
progress_PostCopyItem,
progress_PreDeleteItem,
progress_PostDeleteItem,
progress_PreNewItem,
progress_PostNewItem,
progress_UpdateProgress,
progress_ResetTimer,
progress_PauseTimer,
progress_ResumeTimer,
};
static IFileOperationProgressSink *create_progress_sink(unsigned int instance_id)
{
struct progress_sink *obj;
obj = calloc(1, sizeof(*obj));
obj->IFileOperationProgressSink_iface.lpVtbl = &progress_vtbl;
obj->instance_id = instance_id;
obj->ref = 1;
return &obj->IFileOperationProgressSink_iface;
}
static void set_shell_item_path(IShellItem *item, const WCHAR *path)
{
IPersistIDList *idlist;
ITEMIDLIST *pidl;
HRESULT hr;
hr = SHParseDisplayName(path, NULL, &pidl, 0, NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
if (FAILED(hr))
return;
hr = IShellItem_QueryInterface(item, &IID_IPersistIDList, (void **)&idlist);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
hr = IPersistIDList_SetIDList(idlist, pidl);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
IPersistIDList_Release(idlist);
ILFree(pidl);
}
static void test_file_operation(void)
{
#define DEFAULT_TSF_FLAGS (TSF_COPY_LOCALIZED_NAME | TSF_COPY_WRITE_TIME | TSF_COPY_CREATION_TIME | TSF_OVERWRITE_EXIST)
#define MEGRE_TSF_FLAGS (TSF_COPY_WRITE_TIME | TSF_COPY_CREATION_TIME | TSF_OVERWRITE_EXIST)
#define UNKNOWN_POST_MERGE_TSF_FLAG 0x1000
static const struct progress_expected_notification notifications1[] =
{
{"[0] StartOperations"},
{"[0] ResetTimer"},
{"[0] PreMoveItem <prefix>\"\\\\testfile1\", <prefix>\"\", \"test\"", DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS},
{"[1] PreMoveItem <prefix>\"\\\\testfile1\", <prefix>\"\", \"test\"", DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS},
{"[1] PostMoveItem <prefix>\"\\\\testfile1\", <prefix>\"\", \"test\" -> <prefix>\"\\\\test\"",
DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] PostMoveItem <prefix>\"\\\\testfile1\", <prefix>\"\", \"test\" -> <prefix>\"\\\\test\"",
DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] FinishOperations"},
};
static const struct progress_expected_notification notifications2[] =
{
{"[0] StartOperations"},
{"[0] ResetTimer"},
{"[0] PreMoveItem <prefix>\"\\\\testfile1\", <prefix>\"\", \"test2\"", DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS},
{"[0] PostMoveItem <prefix>\"\\\\testfile1\", <prefix>\"\", \"test2\" -> <null>",
DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS,
0x80070002, COPYENGINE_S_USER_IGNORED},
{"[0] FinishOperations"},
};
static const struct progress_expected_notification notifications3[] =
{
{"[0] StartOperations"},
{"[0] ResetTimer"},
{"[0] PreMoveItem <prefix>\"\\\\test\", <prefix>\"\", \"test2\"", DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS},
{"[0] PostMoveItem <prefix>\"\\\\test\", <prefix>\"\", \"test2\" -> <prefix>\"\\\\test2\"",
DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] FinishOperations"},
};
static const struct progress_expected_notification notifications4[] =
{
{"[0] StartOperations"},
{"[0] ResetTimer"},
{"[0] PreMoveItem <prefix>\"\\\\test_dir1\", <prefix>\"\\\\test_dir2\", \"test2\"", DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS},
{"[0] PostMoveItem <prefix>\"\\\\test_dir1\", <prefix>\"\\\\test_dir2\", \"test2\" -> <null>",
DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS,
COPYENGINE_E_FLD_IS_FILE_DEST, COPYENGINE_S_USER_IGNORED},
{"[0] FinishOperations"},
};
static const struct progress_expected_notification notifications5[] =
{
{"[0] StartOperations"},
{"[0] ResetTimer"},
{"[0] PreMoveItem <prefix>\"\\\\test_dir1\", <prefix>\"\\\\test_dir2\", \"test2\"", DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS},
{"[0] PostMoveItem <prefix>\"\\\\test_dir1\", <prefix>\"\\\\test_dir2\", \"test2\" -> <prefix>\"\\\\test_dir2\\\\test2\"",
DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] FinishOperations"},
};
static const struct progress_expected_notification notifications6[] =
{
{"[0] StartOperations"},
{"[0] ResetTimer"},
{"[0] PreMoveItem <prefix>\"\\\\test_dir3\", <prefix>\"\\\\test_dir2\", \"test2\"", DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS},
{"[1] PreMoveItem <prefix>\"\\\\test_dir3\", <prefix>\"\\\\test_dir2\", \"test2\"", DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS},
{"[1] PostMoveItem <prefix>\"\\\\test_dir3\", <prefix>\"\\\\test_dir2\", \"test2\" -> <prefix>\"\\\\test_dir2\\\\test2\"",
DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS,
COPYENGINE_S_NOT_HANDLED, COPYENGINE_S_MERGE},
{"[0] PostMoveItem <prefix>\"\\\\test_dir3\", <prefix>\"\\\\test_dir2\", \"test2\" -> <prefix>\"\\\\test_dir2\\\\test2\"",
DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS,
COPYENGINE_S_NOT_HANDLED, COPYENGINE_S_MERGE},
{"[0] PreMoveItem <prefix>\"\\\\test_dir3\\\\testfile5\", <prefix>\"\\\\test_dir2\\\\test2\", \"\"", MEGRE_TSF_FLAGS, MEGRE_TSF_FLAGS},
{"[1] PreMoveItem <prefix>\"\\\\test_dir3\\\\testfile5\", <prefix>\"\\\\test_dir2\\\\test2\", \"\"", MEGRE_TSF_FLAGS, MEGRE_TSF_FLAGS},
{"[1] PostMoveItem <prefix>\"\\\\test_dir3\\\\testfile5\", <prefix>\"\\\\test_dir2\\\\test2\", \"testfile5\" -> <prefix>\"\\\\test_dir2\\\\test2\\\\testfile5\"",
MEGRE_TSF_FLAGS | UNKNOWN_POST_MERGE_TSF_FLAG, MEGRE_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] PostMoveItem <prefix>\"\\\\test_dir3\\\\testfile5\", <prefix>\"\\\\test_dir2\\\\test2\", \"testfile5\" -> <prefix>\"\\\\test_dir2\\\\test2\\\\testfile5\"",
MEGRE_TSF_FLAGS | UNKNOWN_POST_MERGE_TSF_FLAG, MEGRE_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] PreMoveItem <prefix>\"\\\\test_dir3\\\\testfile6\", <prefix>\"\\\\test_dir2\\\\test2\", \"\"", MEGRE_TSF_FLAGS, MEGRE_TSF_FLAGS},
{"[1] PreMoveItem <prefix>\"\\\\test_dir3\\\\testfile6\", <prefix>\"\\\\test_dir2\\\\test2\", \"\"", MEGRE_TSF_FLAGS, MEGRE_TSF_FLAGS},
{"[1] PostMoveItem <prefix>\"\\\\test_dir3\\\\testfile6\", <prefix>\"\\\\test_dir2\\\\test2\", \"testfile6\" -> <prefix>\"\\\\test_dir2\\\\test2\\\\testfile6\"",
MEGRE_TSF_FLAGS | UNKNOWN_POST_MERGE_TSF_FLAG, MEGRE_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] PostMoveItem <prefix>\"\\\\test_dir3\\\\testfile6\", <prefix>\"\\\\test_dir2\\\\test2\", \"testfile6\" -> <prefix>\"\\\\test_dir2\\\\test2\\\\testfile6\"",
MEGRE_TSF_FLAGS | UNKNOWN_POST_MERGE_TSF_FLAG, MEGRE_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] PreMoveItem <prefix>\"\\\\test_dir3\\\\inner_dir\", <prefix>\"\\\\test_dir2\\\\test2\", \"\"", MEGRE_TSF_FLAGS, MEGRE_TSF_FLAGS},
{"[1] PreMoveItem <prefix>\"\\\\test_dir3\\\\inner_dir\", <prefix>\"\\\\test_dir2\\\\test2\", \"\"", MEGRE_TSF_FLAGS, MEGRE_TSF_FLAGS},
{"[1] PostMoveItem <prefix>\"\\\\test_dir3\\\\inner_dir\", <prefix>\"\\\\test_dir2\\\\test2\", \"inner_dir\" -> <prefix>\"\\\\test_dir2\\\\test2\\\\inner_dir\"",
MEGRE_TSF_FLAGS | UNKNOWN_POST_MERGE_TSF_FLAG, MEGRE_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] PostMoveItem <prefix>\"\\\\test_dir3\\\\inner_dir\", <prefix>\"\\\\test_dir2\\\\test2\", \"inner_dir\" -> <prefix>\"\\\\test_dir2\\\\test2\\\\inner_dir\"",
MEGRE_TSF_FLAGS | UNKNOWN_POST_MERGE_TSF_FLAG, MEGRE_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] PreMoveItem <prefix>\"\\\\testfile8\", <prefix>\"\\\\test_dir2\", \"\"", DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS},
{"[0] PostMoveItem <prefix>\"\\\\testfile8\", <prefix>\"\\\\test_dir2\", \"testfile8\" -> <prefix>\"\\\\test_dir2\\\\testfile8\"",
DEFAULT_TSF_FLAGS, DEFAULT_TSF_FLAGS,
COPYENGINE_S_DONT_PROCESS_CHILDREN, COPYENGINE_S_DONT_PROCESS_CHILDREN},
{"[0] FinishOperations"},
};
WCHAR dirpath[MAX_PATH], tmpfile[MAX_PATH], path[MAX_PATH];
struct progress_expected_notifications expected_notif;
IFileOperationProgressSink *progress, *progress2;
IFileOperation *operation;
IShellItem *item, *item2;
IShellItem *folder;
LONG refcount;
IUnknown *unk;
DWORD cookie;
BOOL aborted;
HRESULT hr;
BOOL bret;
DWORD ret;
hr = CoCreateInstance(&CLSID_FileOperation, NULL, CLSCTX_INPROC_SERVER,
&IID_IFileOperation, (void **)&operation);
ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /* before vista */,
"Got hr %#lx.\n", hr);
if (hr == REGDB_E_CLASSNOTREG)
{
win_skip("IFileOperation isn't supported.\n");
return;
}
hr = IFileOperation_QueryInterface(operation, &IID_IUnknown, (void **)&unk);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
IUnknown_Release(unk);
hr = IFileOperation_Advise(operation, NULL, &cookie);
ok(hr == E_INVALIDARG, "got %#lx.\n", hr);
progress = create_progress_sink(0);
hr = IFileOperation_Advise(operation, progress, &cookie);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_PerformOperations(operation);
ok(hr == E_UNEXPECTED, "got %#lx.\n", hr);
hr = CoCreateInstance(&CLSID_ShellItem, NULL, CLSCTX_INPROC_SERVER, &IID_IShellItem, (void **)&item);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = CoCreateInstance(&CLSID_ShellItem, NULL, CLSCTX_INPROC_SERVER, &IID_IShellItem, (void **)&folder);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_MoveItem(operation, item, folder, L"test", NULL);
ok(hr == E_INVALIDARG, "got %#lx.\n", hr);
GetTempPathW(ARRAY_SIZE(dirpath), dirpath);
PathCombineW(tmpfile, dirpath, L"testfile1");
createTestFileW(tmpfile);
set_shell_item_path(folder, dirpath);
set_shell_item_path(item, tmpfile);
hr = IFileOperation_SetOperationFlags(operation, 0);
ok(hr == S_OK, "got %#lx.\n", hr);
progress2 = create_progress_sink(1);
progress_init_check_notifications(progress, ARRAY_SIZE(notifications1), notifications1, dirpath, &expected_notif);
progress_init_check_notifications(progress2, ARRAY_SIZE(notifications1), notifications1, dirpath, &expected_notif);
hr = IFileOperation_MoveItem(operation, item, folder, L"test", progress2);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_SetOperationFlags(operation, FOF_NO_UI);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_PerformOperations(operation);
ok(hr == S_OK, "got %#lx.\n", hr);
aborted = 0xdeadbeef;
hr = IFileOperation_GetAnyOperationsAborted(operation, &aborted);
ok(hr == S_OK, "got %#lx.\n", hr);
ok(!aborted, "got %d.\n", aborted);
progress_end_check_notifications(progress);
hr = IFileOperation_PerformOperations(operation);
ok(hr == E_UNEXPECTED, "got %#lx.\n", hr);
/* Input file does not exist: PerformOperations succeeds, 'aborted' is set. */
hr = IFileOperation_MoveItem(operation, item, folder, L"test2", NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
progress_init_check_notifications(progress, ARRAY_SIZE(notifications2), notifications2, dirpath, &expected_notif);
hr = IFileOperation_PerformOperations(operation);
ok(hr == S_OK, "got %#lx.\n", hr);
progress_end_check_notifications(progress);
aborted = 0;
hr = IFileOperation_GetAnyOperationsAborted(operation, &aborted);
ok(hr == S_OK, "got %#lx.\n", hr);
ok(aborted == TRUE, "got %d.\n", aborted);
aborted = 0;
hr = IFileOperation_GetAnyOperationsAborted(operation, &aborted);
ok(hr == S_OK, "got %#lx.\n", hr);
ok(aborted == TRUE, "got %d.\n", aborted);
/* Input file exists: PerformOperations succeeds, the item data at the moment of MoveItem is used. */
PathCombineW(path, dirpath, L"test");
set_shell_item_path(item, path);
hr = IFileOperation_MoveItem(operation, item, folder, L"test2", NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
PathCombineW(tmpfile, dirpath, L"testfile2");
/* Actual paths are fetched at _MoveItem and not at _Perform operation: changing item after doesn't matter. */
createTestFileW(tmpfile);
set_shell_item_path(item, tmpfile);
bret = DeleteFileW(tmpfile);
ok(bret, "got error %ld.\n", GetLastError());
progress_init_check_notifications(progress, ARRAY_SIZE(notifications3), notifications3, dirpath, &expected_notif);
hr = IFileOperation_PerformOperations(operation);
ok(hr == S_OK, "got %#lx.\n", hr);
progress_end_check_notifications(progress);
aborted = 0;
hr = IFileOperation_GetAnyOperationsAborted(operation, &aborted);
ok(hr == S_OK, "got %#lx.\n", hr);
ok(aborted == TRUE, "got %d.\n", aborted);
ret = GetFileAttributesW(tmpfile);
ok(ret == INVALID_FILE_ATTRIBUTES, "got %#lx.\n", ret);
PathCombineW(path, dirpath, L"test");
ret = GetFileAttributesW(path);
ok(ret == INVALID_FILE_ATTRIBUTES, "got %#lx.\n", ret);
PathCombineW(path, dirpath, L"test2");
ret = GetFileAttributesW(path);
ok(ret != INVALID_FILE_ATTRIBUTES, "got %#lx.\n", ret);
bret = DeleteFileW(path);
ok(bret, "got error %ld.\n", GetLastError());
refcount = IShellItem_Release(item);
ok(!refcount, "got %ld.\n", refcount);
IShellItem_AddRef(folder);
refcount = IShellItem_Release(folder);
todo_wine ok(refcount > 1, "got %ld.\n", refcount);
hr = IFileOperation_Unadvise(operation, 0xdeadbeef);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_Unadvise(operation, cookie);
ok(hr == S_OK, "got %#lx.\n", hr);
IFileOperation_Release(operation);
refcount = IShellItem_Release(folder);
ok(!refcount, "got %ld.\n", refcount);
/* Move directory to directory. */
hr = CoCreateInstance(&CLSID_FileOperation, NULL, CLSCTX_INPROC_SERVER, &IID_IFileOperation, (void **)&operation);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_SetOperationFlags(operation, FOF_NO_UI);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_Advise(operation, progress, &cookie);
ok(hr == S_OK, "got %#lx.\n", hr);
PathCombineW(path, dirpath, L"test_dir1");
bret = CreateDirectoryW(path, NULL);
PathCombineW(tmpfile, path, L"testfile3");
createTestFileW(tmpfile);
PathCombineW(tmpfile, path, L"testfile4");
createTestFileW(tmpfile);
hr = SHCreateItemFromParsingName(path, NULL, &IID_IShellItem, (void**)&item);
ok(hr == S_OK, "got %#lx.\n", hr);
PathCombineW(path, dirpath, L"test_dir2");
bret = CreateDirectoryW(path, NULL);
ok(bret, "got error %ld.\n", GetLastError());
hr = SHCreateItemFromParsingName(path, NULL, &IID_IShellItem, (void**)&folder);
ok(hr == S_OK, "got %#lx.\n", hr);
PathCombineW(path, path, L"test2");
createTestFileW(path);
/* Source is directory, destination test2 is file. */
hr = IFileOperation_MoveItem(operation, item, folder, L"test2", NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
progress_init_check_notifications(progress, ARRAY_SIZE(notifications4), notifications4, dirpath, &expected_notif);
hr = IFileOperation_PerformOperations(operation);
ok(hr == S_OK, "got %#lx.\n", hr);
progress_end_check_notifications(progress);
aborted = 0;
hr = IFileOperation_GetAnyOperationsAborted(operation, &aborted);
ok(hr == S_OK, "got %#lx.\n", hr);
ok(aborted, "got %d.\n", aborted);
bret = DeleteFileW(path);
ok(bret, "got error %ld.\n", GetLastError());
IFileOperation_Release(operation);
/* Source is directory, destination is absent (simple move). */
hr = CoCreateInstance(&CLSID_FileOperation, NULL, CLSCTX_INPROC_SERVER, &IID_IFileOperation, (void **)&operation);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_Advise(operation, progress, &cookie);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_SetOperationFlags(operation, FOF_NO_UI);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_MoveItem(operation, item, folder, L"test2", NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
progress_init_check_notifications(progress, ARRAY_SIZE(notifications5), notifications5, dirpath, &expected_notif);
hr = IFileOperation_PerformOperations(operation);
ok(hr == S_OK, "got %#lx.\n", hr);
progress_end_check_notifications(progress);
IFileOperation_Release(operation);
/* Source and dest are directories, merge is performed. */
hr = CoCreateInstance(&CLSID_FileOperation, NULL, CLSCTX_INPROC_SERVER, &IID_IFileOperation, (void **)&operation);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_Advise(operation, progress, &cookie);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_SetOperationFlags(operation, FOF_NO_UI);
ok(hr == S_OK, "got %#lx.\n", hr);
PathCombineW(path, dirpath, L"test_dir3");
bret = CreateDirectoryW(path, NULL);
set_shell_item_path(item, path);
ok(bret, "got error %ld.\n", GetLastError());
PathCombineW(tmpfile, path, L"testfile5");
createTestFileW(tmpfile);
PathCombineW(tmpfile, path, L"testfile6");
createTestFileW(tmpfile);
PathCombineW(path, path, L"inner_dir");
bret = CreateDirectoryW(path, NULL);
ok(bret, "got error %ld.\n", GetLastError());
PathCombineW(tmpfile, path, L"testfile7");
createTestFileW(tmpfile);
PathCombineW(tmpfile, dirpath, L"testfile8");
createTestFileW(tmpfile);
hr = SHCreateItemFromParsingName(tmpfile, NULL, &IID_IShellItem, (void**)&item2);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_MoveItem(operation, item, folder, L"test2", progress2);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IFileOperation_MoveItem(operation, item2, folder, NULL, NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
refcount = IShellItem_Release(item2);
ok(!refcount, "got %ld.\n", refcount);
progress_init_check_notifications(progress, ARRAY_SIZE(notifications6), notifications6, dirpath, &expected_notif);
hr = IFileOperation_PerformOperations(operation);
ok(hr == S_OK, "got %#lx.\n", hr);
progress_end_check_notifications(progress);
PathCombineW(path, dirpath, L"test_dir2");
PathCombineW(tmpfile, dirpath, L"test_dir2\\test2\\testfile6");
ret = GetFileAttributesW(tmpfile);
ok(ret != INVALID_FILE_ATTRIBUTES, "got %#lx.\n", ret);
remove_directory(path);
PathCombineW(path, dirpath, L"test_dir3");
ret = GetFileAttributesW(path);
ok(ret == INVALID_FILE_ATTRIBUTES, "got %#lx.\n", ret);
remove_directory(path);
IFileOperation_Release(operation);
refcount = IShellItem_Release(item);
ok(!refcount, "got %ld.\n", refcount);
refcount = IShellItem_Release(folder);
ok(!refcount, "got %ld.\n", refcount);
refcount = IFileOperationProgressSink_Release(progress);
ok(!refcount, "got %ld.\n", refcount);
refcount = IFileOperationProgressSink_Release(progress2);
ok(!refcount, "got %ld.\n", refcount);
}
START_TEST(shlfileop)
{
clean_after_shfo_tests();
init_shfo_tests();
old_shell32 = is_old_shell32();
if (old_shell32)
win_skip("Need to cater for old shell32 (4.0.x) on Win95\n");
clean_after_shfo_tests();
init_shfo_tests();
test_get_file_info();
test_get_file_info_iconlist();
clean_after_shfo_tests();
init_shfo_tests();
test_delete();
clean_after_shfo_tests();
init_shfo_tests();
test_rename();
clean_after_shfo_tests();
init_shfo_tests();
test_copy();
clean_after_shfo_tests();
init_shfo_tests();
test_move();
clean_after_shfo_tests();
test_sh_create_dir();
clean_after_shfo_tests();
init_shfo_tests();
test_sh_path_prepare();
clean_after_shfo_tests();
init_shfo_tests();
test_sh_new_link_info();
clean_after_shfo_tests();
test_unicode();
test_shlmenu();
CoInitialize(NULL);
test_file_operation();
CoUninitialize();
}