Author: akhaldi Date: Sun Dec 9 22:05:54 2012 New Revision: 57858
URL: http://svn.reactos.org/svn/reactos?rev=57858&view=rev Log: [SHELL32_WINETEST]: Sync with Wine 1.5.19.
Modified: trunk/rostests/winetests/shell32/CMakeLists.txt trunk/rostests/winetests/shell32/assoc.c trunk/rostests/winetests/shell32/shelldispatch.c trunk/rostests/winetests/shell32/shelllink.c trunk/rostests/winetests/shell32/shellpath.c trunk/rostests/winetests/shell32/shlexec.c trunk/rostests/winetests/shell32/shlfileop.c trunk/rostests/winetests/shell32/shlfolder.c trunk/rostests/winetests/shell32/shlview.c
Modified: trunk/rostests/winetests/shell32/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/CMakeLis... ============================================================================== --- trunk/rostests/winetests/shell32/CMakeLists.txt [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/CMakeLists.txt [iso-8859-1] Sun Dec 9 22:05:54 2012 @@ -1,9 +1,7 @@
remove_definitions(-DWINVER=0x502 -D_WIN32_IE=0x600 -D_WIN32_WINNT=0x502)
-add_definitions( - -D__ROS_LONG64__ - -D_DLL -D__USE_CRTIMP) +add_definitions(-D__ROS_LONG64__)
list(APPEND SOURCE appbar.c @@ -12,7 +10,7 @@ brsfolder.c ebrowser.c generated.c - #progman_dde.c FIXME: bug 7233 + #progman_dde.c FIXME: CORE-6559 recyclebin.c shelldispatch.c shelllink.c
Modified: trunk/rostests/winetests/shell32/assoc.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/assoc.c?... ============================================================================== --- trunk/rostests/winetests/shell32/assoc.c [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/assoc.c [iso-8859-1] Sun Dec 9 22:05:54 2012 @@ -43,19 +43,19 @@ return; }
- hr = IUnknown_QueryInterface(qa, &IID_IQueryAssociations, (void**)&qa2); + hr = IQueryAssociations_QueryInterface(qa, &IID_IQueryAssociations, (void**)&qa2); ok(hr == S_OK, "QueryInterface (IQueryAssociations) returned 0x%x\n", hr); if (SUCCEEDED(hr)) { - IUnknown_Release(qa2); + IQueryAssociations_Release(qa2); }
- hr = IUnknown_QueryInterface(qa, &IID_IUnknown, (void**)&unk); + hr = IQueryAssociations_QueryInterface(qa, &IID_IUnknown, (void**)&unk); ok(hr == S_OK, "QueryInterface (IUnknown) returned 0x%x\n", hr); if (SUCCEEDED(hr)) { IUnknown_Release(unk); }
- hr = IUnknown_QueryInterface(qa, &IID_IUnknown, NULL); + hr = IQueryAssociations_QueryInterface(qa, &IID_IUnknown, NULL); ok(hr == E_POINTER, "got 0x%x (expected E_POINTER)\n", hr);
IQueryAssociations_Release(qa); @@ -78,19 +78,20 @@ return; }
- hr = IUnknown_QueryInterface(appreg, &IID_IApplicationAssociationRegistration, (void**)&appreg2); + hr = IApplicationAssociationRegistration_QueryInterface(appreg, &IID_IApplicationAssociationRegistration, + (void**)&appreg2); ok(hr == S_OK, "QueryInterface (IApplicationAssociationRegistration) returned 0x%x\n", hr); if (SUCCEEDED(hr)) { - IUnknown_Release(appreg2); + IApplicationAssociationRegistration_Release(appreg2); }
- hr = IUnknown_QueryInterface(appreg, &IID_IUnknown, (void**)&unk); + hr = IApplicationAssociationRegistration_QueryInterface(appreg, &IID_IUnknown, (void**)&unk); ok(hr == S_OK, "QueryInterface (IUnknown) returned 0x%x\n", hr); if (SUCCEEDED(hr)) { IUnknown_Release(unk); }
- hr = IUnknown_QueryInterface(appreg, &IID_IUnknown, NULL); + hr = IApplicationAssociationRegistration_QueryInterface(appreg, &IID_IUnknown, NULL); ok(hr == E_POINTER, "got 0x%x (expected E_POINTER)\n", hr);
IApplicationAssociationRegistration_Release(appreg);
Modified: trunk/rostests/winetests/shell32/shelldispatch.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/shelldis... ============================================================================== --- trunk/rostests/winetests/shell32/shelldispatch.c [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/shelldispatch.c [iso-8859-1] Sun Dec 9 22:05:54 2012 @@ -140,7 +140,7 @@ p = path + lstrlenW(path); while (path < p && *(p - 1) != '\') p--; - ok(!lstrcmpW(title, p), "expected %s, got %s\n", + ok(!lstrcmpiW(title, p), "expected %s, got %s\n", wine_dbgstr_w(p), wine_dbgstr_w(title)); } else skip("skipping Folder::get_Title test\n"); @@ -157,7 +157,7 @@ r = FolderItem_get_Path(item, &item_path); ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r); if (pSHGetFolderPathW) - ok(!lstrcmpW(item_path, path), "expected %s, got %s\n", + ok(!lstrcmpiW(item_path, path), "expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(item_path)); SysFreeString(item_path); FolderItem_Release(item); @@ -360,7 +360,7 @@ ok(V_BOOL(&v) == VARIANT_FALSE, "got %d\n", V_BOOL(&v)); SysFreeString(name);
- IShellDispatch_Release(sd); + IShellDispatch2_Release(sd); }
START_TEST(shelldispatch)
Modified: trunk/rostests/winetests/shell32/shelllink.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/shelllin... ============================================================================== --- trunk/rostests/winetests/shell32/shelllink.c [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/shelllink.c [iso-8859-1] Sun Dec 9 22:05:54 2012 @@ -16,9 +16,6 @@ * 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 - * This is a test program for the SHGet{Special}Folder{Path|Location} functions - * of shell32, that get either a filesystem path or a LPITEMIDLIST (shell - * namespace) path for a given folder (CSIDL value). * */
@@ -37,15 +34,10 @@ # define SLDF_HAS_LOGO3ID 0x00000800 /* not available in the Vista SDK */ #endif
-typedef void (WINAPI *fnILFree)(LPITEMIDLIST); -typedef BOOL (WINAPI *fnILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST); -typedef HRESULT (WINAPI *fnSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*); -typedef HRESULT (WINAPI *fnSHDefExtractIconA)(LPCSTR, int, UINT, HICON*, HICON*, UINT); - -static fnILFree pILFree; -static fnILIsEqual pILIsEqual; -static fnSHILCreateFromPath pSHILCreateFromPath; -static fnSHDefExtractIconA pSHDefExtractIconA; +static void (WINAPI *pILFree)(LPITEMIDLIST); +static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST); +static HRESULT (WINAPI *pSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*); +static HRESULT (WINAPI *pSHDefExtractIconA)(LPCSTR, int, UINT, HICON*, HICON*, UINT);
static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR, LPSTR, DWORD); static DWORD (WINAPI *pGetShortPathNameA)(LPCSTR, LPSTR, DWORD); @@ -422,7 +414,7 @@ lok(r == S_OK, "SetHotkey failed (0x%08x)\n", r); }
- r = IShellLinkW_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf); + r = IShellLinkA_QueryInterface(sl, &IID_IPersistFile, (void**)&pf); lok(r == S_OK, "no IID_IPersistFile (0x%08x)\n", r); if (r == S_OK) { @@ -907,7 +899,7 @@
LocalFree( dar );
- IUnknown_Release( dl ); + IShellLinkDataList_Release( dl ); IShellLinkW_Release( sl ); }
@@ -1005,10 +997,10 @@ HMODULE hmod = GetModuleHandleA("shell32.dll"); HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
- pILFree = (fnILFree) GetProcAddress(hmod, (LPSTR)155); - pILIsEqual = (fnILIsEqual) GetProcAddress(hmod, (LPSTR)21); - pSHILCreateFromPath = (fnSHILCreateFromPath) GetProcAddress(hmod, (LPSTR)28); - pSHDefExtractIconA = (fnSHDefExtractIconA) GetProcAddress(hmod, "SHDefExtractIconA"); + pILFree = (void *)GetProcAddress(hmod, (LPSTR)155); + pILIsEqual = (void *)GetProcAddress(hmod, (LPSTR)21); + pSHILCreateFromPath = (void *)GetProcAddress(hmod, (LPSTR)28); + pSHDefExtractIconA = (void *)GetProcAddress(hmod, "SHDefExtractIconA");
pGetLongPathNameA = (void *)GetProcAddress(hkernel32, "GetLongPathNameA"); pGetShortPathNameA = (void *)GetProcAddress(hkernel32, "GetShortPathNameA");
Modified: trunk/rostests/winetests/shell32/shellpath.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/shellpat... ============================================================================== --- trunk/rostests/winetests/shell32/shellpath.c [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/shellpath.c [iso-8859-1] Sun Dec 9 22:05:54 2012 @@ -30,9 +30,10 @@ #include "shlguid.h" #include "shlobj.h" #include "shlwapi.h" -#include "initguid.h" #include "knownfolders.h" #include "wine/test.h" + +#include "initguid.h"
/* CSIDL_MYDOCUMENTS is now the same as CSIDL_PERSONAL, but what we want * here is its original value. @@ -2494,6 +2495,157 @@ CoUninitialize(); }
+ +static void test_DoEnvironmentSubst(void) +{ + WCHAR expectedW[MAX_PATH]; + WCHAR bufferW[MAX_PATH]; + CHAR expectedA[MAX_PATH]; + CHAR bufferA[MAX_PATH]; + DWORD res; + DWORD res2; + DWORD len; + INT i; + static const WCHAR does_not_existW[] = {'%','D','O','E','S','_','N','O','T','_','E','X','I','S','T','%',0}; + static const CHAR does_not_existA[] = "%DOES_NOT_EXIST%"; + static const CHAR *names[] = { + /* interactive apps and services (works on all windows versions) */ + "%ALLUSERSPROFILE%", "%APPDATA%", "%LOCALAPPDATA%", + "%NUMBER_OF_PROCESSORS%", "%OS%", "%PROCESSOR_ARCHITECTURE%", + "%PROCESSOR_IDENTIFIER%", "%PROCESSOR_LEVEL%", "%PROCESSOR_REVISION%", + "%ProgramFiles%", "%SystemDrive%", + "%SystemRoot%", "%USERPROFILE%", "%windir%", + /* todo_wine: "%COMPUTERNAME%", "%ProgramData%", "%PUBLIC%", */ + + /* replace more than one var is allowed */ + "%HOMEDRIVE%%HOMEPATH%", + "%OS% %windir%"}; /* always the last entry in the table */ + + for (i = 0; i < (sizeof(names)/sizeof(LPSTR)); i++) + { + memset(bufferA, '#', MAX_PATH - 1); + bufferA[MAX_PATH - 1] = 0; + lstrcpyA(bufferA, names[i]); + MultiByteToWideChar(CP_ACP, 0, bufferA, MAX_PATH, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + + res2 = ExpandEnvironmentStringsA(names[i], expectedA, MAX_PATH); + res = DoEnvironmentSubstA(bufferA, MAX_PATH); + + /* is the space for the terminating 0 included? */ + if (!i && HIWORD(res) && (LOWORD(res) == (lstrlenA(bufferA)))) + { + win_skip("DoEnvironmentSubstA/W are broken on NT 4\n"); + return; + } + ok(HIWORD(res) && (LOWORD(res) == res2), + "%d: got %d/%d (expected TRUE/%d)\n", i, HIWORD(res), LOWORD(res), res2); + ok(!lstrcmpA(bufferA, expectedA), + "%d: got %s (expected %s)\n", i, bufferA, expectedA); + + res2 = ExpandEnvironmentStringsW(bufferW, expectedW, MAX_PATH); + res = DoEnvironmentSubstW(bufferW, MAX_PATH); + ok(HIWORD(res) && (LOWORD(res) == res2), + "%d: got %d/%d (expected TRUE/%d)\n", i, HIWORD(res), LOWORD(res), res2); + ok(!lstrcmpW(bufferW, expectedW), + "%d: got %s (expected %s)\n", i, wine_dbgstr_w(bufferW), wine_dbgstr_w(expectedW)); + } + + i--; /* reuse data in the last table entry */ + len = LOWORD(res); /* needed length */ + + /* one character extra is fine */ + memset(bufferA, '#', MAX_PATH - 1); + bufferA[len + 2] = 0; + lstrcpyA(bufferA, names[i]); + MultiByteToWideChar(CP_ACP, 0, bufferA, MAX_PATH, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + + res2 = ExpandEnvironmentStringsA(bufferA, expectedA, MAX_PATH); + res = DoEnvironmentSubstA(bufferA, len + 1); + ok(HIWORD(res) && (LOWORD(res) == res2), + "+1: got %d/%d (expected TRUE/%d)\n", HIWORD(res), LOWORD(res), res2); + ok(!lstrcmpA(bufferA, expectedA), + "+1: got %s (expected %s)\n", bufferA, expectedA); + + res2 = ExpandEnvironmentStringsW(bufferW, expectedW, MAX_PATH); + res = DoEnvironmentSubstW(bufferW, len + 1); + ok(HIWORD(res) && (LOWORD(res) == res2), + "+1: got %d/%d (expected TRUE/%d)\n", HIWORD(res), LOWORD(res), res2); + ok(!lstrcmpW(bufferW, expectedW), + "+1: got %s (expected %s)\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(expectedW)); + + + /* minimal buffer length (result string and terminating 0) */ + memset(bufferA, '#', MAX_PATH - 1); + bufferA[len + 2] = 0; + lstrcpyA(bufferA, names[i]); + MultiByteToWideChar(CP_ACP, 0, bufferA, MAX_PATH, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + + /* ANSI version failed without an extra byte, as documented on msdn */ + res = DoEnvironmentSubstA(bufferA, len); + ok(!HIWORD(res) && (LOWORD(res) == len), + " 0: got %d/%d (expected FALSE/%d)\n", HIWORD(res), LOWORD(res), len); + ok(!lstrcmpA(bufferA, names[i]), + " 0: got %s (expected %s)\n", bufferA, names[i]); + + /* DoEnvironmentSubstW works as expected */ + res2 = ExpandEnvironmentStringsW(bufferW, expectedW, MAX_PATH); + res = DoEnvironmentSubstW(bufferW, len); + ok(HIWORD(res) && (LOWORD(res) == res2), + " 0: got %d/%d (expected TRUE/%d)\n", HIWORD(res), LOWORD(res), res2); + ok(!lstrcmpW(bufferW, expectedW), + " 0: got %s (expected %s)\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(expectedW)); + + + /* buffer to small */ + /* result: FALSE / provided buffer length / the buffer is untouched */ + memset(bufferA, '#', MAX_PATH - 1); + bufferA[len + 2] = 0; + lstrcpyA(bufferA, names[i]); + MultiByteToWideChar(CP_ACP, 0, bufferA, MAX_PATH, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + + res = DoEnvironmentSubstA(bufferA, len - 1); + ok(!HIWORD(res) && (LOWORD(res) == (len - 1)), + "-1: got %d/%d (expected FALSE/%d)\n", HIWORD(res), LOWORD(res), len - 1); + ok(!lstrcmpA(bufferA, names[i]), + "-1: got %s (expected %s)\n", bufferA, names[i]); + + lstrcpyW(expectedW, bufferW); + res = DoEnvironmentSubstW(bufferW, len - 1); + ok(!HIWORD(res) && (LOWORD(res) == (len - 1)), + "-1: got %d/%d (expected FALSE/%d)\n", HIWORD(res), LOWORD(res), len - 1); + ok(!lstrcmpW(bufferW, expectedW), + "-1: got %s (expected %s)\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(expectedW)); + + + /* unknown variable */ + /* result: TRUE / string length including terminating 0 / the buffer is untouched */ + memset(bufferA, '#', MAX_PATH - 1); + bufferA[MAX_PATH - 1] = 0; + lstrcpyA(bufferA, does_not_existA); + MultiByteToWideChar(CP_ACP, 0, bufferA, MAX_PATH, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + + res2 = lstrlenA(does_not_existA) + 1; + res = DoEnvironmentSubstA(bufferA, MAX_PATH); + ok(HIWORD(res) && (LOWORD(res) == res2), + "%d: got %d/%d (expected TRUE/%d)\n", i, HIWORD(res), LOWORD(res), res2); + ok(!lstrcmpA(bufferA, does_not_existA), + "%d: got %s (expected %s)\n", i, bufferA, does_not_existA); + + res = DoEnvironmentSubstW(bufferW, MAX_PATH); + ok(HIWORD(res) && (LOWORD(res) == res2), + "%d: got %d/%d (expected TRUE/%d)\n", i, HIWORD(res), LOWORD(res), res2); + ok(!lstrcmpW(bufferW, does_not_existW), + "%d: got %s (expected %s)\n", i, wine_dbgstr_w(bufferW), wine_dbgstr_w(does_not_existW)); + + + if (0) + { + /* NULL crashes on windows */ + res = DoEnvironmentSubstA(NULL, MAX_PATH); + res = DoEnvironmentSubstW(NULL, MAX_PATH); + } +} + START_TEST(shellpath) { if (!init()) return; @@ -2521,5 +2673,6 @@ test_NonExistentPath(); test_SHGetFolderPathEx(); test_knownFolders(); + test_DoEnvironmentSubst(); } }
Modified: trunk/rostests/winetests/shell32/shlexec.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/shlexec.... ============================================================================== --- trunk/rostests/winetests/shell32/shlexec.c [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/shlexec.c [iso-8859-1] Sun Dec 9 22:05:54 2012 @@ -57,7 +57,7 @@ static char child_file[MAX_PATH]; static DLLVERSIONINFO dllver; static BOOL skip_noassoc_tests = FALSE; -//static HANDLE dde_ready_event; FIXME: bug 7233 +//static HANDLE dde_ready_event; FIXME: CORE-6559
/*** @@ -75,36 +75,36 @@ hEvent=CreateEvent(NULL, FALSE, FALSE, event_name); }
-static void strcat_param(char* str, const char* param) -{ - if (param!=NULL) - { - strcat(str, """); +static void strcat_param(char* str, const char* name, const char* param) +{ + if (param) + { + if (str[strlen(str)-1] == '"') + strcat(str, ", "); + strcat(str, name); + strcat(str, "=""); strcat(str, param); strcat(str, """); } - else - { - strcat(str, "null"); - } -} +} + +static int _todo_wait = 0; +#define todo_wait for (_todo_wait = 1; _todo_wait; _todo_wait = 0)
static char shell_call[2048]=""; -static int shell_execute(LPCSTR operation, LPCSTR file, LPCSTR parameters, LPCSTR directory) +static int bad_shellexecute = 0; +static INT_PTR shell_execute(LPCSTR verb, LPCSTR file, LPCSTR parameters, LPCSTR directory) { INT_PTR rc, rcEmpty = 0;
- if(!operation) + if(!verb) rcEmpty = shell_execute("", file, parameters, directory);
strcpy(shell_call, "ShellExecute("); - strcat_param(shell_call, operation); - strcat(shell_call, ", "); - strcat_param(shell_call, file); - strcat(shell_call, ", "); - strcat_param(shell_call, parameters); - strcat(shell_call, ", "); - strcat_param(shell_call, directory); + strcat_param(shell_call, "verb", verb); + strcat_param(shell_call, "file", file); + strcat_param(shell_call, "params", parameters); + strcat_param(shell_call, "dir", directory); strcat(shell_call, ")"); if (winetest_debug > 1) trace("%s\n", shell_call); @@ -116,7 +116,7 @@ * association it displays the 'Open With' dialog and I could not find * a flag to prevent this. */ - rc=(INT_PTR)ShellExecute(NULL, operation, file, parameters, directory, SW_SHOWNORMAL); + rc=(INT_PTR)ShellExecute(NULL, verb, file, parameters, directory, SW_SHOWNORMAL);
if (rc > 32) { @@ -133,7 +133,10 @@ rc = SE_ERR_NOASSOC; } } - ok(wait_rc==WAIT_OBJECT_0 || rc <= 32, "WaitForSingleObject returned %d\n", wait_rc); + if (!_todo_wait) + ok(wait_rc==WAIT_OBJECT_0 || rc <= 32, "%s WaitForSingleObject returned %d\n", shell_call, wait_rc); + else todo_wine + ok(wait_rc==WAIT_OBJECT_0 || rc <= 32, "%s WaitForSingleObject returned %d\n", shell_call, wait_rc); } /* The child process may have changed the result file, so let profile * functions know about it @@ -142,28 +145,37 @@ if (rc > 32) dump_child();
- if(!operation) - ok(rc == rcEmpty || broken(rc > 32 && rcEmpty == SE_ERR_NOASSOC) /* NT4 */, - "Got different return value with empty string: %lu %lu\n", rc, rcEmpty); + if(!verb) + { + if (rc != rcEmpty && rcEmpty == SE_ERR_NOASSOC) /* NT4 */ + bad_shellexecute = 1; + ok(rc == rcEmpty || broken(rc != rcEmpty && rcEmpty == SE_ERR_NOASSOC) /* NT4 */, + "%s Got different return value with empty string: %lu %lu\n", shell_call, rc, rcEmpty); + }
return rc; }
-static int shell_execute_ex(DWORD mask, LPCSTR operation, LPCSTR file, - LPCSTR parameters, LPCSTR directory) +static INT_PTR shell_execute_ex(DWORD mask, LPCSTR verb, LPCSTR file, + LPCSTR parameters, LPCSTR directory, + LPCSTR class) { SHELLEXECUTEINFO sei; BOOL success; INT_PTR rc;
strcpy(shell_call, "ShellExecuteEx("); - strcat_param(shell_call, operation); - strcat(shell_call, ", "); - strcat_param(shell_call, file); - strcat(shell_call, ", "); - strcat_param(shell_call, parameters); - strcat(shell_call, ", "); - strcat_param(shell_call, directory); + if (mask) + { + char smask[11]; + sprintf(smask, "0x%x", mask); + strcat_param(shell_call, "mask", smask); + } + strcat_param(shell_call, "verb", verb); + strcat_param(shell_call, "file", file); + strcat_param(shell_call, "params", parameters); + strcat_param(shell_call, "dir", directory); + strcat_param(shell_call, "class", class); strcat(shell_call, ")"); if (winetest_debug > 1) trace("%s\n", shell_call); @@ -171,14 +183,14 @@ sei.cbSize=sizeof(sei); sei.fMask=SEE_MASK_NOCLOSEPROCESS | mask; sei.hwnd=NULL; - sei.lpVerb=operation; + sei.lpVerb=verb; sei.lpFile=file; sei.lpParameters=parameters; sei.lpDirectory=directory; sei.nShow=SW_SHOWNORMAL; sei.hInstApp=NULL; /* Out */ sei.lpIDList=NULL; - sei.lpClass=NULL; + sei.lpClass=class; sei.hkeyClass=NULL; sei.dwHotKey=0; U(sei).hIcon=NULL; @@ -200,7 +212,10 @@ ok(wait_rc==WAIT_OBJECT_0, "WaitForSingleObject(hProcess) returned %d\n", wait_rc); } wait_rc=WaitForSingleObject(hEvent, 5000); - ok(wait_rc==WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", wait_rc); + if (!_todo_wait) + ok(wait_rc==WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", wait_rc); + else todo_wine + ok(wait_rc==WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", wait_rc); } /* The child process may have changed the result file, so let profile * functions know about it @@ -552,12 +567,16 @@ /* Arguments */ childPrintf(hFile, "[Arguments]\r\n"); if (winetest_debug > 2) + { + trace("cmdlineA='%s'\n", GetCommandLineA()); trace("argcA=%d\n", argc); + } + childPrintf(hFile, "cmdlineA=%s\r\n", encodeA(GetCommandLineA())); childPrintf(hFile, "argcA=%d\r\n", argc); for (i = 0; i < argc; i++) { if (winetest_debug > 2) - trace("argvA%d=%s\n", i, argv[i]); + trace("argvA%d='%s'\n", i, argv[i]); childPrintf(hFile, "argvA%d=%s\r\n", i, encodeA(argv[i])); } GetModuleFileNameA(GetModuleHandleA(NULL), longpath, MAX_PATH); @@ -635,13 +654,15 @@ char* str; int i, c;
+ str=getChildString("Arguments", "cmdlineA"); + trace("cmdlineA='%s'\n", str); c=GetPrivateProfileIntA("Arguments", "argcA", -1, child_file); trace("argcA=%d\n",c); for (i=0;i<c;i++) { sprintf(key, "argvA%d", i); str=getChildString("Arguments", key); - trace("%s=%s\n", key, str); + trace("%s='%s'\n", key, str); } } } @@ -683,7 +704,7 @@ return 0; }
-static void _okChildString(const char* file, int line, const char* key, const char* expected) +static void _okChildString(const char* file, int line, const char* key, const char* expected, const char* bad) { char* result; result=getChildString("Arguments", key); @@ -692,7 +713,8 @@ ok_(file, line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected); return; } - ok_(file, line)(lstrcmpiA(result, expected) == 0, + ok_(file, line)(lstrcmpiA(result, expected) == 0 || + broken(lstrcmpiA(result, bad) == 0), "%s expected '%s', got '%s'\n", key, expected, result); }
@@ -717,7 +739,8 @@ "%s expected %d, but got %d\n", key, expected, result); }
-#define okChildString(key, expected) _okChildString(__FILE__, __LINE__, (key), (expected)) +#define okChildString(key, expected) _okChildString(__FILE__, __LINE__, (key), (expected), (expected)) +#define okChildStringBroken(key, expected, broken) _okChildString(__FILE__, __LINE__, (key), (expected), (broken)) #define okChildPath(key, expected) _okChildPath(__FILE__, __LINE__, (key), (expected)) #define okChildInt(key, expected) _okChildInt(__FILE__, __LINE__, (key), (expected))
@@ -793,26 +816,6 @@ }
return tmplen; -} - -/*** - * - * PathFindFileNameA equivalent that supports WinNT - * - ***/ - -static LPSTR path_find_file_name(LPCSTR lpszPath) -{ - LPCSTR lastSlash = lpszPath; - - while (lpszPath && *lpszPath) - { - if ((*lpszPath == '\' || *lpszPath == '/' || *lpszPath == ':') && - lpszPath[1] && lpszPath[1] != '\' && lpszPath[1] != '/') - lastSlash = lpszPath + 1; - lpszPath = CharNext(lpszPath); - } - return (LPSTR)lastSlash; }
/*** @@ -850,7 +853,7 @@ const char* verb; const char* basename; int todo; - int rc; + INT_PTR rc; } filename_tests_t;
static filename_tests_t filename_tests[]= @@ -899,235 +902,559 @@
static void test_lpFile_parsed(void) { - /* basename tmpdir */ - const char* shorttmpdir; - - const char *testfile; char fileA[MAX_PATH]; - - int rc; - - GetTempPathA(sizeof(fileA), fileA); - shorttmpdir = tmpdir + strlen(fileA); - - /* ensure tmpdir is in %TEMP%: GetTempPath() can succeed even if TEMP is undefined */ - SetEnvironmentVariableA("TEMP", fileA); + INT_PTR rc;
/* existing "drawback_file.noassoc" prevents finding "drawback_file.noassoc foo.shlexec" on wine */ - testfile = "%s\drawback_file.noassoc foo.shlexec"; - sprintf(fileA, testfile, tmpdir); + sprintf(fileA, "%s\drawback_file.noassoc foo.shlexec", tmpdir); rc=shell_execute(NULL, fileA, NULL, NULL); - todo_wine { - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - } + todo_wine ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc);
/* if quoted, existing "drawback_file.noassoc" not prevents finding "drawback_file.noassoc foo.shlexec" on wine */ - testfile = ""%s\drawback_file.noassoc foo.shlexec""; - sprintf(fileA, testfile, tmpdir); + sprintf(fileA, ""%s\drawback_file.noassoc foo.shlexec"", tmpdir); rc=shell_execute(NULL, fileA, NULL, NULL); - ok(rc>32 || broken(rc == 2) /* Win95/NT4 */, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - - /* error should be 2, not 31 */ - testfile = ""%s\drawback_file.noassoc" foo.shlexec"; - sprintf(fileA, testfile, tmpdir); + ok(rc > 32 || broken(rc == SE_ERR_FNF) /* Win95/NT4 */, + "%s failed: rc=%lu\n", shell_call, rc); + + /* error should be SE_ERR_FNF, not SE_ERR_NOASSOC */ + sprintf(fileA, ""%s\drawback_file.noassoc" foo.shlexec", tmpdir); rc=shell_execute(NULL, fileA, NULL, NULL); - ok(rc==2, - "expected failure (2), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); + ok(rc == SE_ERR_FNF, "%s succeeded: rc=%lu\n", shell_call, rc);
/* ""command"" not works on wine (and real win9x and w2k) */ - testfile = """%s\simple.shlexec"""; - sprintf(fileA, testfile, tmpdir); + sprintf(fileA, """%s\simple.shlexec""", tmpdir); rc=shell_execute(NULL, fileA, NULL, NULL); - todo_wine { - ok(rc>32 || broken(rc == 2) /* Win9x/2000 */, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - } + todo_wine ok(rc > 32 || broken(rc == SE_ERR_FNF) /* Win9x/2000 */, + "%s failed: rc=%lu\n", shell_call, rc);
/* nonexisting "drawback_nonexist.noassoc" not prevents finding "drawback_nonexist.noassoc foo.shlexec" on wine */ - testfile = "%s\drawback_nonexist.noassoc foo.shlexec"; - sprintf(fileA, testfile, tmpdir); + sprintf(fileA, "%s\drawback_nonexist.noassoc foo.shlexec", tmpdir); rc=shell_execute(NULL, fileA, NULL, NULL); - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); + ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc);
/* is SEE_MASK_DOENVSUBST default flag? Should only be when XP emulates 9x (XP bug or real 95 or ME behavior ?) */ - testfile = "%%TEMP%%\%s\simple.shlexec"; - sprintf(fileA, testfile, shorttmpdir); - rc=shell_execute(NULL, fileA, NULL, NULL); - todo_wine { - ok(rc==2, - "expected failure (2), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - } + rc=shell_execute(NULL, "%TMPDIR%\simple.shlexec", NULL, NULL); + todo_wine ok(rc == SE_ERR_FNF, "%s succeeded: rc=%lu\n", shell_call, rc);
/* quoted */ - testfile = ""%%TEMP%%\%s\simple.shlexec""; - sprintf(fileA, testfile, shorttmpdir); - rc=shell_execute(NULL, fileA, NULL, NULL); - todo_wine { - ok(rc==2, - "expected failure (2), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - } + rc=shell_execute(NULL, ""%TMPDIR%\simple.shlexec"", NULL, NULL); + todo_wine ok(rc == SE_ERR_FNF, "%s succeeded: rc=%lu\n", shell_call, rc);
/* test SEE_MASK_DOENVSUBST works */ - testfile = "%%TEMP%%\%s\simple.shlexec"; - sprintf(fileA, testfile, shorttmpdir); - rc=shell_execute_ex(SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI, NULL, fileA, NULL, NULL); - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - - /* quoted lpFile not works only on real win95 and nt4 */ - testfile = ""%%TEMP%%\%s\simple.shlexec""; - sprintf(fileA, testfile, shorttmpdir); - rc=shell_execute_ex(SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI, NULL, fileA, NULL, NULL); - ok(rc>32 || broken(rc == 2) /* Win95/NT4 */, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - -} + rc=shell_execute_ex(SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI, + NULL, "%TMPDIR%\simple.shlexec", NULL, NULL, NULL); + ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc); + + /* quoted lpFile does not work on real win95 and nt4 */ + rc=shell_execute_ex(SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI, + NULL, ""%TMPDIR%\simple.shlexec"", NULL, NULL, NULL); + ok(rc > 32 || broken(rc == SE_ERR_FNF) /* Win95/NT4 */, + "%s failed: rc=%lu\n", shell_call, rc); +} + +typedef struct +{ + const char* cmd; + const char* args[11]; + int todo; +} cmdline_tests_t; + +static const cmdline_tests_t cmdline_tests[] = +{ + {"exe", + {"exe", NULL}, 0}, + + {"exe arg1 arg2 "arg three" 'four five` six\ $even)", + {"exe", "arg1", "arg2", "arg three", "'four", "five`", "six\", "$even)", NULL}, 0}, + + {"exe arg=1 arg-2 three\tfour\rfour\nfour ", + {"exe", "arg=1", "arg-2", "three", "four\rfour\nfour", NULL}, 0}, + + {"exe arg"one" "second"arg thirdarg ", + {"exe", "argone", "secondarg", "thirdarg", NULL}, 0}, + + /* Don't lose unclosed quoted arguments */ + {"exe arg1 "unclosed", + {"exe", "arg1", "unclosed", NULL}, 0}, + + {"exe arg1 "", + {"exe", "arg1", "", NULL}, 0}, + + /* cmd's metacharacters have no special meaning */ + {"exe "one^" "arg"&two three|four", + {"exe", "one^", "arg&two", "three|four", NULL}, 0}, + + /* Environment variables are not interpreted either */ + {"exe %TMPDIR% %2", + {"exe", "%TMPDIR%", "%2", NULL}, 0}, + + /* If not followed by a quote, backslashes go through as is */ + {"exe o\ne t\\wo t\\\ree f\\\\our ", + {"exe", "o\ne", "t\\wo", "t\\\ree", "f\\\\our", NULL}, 0}, + + {"exe "o\ne" "t\\wo" "t\\\ree" "f\\\\our" ", + {"exe", "o\ne", "t\\wo", "t\\\ree", "f\\\\our", NULL}, 0}, + + /* When followed by a quote their number is halved and the remainder + * escapes the quote + */ + {"exe \"one \\"two" \\\"three \\\\"four" end", + {"exe", ""one", "\two", "\"three", "\\four", "end", NULL}, 0}, + + {"exe "one\" still" "two\\" "three\\\" still" "four\\\\" end", + {"exe", "one" still", "two\", "three\" still", "four\\", "end", NULL}, 0}, + + /* One can put a quote in an unquoted string by tripling it, that is in + * effect quoting it like so """ -> ". The general rule is as follows: + * 3n quotes -> n quotes + * 3n+1 quotes -> n quotes plus start of a quoted string + * 3n+2 quotes -> n quotes (plus an empty string from the remaining pair) + * Nicely, when n is 0 we get the standard rules back. + */ + {"exe two""quotes next", + {"exe", "twoquotes", "next", NULL}, 0}, + + {"exe three"""quotes next", + {"exe", "three"quotes", "next", NULL}, 0}, + + {"exe four"""" quotes" next 4%3=1", + {"exe", "four" quotes", "next", "4%3=1", NULL}, 0}, + + {"exe five"""""quotes next", + {"exe", "five"quotes", "next", NULL}, 0}, + + {"exe six""""""quotes next", + {"exe", "six""quotes", "next", NULL}, 0}, + + {"exe seven""""""" quotes" next 7%3=1", + {"exe", "seven"" quotes", "next", "7%3=1", NULL}, 0}, + + {"exe twelve""""""""""""quotes next", + {"exe", "twelve""""quotes", "next", NULL}, 0}, + + {"exe thirteen""""""""""""" quotes" next 13%3=1", + {"exe", "thirteen"""" quotes", "next", "13%3=1", NULL}, 0}, + + /* Inside a quoted string the opening quote is added to the set of + * consecutive quotes to get the effective quotes count. This gives: + * 1+3n quotes -> n quotes + * 1+3n+1 quotes -> n quotes plus closes the quoted string + * 1+3n+2 quotes -> n+1 quotes plus closes the quoted string + */ + {"exe "two""quotes next", + {"exe", "two"quotes", "next", NULL}, 0}, + + {"exe "two"" next", + {"exe", "two"", "next", NULL}, 0}, + + {"exe "three""" quotes" next 4%3=1", + {"exe", "three" quotes", "next", "4%3=1", NULL}, 0}, + + {"exe "four""""quotes next", + {"exe", "four"quotes", "next", NULL}, 0}, + + {"exe "five"""""quotes next", + {"exe", "five""quotes", "next", NULL}, 0}, + + {"exe "six"""""" quotes" next 7%3=1", + {"exe", "six"" quotes", "next", "7%3=1", NULL}, 0}, + + {"exe "eleven"""""""""""quotes next", + {"exe", "eleven""""quotes", "next", NULL}, 0}, + + {"exe "twelve"""""""""""" quotes" next 13%3=1", + {"exe", "twelve"""" quotes", "next", "13%3=1", NULL}, 0}, + + /* Escaped consecutive quotes are fun */ + {"exe "the crazy \\"""\\" quotes", + {"exe", "the crazy \"\", "quotes", NULL}, 0}, + + /* The executable path has its own rules!!! + * - Backslashes have no special meaning. + * - If the first character is a quote, then the second quote ends the + * executable path. + * - The previous rule holds even if the next character is not a space! + * - If the first character is not a quote, then quotes have no special + * meaning either and the executable path stops at the first space. + * - The consecutive quotes rules don't apply either. + * - Even if there is no space between the executable path and the first + * argument, the latter is parsed using the regular rules. + */ + {"exe"file"path arg1", + {"exe"file"path", "arg1", NULL}, 0}, + + {"exe"file"path\targ1", + {"exe"file"path", "arg1", NULL}, 0}, + + {"exe"path\ arg1", + {"exe"path\", "arg1", NULL}, 0}, + + {"\"exe "arg one"", + {"\"exe", "arg one", NULL}, 0}, + + {""spaced exe" "next arg"", + {"spaced exe", "next arg", NULL}, 0}, + + {""spaced exe"\t"next arg"", + {"spaced exe", "next arg", NULL}, 0}, + + {""exe"arg" one" argtwo", + {"exe", "arg one", "argtwo", NULL}, 0}, + + {""spaced exe\"arg1 arg2", + {"spaced exe\", "arg1", "arg2", NULL}, 0}, + + {""two"" arg1 ", + {"two", " arg1 ", NULL}, 0}, + + {""three""" arg2", + {"three", "", "arg2", NULL}, 0}, + + {""four""""arg1", + {"four", ""arg1", NULL}, 0}, + + /* If the first character is a space then the executable path is empty */ + {" "arg"one argtwo", + {"", "argone", "argtwo", NULL}, 0}, + + {NULL, {NULL}, 0} +}; + +static BOOL test_one_cmdline(const cmdline_tests_t* test) +{ + WCHAR cmdW[MAX_PATH], argW[MAX_PATH]; + LPWSTR *cl2a; + int cl2a_count; + LPWSTR *argsW; + int i, count; + + /* trace("----- cmd='%s'\n", test->cmd); */ + MultiByteToWideChar(CP_ACP, 0, test->cmd, -1, cmdW, sizeof(cmdW)/sizeof(*cmdW)); + argsW = cl2a = CommandLineToArgvW(cmdW, &cl2a_count); + if (argsW == NULL && cl2a_count == -1) + { + win_skip("CommandLineToArgvW not implemented, skipping\n"); + return FALSE; + } + + count = 0; + while (test->args[count]) + count++; + if ((test->todo & 0x1) == 0) + ok(cl2a_count == count, "%s: expected %d arguments, but got %d\n", test->cmd, count, cl2a_count); + else todo_wine + ok(cl2a_count == count, "%s: expected %d arguments, but got %d\n", test->cmd, count, cl2a_count); + + for (i = 0; i < cl2a_count; i++) + { + if (i < count) + { + MultiByteToWideChar(CP_ACP, 0, test->args[i], -1, argW, sizeof(argW)/sizeof(*argW)); + if ((test->todo & (1 << (i+4))) == 0) + ok(!lstrcmpW(*argsW, argW), "%s: arg[%d] expected %s but got %s\n", test->cmd, i, wine_dbgstr_w(argW), wine_dbgstr_w(*argsW)); + else todo_wine + ok(!lstrcmpW(*argsW, argW), "%s: arg[%d] expected %s but got %s\n", test->cmd, i, wine_dbgstr_w(argW), wine_dbgstr_w(*argsW)); + } + else if ((test->todo & 0x1) == 0) + ok(0, "%s: got extra arg[%d]=%s\n", test->cmd, i, wine_dbgstr_w(*argsW)); + else todo_wine + ok(0, "%s: got extra arg[%d]=%s\n", test->cmd, i, wine_dbgstr_w(*argsW)); + argsW++; + } + LocalFree(cl2a); + return TRUE; +} + +static void test_commandline2argv(void) +{ + static const WCHAR exeW[] = {'e','x','e',0}; + const cmdline_tests_t* test; + WCHAR strW[MAX_PATH]; + LPWSTR *args; + int numargs; + DWORD le; + + test = cmdline_tests; + while (test->cmd) + { + if (!test_one_cmdline(test)) + return; + test++; + } + + SetLastError(0xdeadbeef); + args = CommandLineToArgvW(exeW, NULL); + le = GetLastError(); + ok(args == NULL && le == ERROR_INVALID_PARAMETER, "expected NULL with ERROR_INVALID_PARAMETER got %p with %u\n", args, le); + + SetLastError(0xdeadbeef); + args = CommandLineToArgvW(NULL, NULL); + le = GetLastError(); + ok(args == NULL && le == ERROR_INVALID_PARAMETER, "expected NULL with ERROR_INVALID_PARAMETER got %p with %u\n", args, le); + + *strW = 0; + args = CommandLineToArgvW(strW, &numargs); + ok(numargs == 1, "expected 1 args, got %d\n", numargs); + if (numargs == 1) + { + GetModuleFileNameW(NULL, strW, sizeof(strW)/sizeof(*strW)); + ok(!lstrcmpW(args[0], strW), "wrong path to the current executable: %s instead of %s\n", wine_dbgstr_w(args[0]), wine_dbgstr_w(strW)); + } + if (args) LocalFree(args); +} + +/* The goal here is to analyze how ShellExecute() builds the command that + * will be run. The tricky part is that there are three transformation + * steps between the 'parameters' string we pass to ShellExecute() and the + * argument list we observe in the child process: + * - The parsing of 'parameters' string into individual arguments. The tests + * show this is done differently from both CreateProcess() and + * CommandLineToArgv()! + * - The way the command 'formatting directives' such as %1, %2, etc are + * handled. + * - And the way the resulting command line is then parsed to yield the + * argument list we check. + */ +typedef struct +{ + const char* verb; + const char* params; + int todo; + cmdline_tests_t cmd; + cmdline_tests_t broken; +} argify_tests_t; + +static const argify_tests_t argify_tests[] = +{ + /* Start with three simple parameters. Notice that one can reorder and + * duplicate the parameters. Also notice how %* take the raw input + * parameters string, including the trailing spaces, no matter what + * arguments have already been used. + */ + {"Params232S", "p2 p3 p4 ", 0xc2, + {" p2 p3 "p2" "p2 p3 p4 "", + {"", "p2", "p3", "p2", "p2 p3 p4 ", NULL}, 0}}, + + /* Unquoted argument references like %2 don't automatically quote their + * argument. Similarly, when they are quoted they don't escape the quotes + * that their argument may contain. + */ + {"Params232S", ""p two" p3 p4 ", 0x3f3, + {" p two p3 "p two" ""p two" p3 p4 "", + {"", "p", "two", "p3", "p two", "p", "two p3 p4 ", NULL}, 0}}, + + /* Only single digits are supported so only %1 to %9. Shown here with %20 + * because %10 is a pain. + */ + {"Params20", "p", 0, + {" "p0"", + {"", "p0", NULL}, 0}}, + + /* Only (double-)quotes have a special meaning. */ + {"Params23456", "'p2 p3` p4\ $even", 0x40, + {" "'p2" "p3`" "p4\" "$even" """, + {"", "'p2", "p3`", "p4" $even "", NULL}, 0}}, + + {"Params23456", "p=2 p-3 p4\tp4\rp4\np4", 0x1c2, + {" "p=2" "p-3" "p4\tp4\rp4\np4" "" """, + {"", "p=2", "p-3", "p4\tp4\rp4\np4", "", "", NULL}, 0}}, + + /* In unquoted strings, quotes are treated are a parameter separator just + * like spaces! However they can be doubled to get a literal quote. + * Specifically: + * 2n quotes -> n quotes + * 2n+1 quotes -> n quotes and a parameter separator + */ + {"Params23456789", "one"quote "p four" one"quote p7", 0xff3, + {" "one" "quote" "p four" "one" "quote" "p7" "" """, + {"", "one", "quote", "p four", "one", "quote", "p7", "", "", NULL}, 0}}, + + {"Params23456789", "two""quotes "p three" two""quotes p5", 0xf2, + {" "two"quotes" "p three" "two"quotes" "p5" "" "" "" """, + {"", "twoquotes p", "three twoquotes", "p5", "", "", "", "", NULL}, 0}}, + + {"Params23456789", "three"""quotes "p four" three"""quotes p6", 0xff3, + {" "three"" "quotes" "p four" "three"" "quotes" "p6" "" """, + {"", "three"", "quotes", "p four", "three"", "quotes", "p6", "", "", NULL}, 0}}, + + {"Params23456789", "four""""quotes "p three" four""""quotes p5", 0xf3, + {" "four""quotes" "p three" "four""quotes" "p5" "" "" "" """, + {"", "four"quotes p", "three fourquotes p5 "", "", "", "", NULL}, 0}}, + + /* Quoted strings cannot be continued by tacking on a non space character + * either. + */ + {"Params23456", ""p two"p3 "p four"p5 p6", 0x1f3, + {" "p two" "p3" "p four" "p5" "p6"", + {"", "p two", "p3", "p four", "p5", "p6", NULL}, 0}}, + + /* In quoted strings, the quotes are halved and an odd number closes the + * string. Specifically: + * 2n quotes -> n quotes + * 2n+1 quotes -> n quotes and closes the string and hence the parameter + */ + {"Params23456789", ""one q"uote "p four" "one q"uote p7", 0xff3, + {" "one q" "uote" "p four" "one q" "uote" "p7" "" """, + {"", "one q", "uote", "p four", "one q", "uote", "p7", "", "", NULL}, 0}}, + + {"Params23456789", ""two "" quotes" "p three" "two "" quotes" p5", 0x1ff3, + {" "two " quotes" "p three" "two " quotes" "p5" "" "" "" """, + {"", "two ", "quotes p", "three two", " quotes", "p5", "", "", "", "", NULL}, 0}}, + + {"Params23456789", ""three q"""uotes "p four" "three q"""uotes p7", 0xff3, + {" "three q"" "uotes" "p four" "three q"" "uotes" "p7" "" """, + {"", "three q"", "uotes", "p four", "three q"", "uotes", "p7", "", "", NULL}, 0}}, + + {"Params23456789", ""four """" quotes" "p three" "four """" quotes" p5", 0xff3, + {" "four "" quotes" "p three" "four "" quotes" "p5" "" "" "" """, + {"", "four "", "quotes p", "three four", "", "quotes p5 "", "", "", "", NULL}, 0}}, + + /* The quoted string rules also apply to consecutive quotes at the start + * of a parameter but don't count the opening quote! + */ + {"Params23456789", """twoquotes "p four" ""twoquotes p7", 0xbf3, + {" "" "twoquotes" "p four" "" "twoquotes" "p7" "" """, + {"", "", "twoquotes", "p four", "", "twoquotes", "p7", "", "", NULL}, 0}}, + + {"Params23456789", """"three quotes" "p three" """three quotes" p5", 0x6f3, + {" ""three quotes" "p three" ""three quotes" "p5" "" "" "" """, + {"", "three", "quotes p", "three "three", "quotes p5 "", "", "", "", NULL}, 0}}, + + {"Params23456789", """""fourquotes "p four" """"fourquotes p7", 0xbf3, + {" """ "fourquotes" "p four" """ "fourquotes" "p7" "" """, + {"", """, "fourquotes", "p four", """, "fourquotes", "p7", "", "", NULL}, 0}}, + + /* An unclosed quoted string gets lost! */ + {"Params23456", "p2 "p3" "p4 is lost", 0x1c3, + {" "p2" "p3" "" "" """, + {"", "p2", "p3", "", "", "", NULL}, 0}, + {" "p2" "p3" "p3" "" """, + {"", "p2", "p3", "p3", "", "", NULL}, 0}}, + + /* Backslashes have no special meaning even when preceding quotes. All + * they do is start an unquoted string. + */ + {"Params23456", "\"p\three "pfour\" pfive", 0x73, + {" "\" "p\three" "pfour\" "pfive" """, + {"", "" p\three pfour"", "pfive", "", NULL}, 0}}, + + /* Environment variables are left untouched. */ + {"Params23456", "%TMPDIR% %t %c", 0, + {" "%TMPDIR%" "%t" "%c" "" """, + {"", "%TMPDIR%", "%t", "%c", "", "", NULL}, 0}}, + + /* %~2 is equivalent to %*. However %~3 and higher include the spaces + * before the parameter! + * (but not the previous parameter's closing quote fortunately) + */ + {"Params2345Etc", "p2 p3 "p4" p5 p6 ", 0x3f3, + {" ~2="p2 p3 "p4" p5 p6 " ~3=" p3 "p4" p5 p6 " ~4=" "p4" p5 p6 " ~5= p5 p6 ", + {"", "~2=p2 p3 p4 p5 p6 ", "~3= p3 p4 p5 p6 ", "~4= p4 p5 p6 ", "~5=", "p5", "p6", NULL}, 0}}, + + /* %~n works even if there is no nth parameter. */ + {"Params9Etc", "p2 p3 p4 p5 p6 p7 p8 ", 0x12, + {" ~9=" "", + {"", "~9= ", NULL}, 0}}, + + {"Params9Etc", "p2 p3 p4 p5 p6 p7 ", 0x12, + {" ~9=""", + {"", "~9=", NULL}, 0}}, + + /* The %~n directives also transmit the tenth parameter and beyond. */ + {"Params9Etc", "p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 and beyond!", 0x12, + {" ~9=" p9 p10 p11 and beyond!"", + {"", "~9= p9 p10 p11 and beyond!", NULL}, 0}}, + + /* Bad formatting directives lose their % sign, except those followed by + * a tilde! Environment variables are not expanded but lose their % sign. + */ + {"ParamsBad", "p2 p3 p4 p5", 0x12, + {" "% - %~ %~0 %~1 %~a %~* a b c TMPDIR"", + {"", "% - %~ %~0 %~1 %~a %~* a b c TMPDIR", NULL}, 0}}, + + {NULL, NULL, 0, {NULL, {NULL}, 0}} +};
static void test_argify(void) { - char fileA[MAX_PATH]; - - int rc; + BOOL has_cl2a = TRUE; + char fileA[MAX_PATH], params[2*MAX_PATH+12]; + INT_PTR rc; + const argify_tests_t* test; + const cmdline_tests_t *bad; + const char* cmd; + unsigned i, count; + + create_test_verb(".shlexec", "Params232S", 0, "Params232S %2 %3 "%2" "%*""); + create_test_verb(".shlexec", "Params23456", 0, "Params23456 "%2" "%3" "%4" "%5" "%6""); + create_test_verb(".shlexec", "Params23456789", 0, "Params23456789 "%2" "%3" "%4" "%5" "%6" "%7" "%8" "%9""); + create_test_verb(".shlexec", "Params2345Etc", 0, "Params2345Etc ~2="%~2" ~3="%~3" ~4="%~4" ~5=%~5"); + create_test_verb(".shlexec", "Params9Etc", 0, "Params9Etc ~9="%~9""); + create_test_verb(".shlexec", "Params20", 0, "Params20 "%20""); + create_test_verb(".shlexec", "ParamsBad", 0, "ParamsBad "%% %- %~ %~0 %~1 %~a %~* %a %b %c %TMPDIR%"");
sprintf(fileA, "%s\test file.shlexec", tmpdir);
- /* %2 */ - rc=shell_execute("NoQuotesParam2", fileA, "a b", NULL); - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - if (rc>32) - { - okChildInt("argcA", 5); - okChildString("argvA4", "a"); - } - - /* %2 */ - /* '"a"""' -> 'a"' */ - rc=shell_execute("NoQuotesParam2", fileA, ""a:""some string"""", NULL); - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - if (rc>32) - { - okChildInt("argcA", 5); - todo_wine { - okChildString("argvA4", "a:some string"); - } - } - - /* %2 */ - /* backslash isn't escape char - * '"a""' -> '"a""' */ - rc=shell_execute("NoQuotesParam2", fileA, ""a:\"some string\""", NULL); - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - if (rc>32) - { - okChildInt("argcA", 5); - todo_wine { - okChildString("argvA4", "a:\"); - } - } - - /* "%2" */ - /* \t isn't whitespace */ - rc=shell_execute("QuotedParam2", fileA, "a\tb c", NULL); - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - if (rc>32) - { - okChildInt("argcA", 5); - todo_wine { - okChildString("argvA4", "a\tb"); - } - } - - /* %* */ - rc=shell_execute("NoQuotesAllParams", fileA, "a b c d e f g h", NULL); - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - if (rc>32) - { - todo_wine { - okChildInt("argcA", 12); - okChildString("argvA4", "a"); - okChildString("argvA11", "h"); - } - } - - /* %* can sometimes contain only whitespaces and no args */ - rc=shell_execute("QuotedAllParams", fileA, " ", NULL); - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - if (rc>32) - { - todo_wine { - okChildInt("argcA", 5); - okChildString("argvA4", " "); - } - } - - /* %~3 */ - rc=shell_execute("NoQuotesParams345etc", fileA, "a b c d e f g h", NULL); - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - if (rc>32) - { - todo_wine { - okChildInt("argcA", 11); - okChildString("argvA4", "b"); - okChildString("argvA10", "h"); - } - } - - /* %~3 is rest of command line starting with whitespaces after 2nd arg */ - rc=shell_execute("QuotedParams345etc", fileA, "a ", NULL); - ok(rc>32, - "expected success (33), got %s (%d), lpFile: %s\n", - rc > 32 ? "success" : "failure", rc, fileA - ); - if (rc>32) - { - okChildInt("argcA", 5); - todo_wine { - okChildString("argvA4", " "); - } - } - + test = argify_tests; + while (test->params) + { + bad = test->broken.cmd ? &test->broken : &test->cmd; + + /* trace("***** verb='%s' params='%s'\n", test->verb, test->params); */ + rc = shell_execute_ex(SEE_MASK_DOENVSUBST, test->verb, fileA, test->params, NULL, NULL); + ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc); + + count = 0; + while (test->cmd.args[count]) + count++; + if ((test->todo & 0x1) == 0) + /* +4 for the shlexec arguments, -1 because of the added "" + * argument for the CommandLineToArgvW() tests. + */ + okChildInt("argcA", 4 + count - 1); + else todo_wine + okChildInt("argcA", 4 + count - 1); + + cmd = getChildString("Arguments", "cmdlineA"); + /* Our commands are such that the verb immediately precedes the + * part we are interested in. + */ + if (cmd) cmd = strstr(cmd, test->verb); + if (cmd) cmd += strlen(test->verb); + if (!cmd) cmd = "(null)"; + if ((test->todo & 0x2) == 0) + ok(!strcmp(cmd, test->cmd.cmd) || broken(!strcmp(cmd, bad->cmd)), + "%s: the cmdline is '%s' instead of '%s'\n", shell_call, cmd, test->cmd.cmd); + else todo_wine + ok(!strcmp(cmd, test->cmd.cmd) || broken(!strcmp(cmd, bad->cmd)), + "%s: the cmdline is '%s' instead of '%s'\n", shell_call, cmd, test->cmd.cmd); + + for (i = 0; i < count - 1; i++) + { + char argname[18]; + sprintf(argname, "argvA%d", 4 + i); + if ((test->todo & (1 << (i+4))) == 0) + okChildStringBroken(argname, test->cmd.args[i+1], bad->args[i+1]); + else todo_wine + okChildStringBroken(argname, test->cmd.args[i+1], bad->args[i+1]); + } + + if (has_cl2a) + has_cl2a = test_one_cmdline(&(test->cmd)); + test++; + } + + /* Test with a long parameter */ + for (rc = 0; rc < MAX_PATH; rc++) + fileA[rc] = 'a' + rc % 26; + fileA[MAX_PATH-1] = '\0'; + sprintf(params, "shlexec "%s" %s", child_file, fileA); + + /* We need NOZONECHECKS on Win2003 to block a dialog */ + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, argv0, params, NULL, NULL); + ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc); + okChildInt("argcA", 4); + okChildString("argvA3", fileA); }
static void test_filename(void) @@ -1135,7 +1462,7 @@ char filename[MAX_PATH]; const filename_tests_t* test; char* c; - int rc; + INT_PTR rc;
test=filename_tests; while (test->basename) @@ -1177,13 +1504,13 @@ if ((test->todo & 0x1)==0) { ok(rc==test->rc || - broken(quotedfile && rc == 2), /* NT4 */ - "%s failed: rc=%d err=%d\n", shell_call, + broken(quotedfile && rc == SE_ERR_FNF), /* NT4 */ + "%s failed: rc=%ld err=%u\n", shell_call, rc, GetLastError()); } else todo_wine { - ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call, + ok(rc==test->rc, "%s failed: rc=%ld err=%u\n", shell_call, rc, GetLastError()); } if (rc == 33) @@ -1227,12 +1554,12 @@ rc=33; if ((test->todo & 0x1)==0) { - ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call, + ok(rc==test->rc, "%s failed: rc=%ld err=%u\n", shell_call, rc, GetLastError()); } else todo_wine { - ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call, + ok(rc==test->rc, "%s failed: rc=%ld err=%u\n", shell_call, rc, GetLastError()); } if (rc==0) @@ -1296,7 +1623,7 @@ */ sprintf(filename, ""%s\test file.shlexec"", tmpdir); rc=shell_execute(NULL, filename, NULL, NULL); - ok(rc > 32, "%s failed: rc=%d err=%d\n", shell_call, rc, + ok(rc > 32, "%s failed: rc=%ld err=%u\n", shell_call, rc, GetLastError()); okChildInt("argcA", 5); okChildString("argvA3", "Open"); @@ -1305,8 +1632,144 @@ } }
+typedef struct +{ + const char* urlprefix; + const char* basename; + int flags; + int todo; +} fileurl_tests_t; + +#define URL_SUCCESS 0x1 +#define USE_COLON 0x2 +#define USE_BSLASH 0x4 + +static fileurl_tests_t fileurl_tests[]= +{ + /* How many slashes does it take... */ + {"file:", "%s\test file.shlexec", URL_SUCCESS, 0}, + {"file:/", "%s\test file.shlexec", URL_SUCCESS, 0}, + {"file://", "%s\test file.shlexec", URL_SUCCESS, 0}, + {"file:///", "%s\test file.shlexec", URL_SUCCESS, 0}, + {"File:///", "%s\test file.shlexec", URL_SUCCESS, 0}, + {"file:////", "%s\test file.shlexec", URL_SUCCESS, 0}, + {"file://///", "%s\test file.shlexec", 0, 0}, + + /* Test with Windows-style paths */ + {"file:///", "%s\test file.shlexec", URL_SUCCESS | USE_COLON, 0}, + {"file:///", "%s\test file.shlexec", URL_SUCCESS | USE_BSLASH, 0}, + + /* Check handling of hostnames */ + {"file://localhost/", "%s\test file.shlexec", URL_SUCCESS, 0}, + {"file://localhost:80/", "%s\test file.shlexec", 0, 0}, + {"file://LocalHost/", "%s\test file.shlexec", URL_SUCCESS, 0}, + {"file://127.0.0.1/", "%s\test file.shlexec", 0, 0}, + {"file://::1/", "%s\test file.shlexec", 0, 0}, + {"file://notahost/", "%s\test file.shlexec", 0, 0}, + + /* Environment variables are not expanded in URLs */ + {"%urlprefix%", "%s\test file.shlexec", 0, 0x1}, + {"file:///", "%%TMPDIR%%\test file.shlexec", 0, 0}, + + /* Test shortcuts vs. URLs */ + {"file://///", "%s\test_shortcut_shlexec.lnk", 0, 0x1d}, + + {NULL, NULL, 0, 0} +}; + +static void test_fileurls(void) +{ + char filename[MAX_PATH], fileurl[MAX_PATH], longtmpdir[MAX_PATH]; + char command[MAX_PATH]; + const fileurl_tests_t* test; + char *s; + INT_PTR rc; + + rc = (INT_PTR)ShellExecute(NULL, NULL, "file:///nosuchfile.shlexec", NULL, NULL, SW_SHOWNORMAL); + if (rc > 32) + { + win_skip("shell32 is too old (likely < 4.72). Skipping the file URL tests\n"); + return; + } + + get_long_path_name(tmpdir, longtmpdir, sizeof(longtmpdir)/sizeof(*longtmpdir)); + SetEnvironmentVariable("urlprefix", "file:///"); + + test=fileurl_tests; + while (test->basename) + { + /* Build the file URL */ + sprintf(filename, test->basename, longtmpdir); + strcpy(fileurl, test->urlprefix); + strcat(fileurl, filename); + s = fileurl + strlen(test->urlprefix); + while (*s) + { + if (!(test->flags & USE_COLON) && *s == ':') + *s = '|'; + else if (!(test->flags & USE_BSLASH) && *s == '\') + *s = '/'; + s++; + } + + /* Test it first with FindExecutable() */ + rc = (INT_PTR)FindExecutableA(fileurl, NULL, command); + ok(rc == SE_ERR_FNF, "FindExecutable(%s) failed: bad rc=%lu\n", fileurl, rc); + + /* Then ShellExecute() */ + if ((test->todo & 0x10) == 0) + rc = shell_execute(NULL, fileurl, NULL, NULL); + else todo_wait + rc = shell_execute(NULL, fileurl, NULL, NULL); + if (bad_shellexecute) + { + win_skip("shell32 is too old (likely 4.72). Skipping the file URL tests\n"); + break; + } + if (test->flags & URL_SUCCESS) + { + if ((test->todo & 0x1) == 0) + ok(rc > 32, "%s failed: bad rc=%lu\n", shell_call, rc); + else todo_wine + ok(rc > 32, "%s failed: bad rc=%lu\n", shell_call, rc); + } + else + { + if ((test->todo & 0x1) == 0) + ok(rc == SE_ERR_FNF || rc == SE_ERR_PNF || + broken(rc == SE_ERR_ACCESSDENIED) /* win2000 */, + "%s failed: bad rc=%lu\n", shell_call, rc); + else todo_wine + ok(rc == SE_ERR_FNF || rc == SE_ERR_PNF || + broken(rc == SE_ERR_ACCESSDENIED) /* win2000 */, + "%s failed: bad rc=%lu\n", shell_call, rc); + } + if (rc == 33) + { + if ((test->todo & 0x2) == 0) + okChildInt("argcA", 5); + else todo_wine + okChildInt("argcA", 5); + + if ((test->todo & 0x4) == 0) + okChildString("argvA3", "Open"); + else todo_wine + okChildString("argvA3", "Open"); + + if ((test->todo & 0x8) == 0) + okChildPath("argvA4", filename); + else todo_wine + okChildPath("argvA4", filename); + } + test++; + } + + SetEnvironmentVariable("urlprefix", NULL); +} + static void test_find_executable(void) { + char notepad_path[MAX_PATH]; char filename[MAX_PATH]; char command[MAX_PATH]; const filename_tests_t* test; @@ -1328,6 +1791,21 @@ ok(rc == SE_ERR_FNF || rc > 32 /* nt4 */, "FindExecutable(NULL) returned %ld\n", rc); ok(strcmp(command, "your word") != 0, "FindExecutable(NULL) returned command=[%s]\n", command); } + + GetSystemDirectoryA( notepad_path, MAX_PATH ); + strcat( notepad_path, "\notepad.exe" ); + + /* Search for something that should be in the system-wide search path (no default directory) */ + strcpy(command, "your word"); + rc=(INT_PTR)FindExecutableA("notepad.exe", NULL, command); + ok(rc > 32, "FindExecutable(%s) returned %ld\n", "notepad.exe", rc); + ok(strcasecmp(command, notepad_path) == 0, "FindExecutable(%s) returned command=[%s]\n", "notepad.exe", command); + + /* Search for something that should be in the system-wide search path (with default directory) */ + strcpy(command, "your word"); + rc=(INT_PTR)FindExecutableA("notepad.exe", tmpdir, command); + ok(rc > 32, "FindExecutable(%s) returned %ld\n", "notepad.exe", rc); + ok(strcasecmp(command, notepad_path) == 0, "FindExecutable(%s) returned command=[%s]\n", "notepad.exe", command);
strcpy(command, "your word"); rc=(INT_PTR)FindExecutableA(tmpdir, NULL, command); @@ -1448,22 +1926,36 @@ char filename[MAX_PATH]; char params[MAX_PATH]; const filename_tests_t* test; - int rc; - + INT_PTR rc; + + /* Should open through our association */ sprintf(filename, "%s\test_shortcut_shlexec.lnk", tmpdir); - rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL); - ok(rc > 32, "%s failed: rc=%d err=%d\n", shell_call, rc, - GetLastError()); + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL, NULL); + ok(rc > 32, "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); okChildInt("argcA", 5); okChildString("argvA3", "Open"); sprintf(params, "%s\test file.shlexec", tmpdir); get_long_path_name(params, filename, sizeof(filename)); okChildPath("argvA4", filename);
+ todo_wait rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_DOENVSUBST, NULL, "%TMPDIR%\test_shortcut_shlexec.lnk", NULL, NULL, NULL); + ok(rc > 32, "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); + okChildInt("argcA", 5); + todo_wine okChildString("argvA3", "Open"); + sprintf(params, "%s\test file.shlexec", tmpdir); + get_long_path_name(params, filename, sizeof(filename)); + todo_wine okChildPath("argvA4", filename); + + /* Should just run our executable */ sprintf(filename, "%s\test_shortcut_exe.lnk", tmpdir); - rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL); - ok(rc > 32, "%s failed: rc=%d err=%d\n", shell_call, rc, - GetLastError()); + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL, NULL); + ok(rc > 32, "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); + okChildInt("argcA", 4); + okChildString("argvA3", "Lnk"); + + /* Lnk's ContextMenuHandler has priority over an explicit class */ + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL, "shlexec.shlexec"); + ok(rc > 32, "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); okChildInt("argcA", 4); okChildString("argvA3", "Lnk");
@@ -1481,8 +1973,8 @@ *c='/'; c++; } - rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL); - ok(rc > 32, "%s failed: rc=%d err=%d\n", shell_call, rc, + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL, NULL); + ok(rc > 32, "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); okChildInt("argcA", 4); okChildString("argvA3", "Lnk"); @@ -1496,17 +1988,17 @@ sprintf(params+1, test->basename, tmpdir); strcat(params,"""); rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, filename, params, - NULL); + NULL, NULL); if (rc > 32) rc=33; if ((test->todo & 0x1)==0) { - ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call, + ok(rc==test->rc, "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); } else todo_wine { - ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call, + ok(rc==test->rc, "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); } if (rc==0) @@ -1546,14 +2038,14 @@ { char filename[MAX_PATH]; char params[1024]; - int rc; + INT_PTR rc;
sprintf(params, "shlexec "%s" Exec", child_file);
/* We need NOZONECHECKS on Win2003 to block a dialog */ rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, argv0, params, - NULL); - ok(rc > 32, "%s returned %d\n", shell_call, rc); + NULL, NULL); + ok(rc > 32, "%s returned %lu\n", shell_call, rc); okChildInt("argcA", 4); okChildString("argvA3", "Exec");
@@ -1564,45 +2056,7 @@ { rc=shell_execute(NULL, filename, params, NULL); todo_wine { - ok(rc==SE_ERR_NOASSOC, "%s succeeded: rc=%d\n", shell_call, rc); - } - } - } - else - { - win_skip("Skipping shellexecute of file with unassociated extension\n"); - } -} - -static void test_exes_long(void) -{ - char filename[MAX_PATH]; - char params[2024]; - char longparam[MAX_PATH]; - int rc; - - for (rc = 0; rc < MAX_PATH; rc++) - longparam[rc]='a'+rc%26; - longparam[MAX_PATH-1]=0; - - - sprintf(params, "shlexec "%s" %s", child_file,longparam); - - /* We need NOZONECHECKS on Win2003 to block a dialog */ - rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, argv0, params, - NULL); - ok(rc > 32, "%s returned %d\n", shell_call, rc); - okChildInt("argcA", 4); - okChildString("argvA3", longparam); - - if (! skip_noassoc_tests) - { - sprintf(filename, "%s\test file.noassoc", tmpdir); - if (CopyFile(argv0, filename, FALSE)) - { - rc=shell_execute(NULL, filename, params, NULL); - todo_wine { - ok(rc==SE_ERR_NOASSOC, "%s succeeded: rc=%d\n", shell_call, rc); + ok(rc==SE_ERR_NOASSOC, "%s succeeded: rc=%lu\n", shell_call, rc); } } } @@ -1624,7 +2078,7 @@ int todo; } dde_tests_t;
-#if BUG_7233_IS_FIXED +#if CORE_6559_IS_FIXED static dde_tests_t dde_tests[] = { /* Test passing and not passing command-line @@ -1667,7 +2121,7 @@ * by changing the entry for WaitForInputIdle() in the shell32 import address * table. */ -static void hook_WaitForInputIdle(void *new_func) +static void hook_WaitForInputIdle(DWORD (WINAPI *new_func)(HANDLE, DWORD)) { char *base; PIMAGE_NT_HEADERS nt_headers; @@ -1728,11 +2182,11 @@ char filename[MAX_PATH], defApplication[MAX_PATH]; const dde_tests_t* test; char params[1024]; - int rc; + INT_PTR rc; HANDLE map; char *shared_block;
- hook_WaitForInputIdle((void *) hooked_WaitForInputIdle); + hook_WaitForInputIdle(hooked_WaitForInputIdle);
sprintf(filename, "%s\test file.sde", tmpdir);
@@ -1768,16 +2222,16 @@ ddeExec[0] = 0;
dde_ready_event = CreateEventA(NULL, FALSE, FALSE, "winetest_shlexec_dde_ready"); - rc = shell_execute_ex(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI, NULL, filename, NULL, NULL); + rc = shell_execute_ex(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI, NULL, filename, NULL, NULL, NULL); CloseHandle(dde_ready_event); if ((test->todo & 0x1)==0) { - ok(32 < rc, "%s failed: rc=%d err=%d\n", shell_call, + ok(32 < rc, "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); } else todo_wine { - ok(32 < rc, "%s failed: rc=%d err=%d\n", shell_call, + ok(32 < rc, "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); } if (32 < rc) @@ -1832,7 +2286,7 @@ int rc[DDE_DEFAULT_APP_VARIANTS]; } dde_default_app_tests_t;
-#if BUG_7233_IS_FIXED +#if CORE_6559_IS_FIXED static dde_default_app_tests_t dde_default_app_tests[] = { /* Windows XP and 98 handle default DDE app names in different ways. @@ -1887,7 +2341,7 @@ assert(info && info->filename); PostThreadMessage(info->threadIdParent, WM_QUIT, - shell_execute_ex(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI, NULL, info->filename, NULL, NULL), + shell_execute_ex(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI, NULL, info->filename, NULL, NULL, NULL), 0L); ExitThread(0); } @@ -1901,7 +2355,8 @@ char params[1024]; DWORD threadId; MSG msg; - int rc, which = 0; + INT_PTR rc; + int which = 0;
post_quit_on_execute = FALSE; ddeInst = 0; @@ -1958,12 +2413,12 @@
if ((test->todo & 0x1)==0) { - ok(rc==test->rc[which], "%s failed: rc=%d err=%d\n", shell_call, + ok(rc==test->rc[which], "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); } else todo_wine { - ok(rc==test->rc[which], "%s failed: rc=%d err=%d\n", shell_call, + ok(rc==test->rc[which], "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); } if (rc == 33) @@ -2039,6 +2494,9 @@ DeleteFileA( tmpdir ); rc = CreateDirectoryA( tmpdir, NULL ); ok( rc, "failed to create %s err %u\n", tmpdir, GetLastError() ); + /* Set %TMPDIR% for the tests */ + SetEnvironmentVariableA("TMPDIR", tmpdir); + rc = GetTempFileNameA(tmpdir, "wt", 0, child_file); assert(rc != 0); init_event(child_file); @@ -2054,7 +2512,7 @@ FILE_ATTRIBUTE_NORMAL, NULL); if (hfile==INVALID_HANDLE_VALUE) { - trace("unable to create '%s': err=%d\n", filename, GetLastError()); + trace("unable to create '%s': err=%u\n", filename, GetLastError()); assert(0); } CloseHandle(hfile); @@ -2102,15 +2560,6 @@ create_test_verb(".shlexec", "QuotedLowerL", 0, "QuotedLowerL "%l""); create_test_verb(".shlexec", "UpperL", 0, "UpperL %L"); create_test_verb(".shlexec", "QuotedUpperL", 0, "QuotedUpperL "%L""); - - create_test_verb(".shlexec", "NoQuotesParam2", 0, "NoQuotesParam2 %2"); - create_test_verb(".shlexec", "QuotedParam2", 0, "QuotedParam2 "%2""); - - create_test_verb(".shlexec", "NoQuotesAllParams", 0, "NoQuotesAllParams %*"); - create_test_verb(".shlexec", "QuotedAllParams", 0, "QuotedAllParams "%*""); - - create_test_verb(".shlexec", "NoQuotesParams345etc", 0, "NoQuotesParams345etc %~3"); - create_test_verb(".shlexec", "QuotedParams345etc", 0, "QuotedParams345etc "%~3""); }
static void cleanup_test(void) @@ -2139,128 +2588,57 @@ CoUninitialize(); }
-static void test_commandline(void) -{ - static const WCHAR one[] = {'o','n','e',0}; - static const WCHAR two[] = {'t','w','o',0}; - static const WCHAR three[] = {'t','h','r','e','e',0}; - static const WCHAR four[] = {'f','o','u','r',0}; - - static const WCHAR fmt1[] = {'%','s',' ','%','s',' ','%','s',' ','%','s',0}; - static const WCHAR fmt2[] = {' ','%','s',' ','%','s',' ','%','s',' ','%','s',0}; - static const WCHAR fmt3[] = {'%','s','=','%','s',' ','%','s','=','"','%','s','"',0}; - static const WCHAR fmt4[] = {'"','%','s','"',' ','"','%','s',' ','%','s','"',' ','%','s',0}; - static const WCHAR fmt5[] = {'\','"','%','s','"',' ','%','s','=','"','%','s','\','"',' ','"','%','s','\','"',0}; - static const WCHAR fmt6[] = {0}; - - static const WCHAR chkfmt1[] = {'%','s','=','%','s',0}; - static const WCHAR chkfmt2[] = {'%','s',' ','%','s',0}; - static const WCHAR chkfmt3[] = {'\','"','%','s','"',0}; - static const WCHAR chkfmt4[] = {'%','s','=','%','s','"',' ','%','s','"',0}; - WCHAR cmdline[255]; - LPWSTR *args = (LPWSTR*)0xdeadcafe, pbuf; - INT numargs = -1; - size_t buflen; - DWORD lerror; - - wsprintfW(cmdline,fmt1,one,two,three,four); - args=CommandLineToArgvW(cmdline,&numargs); - if (args == NULL && numargs == -1) - { - win_skip("CommandLineToArgvW not implemented, skipping\n"); - return; - } - ok(numargs == 4, "expected 4 args, got %i\n",numargs); - ok(lstrcmpW(args[0],one)==0,"arg0 is not as expected\n"); - ok(lstrcmpW(args[1],two)==0,"arg1 is not as expected\n"); - ok(lstrcmpW(args[2],three)==0,"arg2 is not as expected\n"); - ok(lstrcmpW(args[3],four)==0,"arg3 is not as expected\n"); - - SetLastError(0xdeadbeef); - args=CommandLineToArgvW(cmdline,NULL); - lerror=GetLastError(); - ok(args == NULL && lerror == ERROR_INVALID_PARAMETER, "expected NULL with ERROR_INVALID_PARAMETER got %p with %d\n",args,lerror); - SetLastError(0xdeadbeef); - args=CommandLineToArgvW(NULL,NULL); - lerror=GetLastError(); - ok(args == NULL && lerror == ERROR_INVALID_PARAMETER, "expected NULL with ERROR_INVALID_PARAMETER got %p with %d\n",args,lerror); - - wsprintfW(cmdline,fmt2,one,two,three,four); - args=CommandLineToArgvW(cmdline,&numargs); - ok(numargs == 5, "expected 5 args, got %i\n",numargs); - ok(args[0][0]==0,"arg0 is not as expected\n"); - ok(lstrcmpW(args[1],one)==0,"arg1 is not as expected\n"); - ok(lstrcmpW(args[2],two)==0,"arg2 is not as expected\n"); - ok(lstrcmpW(args[3],three)==0,"arg3 is not as expected\n"); - ok(lstrcmpW(args[4],four)==0,"arg4 is not as expected\n"); - - wsprintfW(cmdline,fmt3,one,two,three,four); - args=CommandLineToArgvW(cmdline,&numargs); - ok(numargs == 2, "expected 2 args, got %i\n",numargs); - wsprintfW(cmdline,chkfmt1,one,two); - ok(lstrcmpW(args[0],cmdline)==0,"arg0 is not as expected\n"); - wsprintfW(cmdline,chkfmt1,three,four); - ok(lstrcmpW(args[1],cmdline)==0,"arg1 is not as expected\n"); - - wsprintfW(cmdline,fmt4,one,two,three,four); - args=CommandLineToArgvW(cmdline,&numargs); - ok(numargs == 3, "expected 3 args, got %i\n",numargs); - ok(lstrcmpW(args[0],one)==0,"arg0 is not as expected\n"); - wsprintfW(cmdline,chkfmt2,two,three); - ok(lstrcmpW(args[1],cmdline)==0,"arg1 is not as expected\n"); - ok(lstrcmpW(args[2],four)==0,"arg2 is not as expected\n"); - - wsprintfW(cmdline,fmt5,one,two,three,four); - args=CommandLineToArgvW(cmdline,&numargs); - ok(numargs == 2, "expected 2 args, got %i\n",numargs); - wsprintfW(cmdline,chkfmt3,one); - todo_wine ok(lstrcmpW(args[0],cmdline)==0,"arg0 is not as expected\n"); - wsprintfW(cmdline,chkfmt4,two,three,four); - todo_wine ok(lstrcmpW(args[1],cmdline)==0,"arg1 is not as expected\n"); - - wsprintfW(cmdline,fmt6); - args=CommandLineToArgvW(cmdline,&numargs); - ok(numargs == 1, "expected 1 args, got %i\n",numargs); - if (numargs == 1) { - buflen = max(lstrlenW(args[0])+1,256); - pbuf = HeapAlloc(GetProcessHeap(), 0, buflen*sizeof(pbuf[0])); - GetModuleFileNameW(NULL, pbuf, buflen); - pbuf[buflen-1] = 0; - /* check args[0] is module file name */ - ok(lstrcmpW(args[0],pbuf)==0, "wrong path to the current executable\n"); - HeapFree(GetProcessHeap(), 0, pbuf); - } -} - static void test_directory(void) { - char path[MAX_PATH], newdir[MAX_PATH]; - char params[1024]; - int rc; - - /* copy this executable to a new folder and cd to it */ - sprintf(newdir, "%s\newfolder", tmpdir); - rc = CreateDirectoryA( newdir, NULL ); - ok( rc, "failed to create %s err %u\n", newdir, GetLastError() ); - sprintf(path, "%s\%s", newdir, path_find_file_name(argv0)); + char path[MAX_PATH], curdir[MAX_PATH]; + char params[1024], dirpath[1024]; + INT_PTR rc; + + sprintf(path, "%s\test2.exe", tmpdir); CopyFileA(argv0, path, FALSE); - SetCurrentDirectory(tmpdir);
sprintf(params, "shlexec "%s" Exec", child_file);
+ /* Test with the current directory */ + GetCurrentDirectoryA(sizeof(curdir), curdir); + SetCurrentDirectoryA(tmpdir); rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_FLAG_NO_UI, - NULL, path_find_file_name(argv0), params, NULL); - todo_wine ok(rc == SE_ERR_FNF, "%s returned %d\n", shell_call, rc); - - rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_FLAG_NO_UI, - NULL, path_find_file_name(argv0), params, newdir); - ok(rc > 32, "%s returned %d\n", shell_call, rc); + NULL, "test2.exe", params, NULL, NULL); + ok(rc > 32, "%s returned %lu\n", shell_call, rc); okChildInt("argcA", 4); okChildString("argvA3", "Exec"); todo_wine okChildPath("longPath", path); - - DeleteFile(path); - RemoveDirectoryA(newdir); + SetCurrentDirectoryA(curdir); + + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_FLAG_NO_UI, + NULL, "test2.exe", params, NULL, NULL); + ok(rc == SE_ERR_FNF, "%s returned %lu\n", shell_call, rc); + + /* Explicitly specify the directory to use */ + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_FLAG_NO_UI, + NULL, "test2.exe", params, tmpdir, NULL); + ok(rc > 32, "%s returned %lu\n", shell_call, rc); + okChildInt("argcA", 4); + okChildString("argvA3", "Exec"); + todo_wine okChildPath("longPath", path); + + /* Specify it through an environment variable */ + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_FLAG_NO_UI, + NULL, "test2.exe", params, "%TMPDIR%", NULL); + todo_wine ok(rc == SE_ERR_FNF, "%s returned %lu\n", shell_call, rc); + + rc=shell_execute_ex(SEE_MASK_DOENVSUBST|SEE_MASK_NOZONECHECKS|SEE_MASK_FLAG_NO_UI, + NULL, "test2.exe", params, "%TMPDIR%", NULL); + ok(rc > 32, "%s returned %lu\n", shell_call, rc); + okChildInt("argcA", 4); + okChildString("argvA3", "Exec"); + todo_wine okChildPath("longPath", path); + + /* Not a colon-separated directory list */ + sprintf(dirpath, "%s:%s", curdir, tmpdir); + rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_FLAG_NO_UI, + NULL, "test2.exe", params, dirpath, NULL); + ok(rc == SE_ERR_FNF, "%s returned %lu\n", shell_call, rc); }
START_TEST(shlexec) @@ -2275,20 +2653,20 @@
init_test();
+ test_commandline2argv(); test_argify(); test_lpFile_parsed(); test_filename(); + test_fileurls(); test_find_executable(); test_lnks(); test_exes(); - test_exes_long(); -#if BUG_7233_IS_FIXED +#if CORE_6559_IS_FIXED test_dde(); test_dde_default_app(); #endif - win_skip("Skipping test_dde() until we have a sane DDE implementation. Bug 7233.\n"); - win_skip("Skipping test_dde_default_app() until we have a sane DDE implementation. Bug 7233.\n"); - test_commandline(); + win_skip("Skipping test_dde() until we have a sane DDE implementation. CORE-6559.\n"); + win_skip("Skipping test_dde_default_app() until we have a sane DDE implementation. CORE-6559.\n"); test_directory();
cleanup_test();
Modified: trunk/rostests/winetests/shell32/shlfileop.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/shlfileo... ============================================================================== --- trunk/rostests/winetests/shell32/shlfileop.c [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/shlfileop.c [iso-8859-1] Sun Dec 9 22:05:54 2012 @@ -995,7 +995,11 @@ shfo.fFlags |= FOF_NOERRORUI; set_curr_dir_path(from, "test1.txt\0test2.txt\0"); set_curr_dir_path(to, "test3.txt\0"); - retval = SHFileOperation(&shfo); + shfo.fAnyOperationsAborted = 0xdeadbeef; + retval = SHFileOperation(&shfo); + ok(shfo.fAnyOperationsAborted != 0xdeadbeef || + broken(shfo.fAnyOperationsAborted == 0xdeadbeef), /* NT4 */ + "Expected TRUE/FALSE fAnyOperationsAborted not 0xdeadbeef\n"); if (retval == DE_FLDDESTISFILE || /* Vista and W2K8 */ retval == DE_INVALIDFILES) /* Win7 */ { @@ -1012,8 +1016,11 @@ /* try to copy many files to nonexistent directory */ DeleteFile(to); shfo.fFlags &= ~FOF_NOERRORUI; - shfo.fAnyOperationsAborted = FALSE; - retval = SHFileOperation(&shfo); + shfo.fAnyOperationsAborted = 0xdeadbeef; + retval = SHFileOperation(&shfo); + ok(!shfo.fAnyOperationsAborted || + broken(shfo.fAnyOperationsAborted == 0xdeadbeef), /* NT4 */ + "Didn't expect aborted operations\n"); ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); ok(DeleteFile("test3.txt\test1.txt"), "Expected test3.txt\test1.txt to exist\n"); ok(DeleteFile("test3.txt\test2.txt"), "Expected test3.txt\test1.txt to exist\n"); @@ -1024,11 +1031,16 @@ shfo.pFrom = "test1.txt\0test2.txt\0test3.txt\0"; shfo.pTo = "testdir2\a.txt\0testdir2\b.txt\0testdir2\c.txt\0testdir2\d.txt\0"; shfo.fFlags |= FOF_NOERRORUI | FOF_MULTIDESTFILES; - retval = SHFileOperation(&shfo); + shfo.fAnyOperationsAborted = 0xdeadbeef; + retval = SHFileOperation(&shfo); + ok(shfo.fAnyOperationsAborted != 0xdeadbeef || + broken(shfo.fAnyOperationsAborted == 0xdeadbeef), /* NT4 */ + "Expected TRUE/FALSE fAnyOperationsAborted not 0xdeadbeef\n"); if (dir_exists("testdir2\a.txt")) { /* Vista and W2K8 (broken or new behavior ?) */ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(!shfo.fAnyOperationsAborted, "Didn't expect aborted operations\n"); ok(DeleteFile("testdir2\a.txt\test1.txt"), "Expected testdir2\a.txt\test1.txt to exist\n"); RemoveDirectory("testdir2\a.txt"); ok(DeleteFile("testdir2\b.txt\test2.txt"), "Expected testdir2\b.txt\test2.txt to exist\n"); @@ -1049,11 +1061,15 @@ /* send in FOF_MULTIDESTFILES with too many destination files */ shfo.pFrom = "test1.txt\0test2.txt\0test3.txt\0"; shfo.pTo = "e.txt\0f.txt\0"; - shfo.fAnyOperationsAborted = FALSE; - retval = SHFileOperation(&shfo); + shfo.fAnyOperationsAborted = 0xdeadbeef; + retval = SHFileOperation(&shfo); + ok(shfo.fAnyOperationsAborted != 0xdeadbeef || + broken(shfo.fAnyOperationsAborted == 0xdeadbeef), /* NT4 */ + "Expected TRUE/FALSE fAnyOperationsAborted not 0xdeadbeef\n"); if (dir_exists("e.txt")) { /* Vista and W2K8 (broken or new behavior ?) */ + ok(!shfo.fAnyOperationsAborted, "Didn't expect aborted operations\n"); ok(retval == DE_SAMEFILE, "Expected DE_SAMEFILE, got %d\n", retval); ok(DeleteFile("e.txt\test1.txt"), "Expected e.txt\test1.txt to exist\n"); RemoveDirectory("e.txt"); @@ -1072,8 +1088,11 @@ /* use FOF_MULTIDESTFILES with files and a source directory */ shfo.pFrom = "test1.txt\0test2.txt\0test4.txt\0"; shfo.pTo = "testdir2\a.txt\0testdir2\b.txt\0testdir2\c.txt\0"; - shfo.fAnyOperationsAborted = FALSE; - retval = SHFileOperation(&shfo); + shfo.fAnyOperationsAborted = 0xdeadbeef; + retval = SHFileOperation(&shfo); + ok(!shfo.fAnyOperationsAborted || + broken(shfo.fAnyOperationsAborted == 0xdeadbeef), /* NT4 */ + "Didn't expect aborted operations\n"); ok(retval == ERROR_SUCCESS || broken(retval == 0x100a1), /* WinMe */ "Expected ERROR_SUCCESS, got %d\n", retval); @@ -1085,13 +1104,17 @@ /* try many dest files without FOF_MULTIDESTFILES flag */ shfo.pFrom = "test1.txt\0test2.txt\0test3.txt\0"; shfo.pTo = "a.txt\0b.txt\0c.txt\0"; - shfo.fAnyOperationsAborted = FALSE; + shfo.fAnyOperationsAborted = 0xdeadbeef; shfo.fFlags &= ~FOF_MULTIDESTFILES; retval = SHFileOperation(&shfo); + ok(shfo.fAnyOperationsAborted != 0xdeadbeef || + broken(shfo.fAnyOperationsAborted == 0xdeadbeef), /* NT4 */ + "Expected TRUE/FALSE fAnyOperationsAborted not 0xdeadbeef\n"); if (dir_exists("a.txt")) { /* Vista and W2K8 (broken or new behavior ?) */ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(!shfo.fAnyOperationsAborted, "Didn't expect aborted operations\n"); ok(DeleteFile("a.txt\test1.txt"), "Expected a.txt\test1.txt to exist\n"); ok(DeleteFile("a.txt\test2.txt"), "Expected a.txt\test2.txt to exist\n"); ok(DeleteFile("a.txt\test3.txt"), "Expected a.txt\test3.txt to exist\n"); @@ -1099,7 +1122,11 @@ } else { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + ok(shfo.fAnyOperationsAborted || + broken(!shfo.fAnyOperationsAborted), /* NT4 */ + "Expected aborted operations\n"); ok(!file_exists("a.txt"), "Expected a.txt to not exist\n"); }
@@ -1157,8 +1184,11 @@ init_shfo_tests(); shfo.pFrom = "test1.txt\0"; shfo.pTo = "b.txt\0c.txt\0"; - shfo.fAnyOperationsAborted = FALSE; - retval = SHFileOperation(&shfo); + shfo.fAnyOperationsAborted = 0xdeadbeef; + retval = SHFileOperation(&shfo); + ok(!shfo.fAnyOperationsAborted || + broken(shfo.fAnyOperationsAborted == 0xdeadbeef), /* NT4 */ + "Didn't expect aborted operations\n"); if (retval == DE_OPCANCELLED) { /* NT4 fails and doesn't copy any files */ @@ -1177,11 +1207,13 @@ /* copy two file to three others, all fail */ shfo.pFrom = "test1.txt\0test2.txt\0"; shfo.pTo = "b.txt\0c.txt\0d.txt\0"; + shfo.fAnyOperationsAborted = 0xdeadbeef; retval = SHFileOperation(&shfo); if (dir_exists("b.txt")) { /* Vista and W2K8 (broken or new behavior ?) */ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(!shfo.fAnyOperationsAborted, "Didn't expect aborted operations\n"); ok(DeleteFile("b.txt\test1.txt"), "Expected b.txt\test1.txt to exist\n"); RemoveDirectory("b.txt"); ok(DeleteFile("c.txt\test2.txt"), "Expected c.txt\test2.txt to exist\n"); @@ -1191,7 +1223,7 @@ { expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); ok(shfo.fAnyOperationsAborted || - broken(!shfo.fAnyOperationsAborted), /* NT4 */ + broken(shfo.fAnyOperationsAborted == 0xdeadbeef), /* NT4 */ "Expected aborted operations\n"); ok(!DeleteFile("b.txt"), "Expected b.txt to not exist\n"); } @@ -1199,12 +1231,13 @@ /* copy one file and one directory to three others */ shfo.pFrom = "test1.txt\0test4.txt\0"; shfo.pTo = "b.txt\0c.txt\0d.txt\0"; - shfo.fAnyOperationsAborted = FALSE; + shfo.fAnyOperationsAborted = 0xdeadbeef; retval = SHFileOperation(&shfo); if (dir_exists("b.txt")) { /* Vista and W2K8 (broken or new behavior ?) */ ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(!shfo.fAnyOperationsAborted, "Didn't expect aborted operations\n"); ok(DeleteFile("b.txt\test1.txt"), "Expected b.txt\test1.txt to exist\n"); RemoveDirectory("b.txt"); ok(RemoveDirectory("c.txt\test4.txt"), "Expected c.txt\test4.txt to exist\n"); @@ -1214,7 +1247,7 @@ { expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); ok(shfo.fAnyOperationsAborted || - broken(!shfo.fAnyOperationsAborted), /* NT4 */ + broken(shfo.fAnyOperationsAborted == 0xdeadbeef), /* NT4 */ "Expected aborted operations\n"); ok(!DeleteFile("b.txt"), "Expected b.txt to not exist\n"); ok(!DeleteFile("c.txt"), "Expected c.txt to not exist\n"); @@ -1383,10 +1416,11 @@ shfo.fFlags = FOF_NOCONFIRMATION; shfo.pFrom = "test1.txt\0"; shfo.pTo = "test2.txt\0"; - shfo.fAnyOperationsAborted = FALSE; + shfo.fAnyOperationsAborted = 0xdeadbeef; /* without FOF_NOCONFIRMATION the confirmation is Yes/No */ retval = SHFileOperation(&shfo); ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(!shfo.fAnyOperationsAborted, "Didn't expect aborted operations\n"); ok(file_has_content("test2.txt", "test1.txt\n"), "The file was not copied\n");
shfo.pFrom = "test3.txt\0test1.txt\0";
Modified: trunk/rostests/winetests/shell32/shlfolder.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/shlfolde... ============================================================================== --- trunk/rostests/winetests/shell32/shlfolder.c [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/shlfolder.c [iso-8859-1] Sun Dec 9 22:05:54 2012 @@ -73,6 +73,18 @@ static UINT (WINAPI *pGetSystemWow64DirectoryW)(LPWSTR, UINT); static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
+static const char *debugstr_guid(REFIID riid) +{ + static char buf[50]; + + sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + riid->Data1, riid->Data2, riid->Data3, riid->Data4[0], + riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4], + riid->Data4[5], riid->Data4[6], riid->Data4[7]); + + return buf; +} + static WCHAR *make_wstr(const char *str) { WCHAR *ret; @@ -566,7 +578,9 @@ CLSID id; hr = IPersist_GetClassID(pp, &id); ok(hr == S_OK, "Got 0x%08x\n", hr); - ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid\n"); + /* CLSID_ShellFSFolder on some w2k systems */ + ok(IsEqualIID(&id, &CLSID_ShellDocObjView) || broken(IsEqualIID(&id, &CLSID_ShellFSFolder)), + "Unexpected classid %s\n", debugstr_guid(&id)); IPersist_Release(pp); }
@@ -782,7 +796,7 @@ broken(hr == S_OK), /* Win9x, W2K */ "hr = %08x\n", hr); if (hr == S_OK) { - IShellFolder_Release(psfFile); + IUnknown_Release(psfFile); }
if (!pSHBindToParent)
Modified: trunk/rostests/winetests/shell32/shlview.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/shlview.... ============================================================================== --- trunk/rostests/winetests/shell32/shlview.c [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/shlview.c [iso-8859-1] Sun Dec 9 22:05:54 2012 @@ -170,7 +170,7 @@
if(*ppvObj) { - IUnknown_AddRef(iface); + IDataObject_AddRef(iface); return S_OK; }
@@ -302,7 +302,7 @@
if(*ppvObj) { - IUnknown_AddRef(iface); + IShellBrowser_AddRef(iface); return S_OK; }