diff --git a/configure b/configure index bbb4eaa125c..411e2f9e0d4 100755 --- a/configure +++ b/configure @@ -14102,7 +14102,7 @@ MAKE_TEST_RULES=dlls/Maketest.rules MAKE_PROG_RULES=programs/Makeprog.rules -ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules programs/Makeprog.rules Makefile debugger/Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/d3d8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dsound/Makefile dlls/gdi/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt20/Makefile dlls/msvideo/Makefile dlls/netapi32/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile library/Makefile miscemu/Makefile ole/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineconsole/Makefile programs/winefile/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/wmc/Makefile tools/wpp/Makefile tools/wrc/Makefile tsx11/Makefile unicode/Makefile" +ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules programs/Makeprog.rules Makefile debugger/Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/d3d8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dsound/Makefile dlls/gdi/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt20/Makefile dlls/msvideo/Makefile dlls/netapi32/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile library/Makefile miscemu/Makefile ole/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineconsole/Makefile programs/winefile/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/wmc/Makefile tools/wpp/Makefile tools/wrc/Makefile tsx11/Makefile unicode/Makefile" cat >confcache <<\_ACEOF @@ -14649,6 +14649,7 @@ do "dlls/setupapi/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/setupapi/Makefile" ;; "dlls/shdocvw/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/shdocvw/Makefile" ;; "dlls/shell32/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/shell32/Makefile" ;; + "dlls/shell32/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/shell32/tests/Makefile" ;; "dlls/shfolder/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/shfolder/Makefile" ;; "dlls/shlwapi/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/shlwapi/Makefile" ;; "dlls/shlwapi/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/shlwapi/tests/Makefile" ;; diff --git a/configure.ac b/configure.ac index a9db1214497..ee26e44fb6d 100644 --- a/configure.ac +++ b/configure.ac @@ -1421,6 +1421,7 @@ dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile +dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in index 9e56ae68708..5094c438f3f 100644 --- a/dlls/shell32/Makefile.in +++ b/dlls/shell32/Makefile.in @@ -51,6 +51,8 @@ C_SRCS = \ RC_SRCS= shres.rc RC_SRCS16 = version16.rc +SUBDIRS = tests + @MAKE_DLL_RULES@ install:: diff --git a/dlls/shell32/shlfileop.c b/dlls/shell32/shlfileop.c index 9712486f152..de040135fc9 100644 --- a/dlls/shell32/shlfileop.c +++ b/dlls/shell32/shlfileop.c @@ -266,16 +266,58 @@ DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp) } case FO_DELETE: + { + HANDLE hFind; + WIN32_FIND_DATAA wfd; + char szTemp[MAX_PATH]; + char *file_name; + TRACE("File Delete:\n"); while(1) { if(!pFrom[0]) break; - TRACE(" File='%s'\n", pFrom); - DeleteFileA(pFrom); + TRACE(" Pattern='%s'\n", pFrom); + if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(pFrom, &wfd))) + { + do + { + if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, "..")) + { + strcpy(szTemp, pFrom); + file_name = PathFindFileNameA(szTemp); + file_name[0] = '\0'; + PathAddBackslashA(szTemp); + strcat(szTemp, wfd.cFileName); + + TRACE(" File='%s'\n", szTemp); + if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes) + { + if(!(lpFileOp->fFlags & FOF_FILESONLY)) + SHELL_DeleteDirectoryA(szTemp, FALSE); + } + else + DeleteFileA(szTemp); + } + } while(FindNextFileA(hFind, &wfd)); + + FindClose(hFind); + } pFrom += strlen(pFrom) + 1; } TRACE("Setting AnyOpsAborted=FALSE\n"); lpFileOp->fAnyOperationsAborted=FALSE; return 0; + } + + case FO_RENAME: + TRACE("File Rename:\n"); + if (pFrom[strlen(pFrom) + 1] != '\0') + { + WARN("Attempt to rename more than one file\n"); + return 1; + } + lpFileOp->fAnyOperationsAborted = FALSE; + TRACE("From %s, To %s\n", pFrom, pTo); + return !MoveFileA(pFrom, pTo); default: FIXME("Unhandled shell file operation %d\n", lpFileOp->wFunc); diff --git a/dlls/shell32/tests/.cvsignore b/dlls/shell32/tests/.cvsignore new file mode 100644 index 00000000000..2763d3c8543 --- /dev/null +++ b/dlls/shell32/tests/.cvsignore @@ -0,0 +1,4 @@ +Makefile +shell32_test.exe.spec.c +shlfileop.ok +testlist.c diff --git a/dlls/shell32/tests/Makefile.in b/dlls/shell32/tests/Makefile.in new file mode 100644 index 00000000000..7a2c8097e10 --- /dev/null +++ b/dlls/shell32/tests/Makefile.in @@ -0,0 +1,13 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +TESTDLL = shell32.dll +IMPORTS = shell32 + +CTESTS = \ + shlfileop.c + +@MAKE_TEST_RULES@ + +### Dependencies: diff --git a/dlls/shell32/tests/shlfileop.c b/dlls/shell32/tests/shlfileop.c new file mode 100644 index 00000000000..a4b8a005daf --- /dev/null +++ b/dlls/shell32/tests/shlfileop.c @@ -0,0 +1,196 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "wine/test.h" +#include +#include +#include + +CHAR CURR_DIR[MAX_PATH]; + +/* creates a file with the specified name for tests */ +void createTestFile(CHAR *name) +{ + HANDLE file; + DWORD written; + + file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, (HANDLE)NULL); + ok(file != INVALID_HANDLE_VALUE, "Failure to open file"); + WriteFile(file, name, strlen(name), &written, NULL); + WriteFile(file, "\n", strlen("\n"), &written, NULL); + CloseHandle(file); +} + +BOOL file_exists(CHAR *name) +{ + return GetFileAttributesA(name) != 0xFFFFFFFF; +} + +/* initializes the tests */ +void init_shfo_tests(void) +{ + GetCurrentDirectoryA(MAX_PATH, CURR_DIR); + createTestFile(".\\test1.txt"); + createTestFile(".\\test2.txt"); + createTestFile(".\\test3.txt"); + CreateDirectoryA(".\\test4.txt", NULL); +} + +/* cleans after tests */ +void clean_after_shfo_tests(void) +{ + DeleteFileA(".\\test1.txt"); + DeleteFileA(".\\test2.txt"); + DeleteFileA(".\\test3.txt"); + DeleteFileA(".\\test4.txt\\test1.txt"); + DeleteFileA(".\\test4.txt\\test2.txt"); + DeleteFileA(".\\test4.txt\\test3.txt"); + RemoveDirectoryA(".\\test4.txt"); +} + +/** + 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 */ +void set_curr_dir_path(CHAR *buf, 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; +} + + +/* tests the FO_DELETE action */ +void test_delete(void) +{ + SHFILEOPSTRUCTA shfo; + CHAR buf[MAX_PATH]; + + sprintf(buf, "%s\\%s", CURR_DIR, "test?.txt"); + buf[strlen(buf) + 1] = '\0'; + + shfo.hwnd = (HANDLE)NULL; + shfo.wFunc = FO_DELETE; + shfo.pFrom = buf; + shfo.pTo = "\0"; + shfo.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT; + shfo.hNameMappings = NULL; + shfo.lpszProgressTitle = NULL; + + ok(!SHFileOperationA(&shfo), "Deletion was successful"); + ok(file_exists(".\\test4.txt"), "Directory should not be removed"); + ok(!file_exists(".\\test1.txt"), "File should be removed"); + + ok(!SHFileOperationA(&shfo), "Directory exists, but is not removed"); + ok(file_exists(".\\test4.txt"), "Directory should not be removed"); + + shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT; + + ok(!SHFileOperationA(&shfo), "Directory removed"); + ok(!file_exists(".\\test4.txt"), "Directory should be removed"); + + ok(!SHFileOperationA(&shfo), "The requested file does not exist"); + + init_shfo_tests(); + sprintf(buf, "%s\\%s", CURR_DIR, "test4.txt"); + buf[strlen(buf) + 1] = '\0'; + ok(MoveFileA(".\\test1.txt", ".\\test4.txt\\test1.txt"), "Fill the subdirectory"); + ok(!SHFileOperationA(&shfo), "Directory removed"); + ok(!file_exists(".\\test4.txt"), "Directory is removed"); + + init_shfo_tests(); + shfo.pFrom = ".\\test1.txt\0.\\test4.txt\0"; + ok(!SHFileOperationA(&shfo), "Directory and a file removed"); + ok(!file_exists(".\\test1.txt"), "The file should be removed"); + ok(!file_exists(".\\test4.txt"), "Directory should be removed"); + ok(file_exists(".\\test2.txt"), "This file should not be removed"); +} + +/* tests the FO_RENAME action */ +void test_rename() +{ + SHFILEOPSTRUCTA shfo; + CHAR from[MAX_PATH]; + CHAR to[MAX_PATH]; + + shfo.hwnd = (HANDLE)NULL; + shfo.wFunc = FO_RENAME; + shfo.pFrom = from; + shfo.pTo = to; + shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; + shfo.hNameMappings = NULL; + shfo.lpszProgressTitle = NULL; + + set_curr_dir_path(from, "test1.txt\0"); + set_curr_dir_path(to, "test4.txt\0"); + ok(SHFileOperationA(&shfo), "File is not renamed moving to other directory " + "when specifying directory name only"); + ok(file_exists(".\\test1.txt"), "The file is not removed"); + + set_curr_dir_path(from, "test3.txt\0"); + set_curr_dir_path(to, "test4.txt\\test1.txt\0"); + ok(!SHFileOperationA(&shfo), "File is renamed moving to other directory"); + ok(file_exists(".\\test4.txt\\test1.txt"), "The file is renamed"); + + set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0"); + set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0"); + ok(SHFileOperationA(&shfo), "Can't rename many files"); + ok(file_exists(".\\test1.txt"), "The file is not renamed - many files are specified "); + + set_curr_dir_path(from, "test1.txt\0"); + set_curr_dir_path(to, "test6.txt\0"); + ok(!SHFileOperationA(&shfo), "Rename file"); + ok(!file_exists(".\\test1.txt"), "The file is renamed"); + ok(file_exists(".\\test6.txt"), "The file is renamed "); + set_curr_dir_path(from, "test6.txt\0"); + set_curr_dir_path(to, "test1.txt\0"); + ok(!SHFileOperationA(&shfo), "Rename file back"); + + set_curr_dir_path(from, "test4.txt\0"); + set_curr_dir_path(to, "test6.txt\0"); + ok(!SHFileOperationA(&shfo), "Rename dir"); + ok(!file_exists(".\\test4.txt"), "The dir is renamed"); + ok(file_exists(".\\test6.txt"), "The dir is renamed "); + set_curr_dir_path(from, "test6.txt\0"); + set_curr_dir_path(to, "test4.txt\0"); + ok(!SHFileOperationA(&shfo), "Rename dir back"); +} + +START_TEST(shlfileop) +{ + clean_after_shfo_tests(); + + init_shfo_tests(); + test_delete(); + clean_after_shfo_tests(); + + init_shfo_tests(); + test_rename(); + clean_after_shfo_tests(); +}