[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