[SHELL32] Fix handling of multiple parameters in the 'Run' dialog (#665)
[reactos.git] / dll / win32 / shell32 / shlexec.cpp
index 9133fba..55b3d05 100644 (file)
@@ -1,8 +1,9 @@
 /*
- *                             Shell Library Functions
+ *          Shell Library Functions
  *
  * Copyright 1998 Marcus Meissner
  * Copyright 2002 Eric Pouech
+ * Copyright 2018 Katayama Hirofumi MZ
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <precomp.h>
+#include "precomp.h"
+#include <undocshell.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(exec);
 
-static const WCHAR wszOpen[] = {'o','p','e','n',0};
-static const WCHAR wszExe[] = {'.','e','x','e',0};
-static const WCHAR wszILPtr[] = {':','%','p',0};
-static const WCHAR wszShell[] = {'\\','s','h','e','l','l','\\',0};
-static const WCHAR wszFolder[] = {'F','o','l','d','e','r',0};
-static const WCHAR wszEmpty[] = {0};
+static const WCHAR wszOpen[] = L"open";
+static const WCHAR wszExe[] = L".exe";
+static const WCHAR wszCom[] = L".com";
 
 #define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)
 
+typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
+                const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out);
+
+static void ParseNoTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
+{
+    bool firstCharQuote = false;
+    bool quotes_opened = false;
+    bool backslash_encountered = false;
+
+    for (int curArg = 0; curArg <= argNum && *args; ++curArg)
+    {
+        firstCharQuote = false;
+        if (*args == '"')
+        {
+            quotes_opened = true;
+            firstCharQuote = true;
+            args++;
+        }
+
+        while(*args)
+        {
+            if (*args == '\\')
+            {
+                // if we found a backslash then flip the variable
+                backslash_encountered = !backslash_encountered;
+            }
+            else if (*args == '"')
+            {
+                if (quotes_opened)
+                {
+                    if (*(args + 1) != '"')
+                    {
+                        quotes_opened = false;
+                        args++;
+                        break;
+                    }
+                    else
+                    {
+                        args++;
+                    }
+                }
+                else
+                {
+                    quotes_opened = true;
+                }
+
+                backslash_encountered = false;
+            }
+            else
+            {
+                backslash_encountered = false;
+                if (*args == ' ' && !firstCharQuote)
+                    break;
+            }
+
+            if (curArg == argNum)
+            {
+                used++;
+                if (used < len)
+                    *res++ = *args;
+            }
+
+            args++;
+        }
+
+        while(*args == ' ')
+            ++args;
+    }
+}
+
+static void ParseTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
+{
+    bool quotes_opened = false;
+    bool backslash_encountered = false;
+
+    for (int curArg = 0; curArg <= argNum && *args; ++curArg)
+    {
+        while(*args)
+        {
+            if (*args == '\\')
+            {
+                // if we found a backslash then flip the variable
+                backslash_encountered = !backslash_encountered;
+            }
+            else if (*args == '"')
+            {
+                if (quotes_opened)
+                {
+                    if (*(args + 1) != '"')
+                    {
+                        quotes_opened = false;
+                    }
+                    else
+                    {
+                        args++;
+                    }
+                }
+                else
+                {
+                    quotes_opened = true;
+                }
+
+                backslash_encountered = false;
+            }
+            else
+            {
+                backslash_encountered = false;
+                if (*args == ' ' && !quotes_opened && curArg != argNum)
+                    break;
+            }
+
+            if (curArg == argNum)
+            {
+                used++;
+                if (used < len)
+                    *res++ = *args;
+            }
+
+            args++;
+        }
+    }
+}
 
 /***********************************************************************
- *     SHELL_ArgifyW [Internal]
+ * SHELL_ArgifyW [Internal]
  *
  * this function is supposed to expand the escape sequences found in the registry
  * some diving reported that the following were used:
  * + %1, %2...  seem to report to parameter of index N in ShellExecute pmts
- *     %1 file
- *     %2 printer
- *     %3 driver
- *     %4 port
+ * %1 file
+ * %2 printer
+ * %3 driver
+ * %4 port
  * %I address of a global item ID (explorer switch /idlist)
  * %L seems to be %1 as long filename followed by the 8+3 variation
  * %S ???
  * %* all following parameters (see batfile)
  *
+ * The way we parse the command line arguments was determined through extensive
+ * testing and can be summed up by the following rules"
+ *
+ * - %2
+ *     - if first letter is " break on first non literal " and include any white spaces
+ *     - if first letter is NOT " break on first " or white space
+ *     - if " is opened any pair of consecutive " results in ONE literal "
+ *
+ * - %~2
+ *     - use rules from here http://www.autohotkey.net/~deleyd/parameters/parameters.htm
  */
-static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len)
+
+static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len, const WCHAR* lpDir)
 {
     WCHAR   xlpFile[1024];
     BOOL    done = FALSE;
@@ -57,8 +189,9 @@ static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR*
     PWSTR   res = out;
     PCWSTR  cmd;
     DWORD   used = 0;
+    bool    tildeEffect = false;
 
-    TRACE("%p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
+    TRACE("Before parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
           debugstr_w(lpFile), pidl, args);
 
     while (*fmt)
@@ -67,165 +200,177 @@ static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR*
         {
             switch (*++fmt)
             {
-            case '\0':
-            case '%':
-                used++;
-                if (used < len)
-                    *res++ = '%';
+                case '\0':
+                case '%':
+                {
+                    used++;
+                    if (used < len)
+                        *res++ = '%';
+                };
                 break;
 
-            case '2':
-            case '3':
-            case '4':
-            case '5':
-            case '6':
-            case '7':
-            case '8':
-            case '9':
-            case '0':
-            case '*':
-                if (args)
+                case '*':
                 {
-                    if (*fmt == '*')
+                    if (args)
                     {
-                        used++;
-                        if (used < len)
-                            *res++ = '"';
-                        while(*args)
+                        if (*fmt == '*')
                         {
                             used++;
-                            if (used < len)
-                                *res++ = *args++;
-                            else
-                                args++;
-                        }
-                        used++;
-                        if (used < len)
-                            *res++ = '"';
-                        break;
-                    }
-                    else
-                    {
-                        while(*args && !isspace(*args))
-                        {
+                            while(*args)
+                            {
+                                used++;
+                                if (used < len)
+                                    *res++ = *args++;
+                                else
+                                    args++;
+                            }
                             used++;
-                            if (used < len)
-                                *res++ = *args++;
-                            else
-                                args++;
+                            break;
                         }
-
-                        while(isspace(*args))
-                            ++args;
                     }
-                    break;
-                }
-                else
-                {
-                    break;
-                }
-            case '1':
-                if (!done || (*fmt == '1'))
+                };
+                break;
+
+                case '~':
+
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                    //case '0':
                 {
-                    /*FIXME Is the call to SearchPathW() really needed? We already have separated out the parameter string in args. */
-                    if (SearchPathW(NULL, lpFile, wszExe, sizeof(xlpFile)/sizeof(WCHAR), xlpFile, NULL))
-                        cmd = xlpFile;
-                    else
-                        cmd = lpFile;
+                    if (*fmt == '~')
+                    {
+                        fmt++;
+                        tildeEffect = true;
+                    }
 
-                    used += wcslen(cmd);
-                    if (used < len)
+                    if (args)
                     {
-                        wcscpy(res, cmd);
-                        res += wcslen(cmd);
+                        if (tildeEffect)
+                        {
+                            ParseTildeEffect(res, args, len, used, *fmt - '2');
+                            tildeEffect = false;
+                        }
+                        else
+                        {
+                            ParseNoTildeEffect(res, args, len, used, *fmt - '2');
+                        }
                     }
-                }
-                found_p1 = TRUE;
+                };
                 break;
 
-            /*
-             * IE uses this a lot for activating things such as windows media
-             * player. This is not verified to be fully correct but it appears
-             * to work just fine.
-             */
-            case 'l':
-            case 'L':
-               if (lpFile) {
-                   used += wcslen(lpFile);
-                   if (used < len)
-                   {
-                       wcscpy(res, lpFile);
-                       res += wcslen(lpFile);
-                   }
-               }
-               found_p1 = TRUE;
-                break;
+                case '1':
+                    if (!done || (*fmt == '1'))
+                    {
+                        /*FIXME Is the call to SearchPathW() really needed? We already have separated out the parameter string in args. */
+                        if (SearchPathW(lpDir, lpFile, wszExe, sizeof(xlpFile) / sizeof(WCHAR), xlpFile, NULL))
+                            cmd = xlpFile;
+                        else
+                            cmd = lpFile;
 
-            case 'i':
-            case 'I':
-               if (pidl) {
-                   DWORD chars = 0;
-                   /* %p should not exceed 8, maybe 16 when looking forward to 64bit.
-                    * allowing a buffer of 100 should more than exceed all needs */
-                   WCHAR buf[100];
-                   LPVOID  pv;
-                   HGLOBAL hmem = SHAllocShared(pidl, ILGetSize(pidl), 0);
-                   pv = SHLockShared(hmem, 0);
-                   chars = swprintf(buf, wszILPtr, pv);
-                   if (chars >= sizeof(buf)/sizeof(WCHAR))
-                       ERR("pidl format buffer too small!\n");
-                   used += chars;
-                   if (used < len)
-                   {
-                       wcscpy(res,buf);
-                       res += chars;
-                   }
-                   SHUnlockShared(pv);
-               }
-                found_p1 = TRUE;
-                break;
+                        used += wcslen(cmd);
+                        if (used < len)
+                        {
+                            wcscpy(res, cmd);
+                            res += wcslen(cmd);
+                        }
+                    }
+                    found_p1 = TRUE;
+                    break;
 
-           default:
-                /*
-                 * Check if this is an env-variable here...
-                 */
+                    /*
+                     * IE uses this a lot for activating things such as windows media
+                     * player. This is not verified to be fully correct but it appears
+                     * to work just fine.
+                     */
+                case 'l':
+                case 'L':
+                    if (lpFile)
+                    {
+                        used += wcslen(lpFile);
+                        if (used < len)
+                        {
+                            wcscpy(res, lpFile);
+                            res += wcslen(lpFile);
+                        }
+                    }
+                    found_p1 = TRUE;
+                    break;
 
-                /* Make sure that we have at least one more %.*/
-                if (strchrW(fmt, '%'))
-                {
-                    WCHAR   tmpBuffer[1024];
-                    PWSTR   tmpB = tmpBuffer;
-                    WCHAR   tmpEnvBuff[MAX_PATH];
-                    DWORD   envRet;
+                case 'i':
+                case 'I':
+                    if (pidl)
+                    {
+                        DWORD chars = 0;
+                        /* %p should not exceed 8, maybe 16 when looking forward to 64bit.
+                            * allowing a buffer of 100 should more than exceed all needs */
+                        WCHAR buf[100];
+                        LPVOID  pv;
+                        HGLOBAL hmem = SHAllocShared(pidl, ILGetSize(pidl), 0);
+                        pv = SHLockShared(hmem, 0);
+                        chars = swprintf(buf, L":%p", pv);
 
-                    while (*fmt != '%')
-                        *tmpB++ = *fmt++;
-                    *tmpB++ = 0;
+                        if (chars >= sizeof(buf) / sizeof(WCHAR))
+                            ERR("pidl format buffer too small!\n");
 
-                    TRACE("Checking %s to be an env-var\n", debugstr_w(tmpBuffer));
+                        used += chars;
 
-                    envRet = GetEnvironmentVariableW(tmpBuffer, tmpEnvBuff, MAX_PATH);
-                    if (envRet == 0 || envRet > MAX_PATH)
-                    {
-                        used += wcslen(tmpBuffer);
                         if (used < len)
                         {
-                            wcscpy( res, tmpBuffer );
-                            res += wcslen(tmpBuffer);
+                            wcscpy(res, buf);
+                            res += chars;
                         }
+                        SHUnlockShared(pv);
                     }
-                    else
+                    found_p1 = TRUE;
+                    break;
+
+                default:
+                    /*
+                     * Check if this is an env-variable here...
+                     */
+
+                    /* Make sure that we have at least one more %.*/
+                    if (strchrW(fmt, '%'))
                     {
-                        used += wcslen(tmpEnvBuff);
-                        if (used < len)
+                        WCHAR   tmpBuffer[1024];
+                        PWSTR   tmpB = tmpBuffer;
+                        WCHAR   tmpEnvBuff[MAX_PATH];
+                        DWORD   envRet;
+
+                        while (*fmt != '%')
+                            *tmpB++ = *fmt++;
+                        *tmpB++ = 0;
+
+                        TRACE("Checking %s to be an env-var\n", debugstr_w(tmpBuffer));
+
+                        envRet = GetEnvironmentVariableW(tmpBuffer, tmpEnvBuff, MAX_PATH);
+                        if (envRet == 0 || envRet > MAX_PATH)
                         {
-                            wcscpy( res, tmpEnvBuff );
-                            res += wcslen(tmpEnvBuff);
+                            used += wcslen(tmpBuffer);
+                            if (used < len)
+                            {
+                                wcscpy( res, tmpBuffer );
+                                res += wcslen(tmpBuffer);
+                            }
+                        }
+                        else
+                        {
+                            used += wcslen(tmpEnvBuff);
+                            if (used < len)
+                            {
+                                wcscpy( res, tmpEnvBuff );
+                                res += wcslen(tmpEnvBuff);
+                            }
                         }
                     }
-                }
-                done = TRUE;
-                break;
+                    done = TRUE;
+                    break;
             }
             /* Don't skip past terminator (catch a single '%' at the end) */
             if (*fmt != '\0')
@@ -243,39 +388,46 @@ static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR*
         }
     }
 
-    *res = '\0';
-    TRACE("used %i of %i space\n",used,len);
+    used++;
+    if (res - out < static_cast<int>(len))
+        *res = '\0';
+    else
+        out[len-1] = '\0';
+
+    TRACE("used %i of %i space\n", used, len);
     if (out_len)
         *out_len = used;
 
+    TRACE("After parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
+          debugstr_w(lpFile), pidl, args);
+
     return found_p1;
 }
 
 static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR pszPath, UINT uOutSize)
 {
     STRRET strret;
-    IShellFolder* desktop;
+    CComPtr<IShellFolder> desktop;
 
     HRESULT hr = SHGetDesktopFolder(&desktop);
 
-    if (SUCCEEDED(hr)) {
-       hr = desktop->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret);
-
-       if (SUCCEEDED(hr))
-           StrRetToStrNW(pszPath, uOutSize, &strret, pidl);
+    if (SUCCEEDED(hr))
+    {
+        hr = desktop->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret);
 
-       desktop->Release();
+        if (SUCCEEDED(hr))
+            StrRetToStrNW(pszPath, uOutSize, &strret, pidl);
     }
 
     return hr;
 }
 
 /*************************************************************************
- *     SHELL_ExecuteW [Internal]
+ *    SHELL_ExecuteW [Internal]
  *
  */
 static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
-                           const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
+                               const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
 {
     STARTUPINFOW  startup;
     PROCESS_INFORMATION info;
@@ -298,26 +450,33 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
 
     /* ShellExecute specifies the command from psei->lpDirectory
      * if present. Not from the current dir as CreateProcess does */
-    if( lpDirectory )
-        if( ( gcdret = GetCurrentDirectoryW( MAX_PATH, curdir)))
-            if!SetCurrentDirectoryW( lpDirectory))
+    if (lpDirectory)
+        if ((gcdret = GetCurrentDirectoryW( MAX_PATH, curdir)))
+            if (!SetCurrentDirectoryW( lpDirectory))
                 ERR("cannot set directory %s\n", debugstr_w(lpDirectory));
-    ZeroMemory(&startup,sizeof(STARTUPINFOW));
+
+    ZeroMemory(&startup, sizeof(STARTUPINFOW));
     startup.cb = sizeof(STARTUPINFOW);
     startup.dwFlags = STARTF_USESHOWWINDOW;
     startup.wShowWindow = psei->nShow;
     dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
-    if (psei->fMask & SEE_MASK_NO_CONSOLE)
+    if (!(psei->fMask & SEE_MASK_NO_CONSOLE))
         dwCreationFlags |= CREATE_NEW_CONSOLE;
+    startup.lpTitle = (LPWSTR)(psei->fMask & (SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE) ? psei->lpClass : NULL);
+
+    if (psei->fMask & SEE_MASK_HASLINKNAME)
+        startup.dwFlags |= STARTF_TITLEISLINKNAME;
+
     if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env,
                        lpDirectory, &startup, &info))
     {
         /* Give 30 seconds to the app to come up, if desired. Probably only needed
            when starting app immediately before making a DDE connection. */
         if (shWait)
-            if (WaitForInputIdle( info.hProcess, 30000 ) == WAIT_FAILED)
+            if (WaitForInputIdle(info.hProcess, 30000) == WAIT_FAILED)
                 WARN("WaitForInputIdle failed: Error %d\n", GetLastError() );
         retval = 33;
+
         if (psei->fMask & SEE_MASK_NOCLOSEPROCESS)
             psei_out->hProcess = info.hProcess;
         else
@@ -326,15 +485,16 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
     }
     else if ((retval = GetLastError()) >= 32)
     {
-        TRACE("CreateProcess returned error %ld\n", retval);
+        WARN("CreateProcess returned error %ld\n", retval);
         retval = ERROR_BAD_FORMAT;
     }
 
     TRACE("returning %lu\n", retval);
 
     psei_out->hInstApp = (HINSTANCE)retval;
-    if( gcdret )
-        if( !SetCurrentDirectoryW( curdir))
+
+    if (gcdret)
+        if (!SetCurrentDirectoryW(curdir))
             ERR("cannot return to directory %s\n", debugstr_w(curdir));
 
     return retval;
@@ -342,14 +502,14 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
 
 
 /***********************************************************************
- *           SHELL_BuildEnvW   [Internal]
+ *           SHELL_BuildEnvW    [Internal]
  *
  * Build the environment for the new process, adding the specified
  * path to the PATH variable. Returned pointer must be freed by caller.
  */
 static LPWSTR SHELL_BuildEnvW( const WCHAR *path )
 {
-    static const WCHAR wPath[] = {'P','A','T','H','=',0};
+    static const WCHAR wPath[] = L"PATH=";
     WCHAR *strings, *new_env;
     WCHAR *p, *p2;
     int total = wcslen(path) + 1;
@@ -367,9 +527,9 @@ static LPWSTR SHELL_BuildEnvW( const WCHAR *path )
     if (!got_path) total += 5;  /* we need to create PATH */
     total++;  /* terminating null */
 
-    if (!(new_env = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) )))
+    if (!(new_env = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, total * sizeof(WCHAR))))
     {
-        FreeEnvironmentStringsW( strings );
+        FreeEnvironmentStringsW(strings);
         return NULL;
     }
     p = strings;
@@ -377,7 +537,7 @@ static LPWSTR SHELL_BuildEnvW( const WCHAR *path )
     while (*p)
     {
         int len = wcslen(p) + 1;
-        memcpy( p2, p, len * sizeof(WCHAR) );
+        memcpy(p2, p, len * sizeof(WCHAR));
         if (!_wcsnicmp( p, wPath, 5 ))
         {
             p2[len - 1] = ';';
@@ -389,18 +549,18 @@ static LPWSTR SHELL_BuildEnvW( const WCHAR *path )
     }
     if (!got_path)
     {
-        wcscpy( p2, wPath );
-        wcscat( p2, path );
+        wcscpy(p2, wPath);
+        wcscat(p2, path);
         p2 += wcslen(p2) + 1;
     }
     *p2 = 0;
-    FreeEnvironmentStringsW( strings );
+    FreeEnvironmentStringsW(strings);
     return new_env;
 }
 
 
 /***********************************************************************
- *           SHELL_TryAppPathW [Internal]
+ *           SHELL_TryAppPathW    [Internal]
  *
  * Helper function for SHELL_FindExecutable
  * @param lpResult - pointer to a buffer of size MAX_PATH
@@ -409,9 +569,6 @@ static LPWSTR SHELL_BuildEnvW( const WCHAR *path )
  */
 static BOOL SHELL_TryAppPathW( LPCWSTR szName, LPWSTR lpResult, WCHAR **env)
 {
-    static const WCHAR wszKeyAppPaths[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',
-       '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','A','p','p',' ','P','a','t','h','s','\\',0};
-    static const WCHAR wPath[] = {'P','a','t','h',0};
     HKEY hkApp = 0;
     WCHAR buffer[1024];
     LONG len;
@@ -419,12 +576,20 @@ static BOOL SHELL_TryAppPathW( LPCWSTR szName, LPWSTR lpResult, WCHAR **env)
     BOOL found = FALSE;
 
     if (env) *env = NULL;
-    wcscpy(buffer, wszKeyAppPaths);
+    wcscpy(buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
     wcscat(buffer, szName);
     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp);
-    if (res) goto end;
+    if (res) 
+    {
+        // Add ".exe" extension, if extension does not exists
+        if (PathAddExtensionW(buffer, wszExe))
+        {
+            res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp);
+        }        
+        if (res) goto end;
+    }
 
-    len = MAX_PATH*sizeof(WCHAR);
+    len = MAX_PATH * sizeof(WCHAR);
     res = RegQueryValueW(hkApp, NULL, lpResult, &len);
     if (res) goto end;
     found = TRUE;
@@ -432,8 +597,8 @@ static BOOL SHELL_TryAppPathW( LPCWSTR szName, LPWSTR lpResult, WCHAR **env)
     if (env)
     {
         DWORD count = sizeof(buffer);
-        if (!RegQueryValueExW(hkApp, wPath, NULL, NULL, (LPBYTE)buffer, &count) && buffer[0])
-            *env = SHELL_BuildEnvW( buffer );
+        if (!RegQueryValueExW(hkApp, L"Path", NULL, NULL, (LPBYTE)buffer, &count) && buffer[0])
+            *env = SHELL_BuildEnvW(buffer);
     }
 
 end:
@@ -441,69 +606,87 @@ end:
     return found;
 }
 
-static UINT SHELL_FindExecutableByOperation(LPCWSTR lpOperation, LPWSTR key, LPWSTR filetype, LPWSTR command, LONG commandlen)
+/*************************************************************************
+ *     SHELL_FindExecutableByVerb [Internal]
+ *
+ * called from SHELL_FindExecutable or SHELL_execute_class
+ * in/out:
+ *      classname a buffer, big enough, to get the key name to do actually the
+ *              command   "WordPad.Document.1\\shell\\open\\command"
+ *              passed as "WordPad.Document.1"
+ * in:
+ *      lpVerb the operation on it (open)
+ *      commandlen the size of command buffer (in bytes)
+ * out:
+ *      command a buffer, to store the command to do the
+ *              operation on the file
+ *      key a buffer, big enough, to get the key name to do actually the
+ *              command "WordPad.Document.1\\shell\\open\\command"
+ *              Can be NULL
+ */
+static UINT SHELL_FindExecutableByVerb(LPCWSTR lpVerb, LPWSTR key, LPWSTR classname, LPWSTR command, LONG commandlen)
 {
-    static const WCHAR wCommand[] = {'\\','c','o','m','m','a','n','d',0};
+    static const WCHAR wCommand[] = L"\\command";
     HKEY hkeyClass;
     WCHAR verb[MAX_PATH];
 
-    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, filetype, 0, 0x02000000, &hkeyClass))
+    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, classname, 0, 0x02000000, &hkeyClass))
         return SE_ERR_NOASSOC;
-    if (!HCR_GetDefaultVerbW(hkeyClass, lpOperation, verb, sizeof(verb)/sizeof(verb[0])))
+    if (!HCR_GetDefaultVerbW(hkeyClass, lpVerb, verb, sizeof(verb) / sizeof(verb[0])))
         return SE_ERR_NOASSOC;
     RegCloseKey(hkeyClass);
 
     /* Looking for ...buffer\shell\<verb>\command */
-    wcscat(filetype, wszShell);
-    wcscat(filetype, verb);
-    wcscat(filetype, wCommand);
+    wcscat(classname, L"\\shell\\");
+    wcscat(classname, verb);
+    wcscat(classname, wCommand);
 
-    if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, command,
+    if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, command,
                        &commandlen) == ERROR_SUCCESS)
     {
-       commandlen /= sizeof(WCHAR);
-        if (key) wcscpy(key, filetype);
+        commandlen /= sizeof(WCHAR);
+        if (key) wcscpy(key, classname);
 #if 0
         LPWSTR tmp;
         WCHAR param[256];
-       LONG paramlen = sizeof(param);
-        static const WCHAR wSpace[] = {' ',0};
+        LONG paramlen = sizeof(param);
+        static const WCHAR wSpace[] = {' ', 0};
 
         /* FIXME: it seems all Windows version don't behave the same here.
          * the doc states that this ddeexec information can be found after
          * the exec names.
          * on Win98, it doesn't appear, but I think it does on Win2k
          */
-       /* Get the parameters needed by the application
-          from the associated ddeexec key */
-       tmp = strstrW(filetype, wCommand);
-       tmp[0] = '\0';
-       wcscat(filetype, wDdeexec);
-       if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, param,
-                                    &paramlen) == ERROR_SUCCESS)
-       {
-           paramlen /= sizeof(WCHAR);
+        /* Get the parameters needed by the application
+           from the associated ddeexec key */
+        tmp = strstrW(classname, wCommand);
+        tmp[0] = '\0';
+        wcscat(classname, wDdeexec);
+        if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, param,
+                           &paramlen) == ERROR_SUCCESS)
+        {
+            paramlen /= sizeof(WCHAR);
             wcscat(command, wSpace);
             wcscat(command, param);
             commandlen += paramlen;
-       }
+        }
 #endif
 
-       command[commandlen] = '\0';
+        command[commandlen] = '\0';
 
-       return 33; /* FIXME see SHELL_FindExecutable() */
+        return 33; /* FIXME see SHELL_FindExecutable() */
     }
 
     return SE_ERR_NOASSOC;
 }
 
 /*************************************************************************
- *     SHELL_FindExecutable [Internal]
+ *    SHELL_FindExecutable [Internal]
  *
  * Utility for code sharing between FindExecutable and ShellExecute
  * in:
  *      lpFile the name of a file
- *      lpOperation the operation on it (open)
+ *      lpVerb the operation on it (open)
  * out:
  *      lpResult a buffer, big enough :-(, to store the command to do the
  *              operation on the file
@@ -511,15 +694,12 @@ static UINT SHELL_FindExecutableByOperation(LPCWSTR lpOperation, LPWSTR key, LPW
  *              command (it'll be used afterwards for more information
  *              on the operation)
  */
-static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation,
+static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb,
                                  LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args)
 {
-    static const WCHAR wWindows[] = {'w','i','n','d','o','w','s',0};
-    static const WCHAR wPrograms[] = {'p','r','o','g','r','a','m','s',0};
-    static const WCHAR wExtensions[] = {'e','x','e',' ','p','i','f',' ','b','a','t',' ','c','m','d',' ','c','o','m',0};
     WCHAR *extension = NULL; /* pointer to file extension */
-    WCHAR filetype[256];     /* registry name for this filetype */
-    LONG  filetypelen = sizeof(filetype); /* length of above */
+    WCHAR classname[256];     /* registry name for this file type */
+    LONG  classnamelen = sizeof(classname); /* length of above */
     WCHAR command[1024];     /* command from registry */
     WCHAR wBuffer[256];      /* Used to GetProfileString */
     UINT  retval = SE_ERR_NOASSOC;
@@ -550,23 +730,28 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOpera
         return 33;
     }
 
-    if (SearchPathW(lpPath, lpFile, wszExe, sizeof(xlpFile)/sizeof(WCHAR), xlpFile, NULL))
+    if (SearchPathW(lpPath, lpFile, wszExe, sizeof(xlpFile) / sizeof(WCHAR), xlpFile, NULL))
+    {
+        TRACE("SearchPathW returned non-zero\n");
+        lpFile = xlpFile;
+        /* The file was found in the application-supplied default directory (or the system search path) */
+    }
+    else if (lpPath && SearchPathW(NULL, lpFile, wszExe, sizeof(xlpFile)/sizeof(WCHAR), xlpFile, NULL))
     {
         TRACE("SearchPathW returned non-zero\n");
         lpFile = xlpFile;
-        /* Hey, isn't this value ignored?  Why make this call?  Shouldn't we return here?  --dank*/
+        /* The file was found in one of the directories in the system-wide search path */
     }
 
     attribs = GetFileAttributesW(lpFile);
-    if (attribs!=INVALID_FILE_ATTRIBUTES && (attribs&FILE_ATTRIBUTE_DIRECTORY))
+    if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY))
     {
-       wcscpy(filetype, wszFolder);
-       filetypelen = 6;    /* strlen("Folder") */
+        wcscpy(classname, L"Folder");
     }
     else
     {
         /* Did we get something? Anything? */
-        if (xlpFile[0]==0)
+        if (xlpFile[0] == 0)
         {
             TRACE("Returning SE_ERR_FNF\n");
             return SE_ERR_FNF;
@@ -577,7 +762,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOpera
         /* .\FILE.EXE :( */
         TRACE("xlpFile=%s,extension=%s\n", debugstr_w(xlpFile), debugstr_w(extension));
 
-        if (extension == NULL || extension[1]==0)
+        if (extension == NULL || extension[1] == 0)
         {
             WARN("Returning SE_ERR_NOASSOC\n");
             return SE_ERR_NOASSOC;
@@ -585,7 +770,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOpera
 
         /* Three places to check: */
         /* 1. win.ini, [windows], programs (NB no leading '.') */
-        /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
+        /* 2. Registry, HKEY_CLASS_ROOT\<classname>\shell\open\command */
         /* 3. win.ini, [extensions], extension (NB no leading '.' */
         /* All I know of the order is that registry is checked before */
         /* extensions; however, it'd make sense to check the programs */
@@ -594,7 +779,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOpera
         /* See if it's a program - if GetProfileString fails, we skip this
          * section. Actually, if GetProfileString fails, we've probably
          * got a lot more to worry about than running a program... */
-        if (GetProfileStringW(wWindows, wPrograms, wExtensions, wBuffer, sizeof(wBuffer)/sizeof(WCHAR)) > 0)
+        if (GetProfileStringW(L"windows", L"programs", L"exe pif bat cmd com", wBuffer, sizeof(wBuffer) / sizeof(WCHAR)) > 0)
         {
             CharLowerW(wBuffer);
             tok = wBuffer;
@@ -622,63 +807,59 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOpera
         }
 
         /* Check registry */
-        if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, filetype,
-                           &filetypelen) == ERROR_SUCCESS)
+        if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, classname,
+                           &classnamelen) == ERROR_SUCCESS)
         {
-            filetypelen /= sizeof(WCHAR);
-           if (filetypelen == sizeof(filetype)/sizeof(WCHAR))
-               filetypelen--;
-            filetype[filetypelen] = '\0';
-            TRACE("File type: %s\n", debugstr_w(filetype));
+            classnamelen /= sizeof(WCHAR);
+            if (classnamelen == sizeof(classname) / sizeof(WCHAR))
+                classnamelen--;
+
+            classname[classnamelen] = '\0';
+            TRACE("File type: %s\n", debugstr_w(classname));
         }
         else
         {
-            *filetype = '\0';
-            filetypelen = 0;
+            *classname = '\0';
         }
     }
 
-    if (*filetype)
-    {
-        /* pass the operation string to SHELL_FindExecutableByOperation() */
-        filetype[filetypelen] = '\0';
-        retval = SHELL_FindExecutableByOperation(lpOperation, key, filetype, command, sizeof(command));
-
-       if (retval > 32)
-       {
-           DWORD finishedLen;
-           SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen);
-           if (finishedLen > resultLen)
-               ERR("Argify buffer not large enough.. truncated\n");
-
-           /* Remove double quotation marks and command line arguments */
-           if (*lpResult == '"')
-           {
-               WCHAR *p = lpResult;
-               while (*(p + 1) != '"')
-               {
-                   *p = *(p + 1);
-                   p++;
-               }
-               *p = '\0';
-           }
+    if (*classname)
+    {
+        /* pass the verb string to SHELL_FindExecutableByVerb() */
+        retval = SHELL_FindExecutableByVerb(lpVerb, key, classname, command, sizeof(command));
+
+        if (retval > 32)
+        {
+            DWORD finishedLen;
+            SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen, lpPath);
+            if (finishedLen > resultLen)
+                ERR("Argify buffer not large enough.. truncated\n");
+            /* Remove double quotation marks and command line arguments */
+            if (*lpResult == '"')
+            {
+                WCHAR *p = lpResult;
+                while (*(p + 1) != '"')
+                {
+                    *p = *(p + 1);
+                    p++;
+                }
+                *p = '\0';
+            }
             else
             {
                 /* Truncate on first space */
-               WCHAR *p = lpResult;
-               while (*p != ' ' && *p != '\0')
+                WCHAR *p = lpResult;
+                while (*p != ' ' && *p != '\0')
                     p++;
-                *p='\0';
+                *p = '\0';
             }
-       }
+        }
     }
     else /* Check win.ini */
     {
-       static const WCHAR wExtensions[] = {'e','x','t','e','n','s','i','o','n','s',0};
-
-       /* Toss the leading dot */
-       extension++;
-       if (GetProfileStringW(wExtensions, extension, wszEmpty, command, sizeof(command)/sizeof(WCHAR)) > 0)
+        /* Toss the leading dot */
+        extension++;
+        if (GetProfileStringW(L"extensions", extension, L"", command, sizeof(command) / sizeof(WCHAR)) > 0)
         {
             if (wcslen(command) != 0)
             {
@@ -689,7 +870,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOpera
                     tok[0] = '\0';
                     wcscat(lpResult, xlpFile); /* what if no dir in xlpFile? */
                     tok = wcschr(command, '^'); /* see above */
-                    if ((tok != NULL) && (wcslen(tok)>5))
+                    if ((tok != NULL) && (wcslen(tok) > 5))
                     {
                         wcscat(lpResult, &tok[5]);
                     }
@@ -704,7 +885,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOpera
 }
 
 /******************************************************************
- *             dde_cb
+ *        dde_cb
  *
  * callback for the DDE connection. not really useful
  */
@@ -713,12 +894,12 @@ static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv,
                                 ULONG_PTR dwData1, ULONG_PTR dwData2)
 {
     TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
-           uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
+          uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
     return NULL;
 }
 
 /******************************************************************
- *             dde_connect
+ *        dde_connect
  *
  * ShellExecute helper. Used to do an operation with a DDE connection
  *
@@ -728,57 +909,76 @@ static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv,
  */
 static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec,
                             const WCHAR* lpFile, WCHAR *env,
-                           LPCWSTR szCommandline, LPITEMIDLIST pidl, SHELL_ExecuteW32 execfunc,
+                            LPCWSTR szCommandline, LPITEMIDLIST pidl, SHELL_ExecuteW32 execfunc,
                             const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
 {
-    static const WCHAR wApplication[] = {'\\','a','p','p','l','i','c','a','t','i','o','n',0};
-    static const WCHAR wTopic[] = {'\\','t','o','p','i','c',0};
     WCHAR       regkey[256];
     WCHAR *     endkey = regkey + wcslen(key);
-    WCHAR       app[256], topic[256], ifexec[256], res[256];
+    WCHAR       app[256], topic[256], ifexec[256], static_res[256];
+    WCHAR *     dynamic_res=NULL;
+    WCHAR *     res;
     LONG        applen, topiclen, ifexeclen;
     WCHAR *     exec;
     DWORD       ddeInst = 0;
     DWORD       tid;
-    DWORD       resultLen;
+    DWORD       resultLen, endkeyLen;
     HSZ         hszApp, hszTopic;
     HCONV       hConv;
     HDDEDATA    hDdeData;
     unsigned    ret = SE_ERR_NOASSOC;
     BOOL unicode = !(GetVersion() & 0x80000000);
 
+    if (strlenW(key) + 1 > sizeof(regkey) / sizeof(regkey[0]))
+    {
+        FIXME("input parameter %s larger than buffer\n", debugstr_w(key));
+        return 2;
+    }
     wcscpy(regkey, key);
+    static const WCHAR wApplication[] = L"\\application";
+    endkeyLen = sizeof(regkey) / sizeof(regkey[0]) - (endkey - regkey);
+    if (strlenW(wApplication) + 1 > endkeyLen)
+    {
+        FIXME("endkey %s overruns buffer\n", debugstr_w(wApplication));
+        return 2;
+    }
     wcscpy(endkey, wApplication);
     applen = sizeof(app);
     if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, app, &applen) != ERROR_SUCCESS)
     {
         WCHAR command[1024], fullpath[MAX_PATH];
-        static const WCHAR wSo[] = { '.','s','o',0 };
-        DWORD sizeSo = sizeof(wSo)/sizeof(WCHAR);
+        static const WCHAR wSo[] = L".so";
+        DWORD sizeSo = sizeof(wSo) / sizeof(WCHAR);
         LPWSTR ptr = NULL;
         DWORD ret = 0;
 
         /* Get application command from start string and find filename of application */
         if (*start == '"')
         {
-            wcscpy(command, start+1);
+            if (strlenW(start + 1) + 1 > sizeof(command) / sizeof(command[0]))
+            {
+                FIXME("size of input parameter %s larger than buffer\n",
+                      debugstr_w(start + 1));
+                return 2;
+            }
+            wcscpy(command, start + 1);
             if ((ptr = wcschr(command, '"')))
-                *ptr = 0;
-            ret = SearchPathW(NULL, command, wszExe, sizeof(fullpath)/sizeof(WCHAR), fullpath, &ptr);
+                * ptr = 0;
+            ret = SearchPathW(NULL, command, wszExe, sizeof(fullpath) / sizeof(WCHAR), fullpath, &ptr);
         }
         else
         {
-            LPWSTR p,space;
-            for (p=(LPWSTR)start; (space= const_cast<LPWSTR>(strchrW(p, ' '))); p=space+1)
+            LPCWSTR p;
+            LPWSTR space;
+            for (p = start; (space = const_cast<LPWSTR>(strchrW(p, ' '))); p = space + 1)
             {
-                int idx = space-start;
-                memcpy(command, start, idx*sizeof(WCHAR));
+                int idx = space - start;
+                memcpy(command, start, idx * sizeof(WCHAR));
                 command[idx] = '\0';
-                if ((ret = SearchPathW(NULL, command, wszExe, sizeof(fullpath)/sizeof(WCHAR), fullpath, &ptr)))
+                if ((ret = SearchPathW(NULL, command, wszExe, sizeof(fullpath) / sizeof(WCHAR), fullpath, &ptr)))
                     break;
             }
             if (!ret)
-                ret = SearchPathW(NULL, start, wszExe, sizeof(fullpath)/sizeof(WCHAR), fullpath, &ptr);
+                ret = SearchPathW(NULL, start, wszExe, sizeof(fullpath) / sizeof(WCHAR), fullpath, &ptr);
         }
 
         if (!ret)
@@ -786,12 +986,17 @@ static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec
             ERR("Unable to find application path for command %s\n", debugstr_w(start));
             return ERROR_ACCESS_DENIED;
         }
+        if (strlenW(ptr) + 1 > sizeof(app) / sizeof(app[0]))
+        {
+            FIXME("size of found path %s larger than buffer\n", debugstr_w(ptr));
+            return 2;
+        }
         wcscpy(app, ptr);
 
         /* Remove extensions (including .so) */
-        ptr = app + wcslen(app) - (sizeSo-1);
+        ptr = app + wcslen(app) - (sizeSo - 1);
         if (wcslen(app) >= sizeSo &&
-            !wcscmp(ptr, wSo))
+                !wcscmp(ptr, wSo))
             *ptr = 0;
 
         ptr = const_cast<LPWSTR>(strrchrW(app, '.'));
@@ -799,12 +1004,17 @@ static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec
         *ptr = 0;
     }
 
+    static const WCHAR wTopic[] = L"\\topic";
+    if (strlenW(wTopic) + 1 > endkeyLen)
+    {
+        FIXME("endkey %s overruns buffer\n", debugstr_w(wTopic));
+        return 2;
+    }
     wcscpy(endkey, wTopic);
     topiclen = sizeof(topic);
     if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, topic, &topiclen) != ERROR_SUCCESS)
     {
-        static const WCHAR wSystem[] = {'S','y','s','t','e','m',0};
-        wcscpy(topic, wSystem);
+        wcscpy(topic, L"System");
     }
 
     if (unicode)
@@ -825,7 +1035,6 @@ static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec
     exec = ddeexec;
     if (!hConv)
     {
-        static const WCHAR wIfexec[] = {'\\','i','f','e','x','e','c',0};
         TRACE("Launching %s\n", debugstr_w(start));
         ret = execfunc(start, env, TRUE, psei, psei_out);
         if (ret <= 32)
@@ -841,6 +1050,12 @@ static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec
             SetLastError(ERROR_DDE_FAIL);
             return 30; /* whatever */
         }
+        static const WCHAR wIfexec[] = L"\\ifexec";
+        if (strlenW(wIfexec) + 1 > endkeyLen)
+        {
+            FIXME("endkey %s overruns buffer\n", debugstr_w(wIfexec));
+            return 2;
+        }
         strcpyW(endkey, wIfexec);
         ifexeclen = sizeof(ifexec);
         if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, ifexec, &ifexeclen) == ERROR_SUCCESS)
@@ -849,17 +1064,21 @@ static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec
         }
     }
 
-    SHELL_ArgifyW(res, sizeof(res)/sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen);
-    if (resultLen > sizeof(res)/sizeof(WCHAR))
-        ERR("Argify buffer not large enough, truncated\n");
+    SHELL_ArgifyW(static_res, sizeof(static_res)/sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen, NULL);
+    if (resultLen > sizeof(static_res)/sizeof(WCHAR))
+    {
+        res = dynamic_res = static_cast<WCHAR *>(HeapAlloc(GetProcessHeap(), 0, resultLen * sizeof(WCHAR)));
+        SHELL_ArgifyW(dynamic_res, resultLen, exec, lpFile, pidl, szCommandline, NULL, NULL);
+    }
+    else
+        res = static_res;
     TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res));
 
     /* It's documented in the KB 330337 that IE has a bug and returns
      * error DMLERR_NOTPROCESSED on XTYP_EXECUTE request.
      */
     if (unicode)
-        hDdeData = DdeClientTransaction((LPBYTE)res, (strlenW(res) + 1) * sizeof(WCHAR), hConv, 0L, 0,
-                                         XTYP_EXECUTE, 30000, &tid);
+        hDdeData = DdeClientTransaction((LPBYTE)res, (strlenW(res) + 1) * sizeof(WCHAR), hConv, 0L, 0, XTYP_EXECUTE, 30000, &tid);
     else
     {
         DWORD lenA = WideCharToMultiByte(CP_ACP, 0, res, -1, NULL, 0, NULL, NULL);
@@ -875,24 +1094,24 @@ static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec
         WARN("DdeClientTransaction failed with error %04x\n", DdeGetLastError(ddeInst));
     ret = 33;
 
+    HeapFree(GetProcessHeap(), 0, dynamic_res);
+
     DdeDisconnect(hConv);
 
- error:
+error:
     DdeUninitialize(ddeInst);
 
     return ret;
 }
 
 /*************************************************************************
- *     execute_from_key [Internal]
+ *    execute_from_key [Internal]
  */
-static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWSTR szCommandline,
-                             LPCWSTR executable_name,
-                            SHELL_ExecuteW32 execfunc,
-                             LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out)
+static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env,
+                                 LPCWSTR szCommandline, LPCWSTR executable_name,
+                                 SHELL_ExecuteW32 execfunc,
+                                 LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out)
 {
-    static const WCHAR wCommand[] = {'c','o','m','m','a','n','d',0};
-    static const WCHAR wDdeexec[] = {'d','d','e','e','x','e','c',0};
     WCHAR cmd[256], param[1024], ddeexec[256];
     DWORD cmdlen = sizeof(cmd), ddeexeclen = sizeof(ddeexec);
     UINT_PTR retval = SE_ERR_NOASSOC;
@@ -900,7 +1119,7 @@ static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWST
     LPWSTR tmp;
 
     TRACE("%s %s %s %s %s\n", debugstr_w(key), debugstr_w(lpFile), debugstr_w(env),
-           debugstr_w(szCommandline), debugstr_w(executable_name));
+          debugstr_w(szCommandline), debugstr_w(executable_name));
 
     cmd[0] = '\0';
     param[0] = '\0';
@@ -912,19 +1131,20 @@ static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWST
 
         /* Is there a replace() function anywhere? */
         cmdlen /= sizeof(WCHAR);
-       if (cmdlen >= sizeof(cmd)/sizeof(WCHAR))
-           cmdlen = sizeof(cmd)/sizeof(WCHAR)-1;
+        if (cmdlen >= sizeof(cmd) / sizeof(WCHAR))
+            cmdlen = sizeof(cmd) / sizeof(WCHAR) - 1;
         cmd[cmdlen] = '\0';
-        SHELL_ArgifyW(param, sizeof(param)/sizeof(WCHAR), cmd, lpFile, (LPITEMIDLIST)psei->lpIDList, szCommandline, &resultLen);
-        if (resultLen > sizeof(param)/sizeof(WCHAR))
+        SHELL_ArgifyW(param, sizeof(param) / sizeof(WCHAR), cmd, lpFile, (LPITEMIDLIST)psei->lpIDList, szCommandline, &resultLen,
+                      (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL);
+        if (resultLen > sizeof(param) / sizeof(WCHAR))
             ERR("Argify buffer not large enough, truncating\n");
     }
 
     /* Get the parameters needed by the application
        from the associated ddeexec key */
-    tmp = const_cast<LPWSTR>(strstrW(key, wCommand));
+    tmp = const_cast<LPWSTR>(strstrW(key, L"command"));
     assert(tmp);
-    wcscpy(tmp, wDdeexec);
+    wcscpy(tmp, L"ddeexec");
 
     if (RegQueryValueW(HKEY_CLASSES_ROOT, key, ddeexec, (LONG *)&ddeexeclen) == ERROR_SUCCESS)
     {
@@ -944,7 +1164,7 @@ static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWST
 }
 
 /*************************************************************************
- * FindExecutableA                     [SHELL32.@]
+ * FindExecutableA            [SHELL32.@]
  */
 HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
 {
@@ -957,15 +1177,15 @@ HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResu
 
     retval = FindExecutableW(wFile, wDirectory, wResult);
     WideCharToMultiByte(CP_ACP, 0, wResult, -1, lpResult, MAX_PATH, NULL, NULL);
-    SHFree( wFile );
-    SHFree( wDirectory );
+    SHFree(wFile);
+    SHFree(wDirectory);
 
     TRACE("returning %s\n", lpResult);
     return retval;
 }
 
 /*************************************************************************
- * FindExecutableW                     [SHELL32.@]
+ * FindExecutableW            [SHELL32.@]
  *
  * This function returns the executable associated with the specified file
  * for the default verb.
@@ -993,20 +1213,23 @@ HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpR
 {
     UINT_PTR retval = SE_ERR_NOASSOC;
     WCHAR old_dir[1024];
+    WCHAR res[MAX_PATH];
 
     TRACE("File %s, Dir %s\n", debugstr_w(lpFile), debugstr_w(lpDirectory));
 
     lpResult[0] = '\0'; /* Start off with an empty return string */
     if (lpFile == NULL)
-       return (HINSTANCE)SE_ERR_FNF;
+        return (HINSTANCE)SE_ERR_FNF;
 
     if (lpDirectory)
     {
-        GetCurrentDirectoryW(sizeof(old_dir)/sizeof(WCHAR), old_dir);
+        GetCurrentDirectoryW(sizeof(old_dir) / sizeof(WCHAR), old_dir);
         SetCurrentDirectoryW(lpDirectory);
     }
 
-    retval = SHELL_FindExecutable(lpDirectory, lpFile, wszOpen, lpResult, MAX_PATH, NULL, NULL, NULL, NULL);
+    retval = SHELL_FindExecutable(lpDirectory, lpFile, wszOpen, res, MAX_PATH, NULL, NULL, NULL, NULL);
+    if (retval > 32)
+        strcpyW(lpResult, res);
 
     TRACE("returning %s\n", debugstr_w(lpResult));
     if (lpDirectory)
@@ -1015,7 +1238,7 @@ HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpR
 }
 
 /* FIXME: is this already implemented somewhere else? */
-static HKEY ShellExecute_GetClassKey( const SHELLEXECUTEINFOW *sei )
+static HKEY ShellExecute_GetClassKey(const SHELLEXECUTEINFOW *sei)
 {
     LPCWSTR ext = NULL, lpClass = NULL;
     LPWSTR cls = NULL;
@@ -1030,35 +1253,35 @@ static HKEY ShellExecute_GetClassKey( const SHELLEXECUTEINFOW *sei )
         lpClass = sei->lpClass;
     else
     {
-        ext = PathFindExtensionW( sei->lpFile );
-        TRACE("ext = %s\n", debugstr_w( ext ) );
+        ext = PathFindExtensionW(sei->lpFile);
+        TRACE("ext = %s\n", debugstr_w(ext));
         if (!ext)
             return hkey;
 
-        r = RegOpenKeyW( HKEY_CLASSES_ROOT, ext, &hkey );
-        if (r != ERROR_SUCCESS )
+        r = RegOpenKeyW(HKEY_CLASSES_ROOT, ext, &hkey);
+        if (r != ERROR_SUCCESS)
             return hkey;
 
-        r = RegQueryValueExW( hkey, NULL, 0, &type, NULL, &sz );
-        if ( r == ERROR_SUCCESS && type == REG_SZ )
+        r = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &sz);
+        if (r == ERROR_SUCCESS && type == REG_SZ)
         {
             sz += sizeof (WCHAR);
-            cls = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, sz );
+            cls = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sz);
             cls[0] = 0;
-            RegQueryValueExW( hkey, NULL, 0, &type, (LPBYTE) cls, &sz );
+            RegQueryValueExW(hkey, NULL, 0, &type, (LPBYTE) cls, &sz);
         }
 
         RegCloseKey( hkey );
         lpClass = cls;
     }
 
-    TRACE("class = %s\n", debugstr_w(lpClass) );
+    TRACE("class = %s\n", debugstr_w(lpClass));
 
     hkey = 0;
-    if ( lpClass )
-        RegOpenKeyW( HKEY_CLASSES_ROOT, lpClass, &hkey );
+    if (lpClass)
+        RegOpenKeyW( HKEY_CLASSES_ROOT, lpClass, &hkey);
 
-    HeapFree( GetProcessHeap(), 0, cls );
+    HeapFree(GetProcessHeap(), 0, cls);
 
     return hkey;
 }
@@ -1066,8 +1289,8 @@ static HKEY ShellExecute_GetClassKey( const SHELLEXECUTEINFOW *sei )
 static IDataObject *shellex_get_dataobj( LPSHELLEXECUTEINFOW sei )
 {
     LPCITEMIDLIST pidllast = NULL;
-    IDataObject *dataobj = NULL;
-    IShellFolder *shf = NULL;
+    CComPtr<IDataObject> dataobj;
+    CComPtr<IShellFolder> shf;
     LPITEMIDLIST pidl = NULL;
     HRESULT r;
 
@@ -1079,32 +1302,29 @@ static IDataObject *shellex_get_dataobj( LPSHELLEXECUTEINFOW sei )
         BOOL ret;
 
         fullpath[0] = 0;
-        ret = GetFullPathNameW( sei->lpFile, MAX_PATH, fullpath, NULL );
+        ret = GetFullPathNameW(sei->lpFile, MAX_PATH, fullpath, NULL);
         if (!ret)
             goto end;
 
-        pidl = ILCreateFromPathW( fullpath );
+        pidl = ILCreateFromPathW(fullpath);
     }
 
-    r = SHBindToParent( pidl, IID_IShellFolder, (LPVOID*)&shf, &pidllast );
-    if ( FAILED( r ) )
+    r = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf), &pidllast);
+    if (FAILED(r))
         goto end;
 
-    shf->GetUIObjectOf(NULL, 1, &pidllast,
-                                IID_IDataObject, NULL, (LPVOID*) &dataobj );
+    shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IDataObject, &dataobj));
 
 end:
-    if ( pidl != sei->lpIDList )
-        ILFree( pidl );
-    if ( shf )
-        shf->Release();
-    return dataobj;
+    if (pidl != sei->lpIDList)
+        ILFree(pidl);
+    return dataobj.Detach();
 }
 
-static HRESULT shellex_run_context_menu_default( IShellExtInit *obj,
-                                                 LPSHELLEXECUTEINFOW sei )
+static HRESULT shellex_run_context_menu_default(IShellExtInit *obj,
+        LPSHELLEXECUTEINFOW sei)
 {
-    IContextMenu *cm = NULL;
+    CComPtr<IContextMenu> cm = NULL;
     CMINVOKECOMMANDINFOEX ici;
     MENUITEMINFOW info;
     WCHAR string[0x80];
@@ -1112,36 +1332,36 @@ static HRESULT shellex_run_context_menu_default( IShellExtInit *obj,
     HMENU hmenu = 0;
     HRESULT r;
 
-    TRACE("%p %p\n", obj, sei );
+    TRACE("%p %p\n", obj, sei);
 
-    r = obj->QueryInterface(IID_IContextMenu, (LPVOID*) &cm );
-    if ( FAILED( r ) )
+    r = obj->QueryInterface(IID_PPV_ARG(IContextMenu, &cm));
+    if (FAILED(r))
         return r;
 
     hmenu = CreateMenu();
-    if ( !hmenu )
+    if (!hmenu)
         goto end;
 
     /* the number of the last menu added is returned in r */
-    r = cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY );
-    if ( FAILED( r ) )
+    r = cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY);
+    if (FAILED(r))
         goto end;
 
-    n = GetMenuItemCount( hmenu );
-    for ( i = 0; i < n; i++ )
+    n = GetMenuItemCount(hmenu);
+    for (i = 0; i < n; i++)
     {
-        memset( &info, 0, sizeof info );
+        memset(&info, 0, sizeof(info));
         info.cbSize = sizeof info;
         info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
         info.dwTypeData = string;
         info.cch = sizeof string;
         string[0] = 0;
-        GetMenuItemInfoW( hmenu, i, TRUE, &info );
+        GetMenuItemInfoW(hmenu, i, TRUE, &info);
 
         TRACE("menu %d %s %08x %08lx %08x %08x\n", i, debugstr_w(string),
-            info.fState, info.dwItemData, info.fType, info.wID );
-        if ( ( !sei->lpVerb && (info.fState & MFS_DEFAULT) ) ||
-             ( sei->lpVerb && !lstrcmpiW( sei->lpVerb, string ) ) )
+              info.fState, info.dwItemData, info.fType, info.wID);
+        if ((!sei->lpVerb && (info.fState & MFS_DEFAULT)) ||
+            (sei->lpVerb && !lstrcmpiW(sei->lpVerb, string)))
         {
             def = i;
             break;
@@ -1149,75 +1369,75 @@ static HRESULT shellex_run_context_menu_default( IShellExtInit *obj,
     }
 
     r = E_FAIL;
-    if ( def == -1 )
+    if (def == -1)
         goto end;
 
-    memset( &ici, 0, sizeof ici );
+    memset(&ici, 0, sizeof ici);
     ici.cbSize = sizeof ici;
-    ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NOASYNC|SEE_MASK_ASYNCOK|SEE_MASK_FLAG_NO_UI));
+    ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI));
     ici.nShow = sei->nShow;
-    ici.lpVerb = MAKEINTRESOURCEA( def );
+    ici.lpVerb = MAKEINTRESOURCEA(def);
     ici.hwnd = sei->hwnd;
     ici.lpParametersW = sei->lpParameters;
 
-    r = cm->InvokeCommand((LPCMINVOKECOMMANDINFO) &ici );
+    r = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
 
-    TRACE("invoke command returned %08x\n", r );
+    TRACE("invoke command returned %08x\n", r);
 
 end:
-    if ( hmenu )
+    if (hmenu)
         DestroyMenu( hmenu );
-    if ( cm )
-        cm->Release();
     return r;
 }
 
-static HRESULT shellex_load_object_and_run( HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW sei )
+static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW sei)
 {
+    // Can not use CComPtr here because of CoUninitialize at the end, before the destructors would run.
     IDataObject *dataobj = NULL;
     IObjectWithSite *ows = NULL;
     IShellExtInit *obj = NULL;
     HRESULT r;
 
-    TRACE("%p %s %p\n", hkey, debugstr_guid( guid ), sei );
+    TRACE("%p %s %p\n", hkey, debugstr_guid(guid), sei);
 
-    r = CoInitialize( NULL );
-    if ( FAILED( r ) )
+    r = CoInitialize(NULL);
+    if (FAILED(r))
         goto end;
 
     r = CoCreateInstance(*guid, NULL, CLSCTX_INPROC_SERVER,
-                           IID_IShellExtInit, (LPVOID*)&obj );
-    if ( FAILED( r ) )
+                         IID_PPV_ARG(IShellExtInit, &obj));
+    if (FAILED(r))
     {
-        ERR("failed %08x\n", r );
+        ERR("failed %08x\n", r);
         goto end;
     }
 
-    dataobj = shellex_get_dataobj( sei );
-    if ( !dataobj )
+    dataobj = shellex_get_dataobj(sei);
+    if (!dataobj)
     {
         ERR("failed to get data object\n");
+        r = E_FAIL;
         goto end;
     }
 
-    r = obj->Initialize(NULL, dataobj, hkey );
-    if ( FAILED( r ) )
+    r = obj->Initialize(NULL, dataobj, hkey);
+    if (FAILED(r))
         goto end;
 
-    r = obj->QueryInterface(IID_IObjectWithSite, (LPVOID*) &ows );
-    if ( FAILED( r ) )
+    r = obj->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ows));
+    if (FAILED(r))
         goto end;
 
-    ows->SetSite(NULL );
+    ows->SetSite(NULL);
 
-    r = shellex_run_context_menu_default( obj, sei );
+    r = shellex_run_context_menu_default(obj, sei);
 
 end:
-    if ( ows )
+    if (ows)
         ows->Release();
-    if ( dataobj )
+    if (dataobj)
         dataobj->Release();
-    if ( obj )
+    if (obj)
         obj->Release();
     CoUninitialize();
     return r;
@@ -1225,12 +1445,10 @@ end:
 
 
 /*************************************************************************
- *     ShellExecute_FromContextMenu [Internal]
+ *    ShellExecute_FromContextMenu [Internal]
  */
 static LONG ShellExecute_FromContextMenu( LPSHELLEXECUTEINFOW sei )
 {
-    static const WCHAR szcm[] = { 's','h','e','l','l','e','x','\\',
-        'C','o','n','t','e','x','t','M','e','n','u','H','a','n','d','l','e','r','s',0 };
     HKEY hkey, hkeycm = 0;
     WCHAR szguid[39];
     HRESULT hr;
@@ -1238,79 +1456,106 @@ static LONG ShellExecute_FromContextMenu( LPSHELLEXECUTEINFOW sei )
     DWORD i;
     LONG r;
 
-    TRACE("%s\n", debugstr_w(sei->lpFile) );
+    TRACE("%s\n", debugstr_w(sei->lpFile));
 
-    hkey = ShellExecute_GetClassKey( sei );
-    if ( !hkey )
+    hkey = ShellExecute_GetClassKey(sei);
+    if (!hkey)
         return ERROR_FUNCTION_FAILED;
 
-    r = RegOpenKeyW( hkey, szcm, &hkeycm );
-    if ( r == ERROR_SUCCESS )
+    r = RegOpenKeyW(hkey, L"shellex\\ContextMenuHandlers", &hkeycm);
+    if (r == ERROR_SUCCESS)
     {
         i = 0;
-        while ( 1 )
+        while (1)
         {
-            r = RegEnumKeyW( hkeycm, i++, szguid, sizeof(szguid)/sizeof(szguid[0]) );
-            if ( r != ERROR_SUCCESS )
+            r = RegEnumKeyW(hkeycm, i++, szguid, sizeof(szguid) / sizeof(szguid[0]));
+            if (r != ERROR_SUCCESS)
                 break;
 
-            hr = CLSIDFromString( szguid, &guid );
+            hr = CLSIDFromString(szguid, &guid);
             if (SUCCEEDED(hr))
             {
                 /* stop at the first one that succeeds in running */
-                hr = shellex_load_object_and_run( hkey, &guid, sei );
-                if ( SUCCEEDED( hr ) )
+                hr = shellex_load_object_and_run(hkey, &guid, sei);
+                if (SUCCEEDED(hr))
                     break;
             }
         }
-        RegCloseKey( hkeycm );
+        RegCloseKey(hkeycm);
     }
 
-    if ( hkey != sei->hkeyClass )
-        RegCloseKey( hkey );
+    if (hkey != sei->hkeyClass)
+        RegCloseKey(hkey);
     return r;
 }
 
-static UINT_PTR SHELL_execute_class( LPCWSTR wszApplicationName, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc )
+static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR lpstrProtocol, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc);
+
+static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
 {
-    static const WCHAR wSpace[] = {' ',0};
-    WCHAR execCmd[1024], wcmd[1024];
+    WCHAR execCmd[1024], classname[1024];
     /* launch a document by fileclass like 'WordPad.Document.1' */
     /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */
     /* FIXME: wcmd should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */
-    ULONG cmask=(psei->fMask & SEE_MASK_CLASSALL);
+    ULONG cmask = (psei->fMask & SEE_MASK_CLASSALL);
     DWORD resultLen;
     BOOL done;
+    UINT_PTR rslt;
 
-    HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL,
-                           (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass: NULL,
-                           psei->lpVerb,
-                           execCmd, sizeof(execCmd));
-
-    /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
-    TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName));
-
-    wcmd[0] = '\0';
-    done = SHELL_ArgifyW(wcmd, sizeof(wcmd)/sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen);
-    if (!done && wszApplicationName[0])
+    /* FIXME: remove following block when SHELL_quote_and_execute supports hkeyClass parameter */
+    if (cmask != SEE_MASK_CLASSNAME)
     {
-        strcatW(wcmd, wSpace);
-        strcatW(wcmd, wszApplicationName);
+        WCHAR wcmd[1024];
+        HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL,
+                               (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL,
+                               psei->lpVerb,
+                               execCmd, sizeof(execCmd));
+
+        /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
+        TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName));
+
+        wcmd[0] = '\0';
+        done = SHELL_ArgifyW(wcmd, sizeof(wcmd) / sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen,
+                             (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL);
+        if (!done && wszApplicationName[0])
+        {
+            strcatW(wcmd, L" ");
+            if (*wszApplicationName != '"')
+            {
+                strcatW(wcmd, L"\"");
+                strcatW(wcmd, wszApplicationName);
+                strcatW(wcmd, L"\"");
+            }
+            else
+                strcatW(wcmd, wszApplicationName);
+        }
+        if (resultLen > sizeof(wcmd) / sizeof(WCHAR))
+            ERR("Argify buffer not large enough... truncating\n");
+        return execfunc(wcmd, NULL, FALSE, psei, psei_out);
     }
-    if (resultLen > sizeof(wcmd)/sizeof(WCHAR))
-        ERR("Argify buffer not large enough... truncating\n");
-    return execfunc(wcmd, NULL, FALSE, psei, psei_out);
+
+    strcpyW(classname, psei->lpClass);
+    rslt = SHELL_FindExecutableByVerb(psei->lpVerb, NULL, classname, execCmd, sizeof(execCmd));
+
+    TRACE("SHELL_FindExecutableByVerb returned %u (%s, %s)\n", (unsigned int)rslt, debugstr_w(classname), debugstr_w(execCmd));
+    if (33 > rslt)
+        return rslt;
+    rslt = SHELL_quote_and_execute( execCmd, L"", classname,
+                                      wszApplicationName, NULL, psei,
+                                      psei_out, execfunc );
+    return rslt;
+
 }
 
-static BOOL SHELL_translate_idlist( LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen )
+static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen)
 {
-    static const WCHAR wExplorer[] = {'e','x','p','l','o','r','e','r','.','e','x','e',0};
+    static const WCHAR wExplorer[] = L"explorer.exe";
     WCHAR buffer[MAX_PATH];
     BOOL appKnownSingular = FALSE;
 
     /* last chance to translate IDList: now also allow CLSID paths */
-    if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, sizeof(buffer)))) {
-        if (buffer[0]==':' && buffer[1]==':') {
+    if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, sizeof(buffer)/sizeof(WCHAR)))) {
+        if (buffer[0] == ':' && buffer[1] == ':') {
             /* open shell folder for the specified class GUID */
             if (strlenW(buffer) + 1 > parametersLen)
                 ERR("parameters len exceeds buffer size (%i > %i), truncating\n",
@@ -1332,12 +1577,13 @@ static BOOL SHELL_translate_idlist( LPSHELLEXECUTEINFOW sei, LPWSTR wszParameter
             strcpyW(target, buffer);
             attribs = GetFileAttributesW(buffer);
             if (attribs != INVALID_FILE_ATTRIBUTES &&
-                (attribs & FILE_ATTRIBUTE_DIRECTORY) &&
-                HCR_GetExecuteCommandW(0, wszFolder,
-                                       sei->lpVerb,
-                                       buffer, sizeof(buffer))) {
+                    (attribs & FILE_ATTRIBUTE_DIRECTORY) &&
+                    HCR_GetExecuteCommandW(0, L"Folder",
+                                           sei->lpVerb,
+                                           buffer, sizeof(buffer))) {
                 SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
-                              buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen);
+                              buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen,
+                              (sei->lpDirectory && *sei->lpDirectory) ? sei->lpDirectory : NULL);
                 if (resultLen > dwApplicationNameLen)
                     ERR("Argify buffer not large enough... truncating\n");
                 appKnownSingular = FALSE;
@@ -1348,10 +1594,8 @@ static BOOL SHELL_translate_idlist( LPSHELLEXECUTEINFOW sei, LPWSTR wszParameter
     return appKnownSingular;
 }
 
-static UINT_PTR SHELL_quote_and_execute( LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR lpstrProtocol, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc )
+static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR wszKeyname, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
 {
-    static const WCHAR wQuote[] = {'"',0};
-    static const WCHAR wSpace[] = {' ',0};
     UINT_PTR retval;
     DWORD len;
     WCHAR *wszQuotedCmd;
@@ -1367,26 +1611,29 @@ static UINT_PTR SHELL_quote_and_execute( LPCWSTR wcmd, LPCWSTR wszParameters, LP
     /* Must quote to handle case where cmd contains spaces,
      * else security hole if malicious user creates executable file "C:\\Program"
      */
-    strcpyW(wszQuotedCmd, wQuote);
+    strcpyW(wszQuotedCmd, L"\"");
     strcatW(wszQuotedCmd, wcmd);
-    strcatW(wszQuotedCmd, wQuote);
-    if (wszParameters[0]) {
-        strcatW(wszQuotedCmd, wSpace);
+    strcatW(wszQuotedCmd, L"\"");
+    if (wszParameters[0])
+    {
+        strcatW(wszQuotedCmd, L" ");
         strcatW(wszQuotedCmd, wszParameters);
     }
-    TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(lpstrProtocol));
-    if (*lpstrProtocol)
-        retval = execute_from_key(lpstrProtocol, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
+
+    TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(wszKeyname));
+
+    if (*wszKeyname)
+        retval = execute_from_key(wszKeyname, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
     else
         retval = execfunc(wszQuotedCmd, env, FALSE, psei, psei_out);
     HeapFree(GetProcessHeap(), 0, wszQuotedCmd);
     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};
+    static const WCHAR wShell[] = L"\\shell\\";
+    static const WCHAR wCommand[] = L"\\command";
     UINT_PTR retval;
     WCHAR *lpstrProtocol;
     LPCWSTR lpstrRes;
@@ -1400,63 +1647,71 @@ static UINT_PTR SHELL_execute_url( LPCWSTR lpFile, LPCWSTR wFile, LPCWSTR wcmd,
         iSize = strlenW(lpFile);
 
     TRACE("Got URL: %s\n", debugstr_w(lpFile));
-    /* Looking for ...protocol\shell\lpOperation\command */
+    /* Looking for ...<protocol>\shell\<lpVerb>\command */
     len = iSize + lstrlenW(wShell) + lstrlenW(wCommand) + 1;
-    if (psei->lpVerb)
+    if (psei->lpVerb && *psei->lpVerb)
         len += lstrlenW(psei->lpVerb);
     else
         len += lstrlenW(wszOpen);
     lpstrProtocol = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
-    memcpy(lpstrProtocol, lpFile, iSize*sizeof(WCHAR));
+    memcpy(lpstrProtocol, lpFile, iSize * sizeof(WCHAR));
     lpstrProtocol[iSize] = '\0';
     strcatW(lpstrProtocol, wShell);
-    strcatW(lpstrProtocol, psei->lpVerb? psei->lpVerb: wszOpen);
+    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);
     return retval;
 }
 
-void do_error_dialog( UINT_PTR retval, HWND hwnd, WCHAR* filename)
+static void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename)
 {
     WCHAR msg[2048];
     DWORD_PTR msgArguments[3]  = { (DWORD_PTR)filename, 0, 0 };
     DWORD error_code;
 
     error_code = GetLastError();
-
     if (retval == SE_ERR_NOASSOC)
-        LoadStringW(shell32_hInstance, IDS_SHLEXEC_NOASSOC, msg, sizeof(msg)/sizeof(WCHAR));
+        LoadStringW(shell32_hInstance, IDS_SHLEXEC_NOASSOC, msg, sizeof(msg) / sizeof(WCHAR));
     else
         FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
                        NULL,
                        error_code,
                        LANG_USER_DEFAULT,
                        msg,
-                       sizeof(msg)/sizeof(WCHAR),
+                       sizeof(msg) / sizeof(WCHAR),
                        (va_list*)msgArguments);
 
     MessageBoxW(hwnd, msg, NULL, MB_ICONERROR);
 }
 
+static WCHAR *expand_environment( const WCHAR *str )
+{
+    WCHAR *buf;
+    DWORD len;
+
+    len = ExpandEnvironmentStringsW(str, NULL, 0);
+    if (!len) return NULL;
+
+    buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if (!buf) return NULL;
+
+    len = ExpandEnvironmentStringsW(str, buf, len);
+    if (!len)
+    {
+        HeapFree(GetProcessHeap(), 0, buf);
+        return NULL;
+    }
+    return buf;
+}
+
 /*************************************************************************
- *     SHELL_execute [Internal]
+ *    SHELL_execute [Internal]
  */
-BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
+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 |
         SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT |
@@ -1464,15 +1719,15 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
 
     WCHAR parametersBuffer[1024], dirBuffer[MAX_PATH], wcmdBuffer[1024];
     WCHAR *wszApplicationName, *wszParameters, *wszDir, *wcmd;
-    DWORD dwApplicationNameLen = MAX_PATH+2;
+    DWORD dwApplicationNameLen = MAX_PATH + 2;
     DWORD parametersLen = sizeof(parametersBuffer) / sizeof(WCHAR);
     DWORD dirLen = sizeof(dirBuffer) / sizeof(WCHAR);
     DWORD wcmdLen = sizeof(wcmdBuffer) / sizeof(WCHAR);
     DWORD len;
-    SHELLEXECUTEINFOW sei_tmp; /* modifiable copy of SHELLEXECUTEINFO struct */
+    SHELLEXECUTEINFOW sei_tmp;    /* modifiable copy of SHELLEXECUTEINFO struct */
     WCHAR wfileName[MAX_PATH];
     WCHAR *env;
-    WCHAR lpstrProtocol[256];
+    WCHAR wszKeyname[256];
     LPCWSTR lpFile;
     UINT_PTR retval = SE_ERR_NOASSOC;
     BOOL appKnownSingular = FALSE;
@@ -1481,35 +1736,40 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
     sei_tmp = *sei;
 
     TRACE("mask=0x%08x hwnd=%p verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n",
-            sei_tmp.fMask, sei_tmp.hwnd, debugstr_w(sei_tmp.lpVerb),
-            debugstr_w(sei_tmp.lpFile), debugstr_w(sei_tmp.lpParameters),
-            debugstr_w(sei_tmp.lpDirectory), sei_tmp.nShow,
-            ((sei_tmp.fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME) ?
-                debugstr_w(sei_tmp.lpClass) : "not used");
+          sei_tmp.fMask, sei_tmp.hwnd, debugstr_w(sei_tmp.lpVerb),
+          debugstr_w(sei_tmp.lpFile), debugstr_w(sei_tmp.lpParameters),
+          debugstr_w(sei_tmp.lpDirectory), sei_tmp.nShow,
+          ((sei_tmp.fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME) ?
+          debugstr_w(sei_tmp.lpClass) : "not used");
 
     sei->hProcess = NULL;
 
     /* make copies of all path/command strings */
     if (!sei_tmp.lpFile)
     {
-        wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen*sizeof(WCHAR));
+        wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR));
         *wszApplicationName = '\0';
     }
-    else if (*sei_tmp.lpFile == '\"')
+    else if (*sei_tmp.lpFile == '\"' && sei_tmp.lpFile[(len = strlenW(sei_tmp.lpFile))-1] == '\"')
     {
-        DWORD l = strlenW(sei_tmp.lpFile+1);
-        if(l >= dwApplicationNameLen) dwApplicationNameLen = l+1;
-        wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen*sizeof(WCHAR));
-        memcpy(wszApplicationName, sei_tmp.lpFile+1, (l+1)*sizeof(WCHAR));
-        if (wszApplicationName[l-1] == '\"')
-            wszApplicationName[l-1] = '\0';
+        if(len-1 >= dwApplicationNameLen)
+            dwApplicationNameLen = len;
+
+        wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR));
+        memcpy(wszApplicationName, sei_tmp.lpFile + 1, len * sizeof(WCHAR));
+
+        if(len > 2)
+            wszApplicationName[len-2] = '\0';
         appKnownSingular = TRUE;
-        TRACE("wszApplicationName=%s\n",debugstr_w(wszApplicationName));
-    } else {
-        DWORD l = strlenW(sei_tmp.lpFile)+1;
-        if(l > dwApplicationNameLen) dwApplicationNameLen = l+1;
-        wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen*sizeof(WCHAR));
-        memcpy(wszApplicationName, sei_tmp.lpFile, l*sizeof(WCHAR));
+
+        TRACE("wszApplicationName=%s\n", debugstr_w(wszApplicationName));
+    }
+    else
+    {
+        DWORD l = strlenW(sei_tmp.lpFile) + 1;
+        if(l > dwApplicationNameLen) dwApplicationNameLen = l + 1;
+        wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR));
+        memcpy(wszApplicationName, sei_tmp.lpFile, l * sizeof(WCHAR));
     }
 
     wszParameters = parametersBuffer;
@@ -1521,10 +1781,10 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
             wszParameters = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
             parametersLen = len;
         }
-       strcpyW(wszParameters, sei_tmp.lpParameters);
+        strcpyW(wszParameters, sei_tmp.lpParameters);
     }
     else
-       *wszParameters = '\0';
+        *wszParameters = L'\0';
 
     wszDir = dirBuffer;
     if (sei_tmp.lpDirectory)
@@ -1535,10 +1795,10 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
             wszDir = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
             dirLen = len;
         }
-       strcpyW(wszDir, sei_tmp.lpDirectory);
+        strcpyW(wszDir, sei_tmp.lpDirectory);
     }
     else
-       *wszDir = '\0';
+        *wszDir = L'\0';
 
     /* adjust string pointers to point to the new buffers */
     sei_tmp.lpFile = wszApplicationName;
@@ -1553,32 +1813,52 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
     /* process the IDList */
     if (sei_tmp.fMask & SEE_MASK_IDLIST)
     {
-       IShellExecuteHookW* pSEH;
-
-       HRESULT hr = SHBindToParent((LPCITEMIDLIST)sei_tmp.lpIDList, IID_IShellExecuteHookW, (LPVOID*)&pSEH, NULL);
+        CComPtr<IShellExecuteHookW> pSEH;
 
-       if (SUCCEEDED(hr))
-       {
-           hr = pSEH->Execute(&sei_tmp);
+        HRESULT hr = SHBindToParent((LPCITEMIDLIST)sei_tmp.lpIDList, IID_PPV_ARG(IShellExecuteHookW, &pSEH), NULL);
 
-           pSEH->Release();
+        if (SUCCEEDED(hr))
+        {
+            hr = pSEH->Execute(&sei_tmp);
 
-           if (hr == S_OK) {
+            if (hr == S_OK)
+            {
                 HeapFree(GetProcessHeap(), 0, wszApplicationName);
                 if (wszParameters != parametersBuffer)
                     HeapFree(GetProcessHeap(), 0, wszParameters);
                 if (wszDir != dirBuffer)
                     HeapFree(GetProcessHeap(), 0, wszDir);
-               return TRUE;
+                return TRUE;
             }
-       }
+        }
 
         SHGetPathFromIDListW((LPCITEMIDLIST)sei_tmp.lpIDList, wszApplicationName);
         appKnownSingular = TRUE;
         TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName));
     }
 
-    if ( ERROR_SUCCESS == ShellExecute_FromContextMenu( &sei_tmp ) )
+    if (sei_tmp.fMask & SEE_MASK_DOENVSUBST)
+    {
+        WCHAR *tmp;
+
+        tmp = expand_environment(sei_tmp.lpFile);
+        if (!tmp)
+        {
+            return FALSE;
+        }
+        HeapFree(GetProcessHeap(), 0, wszApplicationName);
+        sei_tmp.lpFile = wszApplicationName = tmp;
+
+        tmp = expand_environment(sei_tmp.lpDirectory);
+        if (!tmp)
+        {
+            return FALSE;
+        }
+        if (wszDir != dirBuffer) HeapFree(GetProcessHeap(), 0, wszDir);
+        sei_tmp.lpDirectory = wszDir = tmp;
+    }
+
+    if (ERROR_SUCCESS == ShellExecute_FromContextMenu(&sei_tmp))
     {
         sei->hInstApp = (HINSTANCE) 33;
         HeapFree(GetProcessHeap(), 0, wszApplicationName);
@@ -1591,8 +1871,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
 
     if (sei_tmp.fMask & SEE_MASK_CLASSALL)
     {
-        retval = SHELL_execute_class( wszApplicationName, &sei_tmp, sei,
-                                      execfunc );
+        retval = SHELL_execute_class(wszApplicationName, &sei_tmp, sei, execfunc);
         if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
         {
             OPENASINFO Info;
@@ -1605,7 +1884,8 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
             Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
 
             //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
-               do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
+            DBG_UNREFERENCED_LOCAL_VARIABLE(Info);
+            do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
         }
         HeapFree(GetProcessHeap(), 0, wszApplicationName);
         if (wszParameters != parametersBuffer)
@@ -1619,41 +1899,43 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
     if (sei_tmp.fMask & SEE_MASK_IDLIST)
     {
         appKnownSingular = SHELL_translate_idlist( &sei_tmp, wszParameters,
-                                                   parametersLen,
-                                                   wszApplicationName,
-                                                   dwApplicationNameLen );
+                           parametersLen,
+                           wszApplicationName,
+                           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 = (LPWSTR)HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
+        DWORD size;
+
+        size = MAX_PATH;
+        buf = static_cast<LPWSTR>(HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)));
+        if (!buf || FAILED(PathCreateFromUrlW(sei_tmp.lpFile, buf, &size, 0)))
+        {
+            HeapFree(GetProcessHeap(), 0, buf);
+            return SE_ERR_OOM;
+        }
 
-        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.lpParameters)
+    else /* or expand environment strings (not both!) */
     {
-        len = ExpandEnvironmentStringsW(sei_tmp.lpParameters, NULL, 0);
+        len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0);
         if (len > 0)
         {
             LPWSTR buf;
-            len++;
-            buf = (LPWSTR)HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
-            ExpandEnvironmentStringsW(sei_tmp.lpParameters, buf, len);
-            if (wszParameters != parametersBuffer)
-                HeapFree(GetProcessHeap(), 0, wszParameters);
-            wszParameters = buf;
-            parametersLen = len;
-            sei_tmp.lpParameters = wszParameters;
+            buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+
+            ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len + 1);
+            HeapFree(GetProcessHeap(), 0, wszApplicationName);
+            wszApplicationName = buf;
+            /* appKnownSingular unmodified */
+
+            sei_tmp.lpFile = wszApplicationName;
         }
     }
 
@@ -1664,7 +1946,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
         {
             LPWSTR buf;
             len++;
-            buf = (LPWSTR)HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
+            buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
             ExpandEnvironmentStringsW(sei_tmp.lpDirectory, buf, len);
             if (wszDir != dirBuffer)
                 HeapFree(GetProcessHeap(), 0, wszDir);
@@ -1674,74 +1956,79 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
     }
 
     /* Else, try to execute the filename */
-    TRACE("execute:%s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir));
+    TRACE("execute: %s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir));
 
     /* separate out command line arguments from executable file name */
-    if (!*sei_tmp.lpParameters && !appKnownSingular) {
-       /* If the executable path is quoted, handle the rest of the command line as parameters. */
-       if (sei_tmp.lpFile[0] == '"') {
-           LPWSTR src = wszApplicationName/*sei_tmp.lpFile*/ + 1;
-           LPWSTR dst = wfileName;
-           LPWSTR end;
-
-           /* copy the unquoted executable path to 'wfileName' */
-           while(*src && *src!='"')
-               *dst++ = *src++;
-
-           *dst = '\0';
-
-           if (*src == '"') {
-               end = ++src;
-
-               while(isspace(*src))
-                   ++src;
-           } else
-               end = src;
-
-           /* copy the parameter string to 'wszParameters' */
-           strcpyW(wszParameters, src);
-
-           /* terminate previous command string after the quote character */
-           *end = '\0';
-       }
-       else
-       {
-           /* If the executable name is not quoted, we have to use this search loop here,
-              that in CreateProcess() is not sufficient because it does not handle shell links. */
-           WCHAR buffer[MAX_PATH], xlpFile[MAX_PATH];
-           LPWSTR space, s;
-
-           LPWSTR beg = wszApplicationName/*sei_tmp.lpFile*/;
-           for(s=beg; (space= const_cast<LPWSTR>(strchrW(s, ' '))); s=space+1) {
-               int idx = space-sei_tmp.lpFile;
-               memcpy(buffer, sei_tmp.lpFile, idx * sizeof(WCHAR));
-               buffer[idx] = '\0';
-
-               /*FIXME This finds directory paths if the targeted file name contains spaces. */
-               if (SearchPathW(*sei_tmp.lpDirectory? sei_tmp.lpDirectory: NULL, buffer, wszExe, sizeof(xlpFile)/sizeof(xlpFile[0]), xlpFile, NULL))
-               {
-                   /* separate out command from parameter string */
-                   LPCWSTR p = space + 1;
-
-                   while(isspaceW(*p))
-                       ++p;
-
-                   strcpyW(wszParameters, p);
-                   *space = '\0';
-
-                   break;
-               }
-           }
-
-           lstrcpynW(wfileName, sei_tmp.lpFile,sizeof(wfileName)/sizeof(WCHAR));
-       }
-    } else
-       lstrcpynW(wfileName, sei_tmp.lpFile,sizeof(wfileName)/sizeof(WCHAR));
-
-    lpFile = wfileName;
+    if (!*sei_tmp.lpParameters && !appKnownSingular)
+    {
+        /* If the executable path is quoted, handle the rest of the command line as parameters. */
+        if (sei_tmp.lpFile[0] == L'"')
+        {
+            LPWSTR src = wszApplicationName/*sei_tmp.lpFile*/ + 1;
+            LPWSTR dst = wfileName;
+            LPWSTR end;
+
+            /* copy the unquoted executable path to 'wfileName' */
+            while(*src && *src != L'"')
+                *dst++ = *src++;
+
+            *dst = L'\0';
+
+            if (*src == L'"')
+            {
+                end = ++src;
+
+                while(isspaceW(*src))
+                    ++src;
+            }
+            else
+                end = src;
+
+            /* copy the parameter string to 'wszParameters' */
+            strcpyW(wszParameters, src);
+
+            /* terminate previous command string after the quote character */
+            *end = L'\0';
+            lpFile = wfileName;
+        }
+        else
+        {
+            /* If the executable name is not quoted, we have to use this search loop here,
+               that in CreateProcess() is not sufficient because it does not handle shell links. */
+            WCHAR buffer[MAX_PATH], xlpFile[MAX_PATH];
+            LPWSTR space, s;
+
+            LPWSTR beg = wszApplicationName/*sei_tmp.lpFile*/;
+            for(s = beg; (space = const_cast<LPWSTR>(strchrW(s, L' '))); s = space + 1)
+            {
+                int idx = space - sei_tmp.lpFile;
+                memcpy(buffer, sei_tmp.lpFile, idx * sizeof(WCHAR));
+                buffer[idx] = '\0';
+
+                /*FIXME This finds directory paths if the targeted file name contains spaces. */
+                if (SearchPathW(*sei_tmp.lpDirectory ? sei_tmp.lpDirectory : NULL, buffer, wszExe, sizeof(xlpFile) / sizeof(xlpFile[0]), xlpFile, NULL))
+                {
+                    /* separate out command from parameter string */
+                    LPCWSTR p = space + 1;
+
+                    while(isspaceW(*p))
+                        ++p;
+
+                    strcpyW(wszParameters, p);
+                    *space = L'\0';
+
+                    break;
+                }
+            }
+
+            lpFile = sei_tmp.lpFile;
+        }
+    }
+    else
+        lpFile = sei_tmp.lpFile;
 
     wcmd = wcmdBuffer;
-    len = lstrlenW(wszApplicationName) + 1;
+    len = lstrlenW(wszApplicationName) + 3;
     if (sei_tmp.lpParameters[0])
         len += 1 + lstrlenW(wszParameters);
     if (len > wcmdLen)
@@ -1749,14 +2036,16 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
         wcmd = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
         wcmdLen = len;
     }
-    strcpyW(wcmd, wszApplicationName);
-    if (sei_tmp.lpParameters[0]) {
-        strcatW(wcmd, wSpace);
+    swprintf(wcmd, L"\"%s\"", wszApplicationName);
+    if (sei_tmp.lpParameters[0])
+    {
+        strcatW(wcmd, L" ");
         strcatW(wcmd, wszParameters);
     }
 
     retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei);
-    if (retval > 32) {
+    if (retval > 32)
+    {
         HeapFree(GetProcessHeap(), 0, wszApplicationName);
         if (wszParameters != parametersBuffer)
             HeapFree(GetProcessHeap(), 0, wszParameters);
@@ -1768,53 +2057,49 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
     }
 
     /* Else, try to find the executable */
-    wcmd[0] = '\0';
-    retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, lpstrProtocol, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
+    wcmd[0] = L'\0';
+    retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, wszKeyname, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
     if (retval > 32)  /* Found */
     {
-        retval = SHELL_quote_and_execute( wcmd, wszParameters, lpstrProtocol,
-                                          wszApplicationName, env, &sei_tmp,
-                                          sei, execfunc );
-        HeapFree( GetProcessHeap(), 0, env );
+        retval = SHELL_quote_and_execute(wcmd, wszParameters, wszKeyname,
+                                         wszApplicationName, env, &sei_tmp,
+                                         sei, execfunc);
+        HeapFree(GetProcessHeap(), 0, env);
     }
     else if (PathIsDirectoryW(lpFile))
     {
-        static const WCHAR wExplorer[] = {'e','x','p','l','o','r','e','r',0};
-        static const WCHAR wQuote[] = {'"',0};
         WCHAR wExec[MAX_PATH];
-        WCHAR * lpQuotedFile = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * (strlenW(lpFile) + 3) );
+        WCHAR * lpQuotedFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (strlenW(lpFile) + 3));
 
         if (lpQuotedFile)
         {
-            retval = SHELL_FindExecutable( sei_tmp.lpDirectory, wExplorer,
-                                           wszOpen, wExec, MAX_PATH,
-                                           NULL, &env, NULL, NULL );
+            retval = SHELL_FindExecutable(sei_tmp.lpDirectory, L"explorer",
+                                          wszOpen, wExec, MAX_PATH,
+                                          NULL, &env, NULL, NULL);
             if (retval > 32)
             {
-                strcpyW(lpQuotedFile, wQuote);
-                strcatW(lpQuotedFile, lpFile);
-                strcatW(lpQuotedFile, wQuote);
-                retval = SHELL_quote_and_execute( wExec, lpQuotedFile,
-                                                  lpstrProtocol,
-                                                  wszApplicationName, env,
-                                                  &sei_tmp, sei, execfunc );
-                HeapFree( GetProcessHeap(), 0, env );
+                swprintf(lpQuotedFile, L"\"%s\"", lpFile);
+                retval = SHELL_quote_and_execute(wExec, lpQuotedFile,
+                                                 wszKeyname,
+                                                 wszApplicationName, env,
+                                                 &sei_tmp, sei, execfunc);
+                HeapFree(GetProcessHeap(), 0, env);
             }
-            HeapFree( GetProcessHeap(), 0, lpQuotedFile );
+            HeapFree(GetProcessHeap(), 0, lpQuotedFile);
         }
         else
             retval = 0; /* Out of memory */
     }
     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))
+    else if (!strncmpiW(lpFile, L"www", 3))
     {
-        /* if so, append lpFile http:// and call ShellExecute */
+        /* if so, prefix lpFile with http:// and call ShellExecute */
         WCHAR lpstrTmpFile[256];
-        strcpyW(lpstrTmpFile, wHttp);
+        strcpyW(lpstrTmpFile, L"http://");
         strcatW(lpstrTmpFile, lpFile);
         retval = (UINT_PTR)ShellExecuteW(sei_tmp.hwnd, sei_tmp.lpVerb, lpstrTmpFile, NULL, NULL, 0);
     }
@@ -1833,7 +2118,8 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
         Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
 
         //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
-            do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
+        DBG_UNREFERENCED_LOCAL_VARIABLE(Info);
+        do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
     }
 
     HeapFree(GetProcessHeap(), 0, wszApplicationName);
@@ -1850,21 +2136,21 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
 }
 
 /*************************************************************************
- * ShellExecuteA                       [SHELL32.290]
+ * ShellExecuteA            [SHELL32.290]
  */
-HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpOperation,LPCSTR lpFile,
-                               LPCSTR lpParameters,LPCSTR lpDirectory, INT iShowCmd)
+HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile,
+                               LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
 {
     SHELLEXECUTEINFOA sei;
 
     TRACE("%p,%s,%s,%s,%s,%d\n",
-          hWnd, debugstr_a(lpOperation), debugstr_a(lpFile),
+          hWnd, debugstr_a(lpVerb), debugstr_a(lpFile),
           debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd);
 
     sei.cbSize = sizeof(sei);
     sei.fMask = SEE_MASK_FLAG_NO_UI;
     sei.hwnd = hWnd;
-    sei.lpVerb = lpOperation;
+    sei.lpVerb = lpVerb;
     sei.lpFile = lpFile;
     sei.lpParameters = lpParameters;
     sei.lpDirectory = lpDirectory;
@@ -1875,15 +2161,18 @@ HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpOperation,LPCSTR lpFile,
     sei.dwHotKey = 0;
     sei.hProcess = 0;
 
-    ShellExecuteExA (&sei);
+    ShellExecuteExA(&sei);
     return sei.hInstApp;
 }
 
 /*************************************************************************
- * ShellExecuteExA                             [SHELL32.292]
+ * ShellExecuteExA                [SHELL32.292]
  *
  */
-BOOL WINAPI ShellExecuteExA (LPSHELLEXECUTEINFOA sei)
+BOOL
+WINAPI
+DECLSPEC_HOTPATCH
+ShellExecuteExA(LPSHELLEXECUTEINFOA sei)
 {
     SHELLEXECUTEINFOW seiW;
     BOOL ret;
@@ -1894,7 +2183,7 @@ BOOL WINAPI ShellExecuteExA (LPSHELLEXECUTEINFOA sei)
     memcpy(&seiW, sei, sizeof(SHELLEXECUTEINFOW));
 
     if (sei->lpVerb)
-       seiW.lpVerb = __SHCloneStrAtoW(&wVerb, sei->lpVerb);
+        seiW.lpVerb = __SHCloneStrAtoW(&wVerb, sei->lpVerb);
 
     if (sei->lpFile)
         seiW.lpFile = __SHCloneStrAtoW(&wFile, sei->lpFile);
@@ -1910,7 +2199,7 @@ BOOL WINAPI ShellExecuteExA (LPSHELLEXECUTEINFOA sei)
     else
         seiW.lpClass = NULL;
 
-    ret = SHELL_execute( &seiW, SHELL_ExecuteW );
+    ret = SHELL_execute(&seiW, SHELL_ExecuteW);
 
     sei->hInstApp = seiW.hInstApp;
 
@@ -1927,21 +2216,24 @@ BOOL WINAPI ShellExecuteExA (LPSHELLEXECUTEINFOA sei)
 }
 
 /*************************************************************************
- * ShellExecuteExW                             [SHELL32.293]
+ * ShellExecuteExW                [SHELL32.293]
  *
  */
-BOOL WINAPI ShellExecuteExW (LPSHELLEXECUTEINFOW sei)
+BOOL
+WINAPI
+DECLSPEC_HOTPATCH
+ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
 {
-    return SHELL_execute( sei, SHELL_ExecuteW );
+    return SHELL_execute(sei, SHELL_ExecuteW);
 }
 
 /*************************************************************************
- * ShellExecuteW                       [SHELL32.294]
+ * ShellExecuteW            [SHELL32.294]
  * from shellapi.h
- * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpOperation,
+ * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpVerb,
  * LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd);
  */
-HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile,
+HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile,
                                LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
 {
     SHELLEXECUTEINFOW sei;
@@ -1950,7 +2242,7 @@ HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile,
     sei.cbSize = sizeof(sei);
     sei.fMask = SEE_MASK_FLAG_NO_UI;
     sei.hwnd = hwnd;
-    sei.lpVerb = lpOperation;
+    sei.lpVerb = lpVerb;
     sei.lpFile = lpFile;
     sei.lpParameters = lpParameters;
     sei.lpDirectory = lpDirectory;
@@ -1961,23 +2253,23 @@ HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile,
     sei.dwHotKey = 0;
     sei.hProcess = 0;
 
-    SHELL_execute( &sei, SHELL_ExecuteW );
+    SHELL_execute(&sei, SHELL_ExecuteW);
     return sei.hInstApp;
 }
 
 /*************************************************************************
- * WOWShellExecute                     [SHELL32.@]
+ * WOWShellExecute            [SHELL32.@]
  *
  * FIXME: the callback function most likely doesn't work the same way on Windows.
  */
-EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpOperation,LPCSTR lpFile,
-                                 LPCSTR lpParameters,LPCSTR lpDirectory, INT iShowCmd, void *callback)
+EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile,
+        LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback)
 {
     SHELLEXECUTEINFOW seiW;
     WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL;
     HANDLE hProcess = 0;
 
-    seiW.lpVerb = lpOperation ? __SHCloneStrAtoW(&wVerb, lpOperation) : NULL;
+    seiW.lpVerb = lpVerb ? __SHCloneStrAtoW(&wVerb, lpVerb) : NULL;
     seiW.lpFile = lpFile ? __SHCloneStrAtoW(&wFile, lpFile) : NULL;
     seiW.lpParameters = lpParameters ? __SHCloneStrAtoW(&wParameters, lpParameters) : NULL;
     seiW.lpDirectory = lpDirectory ? __SHCloneStrAtoW(&wDirectory, lpDirectory) : NULL;
@@ -1992,7 +2284,7 @@ EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpOperation,LPCSTR l
     seiW.dwHotKey = 0;
     seiW.hProcess = hProcess;
 
-    SHELL_execute( &seiW, (SHELL_ExecuteW32)callback );
+    SHELL_execute(&seiW, (SHELL_ExecuteW32)callback);
 
     SHFree(wVerb);
     SHFree(wFile);
@@ -2002,17 +2294,211 @@ EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpOperation,LPCSTR l
 }
 
 /*************************************************************************
- * OpenAs_RunDLLA          [SHELL32.@]
+ * OpenAs_RunDLLW          [SHELL32.@]
  */
-EXTERN_C void WINAPI OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int cmdshow)
+EXTERN_C void WINAPI
+OpenAs_RunDLLW(HWND hwnd, HINSTANCE hinst, LPCWSTR cmdline, int cmdshow)
 {
-    FIXME("%p, %p, %s, %d\n", hwnd, hinst, debugstr_a(cmdline), cmdshow);
+    OPENASINFO info;
+    TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_w(cmdline), cmdshow);
+
+    ZeroMemory(&info, sizeof(info));
+    info.pcszFile = cmdline;
+    info.pcszClass = NULL;
+    info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC;
+
+    SHOpenWithDialog(hwnd, &info);
 }
 
 /*************************************************************************
- * OpenAs_RunDLLW          [SHELL32.@]
+ * OpenAs_RunDLLA          [SHELL32.@]
  */
-EXTERN_C void WINAPI OpenAs_RunDLLW(HWND hwnd, HINSTANCE hinst, LPCWSTR cmdline, int cmdshow)
+EXTERN_C void WINAPI
+OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int cmdshow)
+{
+    LPWSTR pszCmdLineW = NULL;
+    TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_a(cmdline), cmdshow);
+
+    if (cmdline)
+        __SHCloneStrAtoW(&pszCmdLineW, cmdline);
+    OpenAs_RunDLLW(hwnd, hinst, pszCmdLineW, cmdshow);
+    SHFree(pszCmdLineW);
+}
+
+/*************************************************************************/
+
+static LPCWSTR
+SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0)
 {
-    FIXME("%p, %p, %s, %d\n", hwnd, hinst, debugstr_w(cmdline), cmdshow);
+    LPCWSTR pch;
+    size_t ich = 0;
+    if (*psz == L'"')
+    {
+        // 1st argument is quoted. the string in quotes is quoted 1st argument.
+        // [pch] --> [pszArg0+ich]
+        for (pch = psz + 1; *pch && ich + 1 < cchArg0; ++ich, ++pch)
+        {
+            if (*pch == L'"' && pch[1] == L'"')
+            {
+                // doubled double quotations found!
+                pszArg0[ich] = L'"';
+            }
+            else if (*pch == L'"')
+            {
+                // single double quotation found!
+                ++pch;
+                break;
+            }
+            else
+            {
+                // otherwise
+                pszArg0[ich] = *pch;
+            }
+        }
+    }
+    else
+    {
+        // 1st argument is unquoted. non-space sequence is 1st argument.
+        // [pch] --> [pszArg0+ich]
+        for (pch = psz; *pch && !iswspace(*pch) && ich + 1 < cchArg0; ++ich, ++pch)
+        {
+            pszArg0[ich] = *pch;
+        }
+    }
+    pszArg0[ich] = 0;
+
+    // skip space
+    while (iswspace(*pch))
+        ++pch;
+
+    return pch;
+}
+
+HRESULT WINAPI ShellExecCmdLine(
+    HWND hwnd,
+    LPCWSTR pwszCommand,
+    LPCWSTR pwszStartDir,
+    int nShow,
+    LPVOID pUnused,
+    DWORD dwSeclFlags)
+{
+    SHELLEXECUTEINFOW info;
+    DWORD dwSize, dwError, dwType, dwFlags = SEE_MASK_DOENVSUBST | SEE_MASK_NOASYNC;
+    LPCWSTR pszVerb = NULL;
+    WCHAR szFile[MAX_PATH], szFile2[MAX_PATH];
+    HRESULT hr;
+    LPCWSTR pchParams;
+    LPWSTR lpCommand = NULL;
+
+    if (pwszCommand == NULL)
+        RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE,
+                       1, (ULONG_PTR*)pwszCommand);
+
+    __SHCloneStrW(&lpCommand, pwszCommand);
+    StrTrimW(lpCommand, L" \t");
+
+    if (dwSeclFlags & SECL_NO_UI)
+        dwFlags |= SEE_MASK_FLAG_NO_UI;
+    if (dwSeclFlags & SECL_LOG_USAGE)
+        dwFlags |= SEE_MASK_FLAG_LOG_USAGE;
+    if (dwSeclFlags & SECL_USE_IDLIST)
+        dwFlags |= SEE_MASK_INVOKEIDLIST;
+
+    if (dwSeclFlags & SECL_RUNAS)
+    {
+        dwSize = 0;
+        hr = AssocQueryStringW(0, ASSOCSTR_COMMAND, lpCommand, L"RunAs", NULL, &dwSize);
+        if (SUCCEEDED(hr) && dwSize != 0)
+        {
+            pszVerb = L"runas";
+        }
+    }
+
+    if (UrlIsFileUrlW(lpCommand))
+    {
+        StringCchCopyW(szFile, _countof(szFile), lpCommand);
+        pchParams = NULL;
+    }
+    else
+    {
+        pchParams = SplitParams(lpCommand, szFile, _countof(szFile));
+        if (SearchPathW(NULL, szFile, NULL, _countof(szFile2), szFile2, NULL) ||
+            SearchPathW(NULL, szFile, wszExe, _countof(szFile2), szFile2, NULL) ||
+            SearchPathW(NULL, szFile, wszCom, _countof(szFile2), szFile2, NULL) ||
+            SearchPathW(pwszStartDir, szFile, NULL, _countof(szFile2), szFile2, NULL) ||
+            SearchPathW(pwszStartDir, szFile, wszExe, _countof(szFile2), szFile2, NULL) ||
+            SearchPathW(pwszStartDir, szFile, wszCom, _countof(szFile2), szFile2, NULL))
+        {
+            StringCchCopyW(szFile, _countof(szFile), szFile2);
+            pchParams = NULL;
+        }
+        else if (SearchPathW(NULL, lpCommand, NULL, _countof(szFile2), szFile2, NULL) ||
+                 SearchPathW(NULL, lpCommand, wszExe, _countof(szFile2), szFile2, NULL) ||
+                 SearchPathW(NULL, lpCommand, wszCom, _countof(szFile2), szFile2, NULL) ||
+                 SearchPathW(pwszStartDir, lpCommand, NULL, _countof(szFile2), szFile2, NULL) ||
+                 SearchPathW(pwszStartDir, lpCommand, wszExe, _countof(szFile2), szFile2, NULL) ||
+                 SearchPathW(pwszStartDir, lpCommand, wszCom, _countof(szFile2), szFile2, NULL))
+        {
+            StringCchCopyW(szFile, _countof(szFile), szFile2);
+            pchParams = NULL;
+        }
+
+        if (!(dwSeclFlags & SECL_ALLOW_NONEXE))
+        {
+            if (!GetBinaryTypeW(szFile, &dwType))
+            {
+                SHFree(lpCommand);
+
+                if (!(dwSeclFlags & SECL_NO_UI))
+                {
+                    WCHAR szText[128 + MAX_PATH], szFormat[128];
+                    LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat));
+                    StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
+                    MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
+                }
+                return CO_E_APPNOTFOUND;
+            }
+        }
+        else
+        {
+            if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
+            {
+                SHFree(lpCommand);
+
+                if (!(dwSeclFlags & SECL_NO_UI))
+                {
+                    WCHAR szText[128 + MAX_PATH], szFormat[128];
+                    LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat));
+                    StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
+                    MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
+                }
+                return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+            }
+        }
+    }
+
+    ZeroMemory(&info, sizeof(info));
+    info.cbSize = sizeof(info);
+    info.fMask = dwFlags;
+    info.hwnd = hwnd;
+    info.lpVerb = pszVerb;
+    info.lpFile = szFile;
+    info.lpParameters = (pchParams && *pchParams) ? pchParams : NULL;
+    info.lpDirectory = pwszStartDir;
+    info.nShow = nShow;
+    if (ShellExecuteExW(&info))
+    {
+        if (info.lpIDList)
+            CoTaskMemFree(info.lpIDList);
+
+        SHFree(lpCommand);
+
+        return S_OK;
+    }
+
+    dwError = GetLastError();
+
+    SHFree(lpCommand);
+
+    return HRESULT_FROM_WIN32(dwError);
 }