From 53e4ddc399cef1f044fb25bdb19a478ced6178d7 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Wed, 10 Oct 2012 00:54:07 +0200 Subject: [PATCH] shell32: Fix ShellExecute()'s handling of file URLs. --- dlls/shell32/shlexec.c | 46 +++++++++++++++++++++++++++----------------- dlls/shell32/tests/shlexec.c | 46 ++++++++++++++++++++++++-------------------- 2 files changed, 53 insertions(+), 39 deletions(-) diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index a714fe8f0fc..5799ab065c2 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -1504,7 +1504,7 @@ static UINT_PTR SHELL_quote_and_execute( LPCWSTR wcmd, LPCWSTR wszParameters, LP return retval; } -static UINT_PTR SHELL_execute_url( LPCWSTR lpFile, LPCWSTR wFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc ) +static UINT_PTR SHELL_execute_url( LPCWSTR lpFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc ) { static const WCHAR wShell[] = {'\\','s','h','e','l','l','\\',0}; static const WCHAR wCommand[] = {'\\','c','o','m','m','a','n','d',0}; @@ -1534,13 +1534,6 @@ static UINT_PTR SHELL_execute_url( LPCWSTR lpFile, LPCWSTR wFile, LPCWSTR wcmd, strcatW(lpstrProtocol, psei->lpVerb && *psei->lpVerb ? psei->lpVerb: wszOpen); strcatW(lpstrProtocol, wCommand); - /* Remove File Protocol from lpFile */ - /* In the case file://path/file */ - if (!strncmpiW(lpFile, wFile, iSize)) - { - lpFile += iSize; - while (*lpFile == ':') lpFile++; - } retval = execute_from_key(lpstrProtocol, lpFile, NULL, psei->lpParameters, wcmd, execfunc, psei, psei_out); HeapFree(GetProcessHeap(), 0, lpstrProtocol); @@ -1567,7 +1560,6 @@ static BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) { static const WCHAR wSpace[] = {' ',0}; static const WCHAR wWww[] = {'w','w','w',0}; - static const WCHAR wFile[] = {'f','i','l','e',0}; static const WCHAR wHttp[] = {'h','t','t','p',':','/','/',0}; static const DWORD unsupportedFlags = SEE_MASK_INVOKEIDLIST | SEE_MASK_ICON | SEE_MASK_HOTKEY | @@ -1724,21 +1716,39 @@ static BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) dwApplicationNameLen ); } - /* expand environment strings */ - len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0); - if (len>0) + /* convert file URLs */ + if (UrlIsFileUrlW(sei_tmp.lpFile)) { LPWSTR buf; - buf = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR)); + DWORD size; + + size = MAX_PATH; + buf = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); + if (FAILED(PathCreateFromUrlW(sei_tmp.lpFile, buf, &size, 0))) + return SE_ERR_OOM; - ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len+1); HeapFree(GetProcessHeap(), 0, wszApplicationName); - dwApplicationNameLen = len+1; + dwApplicationNameLen = lstrlenW(buf) + 1; wszApplicationName = buf; - /* appKnownSingular unmodified */ - sei_tmp.lpFile = wszApplicationName; } + else /* or expand environment strings (not both!) */ + { + len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0); + if (len>0) + { + LPWSTR buf; + buf = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + + ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len + 1); + HeapFree(GetProcessHeap(), 0, wszApplicationName); + dwApplicationNameLen = len + 1; + wszApplicationName = buf; + /* appKnownSingular unmodified */ + + sei_tmp.lpFile = wszApplicationName; + } + } if (*sei_tmp.lpDirectory) { @@ -1889,7 +1899,7 @@ static BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) } else if (PathIsURLW(lpFile)) /* File not found, check for URL */ { - retval = SHELL_execute_url( lpFile, wFile, wcmd, &sei_tmp, sei, execfunc ); + retval = SHELL_execute_url( lpFile, wcmd, &sei_tmp, sei, execfunc ); } /* Check if file specified is in the form www.??????.*** */ else if (!strncmpiW(lpFile, wWww, 3)) diff --git a/dlls/shell32/tests/shlexec.c b/dlls/shell32/tests/shlexec.c index 8d164a63973..e3d5676fe1c 100644 --- a/dlls/shell32/tests/shlexec.c +++ b/dlls/shell32/tests/shlexec.c @@ -1637,34 +1637,37 @@ typedef struct static fileurl_tests_t fileurl_tests[]= { /* How many slashes does it take... */ - {"file:", "%s\\test file.shlexec", URL_SUCCESS, 0x1}, - {"file:/", "%s\\test file.shlexec", URL_SUCCESS, 0x1}, - {"file://", "%s\\test file.shlexec", URL_SUCCESS, 0x1}, - {"file:///", "%s\\test file.shlexec", URL_SUCCESS, 0x1}, - {"File:///", "%s\\test file.shlexec", URL_SUCCESS, 0x1}, - {"file:////", "%s\\test file.shlexec", URL_SUCCESS, 0x1}, - {"file://///", "%s\\test file.shlexec", 0, 0x1}, + {"file:", "%s\\test file.shlexec", URL_SUCCESS, 0}, + {"file:/", "%s\\test file.shlexec", URL_SUCCESS, 0}, + {"file://", "%s\\test file.shlexec", URL_SUCCESS, 0}, + {"file:///", "%s\\test file.shlexec", URL_SUCCESS, 0}, + {"File:///", "%s\\test file.shlexec", URL_SUCCESS, 0}, + {"file:////", "%s\\test file.shlexec", URL_SUCCESS, 0}, + {"file://///", "%s\\test file.shlexec", 0, 0}, /* Test with Windows-style paths */ - {"file:///", "%s\\test file.shlexec", URL_SUCCESS | USE_COLON, 0x1}, - {"file:///", "%s\\test file.shlexec", URL_SUCCESS | USE_BSLASH, 0x1}, + {"file:///", "%s\\test file.shlexec", URL_SUCCESS | USE_COLON, 0}, + {"file:///", "%s\\test file.shlexec", URL_SUCCESS | USE_BSLASH, 0}, /* Check handling of hostnames */ - {"file://localhost/", "%s\\test file.shlexec", URL_SUCCESS, 0x1}, - {"file://localhost:80/", "%s\\test file.shlexec", 0, 0x1}, - {"file://LocalHost/", "%s\\test file.shlexec", URL_SUCCESS, 0x1}, - {"file://127.0.0.1/", "%s\\test file.shlexec", 0, 0x1}, - {"file://::1/", "%s\\test file.shlexec", 0, 0x1}, - {"file://notahost/", "%s\\test file.shlexec", 0, 0x1}, + {"file://localhost/", "%s\\test file.shlexec", URL_SUCCESS, 0}, + {"file://localhost:80/", "%s\\test file.shlexec", 0, 0}, + {"file://LocalHost/", "%s\\test file.shlexec", URL_SUCCESS, 0}, + {"file://127.0.0.1/", "%s\\test file.shlexec", 0, 0}, + {"file://::1/", "%s\\test file.shlexec", 0, 0}, + {"file://notahost/", "%s\\test file.shlexec", 0, 0}, /* Environment variables are not expanded in URLs */ {"%urlprefix%", "%s\\test file.shlexec", 0, 0x1}, - {"file:///", "%s\\%%urlenvvar%% file.shlexec", 0, 0x1}, + {"file:///", "%%TMPDIR%%\\test file.shlexec", 0, 0}, + + /* Test shortcuts vs. URLs */ + {"file://///", "%s\\test_shortcut_shlexec.lnk", 0, 0x1d}, {NULL, NULL, 0, 0} }; -static void test_fileurl(void) +static void test_fileurls(void) { char filename[MAX_PATH], fileurl[MAX_PATH], longtmpdir[MAX_PATH]; char command[MAX_PATH]; @@ -1681,7 +1684,6 @@ static void test_fileurl(void) get_long_path_name(tmpdir, longtmpdir, sizeof(longtmpdir)/sizeof(*longtmpdir)); SetEnvironmentVariable("urlprefix", "file:///"); - SetEnvironmentVariable("urlenvvar", "test"); test=fileurl_tests; while (test->basename) @@ -1705,7 +1707,10 @@ static void test_fileurl(void) ok(rc == SE_ERR_FNF, "FindExecutable(%s) failed: bad rc=%lu\n", fileurl, rc); /* Then ShellExecute() */ - rc = shell_execute(NULL, fileurl, NULL, NULL); + if ((test->todo & 0x10) == 0) + rc = shell_execute(NULL, fileurl, NULL, NULL); + else todo_wait + rc = shell_execute(NULL, fileurl, NULL, NULL); if (bad_shellexecute) { win_skip("shell32 is too old (likely 4.72). Skipping the file URL tests\n"); @@ -1750,7 +1755,6 @@ static void test_fileurl(void) } SetEnvironmentVariable("urlprefix", NULL); - SetEnvironmentVariable("urlenvvar", NULL); } static void test_find_executable(void) @@ -2639,7 +2643,7 @@ START_TEST(shlexec) test_argify(); test_lpFile_parsed(); test_filename(); - test_fileurl(); + test_fileurls(); test_find_executable(); test_lnks(); test_exes(); -- 2.11.4.GIT