shell32/tests: Test ShellExecute()'s URL handling.

Francois Gouget fgouget at codeweavers.com
Wed Oct 17 16:25:43 CDT 2012


Also adapt the helper functions so we can create the classes we need.
---
 dlls/shell32/tests/shlexec.c |  158 +++++++++++++++++++++++++++++++-----------
 1 file changed, 119 insertions(+), 39 deletions(-)

diff --git a/dlls/shell32/tests/shlexec.c b/dlls/shell32/tests/shlexec.c
index 131e334..737e536 100644
--- a/dlls/shell32/tests/shlexec.c
+++ b/dlls/shell32/tests/shlexec.c
@@ -235,9 +235,34 @@ static INT_PTR shell_execute_ex(DWORD mask, LPCSTR verb, LPCSTR file,
  *
  ***/
 
-static BOOL create_test_association(const char* extension)
+static void create_test_class(const char* class, BOOL protocol)
 {
     HKEY hkey, hkey_shell;
+    LONG rc;
+
+    rc = RegCreateKeyEx(HKEY_CLASSES_ROOT, class, 0, NULL, 0,
+                        KEY_CREATE_SUB_KEY | KEY_SET_VALUE, NULL,
+                        &hkey, NULL);
+    ok(rc == ERROR_SUCCESS, "RegCreateKeyEx '%s' failed, expected ERROR_SUCCESS, got %d\n", class, rc);
+
+    if (protocol)
+    {
+        rc = RegSetValueEx(hkey, "URL Protocol", 0, REG_SZ, (LPBYTE)"", 1);
+        ok(rc == ERROR_SUCCESS, "RegSetValueEx '%s' failed, expected ERROR_SUCCESS, got %d\n", class, rc);
+    }
+
+    rc = RegCreateKeyEx(hkey, "shell", 0, NULL, 0,
+                        KEY_CREATE_SUB_KEY, NULL, &hkey_shell, NULL);
+    ok(rc == ERROR_SUCCESS, "RegCreateKeyEx 'shell' failed, expected ERROR_SUCCESS, got %d\n", rc);
+
+    CloseHandle(hkey);
+    CloseHandle(hkey_shell);
+
+}
+
+static BOOL create_test_association(const char* extension)
+{
+    HKEY hkey;
     char class[MAX_PATH];
     LONG rc;
 
@@ -251,17 +276,7 @@ static BOOL create_test_association(const char* extension)
     ok(rc==ERROR_SUCCESS, "RegSetValueEx '%s' failed, expected ERROR_SUCCESS, got %d\n", class, rc);
     CloseHandle(hkey);
 
-    rc=RegCreateKeyEx(HKEY_CLASSES_ROOT, class, 0, NULL, 0,
-                      KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS, NULL, &hkey, NULL);
-    ok(rc==ERROR_SUCCESS, "RegCreateKeyEx '%s' failed, expected ERROR_SUCCESS, got %d\n", class, rc);
-
-    rc=RegCreateKeyEx(hkey, "shell", 0, NULL, 0,
-                      KEY_CREATE_SUB_KEY, NULL, &hkey_shell, NULL);
-    ok(rc==ERROR_SUCCESS, "RegCreateKeyEx 'shell' failed, expected ERROR_SUCCESS, got %d\n", rc);
-
-    CloseHandle(hkey);
-    CloseHandle(hkey_shell);
-
+    create_test_class(class, FALSE);
     return TRUE;
 }
 
@@ -332,16 +347,21 @@ cleanup:
     return ret;
 }
 
+static void delete_test_class(const char* classname)
+{
+    myRegDeleteTreeA(HKEY_CLASSES_ROOT, classname);
+}
+
 static void delete_test_association(const char* extension)
 {
-    char class[MAX_PATH];
+    char classname[MAX_PATH];
 
-    sprintf(class, "shlexec%s", extension);
-    myRegDeleteTreeA(HKEY_CLASSES_ROOT, class);
+    sprintf(classname, "shlexec%s", extension);
+    delete_test_class(classname);
     myRegDeleteTreeA(HKEY_CLASSES_ROOT, extension);
 }
 
-static void create_test_verb_dde(const char* extension, const char* verb,
+static void create_test_verb_dde(const char* classname, const char* verb,
                                  int rawcmd, const char* cmdtail, const char *ddeexec,
                                  const char *application, const char *topic,
                                  const char *ifexec)
@@ -351,7 +371,7 @@ static void create_test_verb_dde(const char* extension, const char* verb,
     char* cmd;
     LONG rc;
 
-    sprintf(shell, "shlexec%s\\shell", extension);
+    sprintf(shell, "%s\\shell", classname);
     rc=RegOpenKeyEx(HKEY_CLASSES_ROOT, shell, 0,
                     KEY_CREATE_SUB_KEY, &hkey_shell);
     assert(rc==ERROR_SUCCESS);
@@ -363,17 +383,15 @@ static void create_test_verb_dde(const char* extension, const char* verb,
     assert(rc==ERROR_SUCCESS);
 
     if (rawcmd)
-    {
         rc=RegSetValueEx(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=RegSetValueEx(hkey_cmd, NULL, 0, REG_SZ, (LPBYTE)cmd, strlen(cmd)+1);
-        assert(rc==ERROR_SUCCESS);
         HeapFree(GetProcessHeap(), 0, cmd);
     }
+    assert(rc==ERROR_SUCCESS);
 
     if (ddeexec)
     {
@@ -423,10 +441,10 @@ static void create_test_verb_dde(const char* extension, const char* verb,
     CloseHandle(hkey_cmd);
 }
 
-static void create_test_verb(const char* extension, const char* verb,
+static void create_test_verb(const char* classname, const char* verb,
                              int rawcmd, const char* cmdtail)
 {
-    create_test_verb_dde(extension, verb, rawcmd, cmdtail, NULL, NULL,
+    create_test_verb_dde(classname, verb, rawcmd, cmdtail, NULL, NULL,
                          NULL, NULL);
 }
 
@@ -1385,13 +1403,13 @@ static void test_argify(void)
     const char* cmd;
     unsigned i, count;
 
-    create_test_verb(".shlexec", "Params232S", 0, "Params232S %2 %3 \"%2\" \"%*\"");
-    create_test_verb(".shlexec", "Params23456", 0, "Params23456 \"%2\" \"%3\" \"%4\" \"%5\" \"%6\"");
-    create_test_verb(".shlexec", "Params23456789", 0, "Params23456789 \"%2\" \"%3\" \"%4\" \"%5\" \"%6\" \"%7\" \"%8\" \"%9\"");
-    create_test_verb(".shlexec", "Params2345Etc", 0, "Params2345Etc ~2=\"%~2\" ~3=\"%~3\" ~4=\"%~4\" ~5=%~5");
-    create_test_verb(".shlexec", "Params9Etc", 0, "Params9Etc ~9=\"%~9\"");
-    create_test_verb(".shlexec", "Params20", 0, "Params20 \"%20\"");
-    create_test_verb(".shlexec", "ParamsBad", 0, "ParamsBad \"%% %- %~ %~0 %~1 %~a %~* %a %b %c %TMPDIR%\"");
+    create_test_verb("shlexec.shlexec", "Params232S", 0, "Params232S %2 %3 \"%2\" \"%*\"");
+    create_test_verb("shlexec.shlexec", "Params23456", 0, "Params23456 \"%2\" \"%3\" \"%4\" \"%5\" \"%6\"");
+    create_test_verb("shlexec.shlexec", "Params23456789", 0, "Params23456789 \"%2\" \"%3\" \"%4\" \"%5\" \"%6\" \"%7\" \"%8\" \"%9\"");
+    create_test_verb("shlexec.shlexec", "Params2345Etc", 0, "Params2345Etc ~2=\"%~2\" ~3=\"%~3\" ~4=\"%~4\" ~5=%~5");
+    create_test_verb("shlexec.shlexec", "Params9Etc", 0, "Params9Etc ~9=\"%~9\"");
+    create_test_verb("shlexec.shlexec", "Params20", 0, "Params20 \"%20\"");
+    create_test_verb("shlexec.shlexec", "ParamsBad", 0, "ParamsBad \"%% %- %~ %~0 %~1 %~a %~* %a %b %c %TMPDIR%\"");
 
     sprintf(fileA, "%s\\test file.shlexec", tmpdir);
 
@@ -1767,6 +1785,67 @@ static void test_fileurls(void)
     SetEnvironmentVariable("urlprefix", NULL);
 }
 
+static void test_urls(void)
+{
+    INT_PTR rc;
+
+    create_test_class("fakeproto", FALSE);
+    create_test_verb("fakeproto", "open", 0, "URL %1");
+
+    create_test_class("shlproto", TRUE);
+    create_test_verb("shlproto", "open", 0, "URL %1");
+
+    /* Protocols must be properly declared */
+    rc = shell_execute(NULL, "notaproto://foo", NULL, NULL);
+    todo_wine ok(rc == SE_ERR_ACCESSDENIED, "%s succeeded: rc=%lu\n", shell_call, rc);
+
+    rc = shell_execute(NULL, "fakeproto://foo/bar", NULL, NULL);
+    todo_wine ok(rc == SE_ERR_ACCESSDENIED, "%s expected SE_ERR_ACCESSDENIED got rc=%lu\n", shell_call, rc);
+
+    /* Here's a real live one */
+    rc = shell_execute(NULL, "shlproto://foo/bar", NULL, NULL);
+    ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc);
+    if (rc > 32)
+    {
+        okChildInt("argcA", 5);
+        okChildString("argvA4", "shlproto://foo/bar");
+    }
+
+    /* A .lnk ending does not turn a URL into a shortcut */
+    todo_wait rc = shell_execute(NULL, "shlproto://foo/bar.lnk", NULL, NULL);
+    ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc);
+    if (rc > 32)
+    {
+        okChildInt("argcA", 5);
+        todo_wine okChildString("argvA4", "shlproto://foo/bar.lnk");
+    }
+
+    /* Environment variables are expanded in URLs (but not in file URLs!) */
+    rc = shell_execute_ex(SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI,
+                          NULL, "shlproto://%TMPDIR%/bar", NULL, NULL, NULL);
+    ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc);
+    if (rc > 32)
+    {
+        char url[MAX_PATH];
+        okChildInt("argcA", 5);
+        sprintf(url, "shlproto://%s/bar", tmpdir);
+        okChildStringBroken("argvA4", url, "shlproto://%TMPDIR%/bar");
+    }
+
+    /* But only after the path has been identified as a URL */
+    SetEnvironmentVariable("urlprefix", "shlproto:///");
+    rc = shell_execute(NULL, "%urlprefix%foo", NULL, NULL);
+    todo_wine ok(rc == SE_ERR_FNF, "%s succeeded: rc=%lu\n", shell_call, rc);
+    SetEnvironmentVariable("urlprefix", NULL);
+
+    /* Try to confuse ShellExecute() by mixing protocols */
+    rc = shell_execute(NULL, "file://shlproto://foo/bar", NULL, NULL);
+    todo_wine ok(rc == SE_ERR_PNF, "%s succeeded: rc=%lu\n", shell_call, rc);
+
+    delete_test_class("fakeproto");
+    delete_test_class("shlproto");
+}
+
 static void test_find_executable(void)
 {
     char notepad_path[MAX_PATH];
@@ -1780,7 +1859,7 @@ static void test_find_executable(void)
         skip("Unable to create association for '.sfe'\n");
         return;
     }
-    create_test_verb(".sfe", "Open", 1, "%1");
+    create_test_verb("shlexec.sfe", "Open", 1, "%1");
 
     /* Don't test FindExecutable(..., NULL), it always crashes */
 
@@ -1830,7 +1909,7 @@ static void test_find_executable(void)
         skip("Unable to create association for '.shl'\n");
         return;
     }
-    create_test_verb(".shl", "Open", 0, "Open");
+    create_test_verb("shlexec.shl", "Open", 0, "Open");
 
     sprintf(filename, "%s\\test file.shl", tmpdir);
     rc=(INT_PTR)FindExecutableA(filename, NULL, command);
@@ -2205,7 +2284,7 @@ static void test_dde(void)
             skip("Unable to create association for '.sde'\n");
             return;
         }
-        create_test_verb_dde(".sde", "Open", 0, test->command, test->ddeexec,
+        create_test_verb_dde("shlexec.sde", "Open", 0, test->command, test->ddeexec,
                              test->application, test->topic, test->ifexec);
 
         if (test->application != NULL || test->topic != NULL)
@@ -2380,7 +2459,7 @@ static void test_dde_default_app(void)
             return;
         }
         sprintf(params, test->command, tmpdir);
-        create_test_verb_dde(".sde", "Open", 1, params, "[test]", NULL,
+        create_test_verb_dde("shlexec.sde", "Open", 1, params, "[test]", NULL,
                              "shlexec", NULL);
         ddeApplication[0] = 0;
 
@@ -2550,12 +2629,12 @@ static void init_test(void)
         skip("Unable to create association for '.shlexec'\n");
         return;
     }
-    create_test_verb(".shlexec", "Open", 0, "Open \"%1\"");
-    create_test_verb(".shlexec", "NoQuotes", 0, "NoQuotes %1");
-    create_test_verb(".shlexec", "LowerL", 0, "LowerL %l");
-    create_test_verb(".shlexec", "QuotedLowerL", 0, "QuotedLowerL \"%l\"");
-    create_test_verb(".shlexec", "UpperL", 0, "UpperL %L");
-    create_test_verb(".shlexec", "QuotedUpperL", 0, "QuotedUpperL \"%L\"");
+    create_test_verb("shlexec.shlexec", "Open", 0, "Open \"%1\"");
+    create_test_verb("shlexec.shlexec", "NoQuotes", 0, "NoQuotes %1");
+    create_test_verb("shlexec.shlexec", "LowerL", 0, "LowerL %l");
+    create_test_verb("shlexec.shlexec", "QuotedLowerL", 0, "QuotedLowerL \"%l\"");
+    create_test_verb("shlexec.shlexec", "UpperL", 0, "UpperL %L");
+    create_test_verb("shlexec.shlexec", "QuotedUpperL", 0, "QuotedUpperL \"%L\"");
 }
 
 static void cleanup_test(void)
@@ -2654,6 +2733,7 @@ START_TEST(shlexec)
     test_lpFile_parsed();
     test_filename();
     test_fileurls();
+    test_urls();
     test_find_executable();
     test_lnks();
     test_exes();
-- 
1.7.10.4



More information about the wine-patches mailing list