[1/6] shell32/tests: Reorder the functions to avoid forward declarations.
Francois Gouget
fgouget at codeweavers.com
Thu Jan 28 17:19:34 CST 2016
This also groups the helpers in a more logical fashion.
Signed-off-by: Francois Gouget <fgouget at codeweavers.com>
---
dlls/shell32/tests/shlexec.c | 999 ++++++++++++++++++++++---------------------
1 file changed, 508 insertions(+), 491 deletions(-)
diff --git a/dlls/shell32/tests/shlexec.c b/dlls/shell32/tests/shlexec.c
index 7844722..682b46b 100644
--- a/dlls/shell32/tests/shlexec.c
+++ b/dlls/shell32/tests/shlexec.c
@@ -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
@@ -64,10 +64,131 @@ static HANDLE dde_ready_event;
/***
*
- * ShellExecute wrappers
+ * 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 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
*
***/
-static void dump_child_(const char* file, int line);
+
+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)
@@ -77,21 +198,131 @@ static void init_event(const char* child_file)
hEvent=CreateEventA(NULL, FALSE, FALSE, event_name);
}
-static void strcat_param(char* str, const char* name, const char* param)
+/*
+ * 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)
{
- if (param)
+ 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)
{
- if (str[strlen(str)-1] == '"')
- strcat(str, ", ");
- strcat(str, name);
- strcat(str, "=\"");
- strcat(str, param);
- strcat(str, "\"");
+ 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 int _todo_wait = 0;
-#define todo_wait for (_todo_wait = 1; _todo_wait; _todo_wait = 0)
+static void dump_child_(const char* file, int line)
+{
+ if (winetest_debug > 1)
+ {
+ char key[18];
+ char* str;
+ int i, c;
+
+ str=getChildString("Arguments", "cmdlineA");
+ trace_(file, line)("cmdlineA='%s'\n", str);
+ c=GetPrivateProfileIntA("Arguments", "argcA", -1, child_file);
+ trace_(file, line)("argcA=%d\n",c);
+ for (i=0;i<c;i++)
+ {
+ sprintf(key, "argvA%d", i);
+ str=getChildString("Arguments", key);
+ trace_(file, line)("%s='%s'\n", key, str);
+ }
+ }
+}
+
+
+/***
+ *
+ * Helpers to check the ShellExecute() / child process results.
+ *
+ ***/
static char shell_call[2048];
static char assoc_desc[2048];
@@ -123,15 +354,124 @@ void reset_association_description(void)
*assoc_desc = '\0';
}
-static int bad_shellexecute = 0;
-static INT_PTR shell_execute_(const char* file, int line, LPCSTR verb, LPCSTR filename, LPCSTR parameters, LPCSTR directory)
+static void okChildString_(const char* file, int line, const char* key, const char* expected, const char* bad)
{
- INT_PTR rc, rcEmpty = 0;
-
- if(!verb)
- rcEmpty = shell_execute_(file, line, "", filename, parameters, directory);
-
- shell_call_traced=0;
+ char* result;
+ result=getChildString("Arguments", 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;
+ result=getChildString("Arguments", key);
+ if (!result)
+ {
+ okShell_(file,line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected);
+ return;
+ }
+ okShell_(file,line)(StrCmpPath(result, expected) == 0,
+ "%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("Arguments", 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("Arguments", 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 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, "\"");
+ }
+}
+
+static int _todo_wait = 0;
+#define todo_wait for (_todo_wait = 1; _todo_wait; _todo_wait = 0)
+
+static int bad_shellexecute = 0;
+
+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, line, "", filename, parameters, directory);
+
+ shell_call_traced=0;
strcpy(shell_call, "ShellExecute(");
strcat_param(shell_call, "verb", verb);
strcat_param(shell_call, "file", filename);
@@ -333,510 +673,186 @@ static LSTATUS myRegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
{
LONG ret;
DWORD dwMaxSubkeyLen, dwMaxValueLen;
- DWORD dwMaxLen, dwSize;
- CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
- HKEY hSubKey = hKey;
-
- if(lpszSubKey)
- {
- ret = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
- if (ret) return ret;
- }
-
- /* Get highest length for keys, values */
- ret = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, NULL,
- &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
- if (ret) goto cleanup;
-
- dwMaxSubkeyLen++;
- dwMaxValueLen++;
- dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
- if (dwMaxLen > sizeof(szNameBuf)/sizeof(CHAR))
- {
- /* Name too big: alloc a buffer for it */
- if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(CHAR))))
- {
- ret = ERROR_NOT_ENOUGH_MEMORY;
- goto cleanup;
- }
- }
-
-
- /* Recursively delete all the subkeys */
- while (TRUE)
- {
- dwSize = dwMaxLen;
- if (RegEnumKeyExA(hSubKey, 0, lpszName, &dwSize, NULL,
- NULL, NULL, NULL)) break;
-
- ret = myRegDeleteTreeA(hSubKey, lpszName);
- if (ret) goto cleanup;
- }
-
- if (lpszSubKey)
- ret = RegDeleteKeyA(hKey, lpszSubKey);
- else
- while (TRUE)
- {
- dwSize = dwMaxLen;
- if (RegEnumValueA(hKey, 0, lpszName, &dwSize,
- NULL, NULL, NULL, NULL)) break;
-
- ret = RegDeleteValueA(hKey, lpszName);
- if (ret) goto cleanup;
- }
-
-cleanup:
- /* Free buffer if allocated */
- if (lpszName != szNameBuf)
- HeapFree( GetProcessHeap(), 0, lpszName);
- if(lpszSubKey)
- RegCloseKey(hSubKey);
- return ret;
-}
-
-static void delete_test_association(const char* extension)
-{
- char class[MAX_PATH];
-
- sprintf(class, "shlexec%s", extension);
- myRegDeleteTreeA(HKEY_CLASSES_ROOT, class);
- myRegDeleteTreeA(HKEY_CLASSES_ROOT, extension);
-}
-
-static void create_test_verb_dde(const char* extension, const char* verb,
- int rawcmd, const char* cmdtail, const char *ddeexec,
- const char *application, const char *topic,
- const char *ifexec)
-{
- HKEY hkey_shell, hkey_verb, hkey_cmd;
- char shell[MAX_PATH];
- 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);
- ok(rc == ERROR_SUCCESS, "%s key creation failed with %d\n", shell, rc);
-
- rc=RegCreateKeyExA(hkey_shell, verb, 0, NULL, 0, KEY_CREATE_SUB_KEY,
- NULL, &hkey_verb, NULL);
- ok(rc == ERROR_SUCCESS, "%s verb key creation failed with %d\n", verb, rc);
-
- rc=RegCreateKeyExA(hkey_verb, "command", 0, NULL, 0, KEY_SET_VALUE,
- NULL, &hkey_cmd, NULL);
- ok(rc == ERROR_SUCCESS, "\'command\' key creation failed with %d\n", rc);
-
- if (rawcmd)
- {
- rc=RegSetValueExA(hkey_cmd, NULL, 0, REG_SZ, (LPBYTE)cmdtail, strlen(cmdtail)+1);
- }
- else
- {
- cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+10+strlen(child_file)+2+strlen(cmdtail)+1);
- sprintf(cmd,"%s shlexec \"%s\" %s", argv0, child_file, cmdtail);
- rc=RegSetValueExA(hkey_cmd, NULL, 0, REG_SZ, (LPBYTE)cmd, strlen(cmd)+1);
- ok(rc == ERROR_SUCCESS, "setting command failed with %d\n", rc);
- HeapFree(GetProcessHeap(), 0, cmd);
- }
-
- if (ddeexec)
- {
- HKEY hkey_ddeexec, hkey_application, hkey_topic, hkey_ifexec;
-
- rc=RegCreateKeyExA(hkey_verb, "ddeexec", 0, NULL, 0, KEY_SET_VALUE |
- KEY_CREATE_SUB_KEY, NULL, &hkey_ddeexec, NULL);
- ok(rc == ERROR_SUCCESS, "\'ddeexec\' key creation failed with %d\n", rc);
- rc=RegSetValueExA(hkey_ddeexec, NULL, 0, REG_SZ, (LPBYTE)ddeexec,
- strlen(ddeexec)+1);
- ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
-
- if (application)
- {
- rc=RegCreateKeyExA(hkey_ddeexec, "application", 0, NULL, 0, KEY_SET_VALUE,
- NULL, &hkey_application, NULL);
- ok(rc == ERROR_SUCCESS, "\'application\' key creation failed with %d\n", rc);
-
- rc=RegSetValueExA(hkey_application, NULL, 0, REG_SZ, (LPBYTE)application,
- strlen(application)+1);
- ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
- CloseHandle(hkey_application);
- }
- if (topic)
- {
- rc=RegCreateKeyExA(hkey_ddeexec, "topic", 0, NULL, 0, KEY_SET_VALUE,
- NULL, &hkey_topic, NULL);
- ok(rc == ERROR_SUCCESS, "\'topic\' key creation failed with %d\n", rc);
- rc=RegSetValueExA(hkey_topic, NULL, 0, REG_SZ, (LPBYTE)topic,
- strlen(topic)+1);
- ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
- CloseHandle(hkey_topic);
- }
- if (ifexec)
- {
- rc=RegCreateKeyExA(hkey_ddeexec, "ifexec", 0, NULL, 0, KEY_SET_VALUE,
- NULL, &hkey_ifexec, NULL);
- ok(rc == ERROR_SUCCESS, "\'ifexec\' key creation failed with %d\n", rc);
- rc=RegSetValueExA(hkey_ifexec, NULL, 0, REG_SZ, (LPBYTE)ifexec,
- strlen(ifexec)+1);
- ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
- CloseHandle(hkey_ifexec);
- }
- CloseHandle(hkey_ddeexec);
- }
-
- CloseHandle(hkey_shell);
- CloseHandle(hkey_verb);
- 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);
- reset_association_description();
-}
-
-/***
- *
- * 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);
+ DWORD dwMaxLen, dwSize;
+ CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
+ HKEY hSubKey = hKey;
- dde_ready = OpenEventA(EVENT_MODIFY_STATE, FALSE, "winetest_shlexec_dde_ready");
- SetEvent(dde_ready);
- CloseHandle(dde_ready);
+ if(lpszSubKey)
+ {
+ ret = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
+ if (ret) return ret;
+ }
- while (GetMessageA(&msg, NULL, 0, 0))
- DispatchMessageA(&msg);
+ /* Get highest length for keys, values */
+ ret = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, NULL,
+ &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
+ if (ret) goto cleanup;
- Sleep(500);
- KillTimer(NULL, timer);
- assert(DdeNameService(ddeInst, hszApplication, 0, DNS_UNREGISTER));
- assert(DdeFreeStringHandle(ddeInst, hszTopic));
- assert(DdeFreeStringHandle(ddeInst, hszApplication));
- assert(DdeUninitialize(ddeInst));
- }
- else
+ dwMaxSubkeyLen++;
+ dwMaxValueLen++;
+ dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
+ if (dwMaxLen > sizeof(szNameBuf)/sizeof(CHAR))
+ {
+ /* Name too big: alloc a buffer for it */
+ if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(CHAR))))
{
- dde_ready = OpenEventA(EVENT_MODIFY_STATE, FALSE, "winetest_shlexec_dde_ready");
- SetEvent(dde_ready);
- CloseHandle(dde_ready);
+ ret = ERROR_NOT_ENOUGH_MEMORY;
+ goto cleanup;
}
+ }
- UnmapViewOfFile(shared_block);
- childPrintf(hFile, "ddeExec=%s\r\n", encodeA(ddeExec));
+ /* Recursively delete all the subkeys */
+ while (TRUE)
+ {
+ dwSize = dwMaxLen;
+ if (RegEnumKeyExA(hSubKey, 0, lpszName, &dwSize, NULL,
+ NULL, NULL, NULL)) break;
+
+ ret = myRegDeleteTreeA(hSubKey, lpszName);
+ if (ret) goto cleanup;
}
- CloseHandle(hFile);
+ if (lpszSubKey)
+ ret = RegDeleteKeyA(hKey, lpszSubKey);
+ else
+ while (TRUE)
+ {
+ dwSize = dwMaxLen;
+ if (RegEnumValueA(hKey, 0, lpszName, &dwSize,
+ NULL, NULL, NULL, NULL)) break;
- init_event(filename);
- SetEvent(hEvent);
- CloseHandle(hEvent);
+ ret = RegDeleteValueA(hKey, lpszName);
+ if (ret) goto cleanup;
+ }
+
+cleanup:
+ /* Free buffer if allocated */
+ if (lpszName != szNameBuf)
+ HeapFree( GetProcessHeap(), 0, lpszName);
+ if(lpszSubKey)
+ RegCloseKey(hSubKey);
+ return ret;
}
-static char* getChildString(const char* sect, const char* key)
+static void delete_test_association(const char* extension)
{
- char buf[1024];
- char* ret;
+ char class[MAX_PATH];
- 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;
+ sprintf(class, "shlexec%s", extension);
+ myRegDeleteTreeA(HKEY_CLASSES_ROOT, class);
+ myRegDeleteTreeA(HKEY_CLASSES_ROOT, extension);
}
-static void dump_child_(const char* file, int line)
+static void create_test_verb_dde(const char* extension, const char* verb,
+ int rawcmd, const char* cmdtail, const char *ddeexec,
+ const char *application, const char *topic,
+ const char *ifexec)
{
- if (winetest_debug > 1)
- {
- char key[18];
- char* str;
- int i, c;
+ HKEY hkey_shell, hkey_verb, hkey_cmd;
+ char shell[MAX_PATH];
+ char* cmd;
+ LONG rc;
- str=getChildString("Arguments", "cmdlineA");
- trace_(file, line)("cmdlineA='%s'\n", str);
- c=GetPrivateProfileIntA("Arguments", "argcA", -1, child_file);
- trace_(file, line)("argcA=%d\n",c);
- for (i=0;i<c;i++)
- {
- sprintf(key, "argvA%d", i);
- str=getChildString("Arguments", key);
- trace_(file, line)("%s='%s'\n", key, str);
- }
+ 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);
+ ok(rc == ERROR_SUCCESS, "%s key creation failed with %d\n", shell, rc);
+
+ rc=RegCreateKeyExA(hkey_shell, verb, 0, NULL, 0, KEY_CREATE_SUB_KEY,
+ NULL, &hkey_verb, NULL);
+ ok(rc == ERROR_SUCCESS, "%s verb key creation failed with %d\n", verb, rc);
+
+ rc=RegCreateKeyExA(hkey_verb, "command", 0, NULL, 0, KEY_SET_VALUE,
+ NULL, &hkey_cmd, NULL);
+ ok(rc == ERROR_SUCCESS, "\'command\' key creation failed with %d\n", rc);
+
+ if (rawcmd)
+ {
+ rc=RegSetValueExA(hkey_cmd, NULL, 0, REG_SZ, (LPBYTE)cmdtail, strlen(cmdtail)+1);
+ }
+ else
+ {
+ cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+10+strlen(child_file)+2+strlen(cmdtail)+1);
+ sprintf(cmd,"%s shlexec \"%s\" %s", argv0, child_file, cmdtail);
+ rc=RegSetValueExA(hkey_cmd, NULL, 0, REG_SZ, (LPBYTE)cmd, strlen(cmd)+1);
+ ok(rc == ERROR_SUCCESS, "setting command failed with %d\n", rc);
+ HeapFree(GetProcessHeap(), 0, cmd);
}
-}
-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 (ddeexec)
{
- if (!*s2)
- {
- if (*s1=='.')
- s1++;
- return (*s1-*s2);
- }
- if ((*s1=='/' || *s1=='\\') && (*s2=='/' || *s2=='\\'))
+ HKEY hkey_ddeexec, hkey_application, hkey_topic, hkey_ifexec;
+
+ rc=RegCreateKeyExA(hkey_verb, "ddeexec", 0, NULL, 0, KEY_SET_VALUE |
+ KEY_CREATE_SUB_KEY, NULL, &hkey_ddeexec, NULL);
+ ok(rc == ERROR_SUCCESS, "\'ddeexec\' key creation failed with %d\n", rc);
+ rc=RegSetValueExA(hkey_ddeexec, NULL, 0, REG_SZ, (LPBYTE)ddeexec,
+ strlen(ddeexec)+1);
+ ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
+
+ if (application)
{
- while (*s1=='/' || *s1=='\\')
- s1++;
- while (*s2=='/' || *s2=='\\')
- s2++;
+ rc=RegCreateKeyExA(hkey_ddeexec, "application", 0, NULL, 0, KEY_SET_VALUE,
+ NULL, &hkey_application, NULL);
+ ok(rc == ERROR_SUCCESS, "\'application\' key creation failed with %d\n", rc);
+
+ rc=RegSetValueExA(hkey_application, NULL, 0, REG_SZ, (LPBYTE)application,
+ strlen(application)+1);
+ ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
+ CloseHandle(hkey_application);
}
- else if (toupper(*s1)==toupper(*s2))
+ if (topic)
{
- s1++;
- s2++;
+ rc=RegCreateKeyExA(hkey_ddeexec, "topic", 0, NULL, 0, KEY_SET_VALUE,
+ NULL, &hkey_topic, NULL);
+ ok(rc == ERROR_SUCCESS, "\'topic\' key creation failed with %d\n", rc);
+ rc=RegSetValueExA(hkey_topic, NULL, 0, REG_SZ, (LPBYTE)topic,
+ strlen(topic)+1);
+ ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
+ CloseHandle(hkey_topic);
}
- else
+ if (ifexec)
{
- return (*s1-*s2);
+ rc=RegCreateKeyExA(hkey_ddeexec, "ifexec", 0, NULL, 0, KEY_SET_VALUE,
+ NULL, &hkey_ifexec, NULL);
+ ok(rc == ERROR_SUCCESS, "\'ifexec\' key creation failed with %d\n", rc);
+ rc=RegSetValueExA(hkey_ifexec, NULL, 0, REG_SZ, (LPBYTE)ifexec,
+ strlen(ifexec)+1);
+ ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
+ CloseHandle(hkey_ifexec);
}
+ CloseHandle(hkey_ddeexec);
}
- 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)
- {
- 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);
-}
-
-static void _okChildPath(const char* file, int line, const char* key, const char* expected)
-{
- char* result;
- result=getChildString("Arguments", key);
- if (!result)
- {
- okShell_(file,line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected);
- return;
- }
- okShell_(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);
- okShell_(file,line)(result == expected,
- "%s expected %d, but got %d\n", key, expected, result);
+ CloseHandle(hkey_shell);
+ CloseHandle(hkey_verb);
+ CloseHandle(hkey_cmd);
}
-static void _okChildIntBroken(const char* file, int line, const char* key, int expected)
+/* 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)
{
- INT result;
- result=GetPrivateProfileIntA("Arguments", key, expected, child_file);
- okShell_(file,line)(result == expected || broken(result != expected),
- "%s expected %d, but got %d\n", key, expected, result);
+ create_test_verb_dde(extension, verb, rawcmd, cmdtail, NULL, NULL,
+ NULL, NULL);
+ reset_association_description();
}
-#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))
/***
*
@@ -912,6 +928,7 @@ static DWORD get_long_path_name(const char* shortpath, char* longpath, DWORD lon
return tmplen;
}
+
/***
*
* Tests
--
2.7.0.rc3
More information about the wine-patches
mailing list