ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

shlexec.cpp
Go to the documentation of this file.
00001 /*
00002  *          Shell Library Functions
00003  *
00004  * Copyright 1998 Marcus Meissner
00005  * Copyright 2002 Eric Pouech
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include <precomp.h>
00023 #include <windef.h>
00024 
00025 WINE_DEFAULT_DEBUG_CHANNEL(exec);
00026 
00027 static const WCHAR wszOpen[] = L"open";
00028 static const WCHAR wszExe[] = L".exe";
00029 
00030 #define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)
00031 
00032 static void ParseNoTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
00033 {
00034     bool firstCharQuote = false;
00035     bool quotes_opened = false;
00036     bool backslash_encountered = false;
00037 
00038     for (int curArg = 0; curArg <= argNum && *args; ++curArg)
00039     {
00040         firstCharQuote = false;
00041         if (*args == '"')
00042         {
00043             quotes_opened = true;
00044             firstCharQuote = true;
00045             args++;
00046         }
00047 
00048         while(*args)
00049         {
00050             if (*args == '\\')
00051             {
00052                 // if we found a backslash then flip the variable
00053                 backslash_encountered = !backslash_encountered;
00054             }
00055             else if (*args == '"')
00056             {
00057                 if (quotes_opened)
00058                 {
00059                     if (*(args + 1) != '"')
00060                     {
00061                         quotes_opened = false;
00062                         args++;
00063                         break;
00064                     }
00065                     else
00066                     {
00067                         args++;
00068                     }
00069                 }
00070                 else
00071                 {
00072                     quotes_opened = true;
00073                 }
00074 
00075                 backslash_encountered = false;
00076             }
00077             else
00078             {
00079                 backslash_encountered = false;
00080                 if (*args == ' ' && !firstCharQuote)
00081                     break;
00082             }
00083 
00084             if (curArg == argNum)
00085             {
00086                 used++;
00087                 if (used < len)
00088                     *res++ = *args;
00089             }
00090 
00091             args++;
00092         }
00093 
00094         while(*args == ' ')
00095             ++args;
00096     }
00097 }
00098 
00099 static void ParseTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
00100 {
00101     bool quotes_opened = false;
00102     bool backslash_encountered = false;
00103 
00104     for (int curArg = 0; curArg <= argNum && *args; ++curArg)
00105     {
00106         while(*args)
00107         {
00108             if (*args == '\\')
00109             {
00110                 // if we found a backslash then flip the variable
00111                 backslash_encountered = !backslash_encountered;
00112             }
00113             else if (*args == '"')
00114             {
00115                 if (quotes_opened)
00116                 {
00117                     if (*(args + 1) != '"')
00118                     {
00119                         quotes_opened = false;
00120                     }
00121                     else
00122                     {
00123                         args++;
00124                     }
00125                 }
00126                 else
00127                 {
00128                     quotes_opened = true;
00129                 }
00130 
00131                 backslash_encountered = false;
00132             }
00133             else
00134             {
00135                 backslash_encountered = false;
00136                 if (*args == ' ' && !quotes_opened && curArg != argNum)
00137                     break;
00138             }
00139 
00140             if (curArg == argNum)
00141             {
00142                 used++;
00143                 if (used < len)
00144                     *res++ = *args;
00145             }
00146 
00147             args++;
00148         }
00149     }
00150 }
00151 
00152 /***********************************************************************
00153  * SHELL_ArgifyW [Internal]
00154  *
00155  * this function is supposed to expand the escape sequences found in the registry
00156  * some diving reported that the following were used:
00157  * + %1, %2...  seem to report to parameter of index N in ShellExecute pmts
00158  * %1 file
00159  * %2 printer
00160  * %3 driver
00161  * %4 port
00162  * %I address of a global item ID (explorer switch /idlist)
00163  * %L seems to be %1 as long filename followed by the 8+3 variation
00164  * %S ???
00165  * %* all following parameters (see batfile)
00166  *
00167  * The way we parse the command line arguments was determined through extensive
00168  * testing and can be summed up by the following rules"
00169  *
00170  * - %2
00171  *     - if first letter is " break on first non literal " and include any white spaces
00172  *     - if first letter is NOT " break on first " or white space
00173  *     - if " is opened any pair of consecutive " results in ONE literal "
00174  *
00175  * - %~2
00176  *     - use rules from here http://www.autohotkey.net/~deleyd/parameters/parameters.htm
00177  */
00178 
00179 static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len)
00180 {
00181     WCHAR   xlpFile[1024];
00182     BOOL    done = FALSE;
00183     BOOL    found_p1 = FALSE;
00184     PWSTR   res = out;
00185     PCWSTR  cmd;
00186     DWORD   used = 0;
00187     bool    tildeEffect = false;
00188 
00189     TRACE("Before parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
00190           debugstr_w(lpFile), pidl, args);
00191 
00192     while (*fmt)
00193     {
00194         if (*fmt == '%')
00195         {
00196             switch (*++fmt)
00197             {
00198                 case '\0':
00199                 case '%':
00200                 {
00201                     used++;
00202                     if (used < len)
00203                         *res++ = '%';
00204                 };
00205                 break;
00206 
00207                 case '*':
00208                 {
00209                     if (args)
00210                     {
00211                         if (*fmt == '*')
00212                         {
00213                             used++;
00214                             while(*args)
00215                             {
00216                                 used++;
00217                                 if (used < len)
00218                                     *res++ = *args++;
00219                                 else
00220                                     args++;
00221                             }
00222                             used++;
00223                             break;
00224                         }
00225                     }
00226                 };
00227                 break;
00228 
00229                 case '~':
00230 
00231                 case '2':
00232                 case '3':
00233                 case '4':
00234                 case '5':
00235                 case '6':
00236                 case '7':
00237                 case '8':
00238                 case '9':
00239                     //case '0':
00240                 {
00241                     if (*fmt == '~')
00242                     {
00243                         fmt++;
00244                         tildeEffect = true;
00245                     }
00246 
00247                     if (args)
00248                     {
00249                         if (tildeEffect)
00250                         {
00251                             ParseTildeEffect(res, args, len, used, *fmt - '2');
00252                             tildeEffect = false;
00253                         }
00254                         else
00255                         {
00256                             ParseNoTildeEffect(res, args, len, used, *fmt - '2');
00257                         }
00258                     }
00259                 };
00260                 break;
00261 
00262                 case '1':
00263                     if (!done || (*fmt == '1'))
00264                     {
00265                         /*FIXME Is the call to SearchPathW() really needed? We already have separated out the parameter string in args. */
00266                         if (SearchPathW(NULL, lpFile, wszExe, sizeof(xlpFile) / sizeof(WCHAR), xlpFile, NULL))
00267                             cmd = xlpFile;
00268                         else
00269                             cmd = lpFile;
00270 
00271                         used += wcslen(cmd);
00272                         if (used < len)
00273                         {
00274                             wcscpy(res, cmd);
00275                             res += wcslen(cmd);
00276                         }
00277                     }
00278                     found_p1 = TRUE;
00279                     break;
00280 
00281                     /*
00282                      * IE uses this a lot for activating things such as windows media
00283                      * player. This is not verified to be fully correct but it appears
00284                      * to work just fine.
00285                      */
00286                 case 'l':
00287                 case 'L':
00288                     if (lpFile)
00289                     {
00290                         used += wcslen(lpFile);
00291                         if (used < len)
00292                         {
00293                             wcscpy(res, lpFile);
00294                             res += wcslen(lpFile);
00295                         }
00296                     }
00297                     found_p1 = TRUE;
00298                     break;
00299 
00300                 case 'i':
00301                 case 'I':
00302                     if (pidl)
00303                     {
00304                         DWORD chars = 0;
00305                         /* %p should not exceed 8, maybe 16 when looking forward to 64bit.
00306                             * allowing a buffer of 100 should more than exceed all needs */
00307                         WCHAR buf[100];
00308                         LPVOID  pv;
00309                         HGLOBAL hmem = SHAllocShared(pidl, ILGetSize(pidl), 0);
00310                         pv = SHLockShared(hmem, 0);
00311                         chars = swprintf(buf, L":%p", pv);
00312 
00313                         if (chars >= sizeof(buf) / sizeof(WCHAR))
00314                             ERR("pidl format buffer too small!\n");
00315 
00316                         used += chars;
00317 
00318                         if (used < len)
00319                         {
00320                             wcscpy(res, buf);
00321                             res += chars;
00322                         }
00323                         SHUnlockShared(pv);
00324                     }
00325                     found_p1 = TRUE;
00326                     break;
00327 
00328                 default:
00329                     /*
00330                      * Check if this is an env-variable here...
00331                      */
00332 
00333                     /* Make sure that we have at least one more %.*/
00334                     if (strchrW(fmt, '%'))
00335                     {
00336                         WCHAR   tmpBuffer[1024];
00337                         PWSTR   tmpB = tmpBuffer;
00338                         WCHAR   tmpEnvBuff[MAX_PATH];
00339                         DWORD   envRet;
00340 
00341                         while (*fmt != '%')
00342                             *tmpB++ = *fmt++;
00343                         *tmpB++ = 0;
00344 
00345                         TRACE("Checking %s to be an env-var\n", debugstr_w(tmpBuffer));
00346 
00347                         envRet = GetEnvironmentVariableW(tmpBuffer, tmpEnvBuff, MAX_PATH);
00348                         if (envRet == 0 || envRet > MAX_PATH)
00349                         {
00350                             used += wcslen(tmpBuffer);
00351                             if (used < len)
00352                             {
00353                                 wcscpy( res, tmpBuffer );
00354                                 res += wcslen(tmpBuffer);
00355                             }
00356                         }
00357                         else
00358                         {
00359                             used += wcslen(tmpEnvBuff);
00360                             if (used < len)
00361                             {
00362                                 wcscpy( res, tmpEnvBuff );
00363                                 res += wcslen(tmpEnvBuff);
00364                             }
00365                         }
00366                     }
00367                     done = TRUE;
00368                     break;
00369             }
00370             /* Don't skip past terminator (catch a single '%' at the end) */
00371             if (*fmt != '\0')
00372             {
00373                 fmt++;
00374             }
00375         }
00376         else
00377         {
00378             used ++;
00379             if (used < len)
00380                 *res++ = *fmt++;
00381             else
00382                 fmt++;
00383         }
00384     }
00385 
00386     *res = '\0';
00387     TRACE("used %i of %i space\n", used, len);
00388     if (out_len)
00389         *out_len = used;
00390 
00391     TRACE("After parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
00392           debugstr_w(lpFile), pidl, args);
00393 
00394     return found_p1;
00395 }
00396 
00397 static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR pszPath, UINT uOutSize)
00398 {
00399     STRRET strret;
00400     IShellFolder *desktop;
00401 
00402     HRESULT hr = SHGetDesktopFolder(&desktop);
00403 
00404     if (SUCCEEDED(hr))
00405     {
00406         hr = desktop->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret);
00407 
00408         if (SUCCEEDED(hr))
00409             StrRetToStrNW(pszPath, uOutSize, &strret, pidl);
00410 
00411         desktop->Release();
00412     }
00413 
00414     return hr;
00415 }
00416 
00417 /*************************************************************************
00418  *    SHELL_ExecuteW [Internal]
00419  *
00420  */
00421 static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
00422                                const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
00423 {
00424     STARTUPINFOW  startup;
00425     PROCESS_INFORMATION info;
00426     UINT_PTR retval = SE_ERR_NOASSOC;
00427     UINT gcdret = 0;
00428     WCHAR curdir[MAX_PATH];
00429     DWORD dwCreationFlags;
00430     const WCHAR *lpDirectory = NULL;
00431 
00432     TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory));
00433 
00434     /* make sure we don't fail the CreateProcess if the calling app passes in
00435      * a bad working directory */
00436     if (psei->lpDirectory && psei->lpDirectory[0])
00437     {
00438         DWORD attr = GetFileAttributesW(psei->lpDirectory);
00439         if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY)
00440             lpDirectory = psei->lpDirectory;
00441     }
00442 
00443     /* ShellExecute specifies the command from psei->lpDirectory
00444      * if present. Not from the current dir as CreateProcess does */
00445     if (lpDirectory)
00446         if ((gcdret = GetCurrentDirectoryW( MAX_PATH, curdir)))
00447             if (!SetCurrentDirectoryW( lpDirectory))
00448                 ERR("cannot set directory %s\n", debugstr_w(lpDirectory));
00449 
00450     ZeroMemory(&startup, sizeof(STARTUPINFOW));
00451     startup.cb = sizeof(STARTUPINFOW);
00452     startup.dwFlags = STARTF_USESHOWWINDOW;
00453     startup.wShowWindow = psei->nShow;
00454     dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
00455 
00456     if (psei->fMask & SEE_MASK_NO_CONSOLE)
00457         dwCreationFlags |= CREATE_NEW_CONSOLE;
00458 
00459     if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env,
00460                        lpDirectory, &startup, &info))
00461     {
00462         /* Give 30 seconds to the app to come up, if desired. Probably only needed
00463            when starting app immediately before making a DDE connection. */
00464         if (shWait)
00465             if (WaitForInputIdle(info.hProcess, 30000) == WAIT_FAILED)
00466                 WARN("WaitForInputIdle failed: Error %d\n", GetLastError() );
00467         retval = 33;
00468 
00469         if (psei->fMask & SEE_MASK_NOCLOSEPROCESS)
00470             psei_out->hProcess = info.hProcess;
00471         else
00472             CloseHandle( info.hProcess );
00473         CloseHandle( info.hThread );
00474     }
00475     else if ((retval = GetLastError()) >= 32)
00476     {
00477         WARN("CreateProcess returned error %ld\n", retval);
00478         retval = ERROR_BAD_FORMAT;
00479     }
00480 
00481     TRACE("returning %lu\n", retval);
00482 
00483     psei_out->hInstApp = (HINSTANCE)retval;
00484 
00485     if (gcdret)
00486         if (!SetCurrentDirectoryW(curdir))
00487             ERR("cannot return to directory %s\n", debugstr_w(curdir));
00488 
00489     return retval;
00490 }
00491 
00492 
00493 /***********************************************************************
00494  *           SHELL_BuildEnvW    [Internal]
00495  *
00496  * Build the environment for the new process, adding the specified
00497  * path to the PATH variable. Returned pointer must be freed by caller.
00498  */
00499 static LPWSTR SHELL_BuildEnvW( const WCHAR *path )
00500 {
00501     static const WCHAR wPath[] = L"PATH=";
00502     WCHAR *strings, *new_env;
00503     WCHAR *p, *p2;
00504     int total = wcslen(path) + 1;
00505     BOOL got_path = FALSE;
00506 
00507     if (!(strings = GetEnvironmentStringsW())) return NULL;
00508     p = strings;
00509     while (*p)
00510     {
00511         int len = wcslen(p) + 1;
00512         if (!_wcsnicmp( p, wPath, 5 )) got_path = TRUE;
00513         total += len;
00514         p += len;
00515     }
00516     if (!got_path) total += 5;  /* we need to create PATH */
00517     total++;  /* terminating null */
00518 
00519     if (!(new_env = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, total * sizeof(WCHAR))))
00520     {
00521         FreeEnvironmentStringsW(strings);
00522         return NULL;
00523     }
00524     p = strings;
00525     p2 = new_env;
00526     while (*p)
00527     {
00528         int len = wcslen(p) + 1;
00529         memcpy(p2, p, len * sizeof(WCHAR));
00530         if (!_wcsnicmp( p, wPath, 5 ))
00531         {
00532             p2[len - 1] = ';';
00533             wcscpy( p2 + len, path );
00534             p2 += wcslen(path) + 1;
00535         }
00536         p += len;
00537         p2 += len;
00538     }
00539     if (!got_path)
00540     {
00541         wcscpy(p2, wPath);
00542         wcscat(p2, path);
00543         p2 += wcslen(p2) + 1;
00544     }
00545     *p2 = 0;
00546     FreeEnvironmentStringsW(strings);
00547     return new_env;
00548 }
00549 
00550 
00551 /***********************************************************************
00552  *           SHELL_TryAppPathW    [Internal]
00553  *
00554  * Helper function for SHELL_FindExecutable
00555  * @param lpResult - pointer to a buffer of size MAX_PATH
00556  * On entry: szName is a filename (probably without path separators).
00557  * On exit: if szName found in "App Path", place full path in lpResult, and return true
00558  */
00559 static BOOL SHELL_TryAppPathW( LPCWSTR szName, LPWSTR lpResult, WCHAR **env)
00560 {
00561     HKEY hkApp = 0;
00562     WCHAR buffer[1024];
00563     LONG len;
00564     LONG res;
00565     BOOL found = FALSE;
00566 
00567     if (env) *env = NULL;
00568     wcscpy(buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
00569     wcscat(buffer, szName);
00570     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp);
00571     if (res) goto end;
00572 
00573     len = MAX_PATH * sizeof(WCHAR);
00574     res = RegQueryValueW(hkApp, NULL, lpResult, &len);
00575     if (res) goto end;
00576     found = TRUE;
00577 
00578     if (env)
00579     {
00580         DWORD count = sizeof(buffer);
00581         if (!RegQueryValueExW(hkApp, L"Path", NULL, NULL, (LPBYTE)buffer, &count) && buffer[0])
00582             *env = SHELL_BuildEnvW(buffer);
00583     }
00584 
00585 end:
00586     if (hkApp) RegCloseKey(hkApp);
00587     return found;
00588 }
00589 
00590 static UINT SHELL_FindExecutableByOperation(LPCWSTR lpOperation, LPWSTR key, LPWSTR filetype, LPWSTR command, LONG commandlen)
00591 {
00592     static const WCHAR wCommand[] = L"\\command";
00593     HKEY hkeyClass;
00594     WCHAR verb[MAX_PATH];
00595 
00596     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, filetype, 0, 0x02000000, &hkeyClass))
00597         return SE_ERR_NOASSOC;
00598     if (!HCR_GetDefaultVerbW(hkeyClass, lpOperation, verb, sizeof(verb) / sizeof(verb[0])))
00599         return SE_ERR_NOASSOC;
00600     RegCloseKey(hkeyClass);
00601 
00602     /* Looking for ...buffer\shell<verb>\command */
00603     wcscat(filetype, L"\\shell\\");
00604     wcscat(filetype, verb);
00605     wcscat(filetype, wCommand);
00606 
00607     if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, command,
00608                        &commandlen) == ERROR_SUCCESS)
00609     {
00610         commandlen /= sizeof(WCHAR);
00611         if (key) wcscpy(key, filetype);
00612 #if 0
00613         LPWSTR tmp;
00614         WCHAR param[256];
00615         LONG paramlen = sizeof(param);
00616         static const WCHAR wSpace[] = {' ', 0};
00617 
00618         /* FIXME: it seems all Windows version don't behave the same here.
00619          * the doc states that this ddeexec information can be found after
00620          * the exec names.
00621          * on Win98, it doesn't appear, but I think it does on Win2k
00622          */
00623         /* Get the parameters needed by the application
00624            from the associated ddeexec key */
00625         tmp = strstrW(filetype, wCommand);
00626         tmp[0] = '\0';
00627         wcscat(filetype, wDdeexec);
00628         if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, param,
00629                            &paramlen) == ERROR_SUCCESS)
00630         {
00631             paramlen /= sizeof(WCHAR);
00632             wcscat(command, wSpace);
00633             wcscat(command, param);
00634             commandlen += paramlen;
00635         }
00636 #endif
00637 
00638         command[commandlen] = '\0';
00639 
00640         return 33; /* FIXME see SHELL_FindExecutable() */
00641     }
00642 
00643     return SE_ERR_NOASSOC;
00644 }
00645 
00646 /*************************************************************************
00647  *    SHELL_FindExecutable [Internal]
00648  *
00649  * Utility for code sharing between FindExecutable and ShellExecute
00650  * in:
00651  *      lpFile the name of a file
00652  *      lpOperation the operation on it (open)
00653  * out:
00654  *      lpResult a buffer, big enough :-(, to store the command to do the
00655  *              operation on the file
00656  *      key a buffer, big enough, to get the key name to do actually the
00657  *              command (it'll be used afterwards for more information
00658  *              on the operation)
00659  */
00660 static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation,
00661                                  LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args)
00662 {
00663     WCHAR *extension = NULL; /* pointer to file extension */
00664     WCHAR filetype[256];     /* registry name for this filetype */
00665     LONG  filetypelen = sizeof(filetype); /* length of above */
00666     WCHAR command[1024];     /* command from registry */
00667     WCHAR wBuffer[256];      /* Used to GetProfileString */
00668     UINT  retval = SE_ERR_NOASSOC;
00669     WCHAR *tok;              /* token pointer */
00670     WCHAR xlpFile[256];      /* result of SearchPath */
00671     DWORD attribs;           /* file attributes */
00672 
00673     TRACE("%s\n", debugstr_w(lpFile));
00674 
00675     if (!lpResult)
00676         return ERROR_INVALID_PARAMETER;
00677 
00678     xlpFile[0] = '\0';
00679     lpResult[0] = '\0'; /* Start off with an empty return string */
00680     if (key) *key = '\0';
00681 
00682     /* trap NULL parameters on entry */
00683     if (!lpFile)
00684     {
00685         WARN("(lpFile=%s,lpResult=%s): NULL parameter\n",
00686              debugstr_w(lpFile), debugstr_w(lpResult));
00687         return ERROR_FILE_NOT_FOUND; /* File not found. Close enough, I guess. */
00688     }
00689 
00690     if (SHELL_TryAppPathW( lpFile, lpResult, env ))
00691     {
00692         TRACE("found %s via App Paths\n", debugstr_w(lpResult));
00693         return 33;
00694     }
00695 
00696     if (SearchPathW(lpPath, lpFile, wszExe, sizeof(xlpFile) / sizeof(WCHAR), xlpFile, NULL))
00697     {
00698         TRACE("SearchPathW returned non-zero\n");
00699         lpFile = xlpFile;
00700         /* Hey, isn't this value ignored?  Why make this call?  Shouldn't we return here?  --dank*/
00701     }
00702 
00703     attribs = GetFileAttributesW(lpFile);
00704     if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY))
00705     {
00706         wcscpy(filetype, L"Folder");
00707         filetypelen = 6;    /* strlen("Folder") */
00708     }
00709     else
00710     {
00711         /* Did we get something? Anything? */
00712         if (xlpFile[0] == 0)
00713         {
00714             TRACE("Returning SE_ERR_FNF\n");
00715             return SE_ERR_FNF;
00716         }
00717         /* First thing we need is the file's extension */
00718         extension = wcsrchr(xlpFile, '.'); /* Assume last "." is the one; */
00719         /* File->Run in progman uses */
00720         /* .\FILE.EXE :( */
00721         TRACE("xlpFile=%s,extension=%s\n", debugstr_w(xlpFile), debugstr_w(extension));
00722 
00723         if (extension == NULL || extension[1] == 0)
00724         {
00725             WARN("Returning SE_ERR_NOASSOC\n");
00726             return SE_ERR_NOASSOC;
00727         }
00728 
00729         /* Three places to check: */
00730         /* 1. win.ini, [windows], programs (NB no leading '.') */
00731         /* 2. Registry, HKEY_CLASS_ROOT<filetype>\shell\open\command */
00732         /* 3. win.ini, [extensions], extension (NB no leading '.' */
00733         /* All I know of the order is that registry is checked before */
00734         /* extensions; however, it'd make sense to check the programs */
00735         /* section first, so that's what happens here. */
00736 
00737         /* See if it's a program - if GetProfileString fails, we skip this
00738          * section. Actually, if GetProfileString fails, we've probably
00739          * got a lot more to worry about than running a program... */
00740         if (GetProfileStringW(L"windows", L"programs", L"exe pif bat cmd com", wBuffer, sizeof(wBuffer) / sizeof(WCHAR)) > 0)
00741         {
00742             CharLowerW(wBuffer);
00743             tok = wBuffer;
00744             while (*tok)
00745             {
00746                 WCHAR *p = tok;
00747                 while (*p && *p != ' ' && *p != '\t') p++;
00748                 if (*p)
00749                 {
00750                     *p++ = 0;
00751                     while (*p == ' ' || *p == '\t') p++;
00752                 }
00753 
00754                 if (wcsicmp(tok, &extension[1]) == 0) /* have to skip the leading "." */
00755                 {
00756                     wcscpy(lpResult, xlpFile);
00757                     /* Need to perhaps check that the file has a path
00758                      * attached */
00759                     TRACE("found %s\n", debugstr_w(lpResult));
00760                     return 33;
00761                     /* Greater than 32 to indicate success */
00762                 }
00763                 tok = p;
00764             }
00765         }
00766 
00767         /* Check registry */
00768         if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, filetype,
00769                            &filetypelen) == ERROR_SUCCESS)
00770         {
00771             filetypelen /= sizeof(WCHAR);
00772             if (filetypelen == sizeof(filetype) / sizeof(WCHAR))
00773                 filetypelen--;
00774 
00775             filetype[filetypelen] = '\0';
00776             TRACE("File type: %s\n", debugstr_w(filetype));
00777         }
00778         else
00779         {
00780             *filetype = '\0';
00781             filetypelen = 0;
00782         }
00783     }
00784 
00785     if (*filetype)
00786     {
00787         /* pass the operation string to SHELL_FindExecutableByOperation() */
00788         filetype[filetypelen] = '\0';
00789         retval = SHELL_FindExecutableByOperation(lpOperation, key, filetype, command, sizeof(command));
00790 
00791         if (retval > 32)
00792         {
00793             DWORD finishedLen;
00794             SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen);
00795             if (finishedLen > resultLen)
00796                 ERR("Argify buffer not large enough.. truncated\n");
00797             /* Remove double quotation marks and command line arguments */
00798             if (*lpResult == '"')
00799             {
00800                 WCHAR *p = lpResult;
00801                 while (*(p + 1) != '"')
00802                 {
00803                     *p = *(p + 1);
00804                     p++;
00805                 }
00806                 *p = '\0';
00807             }
00808             else
00809             {
00810                 /* Truncate on first space */
00811                 WCHAR *p = lpResult;
00812                 while (*p != ' ' && *p != '\0')
00813                     p++;
00814                 *p = '\0';
00815             }
00816         }
00817     }
00818     else /* Check win.ini */
00819     {
00820         /* Toss the leading dot */
00821         extension++;
00822         if (GetProfileStringW(L"extensions", extension, L"", command, sizeof(command) / sizeof(WCHAR)) > 0)
00823         {
00824             if (wcslen(command) != 0)
00825             {
00826                 wcscpy(lpResult, command);
00827                 tok = wcschr(lpResult, '^'); /* should be ^.extension? */
00828                 if (tok != NULL)
00829                 {
00830                     tok[0] = '\0';
00831                     wcscat(lpResult, xlpFile); /* what if no dir in xlpFile? */
00832                     tok = wcschr(command, '^'); /* see above */
00833                     if ((tok != NULL) && (wcslen(tok) > 5))
00834                     {
00835                         wcscat(lpResult, &tok[5]);
00836                     }
00837                 }
00838                 retval = 33; /* FIXME - see above */
00839             }
00840         }
00841     }
00842 
00843     TRACE("returning %s\n", debugstr_w(lpResult));
00844     return retval;
00845 }
00846 
00847 /******************************************************************
00848  *        dde_cb
00849  *
00850  * callback for the DDE connection. not really useful
00851  */
00852 static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv,
00853                                 HSZ hsz1, HSZ hsz2, HDDEDATA hData,
00854                                 ULONG_PTR dwData1, ULONG_PTR dwData2)
00855 {
00856     TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
00857           uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
00858     return NULL;
00859 }
00860 
00861 /******************************************************************
00862  *        dde_connect
00863  *
00864  * ShellExecute helper. Used to do an operation with a DDE connection
00865  *
00866  * Handles both the direct connection (try #1), and if it fails,
00867  * launching an application and trying (#2) to connect to it
00868  *
00869  */
00870 static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec,
00871                             const WCHAR* lpFile, WCHAR *env,
00872                             LPCWSTR szCommandline, LPITEMIDLIST pidl, SHELL_ExecuteW32 execfunc,
00873                             const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
00874 {
00875     WCHAR       regkey[256];
00876     WCHAR *     endkey = regkey + wcslen(key);
00877     WCHAR       app[256], topic[256], ifexec[256], res[256];
00878     LONG        applen, topiclen, ifexeclen;
00879     WCHAR *     exec;
00880     DWORD       ddeInst = 0;
00881     DWORD       tid;
00882     DWORD       resultLen;
00883     HSZ         hszApp, hszTopic;
00884     HCONV       hConv;
00885     HDDEDATA    hDdeData;
00886     unsigned    ret = SE_ERR_NOASSOC;
00887     BOOL unicode = !(GetVersion() & 0x80000000);
00888 
00889     wcscpy(regkey, key);
00890     wcscpy(endkey, L"\\application");
00891     applen = sizeof(app);
00892     if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, app, &applen) != ERROR_SUCCESS)
00893     {
00894         WCHAR command[1024], fullpath[MAX_PATH];
00895         static const WCHAR wSo[] = L".so";
00896         DWORD sizeSo = sizeof(wSo) / sizeof(WCHAR);
00897         LPWSTR ptr = NULL;
00898         DWORD ret = 0;
00899 
00900         /* Get application command from start string and find filename of application */
00901         if (*start == '"')
00902         {
00903             wcscpy(command, start + 1);
00904             if ((ptr = wcschr(command, '"')))
00905                 * ptr = 0;
00906             ret = SearchPathW(NULL, command, wszExe, sizeof(fullpath) / sizeof(WCHAR), fullpath, &ptr);
00907         }
00908         else
00909         {
00910             LPWSTR p, space;
00911             for (p = (LPWSTR)start; (space = const_cast<LPWSTR>(strchrW(p, ' '))); p = space + 1)
00912             {
00913                 int idx = space - start;
00914                 memcpy(command, start, idx * sizeof(WCHAR));
00915                 command[idx] = '\0';
00916                 if ((ret = SearchPathW(NULL, command, wszExe, sizeof(fullpath) / sizeof(WCHAR), fullpath, &ptr)))
00917                     break;
00918             }
00919             if (!ret)
00920                 ret = SearchPathW(NULL, start, wszExe, sizeof(fullpath) / sizeof(WCHAR), fullpath, &ptr);
00921         }
00922 
00923         if (!ret)
00924         {
00925             ERR("Unable to find application path for command %s\n", debugstr_w(start));
00926             return ERROR_ACCESS_DENIED;
00927         }
00928         wcscpy(app, ptr);
00929 
00930         /* Remove extensions (including .so) */
00931         ptr = app + wcslen(app) - (sizeSo - 1);
00932         if (wcslen(app) >= sizeSo &&
00933                 !wcscmp(ptr, wSo))
00934             *ptr = 0;
00935 
00936         ptr = const_cast<LPWSTR>(strrchrW(app, '.'));
00937         assert(ptr);
00938         *ptr = 0;
00939     }
00940 
00941     wcscpy(endkey, L"\\topic");
00942     topiclen = sizeof(topic);
00943     if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, topic, &topiclen) != ERROR_SUCCESS)
00944     {
00945         wcscpy(topic, L"System");
00946     }
00947 
00948     if (unicode)
00949     {
00950         if (DdeInitializeW(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
00951             return 2;
00952     }
00953     else
00954     {
00955         if (DdeInitializeA(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
00956             return 2;
00957     }
00958 
00959     hszApp = DdeCreateStringHandleW(ddeInst, app, CP_WINUNICODE);
00960     hszTopic = DdeCreateStringHandleW(ddeInst, topic, CP_WINUNICODE);
00961 
00962     hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
00963     exec = ddeexec;
00964     if (!hConv)
00965     {
00966         TRACE("Launching %s\n", debugstr_w(start));
00967         ret = execfunc(start, env, TRUE, psei, psei_out);
00968         if (ret <= 32)
00969         {
00970             TRACE("Couldn't launch\n");
00971             goto error;
00972         }
00973         hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
00974         if (!hConv)
00975         {
00976             TRACE("Couldn't connect. ret=%d\n", ret);
00977             DdeUninitialize(ddeInst);
00978             SetLastError(ERROR_DDE_FAIL);
00979             return 30; /* whatever */
00980         }
00981         strcpyW(endkey, L"\\ifexec");
00982         ifexeclen = sizeof(ifexec);
00983         if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, ifexec, &ifexeclen) == ERROR_SUCCESS)
00984         {
00985             exec = ifexec;
00986         }
00987     }
00988 
00989     SHELL_ArgifyW(res, sizeof(res) / sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen);
00990     if (resultLen > sizeof(res) / sizeof(WCHAR))
00991         ERR("Argify buffer not large enough, truncated\n");
00992     TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res));
00993 
00994     /* It's documented in the KB 330337 that IE has a bug and returns
00995      * error DMLERR_NOTPROCESSED on XTYP_EXECUTE request.
00996      */
00997     if (unicode)
00998         hDdeData = DdeClientTransaction((LPBYTE)res, (strlenW(res) + 1) * sizeof(WCHAR), hConv, 0L, 0, XTYP_EXECUTE, 30000, &tid);
00999     else
01000     {
01001         DWORD lenA = WideCharToMultiByte(CP_ACP, 0, res, -1, NULL, 0, NULL, NULL);
01002         char *resA = (LPSTR)HeapAlloc(GetProcessHeap(), 0, lenA);
01003         WideCharToMultiByte(CP_ACP, 0, res, -1, resA, lenA, NULL, NULL);
01004         hDdeData = DdeClientTransaction( (LPBYTE)resA, lenA, hConv, 0L, 0,
01005                                          XTYP_EXECUTE, 10000, &tid );
01006         HeapFree(GetProcessHeap(), 0, resA);
01007     }
01008     if (hDdeData)
01009         DdeFreeDataHandle(hDdeData);
01010     else
01011         WARN("DdeClientTransaction failed with error %04x\n", DdeGetLastError(ddeInst));
01012     ret = 33;
01013 
01014     DdeDisconnect(hConv);
01015 
01016 error:
01017     DdeUninitialize(ddeInst);
01018 
01019     return ret;
01020 }
01021 
01022 /*************************************************************************
01023  *    execute_from_key [Internal]
01024  */
01025 static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env,
01026                                  LPCWSTR szCommandline, LPCWSTR executable_name,
01027                                  SHELL_ExecuteW32 execfunc,
01028                                  LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out)
01029 {
01030     WCHAR cmd[256], param[1024], ddeexec[256];
01031     DWORD cmdlen = sizeof(cmd), ddeexeclen = sizeof(ddeexec);
01032     UINT_PTR retval = SE_ERR_NOASSOC;
01033     DWORD resultLen;
01034     LPWSTR tmp;
01035 
01036     TRACE("%s %s %s %s %s\n", debugstr_w(key), debugstr_w(lpFile), debugstr_w(env),
01037           debugstr_w(szCommandline), debugstr_w(executable_name));
01038 
01039     cmd[0] = '\0';
01040     param[0] = '\0';
01041 
01042     /* Get the application from the registry */
01043     if (RegQueryValueW(HKEY_CLASSES_ROOT, key, cmd, (LONG *)&cmdlen) == ERROR_SUCCESS)
01044     {
01045         TRACE("got cmd: %s\n", debugstr_w(cmd));
01046 
01047         /* Is there a replace() function anywhere? */
01048         cmdlen /= sizeof(WCHAR);
01049         if (cmdlen >= sizeof(cmd) / sizeof(WCHAR))
01050             cmdlen = sizeof(cmd) / sizeof(WCHAR) - 1;
01051         cmd[cmdlen] = '\0';
01052         SHELL_ArgifyW(param, sizeof(param) / sizeof(WCHAR), cmd, lpFile, (LPITEMIDLIST)psei->lpIDList, szCommandline, &resultLen);
01053         if (resultLen > sizeof(param) / sizeof(WCHAR))
01054             ERR("Argify buffer not large enough, truncating\n");
01055     }
01056 
01057     /* Get the parameters needed by the application
01058        from the associated ddeexec key */
01059     tmp = const_cast<LPWSTR>(strstrW(key, L"command"));
01060     assert(tmp);
01061     wcscpy(tmp, L"ddeexec");
01062 
01063     if (RegQueryValueW(HKEY_CLASSES_ROOT, key, ddeexec, (LONG *)&ddeexeclen) == ERROR_SUCCESS)
01064     {
01065         TRACE("Got ddeexec %s => %s\n", debugstr_w(key), debugstr_w(ddeexec));
01066         if (!param[0]) strcpyW(param, executable_name);
01067         retval = dde_connect(key, param, ddeexec, lpFile, env, szCommandline, (LPITEMIDLIST)psei->lpIDList, execfunc, psei, psei_out);
01068     }
01069     else if (param[0])
01070     {
01071         TRACE("executing: %s\n", debugstr_w(param));
01072         retval = execfunc(param, env, FALSE, psei, psei_out);
01073     }
01074     else
01075         WARN("Nothing appropriate found for %s\n", debugstr_w(key));
01076 
01077     return retval;
01078 }
01079 
01080 /*************************************************************************
01081  * FindExecutableA            [SHELL32.@]
01082  */
01083 HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
01084 {
01085     HINSTANCE retval;
01086     WCHAR *wFile = NULL, *wDirectory = NULL;
01087     WCHAR wResult[MAX_PATH];
01088 
01089     if (lpFile) __SHCloneStrAtoW(&wFile, lpFile);
01090     if (lpDirectory) __SHCloneStrAtoW(&wDirectory, lpDirectory);
01091 
01092     retval = FindExecutableW(wFile, wDirectory, wResult);
01093     WideCharToMultiByte(CP_ACP, 0, wResult, -1, lpResult, MAX_PATH, NULL, NULL);
01094     SHFree(wFile);
01095     SHFree(wDirectory);
01096 
01097     TRACE("returning %s\n", lpResult);
01098     return retval;
01099 }
01100 
01101 /*************************************************************************
01102  * FindExecutableW            [SHELL32.@]
01103  *
01104  * This function returns the executable associated with the specified file
01105  * for the default verb.
01106  *
01107  * PARAMS
01108  *  lpFile   [I] The file to find the association for. This must refer to
01109  *               an existing file otherwise FindExecutable fails and returns
01110  *               SE_ERR_FNF.
01111  *  lpResult [O] Points to a buffer into which the executable path is
01112  *               copied. This parameter must not be NULL otherwise
01113  *               FindExecutable() segfaults. The buffer must be of size at
01114  *               least MAX_PATH characters.
01115  *
01116  * RETURNS
01117  *  A value greater than 32 on success, less than or equal to 32 otherwise.
01118  *  See the SE_ERR_* constants.
01119  *
01120  * NOTES
01121  *  On Windows XP and 2003, FindExecutable() seems to first convert the
01122  *  filename into 8.3 format, thus taking into account only the first three
01123  *  characters of the extension, and expects to find an association for those.
01124  *  However other Windows versions behave sanely.
01125  */
01126 HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
01127 {
01128     UINT_PTR retval = SE_ERR_NOASSOC;
01129     WCHAR old_dir[1024];
01130 
01131     TRACE("File %s, Dir %s\n", debugstr_w(lpFile), debugstr_w(lpDirectory));
01132 
01133     lpResult[0] = '\0'; /* Start off with an empty return string */
01134     if (lpFile == NULL)
01135         return (HINSTANCE)SE_ERR_FNF;
01136 
01137     if (lpDirectory)
01138     {
01139         GetCurrentDirectoryW(sizeof(old_dir) / sizeof(WCHAR), old_dir);
01140         SetCurrentDirectoryW(lpDirectory);
01141     }
01142 
01143     retval = SHELL_FindExecutable(lpDirectory, lpFile, wszOpen, lpResult, MAX_PATH, NULL, NULL, NULL, NULL);
01144 
01145     TRACE("returning %s\n", debugstr_w(lpResult));
01146     if (lpDirectory)
01147         SetCurrentDirectoryW(old_dir);
01148     return (HINSTANCE)retval;
01149 }
01150 
01151 /* FIXME: is this already implemented somewhere else? */
01152 static HKEY ShellExecute_GetClassKey(const SHELLEXECUTEINFOW *sei)
01153 {
01154     LPCWSTR ext = NULL, lpClass = NULL;
01155     LPWSTR cls = NULL;
01156     DWORD type = 0, sz = 0;
01157     HKEY hkey = 0;
01158     LONG r;
01159 
01160     if (sei->fMask & SEE_MASK_CLASSALL)
01161         return sei->hkeyClass;
01162 
01163     if (sei->fMask & SEE_MASK_CLASSNAME)
01164         lpClass = sei->lpClass;
01165     else
01166     {
01167         ext = PathFindExtensionW(sei->lpFile);
01168         TRACE("ext = %s\n", debugstr_w(ext));
01169         if (!ext)
01170             return hkey;
01171 
01172         r = RegOpenKeyW(HKEY_CLASSES_ROOT, ext, &hkey);
01173         if (r != ERROR_SUCCESS)
01174             return hkey;
01175 
01176         r = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &sz);
01177         if (r == ERROR_SUCCESS && type == REG_SZ)
01178         {
01179             sz += sizeof (WCHAR);
01180             cls = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sz);
01181             cls[0] = 0;
01182             RegQueryValueExW(hkey, NULL, 0, &type, (LPBYTE) cls, &sz);
01183         }
01184 
01185         RegCloseKey( hkey );
01186         lpClass = cls;
01187     }
01188 
01189     TRACE("class = %s\n", debugstr_w(lpClass));
01190 
01191     hkey = 0;
01192     if (lpClass)
01193         RegOpenKeyW( HKEY_CLASSES_ROOT, lpClass, &hkey);
01194 
01195     HeapFree(GetProcessHeap(), 0, cls);
01196 
01197     return hkey;
01198 }
01199 
01200 static IDataObject *shellex_get_dataobj( LPSHELLEXECUTEINFOW sei )
01201 {
01202     LPCITEMIDLIST pidllast = NULL;
01203     IDataObject *dataobj = NULL;
01204     IShellFolder *shf = NULL;
01205     LPITEMIDLIST pidl = NULL;
01206     HRESULT r;
01207 
01208     if (sei->fMask & SEE_MASK_CLASSALL)
01209         pidl = (LPITEMIDLIST)sei->lpIDList;
01210     else
01211     {
01212         WCHAR fullpath[MAX_PATH];
01213         BOOL ret;
01214 
01215         fullpath[0] = 0;
01216         ret = GetFullPathNameW(sei->lpFile, MAX_PATH, fullpath, NULL);
01217         if (!ret)
01218             goto end;
01219 
01220         pidl = ILCreateFromPathW(fullpath);
01221     }
01222 
01223     r = SHBindToParent(pidl, IID_IShellFolder, (LPVOID*)&shf, &pidllast);
01224     if (FAILED(r))
01225         goto end;
01226 
01227     shf->GetUIObjectOf(NULL, 1, &pidllast,
01228                        IID_IDataObject, NULL, (LPVOID*) &dataobj);
01229 
01230 end:
01231     if (pidl != sei->lpIDList)
01232         ILFree(pidl);
01233     if (shf)
01234         shf->Release();
01235     return dataobj;
01236 }
01237 
01238 static HRESULT shellex_run_context_menu_default(IShellExtInit *obj,
01239         LPSHELLEXECUTEINFOW sei)
01240 {
01241     IContextMenu *cm = NULL;
01242     CMINVOKECOMMANDINFOEX ici;
01243     MENUITEMINFOW info;
01244     WCHAR string[0x80];
01245     INT i, n, def = -1;
01246     HMENU hmenu = 0;
01247     HRESULT r;
01248 
01249     TRACE("%p %p\n", obj, sei);
01250 
01251     r = obj->QueryInterface(IID_IContextMenu, (LPVOID*) &cm);
01252     if (FAILED(r))
01253         return r;
01254 
01255     hmenu = CreateMenu();
01256     if (!hmenu)
01257         goto end;
01258 
01259     /* the number of the last menu added is returned in r */
01260     r = cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY);
01261     if (FAILED(r))
01262         goto end;
01263 
01264     n = GetMenuItemCount(hmenu);
01265     for (i = 0; i < n; i++)
01266     {
01267         memset(&info, 0, sizeof(info));
01268         info.cbSize = sizeof info;
01269         info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
01270         info.dwTypeData = string;
01271         info.cch = sizeof string;
01272         string[0] = 0;
01273         GetMenuItemInfoW(hmenu, i, TRUE, &info);
01274 
01275         TRACE("menu %d %s %08x %08lx %08x %08x\n", i, debugstr_w(string),
01276               info.fState, info.dwItemData, info.fType, info.wID);
01277         if ((!sei->lpVerb && (info.fState & MFS_DEFAULT)) ||
01278             (sei->lpVerb && !lstrcmpiW(sei->lpVerb, string)))
01279         {
01280             def = i;
01281             break;
01282         }
01283     }
01284 
01285     r = E_FAIL;
01286     if (def == -1)
01287         goto end;
01288 
01289     memset(&ici, 0, sizeof ici);
01290     ici.cbSize = sizeof ici;
01291     ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI));
01292     ici.nShow = sei->nShow;
01293     ici.lpVerb = MAKEINTRESOURCEA(def);
01294     ici.hwnd = sei->hwnd;
01295     ici.lpParametersW = sei->lpParameters;
01296 
01297     r = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
01298 
01299     TRACE("invoke command returned %08x\n", r);
01300 
01301 end:
01302     if (hmenu)
01303         DestroyMenu( hmenu );
01304     if (cm)
01305         cm->Release();
01306     return r;
01307 }
01308 
01309 static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW sei)
01310 {
01311     IDataObject *dataobj = NULL;
01312     IObjectWithSite *ows = NULL;
01313     IShellExtInit *obj = NULL;
01314     HRESULT r;
01315 
01316     TRACE("%p %s %p\n", hkey, debugstr_guid(guid), sei);
01317 
01318     r = CoInitialize(NULL);
01319     if (FAILED(r))
01320         goto end;
01321 
01322     r = CoCreateInstance(*guid, NULL, CLSCTX_INPROC_SERVER,
01323                          IID_IShellExtInit, (LPVOID*)&obj);
01324     if (FAILED(r))
01325     {
01326         ERR("failed %08x\n", r);
01327         goto end;
01328     }
01329 
01330     dataobj = shellex_get_dataobj(sei);
01331     if (!dataobj)
01332     {
01333         ERR("failed to get data object\n");
01334         goto end;
01335     }
01336 
01337     r = obj->Initialize(NULL, dataobj, hkey);
01338     if (FAILED(r))
01339         goto end;
01340 
01341     r = obj->QueryInterface(IID_IObjectWithSite, (LPVOID*) &ows);
01342     if (FAILED(r))
01343         goto end;
01344 
01345     ows->SetSite(NULL);
01346 
01347     r = shellex_run_context_menu_default(obj, sei);
01348 
01349 end:
01350     if (ows)
01351         ows->Release();
01352     if (dataobj)
01353         dataobj->Release();
01354     if (obj)
01355         obj->Release();
01356     CoUninitialize();
01357     return r;
01358 }
01359 
01360 
01361 /*************************************************************************
01362  *    ShellExecute_FromContextMenu [Internal]
01363  */
01364 static LONG ShellExecute_FromContextMenu( LPSHELLEXECUTEINFOW sei )
01365 {
01366     HKEY hkey, hkeycm = 0;
01367     WCHAR szguid[39];
01368     HRESULT hr;
01369     GUID guid;
01370     DWORD i;
01371     LONG r;
01372 
01373     TRACE("%s\n", debugstr_w(sei->lpFile));
01374 
01375     hkey = ShellExecute_GetClassKey(sei);
01376     if (!hkey)
01377         return ERROR_FUNCTION_FAILED;
01378 
01379     r = RegOpenKeyW(hkey, L"shellex\\ContextMenuHandlers", &hkeycm);
01380     if (r == ERROR_SUCCESS)
01381     {
01382         i = 0;
01383         while (1)
01384         {
01385             r = RegEnumKeyW(hkeycm, i++, szguid, sizeof(szguid) / sizeof(szguid[0]));
01386             if (r != ERROR_SUCCESS)
01387                 break;
01388 
01389             hr = CLSIDFromString(szguid, &guid);
01390             if (SUCCEEDED(hr))
01391             {
01392                 /* stop at the first one that succeeds in running */
01393                 hr = shellex_load_object_and_run(hkey, &guid, sei);
01394                 if (SUCCEEDED(hr))
01395                     break;
01396             }
01397         }
01398         RegCloseKey(hkeycm);
01399     }
01400 
01401     if (hkey != sei->hkeyClass)
01402         RegCloseKey(hkey);
01403     return r;
01404 }
01405 
01406 static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
01407 {
01408     WCHAR execCmd[1024], wcmd[1024];
01409     /* launch a document by fileclass like 'WordPad.Document.1' */
01410     /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */
01411     /* FIXME: wcmd should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */
01412     ULONG cmask = (psei->fMask & SEE_MASK_CLASSALL);
01413     DWORD resultLen;
01414     BOOL done;
01415 
01416     HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL,
01417                            (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL,
01418                            psei->lpVerb,
01419                            execCmd, sizeof(execCmd));
01420 
01421     /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
01422     TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName));
01423 
01424     wcmd[0] = '\0';
01425     done = SHELL_ArgifyW(wcmd, sizeof(wcmd) / sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen);
01426     if (!done && wszApplicationName[0])
01427     {
01428         strcatW(wcmd, L" ");
01429         strcatW(wcmd, wszApplicationName);
01430     }
01431     if (resultLen > sizeof(wcmd) / sizeof(WCHAR))
01432         ERR("Argify buffer not large enough... truncating\n");
01433     return execfunc(wcmd, NULL, FALSE, psei, psei_out);
01434 }
01435 
01436 static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen)
01437 {
01438     static const WCHAR wExplorer[] = L"explorer.exe";
01439     WCHAR buffer[MAX_PATH];
01440     BOOL appKnownSingular = FALSE;
01441 
01442     /* last chance to translate IDList: now also allow CLSID paths */
01443     if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, sizeof(buffer)))) {
01444         if (buffer[0] == ':' && buffer[1] == ':') {
01445             /* open shell folder for the specified class GUID */
01446             if (strlenW(buffer) + 1 > parametersLen)
01447                 ERR("parameters len exceeds buffer size (%i > %i), truncating\n",
01448                     lstrlenW(buffer) + 1, parametersLen);
01449             lstrcpynW(wszParameters, buffer, parametersLen);
01450             if (strlenW(wExplorer) > dwApplicationNameLen)
01451                 ERR("application len exceeds buffer size (%i > %i), truncating\n",
01452                     lstrlenW(wExplorer) + 1, dwApplicationNameLen);
01453             lstrcpynW(wszApplicationName, wExplorer, dwApplicationNameLen);
01454             appKnownSingular = TRUE;
01455 
01456             sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
01457         } else {
01458             WCHAR target[MAX_PATH];
01459             DWORD attribs;
01460             DWORD resultLen;
01461             /* Check if we're executing a directory and if so use the
01462                handler for the Folder class */
01463             strcpyW(target, buffer);
01464             attribs = GetFileAttributesW(buffer);
01465             if (attribs != INVALID_FILE_ATTRIBUTES &&
01466                     (attribs & FILE_ATTRIBUTE_DIRECTORY) &&
01467                     HCR_GetExecuteCommandW(0, L"Folder",
01468                                            sei->lpVerb,
01469                                            buffer, sizeof(buffer))) {
01470                 SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
01471                               buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen);
01472                 if (resultLen > dwApplicationNameLen)
01473                     ERR("Argify buffer not large enough... truncating\n");
01474                 appKnownSingular = FALSE;
01475             }
01476             sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
01477         }
01478     }
01479     return appKnownSingular;
01480 }
01481 
01482 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)
01483 {
01484     UINT_PTR retval;
01485     DWORD len;
01486     WCHAR *wszQuotedCmd;
01487 
01488     /* Length of quotes plus length of command plus NULL terminator */
01489     len = 2 + lstrlenW(wcmd) + 1;
01490     if (wszParameters[0])
01491     {
01492         /* Length of space plus length of parameters */
01493         len += 1 + lstrlenW(wszParameters);
01494     }
01495     wszQuotedCmd = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01496     /* Must quote to handle case where cmd contains spaces,
01497      * else security hole if malicious user creates executable file "C:\\Program"
01498      */
01499     strcpyW(wszQuotedCmd, L"\"");
01500     strcatW(wszQuotedCmd, wcmd);
01501     strcatW(wszQuotedCmd, L"\"");
01502     if (wszParameters[0])
01503     {
01504         strcatW(wszQuotedCmd, L" ");
01505         strcatW(wszQuotedCmd, wszParameters);
01506     }
01507 
01508     TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(lpstrProtocol));
01509 
01510     if (*lpstrProtocol)
01511         retval = execute_from_key(lpstrProtocol, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
01512     else
01513         retval = execfunc(wszQuotedCmd, env, FALSE, psei, psei_out);
01514     HeapFree(GetProcessHeap(), 0, wszQuotedCmd);
01515     return retval;
01516 }
01517 
01518 static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
01519 {
01520     static const WCHAR wShell[] = L"\\shell\\";
01521     static const WCHAR wCommand[] = L"\\command";
01522     UINT_PTR retval;
01523     WCHAR *lpstrProtocol;
01524     LPCWSTR lpstrRes;
01525     INT iSize;
01526     DWORD len;
01527 
01528     lpstrRes = strchrW(lpFile, ':');
01529     if (lpstrRes)
01530         iSize = lpstrRes - lpFile;
01531     else
01532         iSize = strlenW(lpFile);
01533 
01534     TRACE("Got URL: %s\n", debugstr_w(lpFile));
01535     /* Looking for ...protocol\shell\lpOperation\command */
01536     len = iSize + lstrlenW(wShell) + lstrlenW(wCommand) + 1;
01537     if (psei->lpVerb)
01538         len += lstrlenW(psei->lpVerb);
01539     else
01540         len += lstrlenW(wszOpen);
01541     lpstrProtocol = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01542     memcpy(lpstrProtocol, lpFile, iSize * sizeof(WCHAR));
01543     lpstrProtocol[iSize] = '\0';
01544     strcatW(lpstrProtocol, wShell);
01545     strcatW(lpstrProtocol, psei->lpVerb ? psei->lpVerb : wszOpen);
01546     strcatW(lpstrProtocol, wCommand);
01547 
01548     /* Remove File Protocol from lpFile */
01549     /* In the case file://path/file     */
01550     if (!strncmpiW(lpFile, wFile, iSize))
01551     {
01552         lpFile += iSize;
01553         while (*lpFile == ':') lpFile++;
01554     }
01555     retval = execute_from_key(lpstrProtocol, lpFile, NULL, psei->lpParameters,
01556                               wcmd, execfunc, psei, psei_out);
01557     HeapFree(GetProcessHeap(), 0, lpstrProtocol);
01558     return retval;
01559 }
01560 
01561 void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename)
01562 {
01563     WCHAR msg[2048];
01564     DWORD_PTR msgArguments[3]  = { (DWORD_PTR)filename, 0, 0 };
01565     DWORD error_code;
01566 
01567     error_code = GetLastError();
01568 
01569     if (retval == SE_ERR_NOASSOC)
01570         LoadStringW(shell32_hInstance, IDS_SHLEXEC_NOASSOC, msg, sizeof(msg) / sizeof(WCHAR));
01571     else
01572         FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
01573                        NULL,
01574                        error_code,
01575                        LANG_USER_DEFAULT,
01576                        msg,
01577                        sizeof(msg) / sizeof(WCHAR),
01578                        (va_list*)msgArguments);
01579 
01580     MessageBoxW(hwnd, msg, NULL, MB_ICONERROR);
01581 }
01582 
01583 /*************************************************************************
01584  *    SHELL_execute [Internal]
01585  */
01586 BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
01587 {
01588     static const DWORD unsupportedFlags =
01589         SEE_MASK_INVOKEIDLIST  | SEE_MASK_ICON         | SEE_MASK_HOTKEY |
01590         SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT |
01591         SEE_MASK_UNICODE       | SEE_MASK_ASYNCOK      | SEE_MASK_HMONITOR;
01592 
01593     WCHAR parametersBuffer[1024], dirBuffer[MAX_PATH], wcmdBuffer[1024];
01594     WCHAR *wszApplicationName, *wszParameters, *wszDir, *wcmd;
01595     DWORD dwApplicationNameLen = MAX_PATH + 2;
01596     DWORD parametersLen = sizeof(parametersBuffer) / sizeof(WCHAR);
01597     DWORD dirLen = sizeof(dirBuffer) / sizeof(WCHAR);
01598     DWORD wcmdLen = sizeof(wcmdBuffer) / sizeof(WCHAR);
01599     DWORD len;
01600     SHELLEXECUTEINFOW sei_tmp;    /* modifiable copy of SHELLEXECUTEINFO struct */
01601     WCHAR wfileName[MAX_PATH];
01602     WCHAR *env;
01603     WCHAR lpstrProtocol[256];
01604     LPCWSTR lpFile;
01605     UINT_PTR retval = SE_ERR_NOASSOC;
01606     BOOL appKnownSingular = FALSE;
01607 
01608     /* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */
01609     sei_tmp = *sei;
01610 
01611     TRACE("mask=0x%08x hwnd=%p verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n",
01612           sei_tmp.fMask, sei_tmp.hwnd, debugstr_w(sei_tmp.lpVerb),
01613           debugstr_w(sei_tmp.lpFile), debugstr_w(sei_tmp.lpParameters),
01614           debugstr_w(sei_tmp.lpDirectory), sei_tmp.nShow,
01615           ((sei_tmp.fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME) ?
01616           debugstr_w(sei_tmp.lpClass) : "not used");
01617 
01618     sei->hProcess = NULL;
01619 
01620     /* make copies of all path/command strings */
01621     if (!sei_tmp.lpFile)
01622     {
01623         wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR));
01624         *wszApplicationName = '\0';
01625     }
01626     else if (*sei_tmp.lpFile == '\"')
01627     {
01628         DWORD l = strlenW(sei_tmp.lpFile + 1);
01629         if(l >= dwApplicationNameLen)
01630             dwApplicationNameLen = l + 1;
01631 
01632         wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR));
01633         memcpy(wszApplicationName, sei_tmp.lpFile + 1, (l + 1)*sizeof(WCHAR));
01634 
01635         if (wszApplicationName[l-1] == L'\"')
01636             wszApplicationName[l-1] = L'\0';
01637         appKnownSingular = TRUE;
01638 
01639         TRACE("wszApplicationName=%s\n", debugstr_w(wszApplicationName));
01640     }
01641     else
01642     {
01643         DWORD l = strlenW(sei_tmp.lpFile) + 1;
01644         if(l > dwApplicationNameLen) dwApplicationNameLen = l + 1;
01645         wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR));
01646         memcpy(wszApplicationName, sei_tmp.lpFile, l * sizeof(WCHAR));
01647     }
01648 
01649     wszParameters = parametersBuffer;
01650     if (sei_tmp.lpParameters)
01651     {
01652         len = lstrlenW(sei_tmp.lpParameters) + 1;
01653         if (len > parametersLen)
01654         {
01655             wszParameters = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01656             parametersLen = len;
01657         }
01658         strcpyW(wszParameters, sei_tmp.lpParameters);
01659     }
01660     else
01661         *wszParameters = L'\0';
01662 
01663     wszDir = dirBuffer;
01664     if (sei_tmp.lpDirectory)
01665     {
01666         len = lstrlenW(sei_tmp.lpDirectory) + 1;
01667         if (len > dirLen)
01668         {
01669             wszDir = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01670             dirLen = len;
01671         }
01672         strcpyW(wszDir, sei_tmp.lpDirectory);
01673     }
01674     else
01675         *wszDir = L'\0';
01676 
01677     /* adjust string pointers to point to the new buffers */
01678     sei_tmp.lpFile = wszApplicationName;
01679     sei_tmp.lpParameters = wszParameters;
01680     sei_tmp.lpDirectory = wszDir;
01681 
01682     if (sei_tmp.fMask & unsupportedFlags)
01683     {
01684         FIXME("flags ignored: 0x%08x\n", sei_tmp.fMask & unsupportedFlags);
01685     }
01686 
01687     /* process the IDList */
01688     if (sei_tmp.fMask & SEE_MASK_IDLIST)
01689     {
01690         IShellExecuteHookW* pSEH;
01691 
01692         HRESULT hr = SHBindToParent((LPCITEMIDLIST)sei_tmp.lpIDList, IID_IShellExecuteHookW, (LPVOID*)&pSEH, NULL);
01693 
01694         if (SUCCEEDED(hr))
01695         {
01696             hr = pSEH->Execute(&sei_tmp);
01697 
01698             pSEH->Release();
01699 
01700             if (hr == S_OK)
01701             {
01702                 HeapFree(GetProcessHeap(), 0, wszApplicationName);
01703                 if (wszParameters != parametersBuffer)
01704                     HeapFree(GetProcessHeap(), 0, wszParameters);
01705                 if (wszDir != dirBuffer)
01706                     HeapFree(GetProcessHeap(), 0, wszDir);
01707                 return TRUE;
01708             }
01709         }
01710 
01711         SHGetPathFromIDListW((LPCITEMIDLIST)sei_tmp.lpIDList, wszApplicationName);
01712         appKnownSingular = TRUE;
01713         TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName));
01714     }
01715 
01716     if (ERROR_SUCCESS == ShellExecute_FromContextMenu(&sei_tmp))
01717     {
01718         sei->hInstApp = (HINSTANCE) 33;
01719         HeapFree(GetProcessHeap(), 0, wszApplicationName);
01720         if (wszParameters != parametersBuffer)
01721             HeapFree(GetProcessHeap(), 0, wszParameters);
01722         if (wszDir != dirBuffer)
01723             HeapFree(GetProcessHeap(), 0, wszDir);
01724         return TRUE;
01725     }
01726 
01727     if (sei_tmp.fMask & SEE_MASK_CLASSALL)
01728     {
01729         retval = SHELL_execute_class(wszApplicationName, &sei_tmp, sei, execfunc);
01730         if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
01731         {
01732             OPENASINFO Info;
01733 
01734             //FIXME
01735             // need full path
01736 
01737             Info.pcszFile = wszApplicationName;
01738             Info.pcszClass = NULL;
01739             Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
01740 
01741             //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
01742             do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
01743         }
01744         HeapFree(GetProcessHeap(), 0, wszApplicationName);
01745         if (wszParameters != parametersBuffer)
01746             HeapFree(GetProcessHeap(), 0, wszParameters);
01747         if (wszDir != dirBuffer)
01748             HeapFree(GetProcessHeap(), 0, wszDir);
01749         return retval > 32;
01750     }
01751 
01752     /* Has the IDList not yet been translated? */
01753     if (sei_tmp.fMask & SEE_MASK_IDLIST)
01754     {
01755         appKnownSingular = SHELL_translate_idlist( &sei_tmp, wszParameters,
01756                            parametersLen,
01757                            wszApplicationName,
01758                            dwApplicationNameLen );
01759     }
01760 
01761     /* expand environment strings */
01762     len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0);
01763     if (len > 0)
01764     {
01765         LPWSTR buf;
01766         buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
01767 
01768         ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len + 1);
01769         HeapFree(GetProcessHeap(), 0, wszApplicationName);
01770         dwApplicationNameLen = len + 1;
01771         wszApplicationName = buf;
01772         /* appKnownSingular unmodified */
01773 
01774         sei_tmp.lpFile = wszApplicationName;
01775     }
01776 
01777     if (*sei_tmp.lpParameters)
01778     {
01779         len = ExpandEnvironmentStringsW(sei_tmp.lpParameters, NULL, 0);
01780         if (len > 0)
01781         {
01782             LPWSTR buf;
01783             len++;
01784             buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01785             ExpandEnvironmentStringsW(sei_tmp.lpParameters, buf, len);
01786             if (wszParameters != parametersBuffer)
01787                 HeapFree(GetProcessHeap(), 0, wszParameters);
01788             wszParameters = buf;
01789             parametersLen = len;
01790             sei_tmp.lpParameters = wszParameters;
01791         }
01792     }
01793 
01794     if (*sei_tmp.lpDirectory)
01795     {
01796         len = ExpandEnvironmentStringsW(sei_tmp.lpDirectory, NULL, 0);
01797         if (len > 0)
01798         {
01799             LPWSTR buf;
01800             len++;
01801             buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01802             ExpandEnvironmentStringsW(sei_tmp.lpDirectory, buf, len);
01803             if (wszDir != dirBuffer)
01804                 HeapFree(GetProcessHeap(), 0, wszDir);
01805             wszDir = buf;
01806             sei_tmp.lpDirectory = wszDir;
01807         }
01808     }
01809 
01810     /* Else, try to execute the filename */
01811     TRACE("execute: %s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir));
01812 
01813     /* separate out command line arguments from executable file name */
01814     if (!*sei_tmp.lpParameters && !appKnownSingular)
01815     {
01816         /* If the executable path is quoted, handle the rest of the command line as parameters. */
01817         if (sei_tmp.lpFile[0] == L'"')
01818         {
01819             LPWSTR src = wszApplicationName/*sei_tmp.lpFile*/ + 1;
01820             LPWSTR dst = wfileName;
01821             LPWSTR end;
01822 
01823             /* copy the unquoted executable path to 'wfileName' */
01824             while(*src && *src != L'"')
01825                 *dst++ = *src++;
01826 
01827             *dst = L'\0';
01828 
01829             if (*src == L'"')
01830             {
01831                 end = ++src;
01832 
01833                 while(isspace(*src))
01834                     ++src;
01835             }
01836             else
01837                 end = src;
01838 
01839             /* copy the parameter string to 'wszParameters' */
01840             strcpyW(wszParameters, src);
01841 
01842             /* terminate previous command string after the quote character */
01843             *end = L'\0';
01844         }
01845         else
01846         {
01847             /* If the executable name is not quoted, we have to use this search loop here,
01848                that in CreateProcess() is not sufficient because it does not handle shell links. */
01849             WCHAR buffer[MAX_PATH], xlpFile[MAX_PATH];
01850             LPWSTR space, s;
01851 
01852             LPWSTR beg = wszApplicationName/*sei_tmp.lpFile*/;
01853             for(s = beg; (space = const_cast<LPWSTR>(strchrW(s, L' '))); s = space + 1)
01854             {
01855                 int idx = space - sei_tmp.lpFile;
01856                 memcpy(buffer, sei_tmp.lpFile, idx * sizeof(WCHAR));
01857                 buffer[idx] = '\0';
01858 
01859                 /*FIXME This finds directory paths if the targeted file name contains spaces. */
01860                 if (SearchPathW(*sei_tmp.lpDirectory ? sei_tmp.lpDirectory : NULL, buffer, wszExe, sizeof(xlpFile) / sizeof(xlpFile[0]), xlpFile, NULL))
01861                 {
01862                     /* separate out command from parameter string */
01863                     LPCWSTR p = space + 1;
01864 
01865                     while(isspaceW(*p))
01866                         ++p;
01867 
01868                     strcpyW(wszParameters, p);
01869                     *space = L'\0';
01870 
01871                     break;
01872                 }
01873             }
01874 
01875             lstrcpynW(wfileName, sei_tmp.lpFile, sizeof(wfileName) / sizeof(WCHAR));
01876         }
01877     }
01878     else
01879         lstrcpynW(wfileName, sei_tmp.lpFile, sizeof(wfileName) / sizeof(WCHAR));
01880 
01881     lpFile = wfileName;
01882 
01883     wcmd = wcmdBuffer;
01884     len = lstrlenW(wszApplicationName) + 3;
01885     if (sei_tmp.lpParameters[0])
01886         len += 1 + lstrlenW(wszParameters);
01887     if (len > wcmdLen)
01888     {
01889         wcmd = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01890         wcmdLen = len;
01891     }
01892     swprintf(wcmd, L"\"%s\"", wszApplicationName);
01893     if (sei_tmp.lpParameters[0])
01894     {
01895         strcatW(wcmd, L" ");
01896         strcatW(wcmd, wszParameters);
01897     }
01898 
01899     retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei);
01900     if (retval > 32)
01901     {
01902         HeapFree(GetProcessHeap(), 0, wszApplicationName);
01903         if (wszParameters != parametersBuffer)
01904             HeapFree(GetProcessHeap(), 0, wszParameters);
01905         if (wszDir != dirBuffer)
01906             HeapFree(GetProcessHeap(), 0, wszDir);
01907         if (wcmd != wcmdBuffer)
01908             HeapFree(GetProcessHeap(), 0, wcmd);
01909         return TRUE;
01910     }
01911 
01912     /* Else, try to find the executable */
01913     wcmd[0] = L'\0';
01914     retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, lpstrProtocol, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
01915     if (retval > 32)  /* Found */
01916     {
01917         retval = SHELL_quote_and_execute(wcmd, wszParameters, lpstrProtocol,
01918                                          wszApplicationName, env, &sei_tmp,
01919                                          sei, execfunc);
01920         HeapFree(GetProcessHeap(), 0, env);
01921     }
01922     else if (PathIsDirectoryW(lpFile))
01923     {
01924         WCHAR wExec[MAX_PATH];
01925         WCHAR * lpQuotedFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (strlenW(lpFile) + 3));
01926 
01927         if (lpQuotedFile)
01928         {
01929             retval = SHELL_FindExecutable(sei_tmp.lpDirectory, L"explorer",
01930                                           wszOpen, wExec, MAX_PATH,
01931                                           NULL, &env, NULL, NULL);
01932             if (retval > 32)
01933             {
01934                 swprintf(lpQuotedFile, L"\"%s\"", lpFile);
01935                 retval = SHELL_quote_and_execute(wExec, lpQuotedFile,
01936                                                  lpstrProtocol,
01937                                                  wszApplicationName, env,
01938                                                  &sei_tmp, sei, execfunc);
01939                 HeapFree(GetProcessHeap(), 0, env);
01940             }
01941             HeapFree(GetProcessHeap(), 0, lpQuotedFile);
01942         }
01943         else
01944             retval = 0; /* Out of memory */
01945     }
01946     else if (PathIsURLW(lpFile))    /* File not found, check for URL */
01947     {
01948         retval = SHELL_execute_url(lpFile, L"file", wcmd, &sei_tmp, sei, execfunc );
01949     }
01950     /* Check if file specified is in the form www.??????.*** */
01951     else if (!strncmpiW(lpFile, L"www", 3))
01952     {
01953         /* if so, append lpFile http:// and call ShellExecute */
01954         WCHAR lpstrTmpFile[256];
01955         strcpyW(lpstrTmpFile, L"http://");
01956         strcatW(lpstrTmpFile, lpFile);
01957         retval = (UINT_PTR)ShellExecuteW(sei_tmp.hwnd, sei_tmp.lpVerb, lpstrTmpFile, NULL, NULL, 0);
01958     }
01959 
01960     TRACE("retval %lu\n", retval);
01961 
01962     if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
01963     {
01964         OPENASINFO Info;
01965 
01966         //FIXME
01967         // need full path
01968 
01969         Info.pcszFile = wszApplicationName;
01970         Info.pcszClass = NULL;
01971         Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
01972 
01973         //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
01974         do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
01975     }
01976 
01977     HeapFree(GetProcessHeap(), 0, wszApplicationName);
01978     if (wszParameters != parametersBuffer)
01979         HeapFree(GetProcessHeap(), 0, wszParameters);
01980     if (wszDir != dirBuffer)
01981         HeapFree(GetProcessHeap(), 0, wszDir);
01982     if (wcmd != wcmdBuffer)
01983         HeapFree(GetProcessHeap(), 0, wcmd);
01984 
01985     sei->hInstApp = (HINSTANCE)(retval > 32 ? 33 : retval);
01986 
01987     return retval > 32;
01988 }
01989 
01990 /*************************************************************************
01991  * ShellExecuteA            [SHELL32.290]
01992  */
01993 HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile,
01994                                LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
01995 {
01996     SHELLEXECUTEINFOA sei;
01997 
01998     TRACE("%p,%s,%s,%s,%s,%d\n",
01999           hWnd, debugstr_a(lpOperation), debugstr_a(lpFile),
02000           debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd);
02001 
02002     sei.cbSize = sizeof(sei);
02003     sei.fMask = SEE_MASK_FLAG_NO_UI;
02004     sei.hwnd = hWnd;
02005     sei.lpVerb = lpOperation;
02006     sei.lpFile = lpFile;
02007     sei.lpParameters = lpParameters;
02008     sei.lpDirectory = lpDirectory;
02009     sei.nShow = iShowCmd;
02010     sei.lpIDList = 0;
02011     sei.lpClass = 0;
02012     sei.hkeyClass = 0;
02013     sei.dwHotKey = 0;
02014     sei.hProcess = 0;
02015 
02016     ShellExecuteExA(&sei);
02017     return sei.hInstApp;
02018 }
02019 
02020 /*************************************************************************
02021  * ShellExecuteExA                [SHELL32.292]
02022  *
02023  */
02024 BOOL WINAPI ShellExecuteExA(LPSHELLEXECUTEINFOA sei)
02025 {
02026     SHELLEXECUTEINFOW seiW;
02027     BOOL ret;
02028     WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL, *wClass = NULL;
02029 
02030     TRACE("%p\n", sei);
02031 
02032     memcpy(&seiW, sei, sizeof(SHELLEXECUTEINFOW));
02033 
02034     if (sei->lpVerb)
02035         seiW.lpVerb = __SHCloneStrAtoW(&wVerb, sei->lpVerb);
02036 
02037     if (sei->lpFile)
02038         seiW.lpFile = __SHCloneStrAtoW(&wFile, sei->lpFile);
02039 
02040     if (sei->lpParameters)
02041         seiW.lpParameters = __SHCloneStrAtoW(&wParameters, sei->lpParameters);
02042 
02043     if (sei->lpDirectory)
02044         seiW.lpDirectory = __SHCloneStrAtoW(&wDirectory, sei->lpDirectory);
02045 
02046     if ((sei->fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME && sei->lpClass)
02047         seiW.lpClass = __SHCloneStrAtoW(&wClass, sei->lpClass);
02048     else
02049         seiW.lpClass = NULL;
02050 
02051     ret = SHELL_execute(&seiW, SHELL_ExecuteW);
02052 
02053     sei->hInstApp = seiW.hInstApp;
02054 
02055     if (sei->fMask & SEE_MASK_NOCLOSEPROCESS)
02056         sei->hProcess = seiW.hProcess;
02057 
02058     SHFree(wVerb);
02059     SHFree(wFile);
02060     SHFree(wParameters);
02061     SHFree(wDirectory);
02062     SHFree(wClass);
02063 
02064     return ret;
02065 }
02066 
02067 /*************************************************************************
02068  * ShellExecuteExW                [SHELL32.293]
02069  *
02070  */
02071 BOOL WINAPI ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
02072 {
02073     return SHELL_execute(sei, SHELL_ExecuteW);
02074 }
02075 
02076 /*************************************************************************
02077  * ShellExecuteW            [SHELL32.294]
02078  * from shellapi.h
02079  * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpOperation,
02080  * LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd);
02081  */
02082 HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile,
02083                                LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
02084 {
02085     SHELLEXECUTEINFOW sei;
02086 
02087     TRACE("\n");
02088     sei.cbSize = sizeof(sei);
02089     sei.fMask = SEE_MASK_FLAG_NO_UI;
02090     sei.hwnd = hwnd;
02091     sei.lpVerb = lpOperation;
02092     sei.lpFile = lpFile;
02093     sei.lpParameters = lpParameters;
02094     sei.lpDirectory = lpDirectory;
02095     sei.nShow = nShowCmd;
02096     sei.lpIDList = 0;
02097     sei.lpClass = 0;
02098     sei.hkeyClass = 0;
02099     sei.dwHotKey = 0;
02100     sei.hProcess = 0;
02101 
02102     SHELL_execute(&sei, SHELL_ExecuteW);
02103     return sei.hInstApp;
02104 }
02105 
02106 /*************************************************************************
02107  * WOWShellExecute            [SHELL32.@]
02108  *
02109  * FIXME: the callback function most likely doesn't work the same way on Windows.
02110  */
02111 EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile,
02112         LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback)
02113 {
02114     SHELLEXECUTEINFOW seiW;
02115     WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL;
02116     HANDLE hProcess = 0;
02117 
02118     seiW.lpVerb = lpOperation ? __SHCloneStrAtoW(&wVerb, lpOperation) : NULL;
02119     seiW.lpFile = lpFile ? __SHCloneStrAtoW(&wFile, lpFile) : NULL;
02120     seiW.lpParameters = lpParameters ? __SHCloneStrAtoW(&wParameters, lpParameters) : NULL;
02121     seiW.lpDirectory = lpDirectory ? __SHCloneStrAtoW(&wDirectory, lpDirectory) : NULL;
02122 
02123     seiW.cbSize = sizeof(seiW);
02124     seiW.fMask = 0;
02125     seiW.hwnd = hWnd;
02126     seiW.nShow = iShowCmd;
02127     seiW.lpIDList = 0;
02128     seiW.lpClass = 0;
02129     seiW.hkeyClass = 0;
02130     seiW.dwHotKey = 0;
02131     seiW.hProcess = hProcess;
02132 
02133     SHELL_execute(&seiW, (SHELL_ExecuteW32)callback);
02134 
02135     SHFree(wVerb);
02136     SHFree(wFile);
02137     SHFree(wParameters);
02138     SHFree(wDirectory);
02139     return seiW.hInstApp;
02140 }
02141 
02142 /*************************************************************************
02143  * OpenAs_RunDLLA          [SHELL32.@]
02144  */
02145 EXTERN_C void WINAPI OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int cmdshow)
02146 {
02147     FIXME("%p, %p, %s, %d\n", hwnd, hinst, debugstr_a(cmdline), cmdshow);
02148 }
02149 
02150 /*************************************************************************
02151  * OpenAs_RunDLLW          [SHELL32.@]
02152  */
02153 EXTERN_C void WINAPI OpenAs_RunDLLW(HWND hwnd, HINSTANCE hinst, LPCWSTR cmdline, int cmdshow)
02154 {
02155     FIXME("%p, %p, %s, %d\n", hwnd, hinst, debugstr_w(cmdline), cmdshow);
02156 }

Generated on Sat May 26 2012 04:25:04 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.