Author: akhaldi Date: Wed Mar 9 08:43:20 2016 New Revision: 70977
URL: http://svn.reactos.org/svn/reactos?rev=70977&view=rev Log: [SHELL32_WINETEST] Sync with Wine Staging 1.9.4. CORE-10912
Modified: trunk/rostests/winetests/shell32/progman_dde.c trunk/rostests/winetests/shell32/shellole.c trunk/rostests/winetests/shell32/shlexec.c trunk/rostests/winetests/shell32/shlfolder.c
Modified: trunk/rostests/winetests/shell32/progman_dde.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/progman_... ============================================================================== --- trunk/rostests/winetests/shell32/progman_dde.c [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/progman_dde.c [iso-8859-1] Wed Mar 9 08:43:20 2016 @@ -372,7 +372,13 @@ for (i = 0; window == NULL && i < PDDE_POLL_NUM; i++) { Sleep(PDDE_POLL_TIME); - window = FindWindowA(NULL, winName); + /* Specify the window class name to make sure what we find is really an + * Explorer window. Explorer used two different window classes so try + * both. + */ + window = FindWindowA("ExplorerWClass", winName); + if (!window) + window = FindWindowA("CabinetWClass", winName); } ok (window != NULL, "Window "%s" was not created in %i seconds - assumed failure.%s\n", winName, PDDE_POLL_NUM*PDDE_POLL_TIME/1000, GetStringFromTestParams(testParams));
Modified: trunk/rostests/winetests/shell32/shellole.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/shell32/shellole... ============================================================================== --- trunk/rostests/winetests/shell32/shellole.c [iso-8859-1] (original) +++ trunk/rostests/winetests/shell32/shellole.c [iso-8859-1] Wed Mar 9 08:43:20 2016 @@ -74,6 +74,7 @@ static HRESULT (WINAPI *pSHPropStgWriteMultiple)(IPropertyStorage*, UINT*, ULONG, const PROPSPEC*, PROPVARIANT*, PROPID); static HRESULT (WINAPI *pSHCreateQueryCancelAutoPlayMoniker)(IMoniker**); +static HRESULT (WINAPI *pSHCreateSessionKey)(REGSAM, HKEY*);
static void init(void) { @@ -83,6 +84,7 @@ pSHPropStgReadMultiple = (void*)GetProcAddress(hmod, "SHPropStgReadMultiple"); pSHPropStgWriteMultiple = (void*)GetProcAddress(hmod, "SHPropStgWriteMultiple"); pSHCreateQueryCancelAutoPlayMoniker = (void*)GetProcAddress(hmod, "SHCreateQueryCancelAutoPlayMoniker"); + pSHCreateSessionKey = (void*)GetProcAddress(hmod, (char*)723); }
static HRESULT WINAPI PropertyStorage_QueryInterface(IPropertyStorage *This, @@ -857,6 +859,36 @@ } #undef DROPTEST_FILENAME
+static void test_SHCreateSessionKey(void) +{ + HKEY hkey, hkey2; + HRESULT hr; + + if (!pSHCreateSessionKey) + { + skip("SHCreateSessionKey is not implemented\n"); + return; + } + +if (0) /* crashes on native */ + hr = pSHCreateSessionKey(KEY_READ, NULL); + + hkey = (HKEY)0xdeadbeef; + hr = pSHCreateSessionKey(0, &hkey); + todo_wine ok(hr == E_ACCESSDENIED, "got 0x%08x\n", hr); + todo_wine ok(hkey == NULL, "got %p\n", hkey); + + hr = pSHCreateSessionKey(KEY_READ, &hkey); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = pSHCreateSessionKey(KEY_READ, &hkey2); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(hkey != hkey2, "got %p, %p\n", hkey, hkey2); + + RegCloseKey(hkey); + RegCloseKey(hkey2); +} + START_TEST(shellole) { init(); @@ -864,4 +896,5 @@ test_SHPropStg_functions(); test_SHCreateQueryCancelAutoPlayMoniker(); test_DragQueryFile(); -} + test_SHCreateSessionKey(); +}
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] Wed Mar 9 08:43:20 2016 @@ -1,7 +1,7 @@ /* * Unit test of the ShellExecute function. * - * Copyright 2005 Francois Gouget for CodeWeavers + * Copyright 2005, 2016 Francois Gouget for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,8 +26,6 @@ * - ShellExecute("foo.shlexec") with no path should work if foo.shlexec is * in the PATH * - test associations that use %l, %L or "%1" instead of %1 - * - we may want to test ShellExecuteEx() instead of ShellExecute() - * and then we could also check its return value * - ShellExecuteEx() also calls SetLastError() with meaningful values which * we could check */ @@ -64,18 +62,421 @@
/*** * + * Helpers to read from / write to the child process results file. + * (borrowed from dlls/kernel32/tests/process.c) + * + ***/ + +static const char* encodeA(const char* str) +{ + static char encoded[2*1024+1]; + char* ptr; + size_t len,i; + + if (!str) return ""; + len = strlen(str) + 1; + if (len >= sizeof(encoded)/2) + { + fprintf(stderr, "string is too long!\n"); + assert(0); + } + ptr = encoded; + for (i = 0; i < len; i++) + sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]); + ptr[2 * len] = '\0'; + return ptr; +} + +static unsigned decode_char(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + assert(c >= 'A' && c <= 'F'); + return c - 'A' + 10; +} + +static char* decodeA(const char* str) +{ + static char decoded[1024]; + char* ptr; + size_t len,i; + + len = strlen(str) / 2; + if (!len--) return NULL; + if (len >= sizeof(decoded)) + { + fprintf(stderr, "string is too long!\n"); + assert(0); + } + ptr = decoded; + for (i = 0; i < len; i++) + ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]); + ptr[len] = '\0'; + return ptr; +} + +static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...) +{ + va_list valist; + char buffer[1024]; + DWORD w; + + va_start(valist, fmt); + vsprintf(buffer, fmt, valist); + va_end(valist); + WriteFile(h, buffer, strlen(buffer), &w, NULL); +} + +static char* getChildString(const char* sect, const char* key) +{ + char buf[1024]; + char* ret; + + GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), child_file); + if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL; + assert(!(strlen(buf) & 1)); + ret = decodeA(buf); + return ret; +} + + +/*** + * + * Child code + * + ***/ + +#define CHILD_DDE_TIMEOUT 2500 +static DWORD ddeInst; +static HSZ hszTopic; +static char ddeExec[MAX_PATH], ddeApplication[MAX_PATH]; +static BOOL post_quit_on_execute; + +/* Handle DDE for doChild() and test_dde_default_app() */ +static HDDEDATA CALLBACK ddeCb(UINT uType, UINT uFmt, HCONV hConv, + HSZ hsz1, HSZ hsz2, HDDEDATA hData, + ULONG_PTR dwData1, ULONG_PTR dwData2) +{ + DWORD size = 0; + + if (winetest_debug > 2) + trace("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n", + uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2); + + switch (uType) + { + case XTYP_CONNECT: + if (!DdeCmpStringHandles(hsz1, hszTopic)) + { + size = DdeQueryStringA(ddeInst, hsz2, ddeApplication, MAX_PATH, CP_WINANSI); + ok(size < MAX_PATH, "got size %d\n", size); + assert(size < MAX_PATH); + return (HDDEDATA)TRUE; + } + return (HDDEDATA)FALSE; + + case XTYP_EXECUTE: + size = DdeGetData(hData, (LPBYTE)ddeExec, MAX_PATH, 0); + ok(size < MAX_PATH, "got size %d\n", size); + assert(size < MAX_PATH); + DdeFreeDataHandle(hData); + if (post_quit_on_execute) + PostQuitMessage(0); + return (HDDEDATA)DDE_FACK; + + default: + return NULL; + } +} + +static HANDLE hEvent; +static void init_event(const char* child_file) +{ + char* event_name; + event_name=strrchr(child_file, '\')+1; + hEvent=CreateEventA(NULL, FALSE, FALSE, event_name); +} + +/* + * This is just to make sure the child won't run forever stuck in a + * GetMessage() loop when DDE fails for some reason. + */ +static void CALLBACK childTimeout(HWND wnd, UINT msg, UINT_PTR timer, DWORD time) +{ + trace("childTimeout called\n"); + + PostQuitMessage(0); +} + +static void doChild(int argc, char** argv) +{ + char *filename, buffer[MAX_PATH]; + HANDLE hFile, map; + int i; + UINT_PTR timer; + + filename=argv[2]; + hFile=CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + if (hFile == INVALID_HANDLE_VALUE) + return; + + /* Arguments */ + childPrintf(hFile, "[Child]\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]); + childPrintf(hFile, "argvA%d=%s\r\n", i, encodeA(argv[i])); + } + GetModuleFileNameA(GetModuleHandleA(NULL), buffer, sizeof(buffer)); + childPrintf(hFile, "longPath=%s\r\n", encodeA(buffer)); + + /* Check environment variable inheritance */ + *buffer = '\0'; + SetLastError(0); + GetEnvironmentVariableA("ShlexecVar", buffer, sizeof(buffer)); + childPrintf(hFile, "ShlexecVarLE=%d\r\n", GetLastError()); + childPrintf(hFile, "ShlexecVar=%s\r\n", encodeA(buffer)); + + map = OpenFileMappingA(FILE_MAP_READ, FALSE, "winetest_shlexec_dde_map"); + if (map != NULL) + { + HANDLE dde_ready; + char *shared_block = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 4096); + CloseHandle(map); + if (shared_block[0] != '\0' || shared_block[1] != '\0') + { + HDDEDATA hdde; + HSZ hszApplication; + MSG msg; + UINT rc; + + post_quit_on_execute = TRUE; + ddeInst = 0; + rc = DdeInitializeA(&ddeInst, ddeCb, CBF_SKIP_ALLNOTIFICATIONS | CBF_FAIL_ADVISES | + CBF_FAIL_POKES | CBF_FAIL_REQUESTS, 0); + ok(rc == DMLERR_NO_ERROR, "DdeInitializeA() returned %d\n", rc); + hszApplication = DdeCreateStringHandleA(ddeInst, shared_block, CP_WINANSI); + ok(hszApplication != NULL, "DdeCreateStringHandleA(%s) = NULL\n", shared_block); + shared_block += strlen(shared_block) + 1; + hszTopic = DdeCreateStringHandleA(ddeInst, shared_block, CP_WINANSI); + ok(hszTopic != NULL, "DdeCreateStringHandleA(%s) = NULL\n", shared_block); + hdde = DdeNameService(ddeInst, hszApplication, 0, DNS_REGISTER | DNS_FILTEROFF); + ok(hdde != NULL, "DdeNameService() failed le=%u\n", GetLastError()); + + timer = SetTimer(NULL, 0, CHILD_DDE_TIMEOUT, childTimeout); + + dde_ready = OpenEventA(EVENT_MODIFY_STATE, FALSE, "winetest_shlexec_dde_ready"); + SetEvent(dde_ready); + CloseHandle(dde_ready); + + while (GetMessageA(&msg, NULL, 0, 0)) + { + if (winetest_debug > 2) + trace("msg %d lParam=%ld wParam=%lu\n", msg.message, msg.lParam, msg.wParam); + DispatchMessageA(&msg); + } + + Sleep(500); + KillTimer(NULL, timer); + hdde = DdeNameService(ddeInst, hszApplication, 0, DNS_UNREGISTER); + ok(hdde != NULL, "DdeNameService() failed le=%u\n", GetLastError()); + ok(DdeFreeStringHandle(ddeInst, hszTopic), "DdeFreeStringHandle(topic)\n"); + ok(DdeFreeStringHandle(ddeInst, hszApplication), "DdeFreeStringHandle(application)\n"); + ok(DdeUninitialize(ddeInst), "DdeUninitialize() failed\n"); + } + else + { + dde_ready = OpenEventA(EVENT_MODIFY_STATE, FALSE, "winetest_shlexec_dde_ready"); + SetEvent(dde_ready); + CloseHandle(dde_ready); + } + + UnmapViewOfFile(shared_block); + + childPrintf(hFile, "ddeExec=%s\r\n", encodeA(ddeExec)); + } + + childPrintf(hFile, "Failures=%d\r\n", winetest_get_failures()); + CloseHandle(hFile); + + init_event(filename); + SetEvent(hEvent); + CloseHandle(hEvent); +} + +static void dump_child_(const char* file, int line) +{ + if (winetest_debug > 1) + { + char key[18]; + char* str; + int i, c; + + str=getChildString("Child", "cmdlineA"); + trace_(file, line)("cmdlineA='%s'\n", str); + c=GetPrivateProfileIntA("Child", "argcA", -1, child_file); + trace_(file, line)("argcA=%d\n",c); + for (i=0;i<c;i++) + { + sprintf(key, "argvA%d", i); + str=getChildString("Child", key); + trace_(file, line)("%s='%s'\n", key, str); + } + + c=GetPrivateProfileIntA("Child", "ShlexecVarLE", -1, child_file); + trace_(file, line)("ShlexecVarLE=%d\n", c); + str=getChildString("Child", "ShlexecVar"); + trace_(file, line)("ShlexecVar='%s'\n", str); + + c=GetPrivateProfileIntA("Child", "Failures", -1, child_file); + trace_(file, line)("Failures=%d\n", c); + } +} + + +/*** + * + * Helpers to check the ShellExecute() / child process results. + * + ***/ + +static char shell_call[2048]; +static void WINETEST_PRINTF_ATTR(2,3) _okShell(int condition, const char *msg, ...) +{ + va_list valist; + char buffer[2048]; + + strcpy(buffer, shell_call); + strcat(buffer, " "); + va_start(valist, msg); + vsprintf(buffer+strlen(buffer), msg, valist); + va_end(valist); + winetest_ok(condition, "%s", buffer); +} +#define okShell_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : _okShell +#define okShell okShell_(__FILE__, __LINE__) + +static char assoc_desc[2048]; +void reset_association_description(void) +{ + *assoc_desc = '\0'; +} + +static void okChildString_(const char* file, int line, const char* key, const char* expected, const char* bad) +{ + char* result; + result=getChildString("Child", key); + if (!result) + { + okShell_(file, line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected); + return; + } + okShell_(file, line)(lstrcmpiA(result, expected) == 0 || + broken(lstrcmpiA(result, bad) == 0), + "%s expected '%s', got '%s'\n", key, expected, result); +} +#define okChildString(key, expected) okChildString_(__FILE__, __LINE__, (key), (expected), (expected)) +#define okChildStringBroken(key, expected, broken) okChildString_(__FILE__, __LINE__, (key), (expected), (broken)) + +static int StrCmpPath(const char* s1, const char* s2) +{ + if (!s1 && !s2) return 0; + if (!s2) return 1; + if (!s1) return -1; + while (*s1) + { + if (!*s2) + { + if (*s1=='.') + s1++; + return (*s1-*s2); + } + if ((*s1=='/' || *s1=='\') && (*s2=='/' || *s2=='\')) + { + while (*s1=='/' || *s1=='\') + s1++; + while (*s2=='/' || *s2=='\') + s2++; + } + else if (toupper(*s1)==toupper(*s2)) + { + s1++; + s2++; + } + else + { + return (*s1-*s2); + } + } + if (*s2=='.') + s2++; + if (*s2) + return -1; + return 0; +} + +static void okChildPath_(const char* file, int line, const char* key, const char* expected) +{ + char* result; + int equal, shortequal; + result=getChildString("Child", key); + if (!result) + { + okShell_(file,line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected); + return; + } + shortequal = FALSE; + equal = (StrCmpPath(result, expected) == 0); + if (!equal) + { + char altpath[MAX_PATH]; + DWORD rc = GetLongPathNameA(expected, altpath, sizeof(altpath)); + if (0 < rc && rc < sizeof(altpath)) + equal = (StrCmpPath(result, altpath) == 0); + if (!equal) + { + rc = GetShortPathNameA(expected, altpath, sizeof(altpath)); + if (0 < rc && rc < sizeof(altpath)) + shortequal = (StrCmpPath(result, altpath) == 0); + } + } + okShell_(file,line)(equal || broken(shortequal) /* XP SP1 */, + "%s expected '%s', got '%s'\n", key, expected, result); +} +#define okChildPath(key, expected) okChildPath_(__FILE__, __LINE__, (key), (expected)) + +static void okChildInt_(const char* file, int line, const char* key, int expected) +{ + INT result; + result=GetPrivateProfileIntA("Child", key, expected, child_file); + okShell_(file,line)(result == expected, + "%s expected %d, but got %d\n", key, expected, result); +} +#define okChildInt(key, expected) okChildInt_(__FILE__, __LINE__, (key), (expected)) + +static void okChildIntBroken_(const char* file, int line, const char* key, int expected) +{ + INT result; + result=GetPrivateProfileIntA("Child", key, expected, child_file); + okShell_(file,line)(result == expected || broken(result != expected), + "%s expected %d, but got %d\n", key, expected, result); +} +#define okChildIntBroken(key, expected) okChildIntBroken_(__FILE__, __LINE__, (key), (expected)) + + +/*** + * * ShellExecute wrappers * ***/ -static void dump_child(void); - -static HANDLE hEvent; -static void init_event(const char* child_file) -{ - char* event_name; - event_name=strrchr(child_file, '\')+1; - hEvent=CreateEventA(NULL, FALSE, FALSE, event_name); -}
static void strcat_param(char* str, const char* name, const char* param) { @@ -93,23 +494,24 @@ static int _todo_wait = 0; #define todo_wait for (_todo_wait = 1; _todo_wait; _todo_wait = 0)
-static char shell_call[2048]=""; static int bad_shellexecute = 0; -static INT_PTR shell_execute(LPCSTR verb, LPCSTR file, LPCSTR parameters, LPCSTR directory) + +static INT_PTR shell_execute_(const char* file, int line, LPCSTR verb, LPCSTR filename, LPCSTR parameters, LPCSTR directory) { INT_PTR rc, rcEmpty = 0;
if(!verb) - rcEmpty = shell_execute("", file, parameters, directory); + rcEmpty = shell_execute_(file, line, "", filename, parameters, directory);
strcpy(shell_call, "ShellExecute("); strcat_param(shell_call, "verb", verb); - strcat_param(shell_call, "file", file); + strcat_param(shell_call, "file", filename); strcat_param(shell_call, "params", parameters); strcat_param(shell_call, "dir", directory); strcat(shell_call, ")"); + strcat(shell_call, assoc_desc); if (winetest_debug > 1) - trace("%s\n", shell_call); + trace_(file, line)("Called %s\n", shell_call);
DeleteFileA(child_file); SetLastError(0xcafebabe); @@ -118,7 +520,7 @@ * association it displays the 'Open With' dialog and I could not find * a flag to prevent this. */ - rc=(INT_PTR)ShellExecuteA(NULL, verb, file, parameters, directory, SW_HIDE); + rc=(INT_PTR)ShellExecuteA(NULL, verb, filename, parameters, directory, SW_HIDE);
if (rc > 32) { @@ -137,58 +539,70 @@ rc = SE_ERR_NOASSOC; } } - 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); + todo_wine_if(_todo_wait) + okShell_(file, line)(wait_rc==WAIT_OBJECT_0 || rc <= 32, + "WaitForSingleObject returned %d\n", wait_rc); } /* The child process may have changed the result file, so let profile * functions know about it */ WritePrivateProfileStringA(NULL, NULL, NULL, child_file); - if (rc > 32) - dump_child(); + if (GetFileAttributesA(child_file) != INVALID_FILE_ATTRIBUTES) + { + int c; + dump_child_(file, line); + c = GetPrivateProfileIntA("Child", "Failures", -1, child_file); + if (c > 0) + winetest_add_failures(c); + okChildInt_(file, line, "ShlexecVarLE", 0); + okChildString_(file, line, "ShlexecVar", "Present", "Present"); + }
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); + okShell_(file, line)(rc == rcEmpty || + broken(rc != rcEmpty && rcEmpty == SE_ERR_NOASSOC) /* NT4 */, + "Got different return value with empty string: %lu %lu\n", rc, rcEmpty); }
return rc; } - -static INT_PTR shell_execute_ex(DWORD mask, LPCSTR verb, LPCSTR file, - LPCSTR parameters, LPCSTR directory, - LPCSTR class) -{ +#define shell_execute(verb, filename, parameters, directory) \ + shell_execute_(__FILE__, __LINE__, verb, filename, parameters, directory) + +static INT_PTR shell_execute_ex_(const char* file, int line, + DWORD mask, LPCSTR verb, LPCSTR filename, + LPCSTR parameters, LPCSTR directory, + LPCSTR class) +{ + char smask[11]; SHELLEXECUTEINFOA sei; BOOL success; INT_PTR rc;
+ /* Add some flags so we can wait for the child process */ + mask |= SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE; + strcpy(shell_call, "ShellExecuteEx("); - if (mask) - { - char smask[11]; - sprintf(smask, "0x%x", mask); - strcat_param(shell_call, "mask", smask); - } + 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, "file", filename); strcat_param(shell_call, "params", parameters); strcat_param(shell_call, "dir", directory); strcat_param(shell_call, "class", class); strcat(shell_call, ")"); + strcat(shell_call, assoc_desc); if (winetest_debug > 1) - trace("%s\n", shell_call); + trace_(file, line)("Called %s\n", shell_call);
sei.cbSize=sizeof(sei); - sei.fMask=SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE | mask; + sei.fMask=mask; sei.hwnd=NULL; sei.lpVerb=verb; - sei.lpFile=file; + sei.lpFile=filename; sei.lpParameters=parameters; sei.lpDirectory=directory; sei.nShow=SW_SHOWNORMAL; @@ -198,39 +612,70 @@ sei.hkeyClass=NULL; sei.dwHotKey=0; U(sei).hIcon=NULL; - sei.hProcess=NULL; /* Out */ + sei.hProcess=(HANDLE)0xdeadbeef; /* Out */
DeleteFileA(child_file); SetLastError(0xcafebabe); success=ShellExecuteExA(&sei); rc=(INT_PTR)sei.hInstApp; - ok((success && rc > 32) || (!success && rc <= 32), - "%s rc=%d and hInstApp=%ld is not allowed\n", shell_call, success, rc); + okShell_(file, line)((success && rc > 32) || (!success && rc <= 32), + "rc=%d and hInstApp=%ld is not allowed\n", + success, rc);
if (rc > 32) { - int wait_rc; + DWORD wait_rc, rc; if (sei.hProcess!=NULL) { wait_rc=WaitForSingleObject(sei.hProcess, 5000); - ok(wait_rc==WAIT_OBJECT_0, "WaitForSingleObject(hProcess) returned %d\n", wait_rc); + okShell_(file, line)(wait_rc==WAIT_OBJECT_0, + "WaitForSingleObject(hProcess) returned %d\n", + wait_rc); + wait_rc = GetExitCodeProcess(sei.hProcess, &rc); + okShell_(file, line)(wait_rc, "GetExitCodeProcess() failed le=%u\n", GetLastError()); + todo_wine_if(_todo_wait) + okShell_(file, line)(rc == 0, "child returned %u\n", rc); + CloseHandle(sei.hProcess); } wait_rc=WaitForSingleObject(hEvent, 5000); - 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); - } + todo_wine_if(_todo_wait) + okShell_(file, line)(wait_rc==WAIT_OBJECT_0, + "WaitForSingleObject returned %d\n", wait_rc); + } + else + okShell_(file, line)(sei.hProcess==NULL, + "returned a process handle %p\n", sei.hProcess); + /* The child process may have changed the result file, so let profile * functions know about it */ WritePrivateProfileStringA(NULL, NULL, NULL, child_file); - if (rc > 32) - dump_child(); + if (GetFileAttributesA(child_file) != INVALID_FILE_ATTRIBUTES) + { + int c; + dump_child_(file, line); + c = GetPrivateProfileIntA("Child", "Failures", -1, child_file); + if (c > 0) + winetest_add_failures(c); + /* When NOZONECHECKS is specified the environment variables are not + * inherited if the process does not have elevated privileges. + */ + if ((mask & SEE_MASK_NOZONECHECKS) && skip_shlexec_tests) + { + okChildInt_(file, line, "ShlexecVarLE", 203); + okChildString_(file, line, "ShlexecVar", "", ""); + } + else + { + okChildInt_(file, line, "ShlexecVarLE", 0); + okChildString_(file, line, "ShlexecVar", "Present", "Present"); + } + }
return rc; } - +#define shell_execute_ex(mask, verb, filename, parameters, directory, class) \ + shell_execute_ex_(__FILE__, __LINE__, mask, verb, filename, parameters, directory, class)
/*** @@ -248,6 +693,8 @@ sprintf(class, "shlexec%s", extension); rc=RegCreateKeyExA(HKEY_CLASSES_ROOT, extension, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, NULL); + ok(rc == ERROR_SUCCESS || rc == ERROR_ACCESS_DENIED, + "could not create association %s (rc=%d)\n", class, rc); if (rc != ERROR_SUCCESS) return FALSE;
@@ -355,6 +802,17 @@ char* cmd; LONG rc;
+ strcpy(assoc_desc, " Assoc "); + strcat_param(assoc_desc, "ext", extension); + strcat_param(assoc_desc, "verb", verb); + sprintf(shell, "%d", rawcmd); + strcat_param(assoc_desc, "rawcmd", shell); + strcat_param(assoc_desc, "cmdtail", cmdtail); + strcat_param(assoc_desc, "ddeexec", ddeexec); + strcat_param(assoc_desc, "app", application); + strcat_param(assoc_desc, "topic", topic); + strcat_param(assoc_desc, "ifexec", ifexec); + sprintf(shell, "shlexec%s\shell", extension); rc=RegOpenKeyExA(HKEY_CLASSES_ROOT, shell, 0, KEY_CREATE_SUB_KEY, &hkey_shell); @@ -431,337 +889,18 @@ CloseHandle(hkey_cmd); }
+/* Creates a class' non-DDE test verb. + * This function is meant to be used to create long term test verbs and thus + * does not trace them. + */ static void create_test_verb(const char* extension, const char* verb, int rawcmd, const char* cmdtail) { create_test_verb_dde(extension, verb, rawcmd, cmdtail, NULL, NULL, NULL, NULL); -} - -/*** - * - * Functions to check that the child process was started just right - * (borrowed from dlls/kernel32/tests/process.c) - * - ***/ - -static const char* encodeA(const char* str) -{ - static char encoded[2*1024+1]; - char* ptr; - size_t len,i; - - if (!str) return ""; - len = strlen(str) + 1; - if (len >= sizeof(encoded)/2) - { - fprintf(stderr, "string is too long!\n"); - assert(0); - } - ptr = encoded; - for (i = 0; i < len; i++) - sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]); - ptr[2 * len] = '\0'; - return ptr; -} - -static unsigned decode_char(char c) -{ - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; - assert(c >= 'A' && c <= 'F'); - return c - 'A' + 10; -} - -static char* decodeA(const char* str) -{ - static char decoded[1024]; - char* ptr; - size_t len,i; - - len = strlen(str) / 2; - if (!len--) return NULL; - if (len >= sizeof(decoded)) - { - fprintf(stderr, "string is too long!\n"); - assert(0); - } - ptr = decoded; - for (i = 0; i < len; i++) - ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]); - ptr[len] = '\0'; - return ptr; -} - -static void childPrintf(HANDLE h, const char* fmt, ...) -{ - va_list valist; - char buffer[1024]; - DWORD w; - - va_start(valist, fmt); - vsprintf(buffer, fmt, valist); - va_end(valist); - WriteFile(h, buffer, strlen(buffer), &w, NULL); -} - -static DWORD ddeInst; -static HSZ hszTopic; -static char ddeExec[MAX_PATH], ddeApplication[MAX_PATH]; -static BOOL post_quit_on_execute; - -static HDDEDATA CALLBACK ddeCb(UINT uType, UINT uFmt, HCONV hConv, - HSZ hsz1, HSZ hsz2, HDDEDATA hData, - ULONG_PTR dwData1, ULONG_PTR dwData2) -{ - DWORD size = 0; - - if (winetest_debug > 2) - trace("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n", - uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2); - - switch (uType) - { - case XTYP_CONNECT: - if (!DdeCmpStringHandles(hsz1, hszTopic)) - { - size = DdeQueryStringA(ddeInst, hsz2, ddeApplication, MAX_PATH, CP_WINANSI); - ok(size < MAX_PATH, "got size %d\n", size); - assert(size < MAX_PATH); - return (HDDEDATA)TRUE; - } - return (HDDEDATA)FALSE; - - case XTYP_EXECUTE: - size = DdeGetData(hData, (LPBYTE)ddeExec, MAX_PATH, 0); - ok(size < MAX_PATH, "got size %d\n", size); - assert(size < MAX_PATH); - DdeFreeDataHandle(hData); - if (post_quit_on_execute) - PostQuitMessage(0); - return (HDDEDATA)DDE_FACK; - - default: - return NULL; - } -} - -/* - * This is just to make sure the child won't run forever stuck in a GetMessage() - * loop when DDE fails for some reason. - */ -static void CALLBACK childTimeout(HWND wnd, UINT msg, UINT_PTR timer, DWORD time) -{ - trace("childTimeout called\n"); - - PostQuitMessage(0); -} - -static void doChild(int argc, char** argv) -{ - char *filename, longpath[MAX_PATH] = ""; - HANDLE hFile, map; - int i; - int rc; - HSZ hszApplication; - UINT_PTR timer; - HANDLE dde_ready; - MSG msg; - char *shared_block; - - filename=argv[2]; - hFile=CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); - if (hFile == INVALID_HANDLE_VALUE) - return; - - /* 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]); - childPrintf(hFile, "argvA%d=%s\r\n", i, encodeA(argv[i])); - } - GetModuleFileNameA(GetModuleHandleA(NULL), longpath, MAX_PATH); - childPrintf(hFile, "longPath=%s\r\n", encodeA(longpath)); - - map = OpenFileMappingA(FILE_MAP_READ, FALSE, "winetest_shlexec_dde_map"); - if (map != NULL) - { - shared_block = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 4096); - CloseHandle(map); - if (shared_block[0] != '\0' || shared_block[1] != '\0') - { - post_quit_on_execute = TRUE; - ddeInst = 0; - rc = DdeInitializeA(&ddeInst, ddeCb, CBF_SKIP_ALLNOTIFICATIONS | CBF_FAIL_ADVISES | - CBF_FAIL_POKES | CBF_FAIL_REQUESTS, 0); - ok(rc == DMLERR_NO_ERROR, "got %d\n", rc); - hszApplication = DdeCreateStringHandleA(ddeInst, shared_block, CP_WINANSI); - hszTopic = DdeCreateStringHandleA(ddeInst, shared_block + strlen(shared_block) + 1, CP_WINANSI); - assert(hszApplication && hszTopic); - assert(DdeNameService(ddeInst, hszApplication, 0, DNS_REGISTER | DNS_FILTEROFF)); - - timer = SetTimer(NULL, 0, 2500, childTimeout); - - dde_ready = OpenEventA(EVENT_MODIFY_STATE, FALSE, "winetest_shlexec_dde_ready"); - SetEvent(dde_ready); - CloseHandle(dde_ready); - - while (GetMessageA(&msg, NULL, 0, 0)) - DispatchMessageA(&msg); - - Sleep(500); - KillTimer(NULL, timer); - assert(DdeNameService(ddeInst, hszApplication, 0, DNS_UNREGISTER)); - assert(DdeFreeStringHandle(ddeInst, hszTopic)); - assert(DdeFreeStringHandle(ddeInst, hszApplication)); - assert(DdeUninitialize(ddeInst)); - } - else - { - dde_ready = OpenEventA(EVENT_MODIFY_STATE, FALSE, "winetest_shlexec_dde_ready"); - SetEvent(dde_ready); - CloseHandle(dde_ready); - } - - UnmapViewOfFile(shared_block); - - childPrintf(hFile, "ddeExec=%s\r\n", encodeA(ddeExec)); - } - - CloseHandle(hFile); - - init_event(filename); - SetEvent(hEvent); - CloseHandle(hEvent); -} - -static char* getChildString(const char* sect, const char* key) -{ - char buf[1024]; - char* ret; - - GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), child_file); - if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL; - assert(!(strlen(buf) & 1)); - ret = decodeA(buf); - return ret; -} - -static void dump_child(void) -{ - if (winetest_debug > 1) - { - char key[18]; - 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); - } - } -} - -static int StrCmpPath(const char* s1, const char* s2) -{ - if (!s1 && !s2) return 0; - if (!s2) return 1; - if (!s1) return -1; - while (*s1) - { - if (!*s2) - { - if (*s1=='.') - s1++; - return (*s1-*s2); - } - if ((*s1=='/' || *s1=='\') && (*s2=='/' || *s2=='\')) - { - while (*s1=='/' || *s1=='\') - s1++; - while (*s2=='/' || *s2=='\') - s2++; - } - else if (toupper(*s1)==toupper(*s2)) - { - s1++; - s2++; - } - else - { - return (*s1-*s2); - } - } - if (*s2=='.') - s2++; - if (*s2) - return -1; - return 0; -} - -static void _okChildString(const char* file, int line, const char* key, const char* expected, const char* bad) -{ - char* result; - result=getChildString("Arguments", key); - if (!result) - { - ok_(file, line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected); - return; - } - ok_(file, line)(lstrcmpiA(result, expected) == 0 || - broken(lstrcmpiA(result, bad) == 0), - "%s expected '%s', got '%s'\n", key, expected, result); -} - -static void _okChildPath(const char* file, int line, const char* key, const char* expected) -{ - char* result; - result=getChildString("Arguments", key); - if (!result) - { - ok_(file, line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected); - return; - } - ok_(file, line)(StrCmpPath(result, expected) == 0, - "%s expected '%s', got '%s'\n", key, expected, result); -} - -static void _okChildInt(const char* file, int line, const char* key, int expected) -{ - INT result; - result=GetPrivateProfileIntA("Arguments", key, expected, child_file); - ok_(file, line)(result == expected, - "%s expected %d, but got %d\n", key, expected, result); -} - -static void _okChildIntBroken(const char* file, int line, const char* key, int expected) -{ - INT result; - result=GetPrivateProfileIntA("Arguments", key, expected, child_file); - ok_(file, line)(result == expected || broken(result != expected), - "%s expected %d, but got %d\n", key, expected, result); -} - -#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)) -#define okChildIntBroken(key, expected) _okChildIntBroken(__FILE__, __LINE__, (key), (expected)) + reset_association_description(); +} +
/*** * @@ -836,6 +975,7 @@
return tmplen; } +
/*** * @@ -901,6 +1041,8 @@ {"QuotedLowerL", "%s\test file.shlexec", 0x0, 33}, {"QuotedUpperL", "%s\test file.shlexec", 0x0, 33},
+ {"notaverb", "%s\test file.shlexec", 0x10, SE_ERR_NOASSOC}, + /* Test file masked due to space */ {NULL, "%s\masked file.shlexec", 0x0, 33}, /* Test if quoting prevents the masking */ @@ -935,48 +1077,48 @@ /* existing "drawback_file.noassoc" prevents finding "drawback_file.noassoc foo.shlexec" on wine */ sprintf(fileA, "%s\drawback_file.noassoc foo.shlexec", tmpdir); rc=shell_execute(NULL, fileA, NULL, NULL); - ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc); + okShell(rc > 32, "failed: rc=%lu\n", rc);
/* if quoted, existing "drawback_file.noassoc" not prevents finding "drawback_file.noassoc foo.shlexec" on wine */ sprintf(fileA, ""%s\drawback_file.noassoc foo.shlexec"", tmpdir); rc=shell_execute(NULL, fileA, NULL, NULL); - ok(rc > 32 || broken(rc == SE_ERR_FNF) /* Win95/NT4 */, - "%s failed: rc=%lu\n", shell_call, rc); + okShell(rc > 32 || broken(rc == SE_ERR_FNF) /* Win95/NT4 */, + "failed: rc=%lu\n", 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 == SE_ERR_FNF, "%s succeeded: rc=%lu\n", shell_call, rc); + okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
/* ""command"" not works on wine (and real win9x and w2k) */ sprintf(fileA, """%s\simple.shlexec""", tmpdir); rc=shell_execute(NULL, fileA, NULL, NULL); - todo_wine ok(rc > 32 || broken(rc == SE_ERR_FNF) /* Win9x/2000 */, - "%s failed: rc=%lu\n", shell_call, rc); + todo_wine okShell(rc > 32 || broken(rc == SE_ERR_FNF) /* Win9x/2000 */, + "failed: rc=%lu\n", rc);
/* nonexisting "drawback_nonexist.noassoc" not prevents finding "drawback_nonexist.noassoc foo.shlexec" on wine */ sprintf(fileA, "%s\drawback_nonexist.noassoc foo.shlexec", tmpdir); rc=shell_execute(NULL, fileA, NULL, NULL); - ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc); + okShell(rc > 32, "failed: rc=%lu\n", rc);
/* is SEE_MASK_DOENVSUBST default flag? Should only be when XP emulates 9x (XP bug or real 95 or ME behavior ?) */ rc=shell_execute(NULL, "%TMPDIR%\simple.shlexec", NULL, NULL); - todo_wine ok(rc == SE_ERR_FNF, "%s succeeded: rc=%lu\n", shell_call, rc); + todo_wine okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
/* quoted */ rc=shell_execute(NULL, ""%TMPDIR%\simple.shlexec"", NULL, NULL); - todo_wine ok(rc == SE_ERR_FNF, "%s succeeded: rc=%lu\n", shell_call, rc); + todo_wine okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
/* test SEE_MASK_DOENVSUBST works */ 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); + okShell(rc > 32, "failed: rc=%lu\n", 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); + okShell(rc > 32 || broken(rc == SE_ERR_FNF) /* Win95/NT4 */, + "failed: rc=%lu\n", rc); }
typedef struct @@ -1169,24 +1311,18 @@ count = 0; while (test->args[count]) count++; - if ((test->todo & 0x1) == 0) + todo_wine_if(test->todo & 0x1) 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) + todo_wine_if(test->todo & (1 << (i+4))) 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 + } + else todo_wine_if(test->todo & 0x1) ok(0, "%s: got extra arg[%d]=%s\n", test->cmd, i, wine_dbgstr_w(*argsW)); argsW++; } @@ -1416,6 +1552,18 @@ const char* cmd; unsigned i, count;
+ /* 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); + okShell(rc > 32, "failed: rc=%lu\n", rc); + okChildInt("argcA", 4); + okChildPath("argvA3", fileA); + if (skip_shlexec_tests) { skip("No argify tests due to lack of .shlexec association\n"); @@ -1439,40 +1587,33 @@
/* 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); + okShell(rc > 32, "failed: rc=%lu\n", 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. - */ + /* +4 for the shlexec arguments, -1 because of the added "" + * argument for the CommandLineToArgvW() tests. + */ + todo_wine_if(test->todo & 0x1) okChildInt("argcA", 4 + count - 1); - else todo_wine - okChildInt("argcA", 4 + count - 1); - - cmd = getChildString("Arguments", "cmdlineA"); + + cmd = getChildString("Child", "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); + todo_wine_if(test->todo & 0x2) + okShell(!strcmp(cmd, test->cmd.cmd) || broken(!strcmp(cmd, bad->cmd)), + "the cmdline is '%s' instead of '%s'\n", 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 + todo_wine_if(test->todo & (1 << (i+4))) okChildStringBroken(argname, test->cmd.args[i+1], bad->args[i+1]); }
@@ -1480,18 +1621,6 @@ 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) @@ -1544,38 +1673,19 @@ } if (rc > 32) rc=33; - ok(rc==test->rc || - broken(quotedfile && rc == SE_ERR_FNF), /* NT4 */ - "%s failed: rc=%ld err=%u\n", shell_call, - rc, GetLastError()); + okShell(rc==test->rc || + broken(quotedfile && rc == SE_ERR_FNF), /* NT4 */ + "failed: rc=%ld err=%u\n", rc, GetLastError()); if (rc == 33) { const char* verb; - if ((test->todo & 0x2)==0) - { + todo_wine_if(test->todo & 0x2) okChildInt("argcA", 5); - } - else todo_wine - { - okChildInt("argcA", 5); - } verb=(test->verb ? test->verb : "Open"); - if ((test->todo & 0x4)==0) - { + todo_wine_if(test->todo & 0x4) okChildString("argvA3", verb); - } - else todo_wine - { - okChildString("argvA3", verb); - } - if ((test->todo & 0x8)==0) - { + todo_wine_if(test->todo & 0x8) okChildPath("argvA4", filename); - } - else todo_wine - { - okChildPath("argvA4", filename); - } } test++; } @@ -1587,16 +1697,8 @@ rc=shell_execute(test->verb, filename, NULL, NULL); if (rc > 32) rc=33; - if ((test->todo & 0x1)==0) - { - 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=%ld err=%u\n", shell_call, - rc, GetLastError()); - } + todo_wine_if(test->todo & 0x1) + okShell(rc==test->rc, "failed: rc=%ld err=%u\n", rc, GetLastError()); if (rc==0) { int count; @@ -1604,14 +1706,8 @@ char* str;
verb=(test->verb ? test->verb : "Open"); - if ((test->todo & 0x4)==0) - { + todo_wine_if(test->todo & 0x4) okChildString("argvA3", verb); - } - else todo_wine - { - okChildString("argvA3", verb); - }
count=4; str=filename; @@ -1623,27 +1719,15 @@ if (space) *space='\0'; sprintf(attrib, "argvA%d", count); - if ((test->todo & 0x8)==0) - { + todo_wine_if(test->todo & 0x8) okChildPath(attrib, str); - } - else todo_wine - { - okChildPath(attrib, str); - } count++; if (!space) break; str=space+1; } - if ((test->todo & 0x2)==0) - { + todo_wine_if(test->todo & 0x2) okChildInt("argcA", count); - } - else todo_wine - { - okChildInt("argcA", count); - } } test++; } @@ -1658,8 +1742,7 @@ */ sprintf(filename, ""%s\test file.shlexec"", tmpdir); rc=shell_execute(NULL, filename, NULL, NULL); - ok(rc > 32, "%s failed: rc=%ld err=%u\n", shell_call, rc, - GetLastError()); + okShell(rc > 32, "failed: rc=%ld err=%u\n", rc, GetLastError()); okChildInt("argcA", 5); okChildString("argvA3", "Open"); sprintf(filename, "%s\test file.shlexec", tmpdir); @@ -1726,7 +1809,8 @@ return; }
- rc = (INT_PTR)ShellExecuteA(NULL, NULL, "file:///nosuchfile.shlexec", NULL, NULL, SW_SHOWNORMAL); + rc = shell_execute_ex(SEE_MASK_FLAG_NO_UI, NULL, + "file:///nosuchfile.shlexec", NULL, NULL, NULL); if (rc > 32) { win_skip("shell32 is too old (likely < 4.72). Skipping the file URL tests\n"); @@ -1769,37 +1853,23 @@ } 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); + todo_wine_if(test->todo & 0x1) + okShell(rc > 32, "failed: bad rc=%lu\n", 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); + todo_wine_if(test->todo & 0x1) + okShell(rc == SE_ERR_FNF || rc == SE_ERR_PNF || + broken(rc == SE_ERR_ACCESSDENIED) /* win2000 */, + "failed: bad rc=%lu\n", rc); } if (rc == 33) { - if ((test->todo & 0x2) == 0) + todo_wine_if(test->todo & 0x2) okChildInt("argcA", 5); - else todo_wine - okChildInt("argcA", 5); - - if ((test->todo & 0x4) == 0) + todo_wine_if(test->todo & 0x4) okChildString("argvA3", "Open"); - else todo_wine - okChildString("argvA3", "Open"); - - if ((test->todo & 0x8) == 0) - okChildPath("argvA4", filename); - else todo_wine + todo_wine_if(test->todo & 0x8) okChildPath("argvA4", filename); } test++; @@ -1922,30 +1992,17 @@ rc=(INT_PTR)FindExecutableA(filename, NULL, command); if (rc > 32) rc=33; - if ((test->todo & 0x10)==0) - { + todo_wine_if(test->todo & 0x10) ok(rc==test->rc, "FindExecutable(%s) failed: rc=%ld\n", filename, rc); - } - else todo_wine - { - ok(rc==test->rc, "FindExecutable(%s) failed: rc=%ld\n", filename, rc); - } if (rc > 32) { BOOL equal; equal=strcmp(command, argv0) == 0 || /* NT4 returns an extra 0x8 character! */ (strlen(command) == strlen(argv0)+1 && strncmp(command, argv0, strlen(argv0)) == 0); - if ((test->todo & 0x20)==0) - { + todo_wine_if(test->todo & 0x20) ok(equal, "FindExecutable(%s) returned command='%s' instead of '%s'\n", filename, command, argv0); - } - else todo_wine - { - ok(equal, "FindExecutable(%s) returned command='%s' instead of '%s'\n", - filename, command, argv0); - } } test++; } @@ -1982,7 +2039,7 @@ /* Should open through our association */ sprintf(filename, "%s\test_shortcut_shlexec.lnk", tmpdir); 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()); + okShell(rc > 32, "failed: rc=%lu err=%u\n", rc, GetLastError()); okChildInt("argcA", 5); okChildString("argvA3", "Open"); sprintf(params, "%s\test file.shlexec", tmpdir); @@ -1990,7 +2047,7 @@ 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()); + okShell(rc > 32, "failed: rc=%lu err=%u\n", rc, GetLastError()); okChildInt("argcA", 5); todo_wine okChildString("argvA3", "Open"); sprintf(params, "%s\test file.shlexec", tmpdir); @@ -2001,15 +2058,19 @@ /* Should just run our executable */ sprintf(filename, "%s\test_shortcut_exe.lnk", tmpdir); 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()); + okShell(rc > 32, "failed: rc=%lu err=%u\n", 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"); + if (!skip_shlexec_tests) + { + /* An explicit class overrides lnk's ContextMenuHandler */ + rc=shell_execute_ex(SEE_MASK_CLASSNAME | SEE_MASK_NOZONECHECKS, NULL, filename, NULL, NULL, "shlexec.shlexec"); + okShell(rc > 32, "failed: rc=%lu err=%u\n", rc, GetLastError()); + okChildInt("argcA", 5); + okChildString("argvA3", "Open"); + okChildPath("argvA4", filename); + }
if (dllver.dwMajorVersion>=6) { @@ -2026,8 +2087,7 @@ c++; } 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()); + okShell(rc > 32, "failed: rc=%lu err=%u\n", rc, GetLastError()); okChildInt("argcA", 4); okChildString("argvA3", "Lnk"); } @@ -2043,43 +2103,16 @@ NULL, NULL); if (rc > 32) rc=33; - if ((test->todo & 0x1)==0) - { - 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=%lu err=%u\n", shell_call, - rc, GetLastError()); - } + todo_wine_if(test->todo & 0x1) + okShell(rc==test->rc, "failed: rc=%lu err=%u\n", rc, GetLastError()); if (rc==0) { - if ((test->todo & 0x2)==0) - { + todo_wine_if(test->todo & 0x2) okChildInt("argcA", 5); - } - else - { - okChildInt("argcA", 5); - } - if ((test->todo & 0x4)==0) - { + todo_wine_if(test->todo & 0x4) okChildString("argvA3", "Lnk"); - } - else todo_wine - { - okChildString("argvA3", "Lnk"); - } sprintf(params, test->basename, tmpdir); - if ((test->todo & 0x8)==0) - { - okChildPath("argvA4", params); - } - else - { - okChildPath("argvA4", params); - } + okChildPath("argvA4", params); } test++; } @@ -2097,7 +2130,7 @@ /* 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 returned %lu\n", shell_call, rc); + okShell(rc > 32, "returned %lu\n", rc); okChildInt("argcA", 4); okChildString("argvA3", "Exec");
@@ -2108,7 +2141,7 @@ { rc=shell_execute(NULL, filename, params, NULL); todo_wine { - ok(rc==SE_ERR_NOASSOC, "%s succeeded: rc=%lu\n", shell_call, rc); + okShell(rc==SE_ERR_NOASSOC, "returned %lu\n", rc); } } } @@ -2120,11 +2153,28 @@ /* test combining executable and parameters */ sprintf(filename, "%s shlexec "%s" Exec", argv0, child_file); rc = shell_execute(NULL, filename, NULL, NULL); - ok(rc == SE_ERR_FNF, "%s returned %lu\n", shell_call, rc); + okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
sprintf(filename, ""%s" shlexec "%s" Exec", argv0, child_file); rc = shell_execute(NULL, filename, NULL, NULL); - ok(rc == SE_ERR_FNF, "%s returned %lu\n", shell_call, rc); + okShell(rc == SE_ERR_FNF, "returned %lu\n", rc); + + /* A verb, even if invalid, overrides the normal handling of executables */ + todo_wait rc = shell_execute_ex(SEE_MASK_FLAG_NO_UI, + "notaverb", argv0, NULL, NULL, NULL); + todo_wine okShell(rc == SE_ERR_NOASSOC, "returned %lu\n", rc); + + if (!skip_shlexec_tests) + { + /* A class overrides the normal handling of executables too */ + /* FIXME SEE_MASK_FLAG_NO_UI is only needed due to Wine's bug */ + rc = shell_execute_ex(SEE_MASK_CLASSNAME | SEE_MASK_FLAG_NO_UI, + NULL, argv0, NULL, NULL, ".shlexec"); + todo_wine okShell(rc > 32, "returned %lu\n", rc); + okChildInt("argcA", 5); + todo_wine okChildString("argvA3", "Open"); + todo_wine okChildPath("argvA4", argv0); + } }
typedef struct @@ -2143,32 +2193,37 @@ { /* Test passing and not passing command-line * argument, no DDE */ - {"", NULL, NULL, NULL, NULL, FALSE, ""}, - {""%1"", NULL, NULL, NULL, NULL, TRUE, ""}, + {"", NULL, NULL, NULL, NULL, 0, ""}, + {""%1"", NULL, NULL, NULL, NULL, 1, ""},
/* Test passing and not passing command-line * argument, with DDE */ - {"", "[open("%1")]", "shlexec", "dde", NULL, FALSE, "[open("%s")]"}, - {""%1"", "[open("%1")]", "shlexec", "dde", NULL, TRUE, "[open("%s")]"}, + {"", "[open("%1")]", "shlexec", "dde", NULL, 0, "[open("%s")]"}, + {""%1"", "[open("%1")]", "shlexec", "dde", NULL, 1, "[open("%s")]"},
/* Test unquoted %1 in command and ddeexec * (test filename has space) */ {"%1", "[open(%1)]", "shlexec", "dde", NULL, 2, "[open(%s)]", TRUE /* before vista */},
/* Test ifexec precedence over ddeexec */ - {"", "[open("%1")]", "shlexec", "dde", "[ifexec("%1")]", FALSE, "[ifexec("%s")]"}, + {"", "[open("%1")]", "shlexec", "dde", "[ifexec("%1")]", 0, "[ifexec("%s")]"},
/* Test default DDE topic */ - {"", "[open("%1")]", "shlexec", NULL, NULL, FALSE, "[open("%s")]"}, + {"", "[open("%1")]", "shlexec", NULL, NULL, 0, "[open("%s")]"},
/* Test default DDE application */ - {"", "[open("%1")]", NULL, "dde", NULL, FALSE, "[open("%s")]"}, + {"", "[open("%1")]", NULL, "dde", NULL, 0, "[open("%s")]"},
{NULL} };
+static int waitforinputidle_count; static DWORD WINAPI hooked_WaitForInputIdle(HANDLE process, DWORD timeout) { + waitforinputidle_count++; + if (winetest_debug > 1) + trace("WaitForInputIdle() waiting for dde event timeout=min(%u,5s)\n", timeout); + timeout = timeout < 5000 ? timeout : 5000; return WaitForSingleObject(dde_ready_event, timeout); }
@@ -2187,6 +2242,7 @@ PIMAGE_NT_HEADERS nt_headers; DWORD import_directory_rva; PIMAGE_IMPORT_DESCRIPTOR import_descriptor; + int hook_count = 0;
base = (char *) GetModuleHandleA("shell32.dll"); nt_headers = (PIMAGE_NT_HEADERS)(base + ((PIMAGE_DOS_HEADER) base)->e_lfanew); @@ -2224,6 +2280,9 @@ VirtualProtect(&iat_entry->u1.Function, sizeof(ULONG_PTR), PAGE_READWRITE, &old_prot); iat_entry->u1.Function = (ULONG_PTR) new_func; VirtualProtect(&iat_entry->u1.Function, sizeof(ULONG_PTR), old_prot, &old_prot); + if (winetest_debug > 1) + trace("Hooked %s.WaitForInputIdle\n", import_module_name); + hook_count++; break; } } @@ -2235,6 +2294,7 @@
import_descriptor++; } + ok(hook_count, "Could not hook WaitForInputIdle()\n"); }
static void test_dde(void) @@ -2245,6 +2305,7 @@ INT_PTR rc; HANDLE map; char *shared_block; + DWORD ddeflags;
hook_WaitForInputIdle(hooked_WaitForInputIdle);
@@ -2258,6 +2319,7 @@ 4096, "winetest_shlexec_dde_map"); shared_block = MapViewOfFile(map, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 4096);
+ ddeflags = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI; test = dde_tests; while (test->command) { @@ -2281,10 +2343,33 @@ } 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, NULL); + waitforinputidle_count = 0; + dde_ready_event = CreateEventA(NULL, TRUE, FALSE, "winetest_shlexec_dde_ready"); + rc = shell_execute_ex(ddeflags, NULL, filename, NULL, NULL, NULL); CloseHandle(dde_ready_event); - ok(32 < rc, "%s failed: rc=%lu err=%u\n", shell_call, rc, GetLastError()); + if (!(ddeflags & SEE_MASK_WAITFORINPUTIDLE) && rc == SE_ERR_DDEFAIL && + GetLastError() == ERROR_FILE_NOT_FOUND && + strcmp(winetest_platform, "windows") == 0) + { + /* Windows 10 does not call WaitForInputIdle() for DDE which creates + * a race condition as the DDE server may not have time to start up. + * When that happens the test fails with the above results and we + * compensate by forcing the WaitForInputIdle() call. + */ + trace("Adding SEE_MASK_WAITFORINPUTIDLE for Windows 10\n"); + ddeflags |= SEE_MASK_WAITFORINPUTIDLE; + delete_test_association(".sde"); + Sleep(CHILD_DDE_TIMEOUT); + continue; + } + okShell(32 < rc, "failed: rc=%lu err=%u\n", rc, GetLastError()); + if (test->ddeexec) + okShell(waitforinputidle_count == 1 || + broken(waitforinputidle_count == 0) /* Win10 race */, + "WaitForInputIdle() was called %u times\n", + waitforinputidle_count); + else + okShell(waitforinputidle_count == 0, "WaitForInputIdle() was called %u times for a non-DDE case\n", waitforinputidle_count);
if (32 < rc) { @@ -2298,6 +2383,7 @@ sprintf(params, test->expectedDdeExec, filename); okChildPath("ddeExec", params); } + reset_association_description();
delete_test_association(".sde"); test++; @@ -2308,7 +2394,7 @@ hook_WaitForInputIdle((void *) WaitForInputIdle); }
-#define DDE_DEFAULT_APP_VARIANTS 2 +#define DDE_DEFAULT_APP_VARIANTS 3 typedef struct { const char* command; @@ -2319,42 +2405,44 @@
static dde_default_app_tests_t dde_default_app_tests[] = { - /* Windows XP and 98 handle default DDE app names in different ways. - * The application name we see in the first test determines the pattern - * of application names and return codes we will look for. */ + /* There are three possible sets of results: Windows <= 2000, XP SP1 and + * >= XP SP2. Use the first two tests to determine which results to expect. + */
/* Test unquoted existing filename with a space */ - {"%s\test file.exe", {"test file", "test"}, 0x0, {33, 33}}, - {"%s\test file.exe param", {"test file", "test"}, 0x0, {33, 33}}, + {"%s\test file.exe", {"test file", "test file", "test"}, 0x0, {33, 33, 33}}, + {"%s\test2 file.exe", {"test2", "", "test2"}, 0x0, {33, 5, 33}}, + + /* Test unquoted existing filename with a space */ + {"%s\test file.exe param", {"test file", "test file", "test"}, 0x0, {33, 33, 33}},
/* Test quoted existing filename with a space */ - {""%s\test file.exe"", {"test file", "test file"}, 0x0, {33, 33}}, - {""%s\test file.exe" param", {"test file", "test file"}, 0x0, {33, 33}}, + {""%s\test file.exe"", {"test file", "test file", "test file"}, 0x0, {33, 33, 33}}, + {""%s\test file.exe" param", {"test file", "test file", "test file"}, 0x0, {33, 33, 33}},
/* Test unquoted filename with a space that doesn't exist, but * test2.exe does */ - {"%s\test2 file.exe", {"test2", "test2"}, 0x0, {33, 33}}, - {"%s\test2 file.exe param", {"test2", "test2"}, 0x0, {33, 33}}, + {"%s\test2 file.exe param", {"test2", "", "test2"}, 0x0, {33, 5, 33}},
/* Test quoted filename with a space that does not exist */ - {""%s\test2 file.exe"", {"", "test2 file"}, 0x0, {5, 33}}, - {""%s\test2 file.exe" param", {"", "test2 file"}, 0x0, {5, 33}}, + {""%s\test2 file.exe"", {"", "", "test2 file"}, 0x0, {5, 2, 33}}, + {""%s\test2 file.exe" param", {"", "", "test2 file"}, 0x0, {5, 2, 33}},
/* Test filename supplied without the extension */ - {"%s\test2", {"test2", "test2"}, 0x0, {33, 33}}, - {"%s\test2 param", {"test2", "test2"}, 0x0, {33, 33}}, + {"%s\test2", {"test2", "", "test2"}, 0x0, {33, 5, 33}}, + {"%s\test2 param", {"test2", "", "test2"}, 0x0, {33, 5, 33}},
/* Test an unquoted nonexistent filename */ - {"%s\notexist.exe", {"", "notexist"}, 0x0, {5, 33}}, - {"%s\notexist.exe param", {"", "notexist"}, 0x0, {5, 33}}, + {"%s\notexist.exe", {"", "", "notexist"}, 0x0, {5, 2, 33}}, + {"%s\notexist.exe param", {"", "", "notexist"}, 0x0, {5, 2, 33}},
/* Test an application that will be found on the path */ - {"cmd", {"cmd", "cmd"}, 0x0, {33, 33}}, - {"cmd param", {"cmd", "cmd"}, 0x0, {33, 33}}, + {"cmd", {"cmd", "cmd", "cmd"}, 0x0, {33, 33, 33}}, + {"cmd param", {"cmd", "cmd", "cmd"}, 0x0, {33, 33, 33}},
/* Test an application that will not be found on the path */ - {"xyzwxyzwxyz", {"", "xyzwxyzwxyz"}, 0x0, {5, 33}}, - {"xyzwxyzwxyz param", {"", "xyzwxyzwxyz"}, 0x0, {5, 33}}, + {"xyzwxyzwxyz", {"", "", "xyzwxyzwxyz"}, 0x0, {5, 2, 33}}, + {"xyzwxyzwxyz param", {"", "", "xyzwxyzwxyz"}, 0x0, {5, 2, 33}},
{NULL, {NULL}, 0, {0}} }; @@ -2431,47 +2519,36 @@ while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA(&msg); rc = msg.wParam > 32 ? 33 : msg.wParam;
- /* First test, find which set of test data we expect to see */ - if (test == dde_default_app_tests) - { - int i; - for (i=0; i<DDE_DEFAULT_APP_VARIANTS; i++) + /* The first two tests determine which set of results to expect. + * First check the platform as only the first set of results is + * acceptable for Wine. + */ + if (strcmp(winetest_platform, "wine")) + { + if (test == dde_default_app_tests) { - if (!strcmp(ddeApplication, test->expectedDdeApplication[i])) - { - which = i; - break; - } + if (strcmp(ddeApplication, test->expectedDdeApplication[0])) + which = 2; } - if (i == DDE_DEFAULT_APP_VARIANTS) - skip("Default DDE application test does not match any available results, using first expected data set.\n"); - } - - if ((test->todo & 0x1)==0) - { - 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=%lu err=%u\n", shell_call, - rc, GetLastError()); - } + else if (test == dde_default_app_tests + 1) + { + if (which == 0 && rc == test->rc[1]) + which = 1; + trace("DDE result variant %d\n", which); + } + } + + todo_wine_if(test->todo & 0x1) + okShell(rc==test->rc[which], "failed: rc=%lu err=%u\n", + rc, GetLastError()); if (rc == 33) { - if ((test->todo & 0x2)==0) - { + todo_wine_if(test->todo & 0x2) ok(!strcmp(ddeApplication, test->expectedDdeApplication[which]), "Expected application '%s', got '%s'\n", test->expectedDdeApplication[which], ddeApplication); - } - else todo_wine - { - ok(!strcmp(ddeApplication, test->expectedDdeApplication[which]), - "Expected application '%s', got '%s'\n", - test->expectedDdeApplication[which], ddeApplication); - } - } + } + reset_association_description();
delete_test_association(".sde"); test++; @@ -2606,6 +2683,9 @@ create_test_verb(".shlexec", "QuotedLowerL", 0, "QuotedLowerL "%l""); create_test_verb(".shlexec", "UpperL", 0, "UpperL %L"); create_test_verb(".shlexec", "QuotedUpperL", 0, "QuotedUpperL "%L""); + + /* Set an environment variable to see if it is inherited */ + SetEnvironmentVariableA("ShlexecVar", "Present"); }
static void cleanup_test(void) @@ -2650,7 +2730,7 @@ SetCurrentDirectoryA(tmpdir); rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_FLAG_NO_UI, NULL, "test2.exe", params, NULL, NULL); - ok(rc > 32, "%s returned %lu\n", shell_call, rc); + okShell(rc > 32, "returned %lu\n", rc); okChildInt("argcA", 4); okChildString("argvA3", "Exec"); todo_wine okChildPath("longPath", path); @@ -2658,12 +2738,12 @@
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); + okShell(rc == SE_ERR_FNF, "returned %lu\n", 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); + okShell(rc > 32, "returned %lu\n", rc); okChildInt("argcA", 4); okChildString("argvA3", "Exec"); todo_wine okChildPath("longPath", path); @@ -2671,11 +2751,11 @@ /* 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); + todo_wine okShell(rc == SE_ERR_FNF, "returned %lu\n", 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); + okShell(rc > 32, "returned %lu\n", rc); okChildInt("argcA", 4); okChildString("argvA3", "Exec"); todo_wine okChildPath("longPath", path); @@ -2684,7 +2764,7 @@ 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); + okShell(rc == SE_ERR_FNF, "returned %lu\n", rc); }
START_TEST(shlexec) @@ -2694,7 +2774,8 @@ if (myARGC >= 3) { doChild(myARGC, myARGV); - exit(0); + /* Skip the tests/failures trace for child processes */ + ExitProcess(winetest_get_failures()); }
init_test();
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] Wed Mar 9 08:43:20 2016 @@ -388,6 +388,14 @@ SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM, SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM, }; + static const ULONG full_attrs[5] = + { + SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR, + SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR, + SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM, + SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM, + SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM, + };
hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList); ok(hr == S_OK, "EnumObjects failed %08x\n", hr); @@ -440,6 +448,11 @@ ok(flags == attrs[i] || flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */ "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]); + + flags = ~0u; + hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags); + ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr); + ok((flags & ~SFGAO_HASSUBFOLDER) == full_attrs[i], "%d: got %08x expected %08x\n", i, flags, full_attrs[i]); }
for (i=0;i<5;i++) @@ -1889,14 +1902,14 @@ if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path ); - ok( !hr, "SHGetFolderPathA failed %x\n", hr ); + ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr ); hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 ); if (hr == E_FAIL) { win_skip( "Program Files (x86) not supported\n" ); return; } - ok( !hr, "SHGetFolderPathA failed %x\n", hr ); + ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr ); if (is_win64) { ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path ); @@ -1924,14 +1937,14 @@ }
hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path ); - ok( !hr, "SHGetFolderPathA failed %x\n", hr ); + ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr ); hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 ); if (hr == E_FAIL) { win_skip( "Common Files (x86) not supported\n" ); return; } - ok( !hr, "SHGetFolderPathA failed %x\n", hr ); + ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr ); if (is_win64) { ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path ); @@ -5256,6 +5269,63 @@ IShellFolder_Release(desktop); }
+static void test_DataObject(void) +{ + IShellFolder *desktop; + IDataObject *data_obj; + HRESULT hres; + IEnumIDList *peidl; + LPITEMIDLIST apidl; + FORMATETC fmt; + DWORD cf_shellidlist; + STGMEDIUM medium; + + SHGetDesktopFolder(&desktop); + + hres = IShellFolder_EnumObjects(desktop, NULL, + SHCONTF_NONFOLDERS|SHCONTF_FOLDERS|SHCONTF_INCLUDEHIDDEN, &peidl); + ok(hres == S_OK, "got %x\n", hres); + + if(IEnumIDList_Next(peidl, 1, &apidl, NULL) != S_OK) { + skip("no files on desktop - skipping GetDataObject tests\n"); + IEnumIDList_Release(peidl); + IShellFolder_Release(desktop); + return; + } + IEnumIDList_Release(peidl); + + hres = IShellFolder_GetUIObjectOf(desktop, NULL, 1, (LPCITEMIDLIST*)&apidl, + &IID_IDataObject, NULL, (void**)&data_obj); + ok(hres == S_OK, "got %x\n", hres); + pILFree(apidl); + IShellFolder_Release(desktop); + + cf_shellidlist = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); + fmt.cfFormat = cf_shellidlist; + fmt.ptd = NULL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.tymed = TYMED_HGLOBAL; + hres = IDataObject_QueryGetData(data_obj, &fmt); + ok(hres == S_OK, "got %x\n", hres); + + fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM; + hres = IDataObject_QueryGetData(data_obj, &fmt); + ok(hres == S_OK, "got %x\n", hres); + + fmt.tymed = TYMED_ISTREAM; + hres = IDataObject_QueryGetData(data_obj, &fmt); + todo_wine ok(hres == S_FALSE, "got %x\n", hres); + + fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM; + hres = IDataObject_GetData(data_obj, &fmt, &medium); + ok(hres == S_OK, "got %x\n", hres); + ok(medium.tymed == TYMED_HGLOBAL, "medium.tymed = %x\n", medium.tymed); + ReleaseStgMedium(&medium); + + IDataObject_Release(data_obj); +} + START_TEST(shlfolder) { init_function_pointers(); @@ -5296,6 +5366,7 @@ test_SHCreateDefaultContextMenu(); test_SHCreateShellFolderView(); test_SHCreateShellFolderViewEx(); + test_DataObject();
OleUninitialize(); }