1c2c66affSColin Finck /* 2c2c66affSColin Finck * Shell Library Functions 3c2c66affSColin Finck * 4c2c66affSColin Finck * Copyright 1998 Marcus Meissner 5c2c66affSColin Finck * Copyright 2002 Eric Pouech 6044f1819SKatayama Hirofumi MZ * Copyright 2018-2024 Katayama Hirofumi MZ 7c2c66affSColin Finck * 8c2c66affSColin Finck * This library is free software; you can redistribute it and/or 9c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public 10c2c66affSColin Finck * License as published by the Free Software Foundation; either 11c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version. 12c2c66affSColin Finck * 13c2c66affSColin Finck * This library is distributed in the hope that it will be useful, 14c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of 15c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16c2c66affSColin Finck * Lesser General Public License for more details. 17c2c66affSColin Finck * 18c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public 19c2c66affSColin Finck * License along with this library; if not, write to the Free Software 20c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21c2c66affSColin Finck */ 22c2c66affSColin Finck 23c2c66affSColin Finck #include "precomp.h" 24bfcbda22SKatayama Hirofumi MZ #include <undocshell.h> 25c2c66affSColin Finck 26c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(exec); 27c2c66affSColin Finck 289b716539SAlex Miccolis EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath); 299b716539SAlex Miccolis 30c2c66affSColin Finck #define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY) 31c2c66affSColin Finck 32c2c66affSColin Finck typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, 33c2c66affSColin Finck const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out); 34c2c66affSColin Finck 35044f1819SKatayama Hirofumi MZ // Is the current process a rundll32.exe? 36044f1819SKatayama Hirofumi MZ static BOOL SHELL_InRunDllProcess(VOID) 37044f1819SKatayama Hirofumi MZ { 38044f1819SKatayama Hirofumi MZ WCHAR szModule[MAX_PATH]; 39044f1819SKatayama Hirofumi MZ static INT s_bInDllProcess = -1; 40044f1819SKatayama Hirofumi MZ 41044f1819SKatayama Hirofumi MZ if (s_bInDllProcess != -1) 42044f1819SKatayama Hirofumi MZ return s_bInDllProcess; 43044f1819SKatayama Hirofumi MZ 44044f1819SKatayama Hirofumi MZ s_bInDllProcess = GetModuleFileNameW(NULL, szModule, _countof(szModule)) && 45044f1819SKatayama Hirofumi MZ (StrStrIW(PathFindFileNameW(szModule), L"rundll") != NULL); 46044f1819SKatayama Hirofumi MZ return s_bInDllProcess; 47044f1819SKatayama Hirofumi MZ } 48044f1819SKatayama Hirofumi MZ 49c2c66affSColin Finck static void ParseNoTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum) 50c2c66affSColin Finck { 51c2c66affSColin Finck bool firstCharQuote = false; 52c2c66affSColin Finck bool quotes_opened = false; 53c2c66affSColin Finck bool backslash_encountered = false; 54c2c66affSColin Finck 55c2c66affSColin Finck for (int curArg = 0; curArg <= argNum && *args; ++curArg) 56c2c66affSColin Finck { 57c2c66affSColin Finck firstCharQuote = false; 58c2c66affSColin Finck if (*args == '"') 59c2c66affSColin Finck { 60c2c66affSColin Finck quotes_opened = true; 61c2c66affSColin Finck firstCharQuote = true; 62c2c66affSColin Finck args++; 63c2c66affSColin Finck } 64c2c66affSColin Finck 65c2c66affSColin Finck while(*args) 66c2c66affSColin Finck { 67c2c66affSColin Finck if (*args == '\\') 68c2c66affSColin Finck { 69c2c66affSColin Finck // if we found a backslash then flip the variable 70c2c66affSColin Finck backslash_encountered = !backslash_encountered; 71c2c66affSColin Finck } 72c2c66affSColin Finck else if (*args == '"') 73c2c66affSColin Finck { 74c2c66affSColin Finck if (quotes_opened) 75c2c66affSColin Finck { 76c2c66affSColin Finck if (*(args + 1) != '"') 77c2c66affSColin Finck { 78c2c66affSColin Finck quotes_opened = false; 79c2c66affSColin Finck args++; 80c2c66affSColin Finck break; 81c2c66affSColin Finck } 82c2c66affSColin Finck else 83c2c66affSColin Finck { 84c2c66affSColin Finck args++; 85c2c66affSColin Finck } 86c2c66affSColin Finck } 87c2c66affSColin Finck else 88c2c66affSColin Finck { 89c2c66affSColin Finck quotes_opened = true; 90c2c66affSColin Finck } 91c2c66affSColin Finck 92c2c66affSColin Finck backslash_encountered = false; 93c2c66affSColin Finck } 94c2c66affSColin Finck else 95c2c66affSColin Finck { 96c2c66affSColin Finck backslash_encountered = false; 97c2c66affSColin Finck if (*args == ' ' && !firstCharQuote) 98c2c66affSColin Finck break; 99c2c66affSColin Finck } 100c2c66affSColin Finck 101c2c66affSColin Finck if (curArg == argNum) 102c2c66affSColin Finck { 103c2c66affSColin Finck used++; 104c2c66affSColin Finck if (used < len) 105c2c66affSColin Finck *res++ = *args; 106c2c66affSColin Finck } 107c2c66affSColin Finck 108c2c66affSColin Finck args++; 109c2c66affSColin Finck } 110c2c66affSColin Finck 111c2c66affSColin Finck while(*args == ' ') 112c2c66affSColin Finck ++args; 113c2c66affSColin Finck } 114c2c66affSColin Finck } 115c2c66affSColin Finck 116c2c66affSColin Finck static void ParseTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum) 117c2c66affSColin Finck { 118c2c66affSColin Finck bool quotes_opened = false; 119c2c66affSColin Finck bool backslash_encountered = false; 120c2c66affSColin Finck 121c2c66affSColin Finck for (int curArg = 0; curArg <= argNum && *args; ++curArg) 122c2c66affSColin Finck { 123c2c66affSColin Finck while(*args) 124c2c66affSColin Finck { 125c2c66affSColin Finck if (*args == '\\') 126c2c66affSColin Finck { 127c2c66affSColin Finck // if we found a backslash then flip the variable 128c2c66affSColin Finck backslash_encountered = !backslash_encountered; 129c2c66affSColin Finck } 130c2c66affSColin Finck else if (*args == '"') 131c2c66affSColin Finck { 132c2c66affSColin Finck if (quotes_opened) 133c2c66affSColin Finck { 134c2c66affSColin Finck if (*(args + 1) != '"') 135c2c66affSColin Finck { 136c2c66affSColin Finck quotes_opened = false; 137c2c66affSColin Finck } 138c2c66affSColin Finck else 139c2c66affSColin Finck { 140c2c66affSColin Finck args++; 141c2c66affSColin Finck } 142c2c66affSColin Finck } 143c2c66affSColin Finck else 144c2c66affSColin Finck { 145c2c66affSColin Finck quotes_opened = true; 146c2c66affSColin Finck } 147c2c66affSColin Finck 148c2c66affSColin Finck backslash_encountered = false; 149c2c66affSColin Finck } 150c2c66affSColin Finck else 151c2c66affSColin Finck { 152c2c66affSColin Finck backslash_encountered = false; 153c2c66affSColin Finck if (*args == ' ' && !quotes_opened && curArg != argNum) 154c2c66affSColin Finck break; 155c2c66affSColin Finck } 156c2c66affSColin Finck 157c2c66affSColin Finck if (curArg == argNum) 158c2c66affSColin Finck { 159c2c66affSColin Finck used++; 160c2c66affSColin Finck if (used < len) 161c2c66affSColin Finck *res++ = *args; 162c2c66affSColin Finck } 163c2c66affSColin Finck 164c2c66affSColin Finck args++; 165c2c66affSColin Finck } 166c2c66affSColin Finck } 167c2c66affSColin Finck } 168c2c66affSColin Finck 169c2c66affSColin Finck /*********************************************************************** 170c2c66affSColin Finck * SHELL_ArgifyW [Internal] 171c2c66affSColin Finck * 172c2c66affSColin Finck * this function is supposed to expand the escape sequences found in the registry 173c2c66affSColin Finck * some diving reported that the following were used: 174c2c66affSColin Finck * + %1, %2... seem to report to parameter of index N in ShellExecute pmts 175c2c66affSColin Finck * %1 file 176c2c66affSColin Finck * %2 printer 177c2c66affSColin Finck * %3 driver 178c2c66affSColin Finck * %4 port 179c2c66affSColin Finck * %I address of a global item ID (explorer switch /idlist) 180c2c66affSColin Finck * %L seems to be %1 as long filename followed by the 8+3 variation 181c2c66affSColin Finck * %S ??? 18290c63d12SKatayama Hirofumi MZ * %W Working directory 18390c63d12SKatayama Hirofumi MZ * %V Use either %L or %W 184c2c66affSColin Finck * %* all following parameters (see batfile) 185c2c66affSColin Finck * 186c2c66affSColin Finck * The way we parse the command line arguments was determined through extensive 187c2c66affSColin Finck * testing and can be summed up by the following rules" 188c2c66affSColin Finck * 189c2c66affSColin Finck * - %2 190c2c66affSColin Finck * - if first letter is " break on first non literal " and include any white spaces 191c2c66affSColin Finck * - if first letter is NOT " break on first " or white space 192c2c66affSColin Finck * - if " is opened any pair of consecutive " results in ONE literal " 193c2c66affSColin Finck * 194c2c66affSColin Finck * - %~2 195c2c66affSColin Finck * - use rules from here http://www.autohotkey.net/~deleyd/parameters/parameters.htm 196c2c66affSColin Finck */ 197c2c66affSColin Finck 198e018cceaSKatayama Hirofumi MZ static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len, const WCHAR* lpDir) 199c2c66affSColin Finck { 200c2c66affSColin Finck BOOL done = FALSE; 201c2c66affSColin Finck BOOL found_p1 = FALSE; 202c2c66affSColin Finck PWSTR res = out; 203c2c66affSColin Finck DWORD used = 0; 204c2c66affSColin Finck bool tildeEffect = false; 205c2c66affSColin Finck 206c2c66affSColin Finck TRACE("Before parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt), 207c2c66affSColin Finck debugstr_w(lpFile), pidl, args); 208c2c66affSColin Finck 209c2c66affSColin Finck while (*fmt) 210c2c66affSColin Finck { 211c2c66affSColin Finck if (*fmt == '%') 212c2c66affSColin Finck { 213c2c66affSColin Finck switch (*++fmt) 214c2c66affSColin Finck { 215c2c66affSColin Finck case '\0': 216c2c66affSColin Finck case '%': 217c2c66affSColin Finck { 218c2c66affSColin Finck used++; 219c2c66affSColin Finck if (used < len) 220c2c66affSColin Finck *res++ = '%'; 221c2c66affSColin Finck }; 222c2c66affSColin Finck break; 223c2c66affSColin Finck 224c2c66affSColin Finck case '*': 225c2c66affSColin Finck { 226c2c66affSColin Finck if (args) 227c2c66affSColin Finck { 228c2c66affSColin Finck if (*fmt == '*') 229c2c66affSColin Finck { 230c2c66affSColin Finck used++; 231c2c66affSColin Finck while(*args) 232c2c66affSColin Finck { 233c2c66affSColin Finck used++; 234c2c66affSColin Finck if (used < len) 235c2c66affSColin Finck *res++ = *args++; 236c2c66affSColin Finck else 237c2c66affSColin Finck args++; 238c2c66affSColin Finck } 239c2c66affSColin Finck used++; 240c2c66affSColin Finck break; 241c2c66affSColin Finck } 242c2c66affSColin Finck } 243c2c66affSColin Finck }; 244c2c66affSColin Finck break; 245c2c66affSColin Finck 246c2c66affSColin Finck case '~': 247c2c66affSColin Finck 248c2c66affSColin Finck case '2': 249c2c66affSColin Finck case '3': 250c2c66affSColin Finck case '4': 251c2c66affSColin Finck case '5': 252c2c66affSColin Finck case '6': 253c2c66affSColin Finck case '7': 254c2c66affSColin Finck case '8': 255c2c66affSColin Finck case '9': 256c2c66affSColin Finck //case '0': 257c2c66affSColin Finck { 258c2c66affSColin Finck if (*fmt == '~') 259c2c66affSColin Finck { 260c2c66affSColin Finck fmt++; 261c2c66affSColin Finck tildeEffect = true; 262c2c66affSColin Finck } 263c2c66affSColin Finck 264c2c66affSColin Finck if (args) 265c2c66affSColin Finck { 266c2c66affSColin Finck if (tildeEffect) 267c2c66affSColin Finck { 268c2c66affSColin Finck ParseTildeEffect(res, args, len, used, *fmt - '2'); 269c2c66affSColin Finck tildeEffect = false; 270c2c66affSColin Finck } 271c2c66affSColin Finck else 272c2c66affSColin Finck { 273c2c66affSColin Finck ParseNoTildeEffect(res, args, len, used, *fmt - '2'); 274c2c66affSColin Finck } 275c2c66affSColin Finck } 276c2c66affSColin Finck }; 277c2c66affSColin Finck break; 278c2c66affSColin Finck 279c2c66affSColin Finck case '1': 280*e5a6b0f8SOleg Dubinskiy if ((!done || (*fmt == '1')) && lpFile) 281c2c66affSColin Finck { 282*e5a6b0f8SOleg Dubinskiy SIZE_T filelen = wcslen(lpFile); 283*e5a6b0f8SOleg Dubinskiy used += filelen; 284c2c66affSColin Finck if (used < len) 285c2c66affSColin Finck { 286*e5a6b0f8SOleg Dubinskiy wcscpy(res, lpFile); 287*e5a6b0f8SOleg Dubinskiy res += filelen; 288c2c66affSColin Finck } 289c2c66affSColin Finck } 290c2c66affSColin Finck found_p1 = TRUE; 291c2c66affSColin Finck break; 292c2c66affSColin Finck 293c2c66affSColin Finck /* 294c2c66affSColin Finck * IE uses this a lot for activating things such as windows media 295c2c66affSColin Finck * player. This is not verified to be fully correct but it appears 296c2c66affSColin Finck * to work just fine. 297c2c66affSColin Finck */ 298c2c66affSColin Finck case 'l': 299c2c66affSColin Finck case 'L': 300c2c66affSColin Finck if (lpFile) 301c2c66affSColin Finck { 302c2c66affSColin Finck used += wcslen(lpFile); 303c2c66affSColin Finck if (used < len) 304c2c66affSColin Finck { 305c2c66affSColin Finck wcscpy(res, lpFile); 306c2c66affSColin Finck res += wcslen(lpFile); 307c2c66affSColin Finck } 308c2c66affSColin Finck } 309c2c66affSColin Finck found_p1 = TRUE; 310c2c66affSColin Finck break; 311c2c66affSColin Finck 31290c63d12SKatayama Hirofumi MZ case 'w': 31390c63d12SKatayama Hirofumi MZ case 'W': 31490c63d12SKatayama Hirofumi MZ if (lpDir) 31590c63d12SKatayama Hirofumi MZ { 31690c63d12SKatayama Hirofumi MZ used += wcslen(lpDir); 31790c63d12SKatayama Hirofumi MZ if (used < len) 31890c63d12SKatayama Hirofumi MZ { 31990c63d12SKatayama Hirofumi MZ wcscpy(res, lpDir); 32090c63d12SKatayama Hirofumi MZ res += wcslen(lpDir); 32190c63d12SKatayama Hirofumi MZ } 32290c63d12SKatayama Hirofumi MZ } 32390c63d12SKatayama Hirofumi MZ break; 32490c63d12SKatayama Hirofumi MZ 32590c63d12SKatayama Hirofumi MZ case 'v': 32690c63d12SKatayama Hirofumi MZ case 'V': 32790c63d12SKatayama Hirofumi MZ if (lpFile) 32890c63d12SKatayama Hirofumi MZ { 32990c63d12SKatayama Hirofumi MZ used += wcslen(lpFile); 33090c63d12SKatayama Hirofumi MZ if (used < len) 33190c63d12SKatayama Hirofumi MZ { 33290c63d12SKatayama Hirofumi MZ wcscpy(res, lpFile); 33390c63d12SKatayama Hirofumi MZ res += wcslen(lpFile); 33490c63d12SKatayama Hirofumi MZ } 33590c63d12SKatayama Hirofumi MZ found_p1 = TRUE; 33690c63d12SKatayama Hirofumi MZ } 33790c63d12SKatayama Hirofumi MZ else if (lpDir) 33890c63d12SKatayama Hirofumi MZ { 33990c63d12SKatayama Hirofumi MZ used += wcslen(lpDir); 34090c63d12SKatayama Hirofumi MZ if (used < len) 34190c63d12SKatayama Hirofumi MZ { 34290c63d12SKatayama Hirofumi MZ wcscpy(res, lpDir); 34390c63d12SKatayama Hirofumi MZ res += wcslen(lpDir); 34490c63d12SKatayama Hirofumi MZ } 34590c63d12SKatayama Hirofumi MZ } 34690c63d12SKatayama Hirofumi MZ break; 34790c63d12SKatayama Hirofumi MZ 348c2c66affSColin Finck case 'i': 349c2c66affSColin Finck case 'I': 350c2c66affSColin Finck if (pidl) 351c2c66affSColin Finck { 352c2c66affSColin Finck DWORD chars = 0; 353c2c66affSColin Finck /* %p should not exceed 8, maybe 16 when looking forward to 64bit. 354c2c66affSColin Finck * allowing a buffer of 100 should more than exceed all needs */ 355c2c66affSColin Finck WCHAR buf[100]; 356c2c66affSColin Finck LPVOID pv; 357c2c66affSColin Finck HGLOBAL hmem = SHAllocShared(pidl, ILGetSize(pidl), 0); 358c2c66affSColin Finck pv = SHLockShared(hmem, 0); 359c2c66affSColin Finck chars = swprintf(buf, L":%p", pv); 360c2c66affSColin Finck 36183be315aSHermès Bélusca-Maïto if (chars >= ARRAY_SIZE(buf)) 362c2c66affSColin Finck ERR("pidl format buffer too small!\n"); 363c2c66affSColin Finck 364c2c66affSColin Finck used += chars; 365c2c66affSColin Finck 366c2c66affSColin Finck if (used < len) 367c2c66affSColin Finck { 368c2c66affSColin Finck wcscpy(res, buf); 369c2c66affSColin Finck res += chars; 370c2c66affSColin Finck } 371c2c66affSColin Finck SHUnlockShared(pv); 372c2c66affSColin Finck } 373c2c66affSColin Finck found_p1 = TRUE; 374c2c66affSColin Finck break; 375c2c66affSColin Finck 376c2c66affSColin Finck default: 377c2c66affSColin Finck /* 378c2c66affSColin Finck * Check if this is an env-variable here... 379c2c66affSColin Finck */ 380c2c66affSColin Finck 381c2c66affSColin Finck /* Make sure that we have at least one more %.*/ 382c2c66affSColin Finck if (strchrW(fmt, '%')) 383c2c66affSColin Finck { 384c2c66affSColin Finck WCHAR tmpBuffer[1024]; 385c2c66affSColin Finck PWSTR tmpB = tmpBuffer; 386c2c66affSColin Finck WCHAR tmpEnvBuff[MAX_PATH]; 387c2c66affSColin Finck DWORD envRet; 388c2c66affSColin Finck 389c2c66affSColin Finck while (*fmt != '%') 390c2c66affSColin Finck *tmpB++ = *fmt++; 391c2c66affSColin Finck *tmpB++ = 0; 392c2c66affSColin Finck 393c2c66affSColin Finck TRACE("Checking %s to be an env-var\n", debugstr_w(tmpBuffer)); 394c2c66affSColin Finck 395c2c66affSColin Finck envRet = GetEnvironmentVariableW(tmpBuffer, tmpEnvBuff, MAX_PATH); 396c2c66affSColin Finck if (envRet == 0 || envRet > MAX_PATH) 397c2c66affSColin Finck { 398c2c66affSColin Finck used += wcslen(tmpBuffer); 399c2c66affSColin Finck if (used < len) 400c2c66affSColin Finck { 401c2c66affSColin Finck wcscpy( res, tmpBuffer ); 402c2c66affSColin Finck res += wcslen(tmpBuffer); 403c2c66affSColin Finck } 404c2c66affSColin Finck } 405c2c66affSColin Finck else 406c2c66affSColin Finck { 407c2c66affSColin Finck used += wcslen(tmpEnvBuff); 408c2c66affSColin Finck if (used < len) 409c2c66affSColin Finck { 410c2c66affSColin Finck wcscpy( res, tmpEnvBuff ); 411c2c66affSColin Finck res += wcslen(tmpEnvBuff); 412c2c66affSColin Finck } 413c2c66affSColin Finck } 414c2c66affSColin Finck } 415c2c66affSColin Finck done = TRUE; 416c2c66affSColin Finck break; 417c2c66affSColin Finck } 418c2c66affSColin Finck /* Don't skip past terminator (catch a single '%' at the end) */ 419c2c66affSColin Finck if (*fmt != '\0') 420c2c66affSColin Finck { 421c2c66affSColin Finck fmt++; 422c2c66affSColin Finck } 423c2c66affSColin Finck } 424c2c66affSColin Finck else 425c2c66affSColin Finck { 426c2c66affSColin Finck used ++; 427c2c66affSColin Finck if (used < len) 428c2c66affSColin Finck *res++ = *fmt++; 429c2c66affSColin Finck else 430c2c66affSColin Finck fmt++; 431c2c66affSColin Finck } 432c2c66affSColin Finck } 433c2c66affSColin Finck 434c2c66affSColin Finck used++; 435c2c66affSColin Finck if (res - out < static_cast<int>(len)) 436c2c66affSColin Finck *res = '\0'; 437c2c66affSColin Finck else 438c2c66affSColin Finck out[len-1] = '\0'; 439c2c66affSColin Finck 440c2c66affSColin Finck TRACE("used %i of %i space\n", used, len); 441c2c66affSColin Finck if (out_len) 442c2c66affSColin Finck *out_len = used; 443c2c66affSColin Finck 444c2c66affSColin Finck TRACE("After parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt), 445c2c66affSColin Finck debugstr_w(lpFile), pidl, args); 446c2c66affSColin Finck 447c2c66affSColin Finck return found_p1; 448c2c66affSColin Finck } 449c2c66affSColin Finck 450c2c66affSColin Finck static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR pszPath, UINT uOutSize) 451c2c66affSColin Finck { 452c2c66affSColin Finck STRRET strret; 453c2c66affSColin Finck CComPtr<IShellFolder> desktop; 454c2c66affSColin Finck 455c2c66affSColin Finck HRESULT hr = SHGetDesktopFolder(&desktop); 456c2c66affSColin Finck 457c2c66affSColin Finck if (SUCCEEDED(hr)) 458c2c66affSColin Finck { 459c2c66affSColin Finck hr = desktop->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret); 460c2c66affSColin Finck 461c2c66affSColin Finck if (SUCCEEDED(hr)) 462c2c66affSColin Finck StrRetToStrNW(pszPath, uOutSize, &strret, pidl); 463c2c66affSColin Finck } 464c2c66affSColin Finck 465c2c66affSColin Finck return hr; 466c2c66affSColin Finck } 467c2c66affSColin Finck 468c2c66affSColin Finck /************************************************************************* 469c2c66affSColin Finck * SHELL_ExecuteW [Internal] 470c2c66affSColin Finck * 471c2c66affSColin Finck */ 472c2c66affSColin Finck static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, 473c2c66affSColin Finck const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out) 474c2c66affSColin Finck { 475c2c66affSColin Finck STARTUPINFOW startup; 476c2c66affSColin Finck PROCESS_INFORMATION info; 477c2c66affSColin Finck UINT_PTR retval = SE_ERR_NOASSOC; 478c2c66affSColin Finck UINT gcdret = 0; 479c2c66affSColin Finck WCHAR curdir[MAX_PATH]; 480c2c66affSColin Finck DWORD dwCreationFlags; 481c2c66affSColin Finck const WCHAR *lpDirectory = NULL; 482c2c66affSColin Finck 483c2c66affSColin Finck TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory)); 484c2c66affSColin Finck 485c2c66affSColin Finck /* make sure we don't fail the CreateProcess if the calling app passes in 486c2c66affSColin Finck * a bad working directory */ 487724b20d4SWhindmar Saksit if (!StrIsNullOrEmpty(psei->lpDirectory)) 488c2c66affSColin Finck { 489c2c66affSColin Finck DWORD attr = GetFileAttributesW(psei->lpDirectory); 490c2c66affSColin Finck if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY) 491c2c66affSColin Finck lpDirectory = psei->lpDirectory; 492c2c66affSColin Finck } 493c2c66affSColin Finck 494c2c66affSColin Finck /* ShellExecute specifies the command from psei->lpDirectory 495c2c66affSColin Finck * if present. Not from the current dir as CreateProcess does */ 496c2c66affSColin Finck if (lpDirectory) 497c2c66affSColin Finck if ((gcdret = GetCurrentDirectoryW( MAX_PATH, curdir))) 498c2c66affSColin Finck if (!SetCurrentDirectoryW( lpDirectory)) 499c2c66affSColin Finck ERR("cannot set directory %s\n", debugstr_w(lpDirectory)); 500c2c66affSColin Finck 501c2c66affSColin Finck ZeroMemory(&startup, sizeof(STARTUPINFOW)); 502c2c66affSColin Finck startup.cb = sizeof(STARTUPINFOW); 503c2c66affSColin Finck startup.dwFlags = STARTF_USESHOWWINDOW; 504c2c66affSColin Finck startup.wShowWindow = psei->nShow; 505c2c66affSColin Finck dwCreationFlags = CREATE_UNICODE_ENVIRONMENT; 506c2c66affSColin Finck if (!(psei->fMask & SEE_MASK_NO_CONSOLE)) 507c2c66affSColin Finck dwCreationFlags |= CREATE_NEW_CONSOLE; 50851b662f9SKatayama Hirofumi MZ if (psei->fMask & SEE_MASK_FLAG_SEPVDM) 50951b662f9SKatayama Hirofumi MZ dwCreationFlags |= CREATE_SEPARATE_WOW_VDM; 510c2c66affSColin Finck startup.lpTitle = (LPWSTR)(psei->fMask & (SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE) ? psei->lpClass : NULL); 511c2c66affSColin Finck 512c2c66affSColin Finck if (psei->fMask & SEE_MASK_HASLINKNAME) 513c2c66affSColin Finck startup.dwFlags |= STARTF_TITLEISLINKNAME; 514c2c66affSColin Finck 515c2c66affSColin Finck if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env, 516c2c66affSColin Finck lpDirectory, &startup, &info)) 517c2c66affSColin Finck { 518c2c66affSColin Finck /* Give 30 seconds to the app to come up, if desired. Probably only needed 519c2c66affSColin Finck when starting app immediately before making a DDE connection. */ 520c2c66affSColin Finck if (shWait) 521c2c66affSColin Finck if (WaitForInputIdle(info.hProcess, 30000) == WAIT_FAILED) 522c2c66affSColin Finck WARN("WaitForInputIdle failed: Error %d\n", GetLastError() ); 523c2c66affSColin Finck retval = 33; 524c2c66affSColin Finck 525c2c66affSColin Finck if (psei->fMask & SEE_MASK_NOCLOSEPROCESS) 526c2c66affSColin Finck psei_out->hProcess = info.hProcess; 527c2c66affSColin Finck else 528c2c66affSColin Finck CloseHandle( info.hProcess ); 529c2c66affSColin Finck CloseHandle( info.hThread ); 530c2c66affSColin Finck } 531c2c66affSColin Finck else if ((retval = GetLastError()) >= 32) 532c2c66affSColin Finck { 533c2c66affSColin Finck WARN("CreateProcess returned error %ld\n", retval); 534c2c66affSColin Finck retval = ERROR_BAD_FORMAT; 535c2c66affSColin Finck } 536c2c66affSColin Finck 537c2c66affSColin Finck TRACE("returning %lu\n", retval); 538c2c66affSColin Finck 539c2c66affSColin Finck psei_out->hInstApp = (HINSTANCE)retval; 540c2c66affSColin Finck 541c2c66affSColin Finck if (gcdret) 542c2c66affSColin Finck if (!SetCurrentDirectoryW(curdir)) 543c2c66affSColin Finck ERR("cannot return to directory %s\n", debugstr_w(curdir)); 544c2c66affSColin Finck 545c2c66affSColin Finck return retval; 546c2c66affSColin Finck } 547c2c66affSColin Finck 548c2c66affSColin Finck 549c2c66affSColin Finck /*********************************************************************** 550c2c66affSColin Finck * SHELL_BuildEnvW [Internal] 551c2c66affSColin Finck * 552c2c66affSColin Finck * Build the environment for the new process, adding the specified 553c2c66affSColin Finck * path to the PATH variable. Returned pointer must be freed by caller. 554c2c66affSColin Finck */ 555c2c66affSColin Finck static LPWSTR SHELL_BuildEnvW( const WCHAR *path ) 556c2c66affSColin Finck { 55706b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> new_env; 55806b6833cSKatayama Hirofumi MZ WCHAR *strings, *p, *p2; 559c2c66affSColin Finck int total = wcslen(path) + 1; 560c2c66affSColin Finck BOOL got_path = FALSE; 561c2c66affSColin Finck 562c2c66affSColin Finck if (!(strings = GetEnvironmentStringsW())) return NULL; 563c2c66affSColin Finck p = strings; 564c2c66affSColin Finck while (*p) 565c2c66affSColin Finck { 566c2c66affSColin Finck int len = wcslen(p) + 1; 56783be315aSHermès Bélusca-Maïto if (!_wcsnicmp( p, L"PATH=", 5 )) got_path = TRUE; 568c2c66affSColin Finck total += len; 569c2c66affSColin Finck p += len; 570c2c66affSColin Finck } 571c2c66affSColin Finck if (!got_path) total += 5; /* we need to create PATH */ 572c2c66affSColin Finck total++; /* terminating null */ 573c2c66affSColin Finck 57406b6833cSKatayama Hirofumi MZ if (!new_env.Allocate(total)) 575c2c66affSColin Finck { 576c2c66affSColin Finck FreeEnvironmentStringsW(strings); 577c2c66affSColin Finck return NULL; 578c2c66affSColin Finck } 579c2c66affSColin Finck p = strings; 580c2c66affSColin Finck p2 = new_env; 581c2c66affSColin Finck while (*p) 582c2c66affSColin Finck { 583c2c66affSColin Finck int len = wcslen(p) + 1; 584c2c66affSColin Finck memcpy(p2, p, len * sizeof(WCHAR)); 58583be315aSHermès Bélusca-Maïto if (!_wcsnicmp( p, L"PATH=", 5 )) 586c2c66affSColin Finck { 587c2c66affSColin Finck p2[len - 1] = ';'; 588c2c66affSColin Finck wcscpy( p2 + len, path ); 589c2c66affSColin Finck p2 += wcslen(path) + 1; 590c2c66affSColin Finck } 591c2c66affSColin Finck p += len; 592c2c66affSColin Finck p2 += len; 593c2c66affSColin Finck } 594c2c66affSColin Finck if (!got_path) 595c2c66affSColin Finck { 59683be315aSHermès Bélusca-Maïto wcscpy(p2, L"PATH="); 597c2c66affSColin Finck wcscat(p2, path); 598c2c66affSColin Finck p2 += wcslen(p2) + 1; 599c2c66affSColin Finck } 600c2c66affSColin Finck *p2 = 0; 601c2c66affSColin Finck FreeEnvironmentStringsW(strings); 60206b6833cSKatayama Hirofumi MZ return new_env.Detach(); 603c2c66affSColin Finck } 604c2c66affSColin Finck 605c2c66affSColin Finck /*********************************************************************** 606c2c66affSColin Finck * SHELL_TryAppPathW [Internal] 607c2c66affSColin Finck * 608c2c66affSColin Finck * Helper function for SHELL_FindExecutable 609c2c66affSColin Finck * @param lpResult - pointer to a buffer of size MAX_PATH 610c2c66affSColin Finck * On entry: szName is a filename (probably without path separators). 611c2c66affSColin Finck * On exit: if szName found in "App Path", place full path in lpResult, and return true 612c2c66affSColin Finck */ 613c2c66affSColin Finck static BOOL SHELL_TryAppPathW( LPCWSTR szName, LPWSTR lpResult, WCHAR **env) 614c2c66affSColin Finck { 615140aa11cSKatayama Hirofumi MZ HKEY hkApp = NULL; 616c2c66affSColin Finck WCHAR buffer[1024]; 617140aa11cSKatayama Hirofumi MZ DWORD len, dwType; 618c2c66affSColin Finck LONG res; 619c2c66affSColin Finck BOOL found = FALSE; 620c2c66affSColin Finck 621c2c66affSColin Finck if (env) *env = NULL; 622c2c66affSColin Finck wcscpy(buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"); 623c2c66affSColin Finck wcscat(buffer, szName); 624c2c66affSColin Finck res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp); 625c2c66affSColin Finck if (res) 626c2c66affSColin Finck { 627c2c66affSColin Finck // Add ".exe" extension, if extension does not exists 62883be315aSHermès Bélusca-Maïto if (PathAddExtensionW(buffer, L".exe")) 629c2c66affSColin Finck { 630c2c66affSColin Finck res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp); 631c2c66affSColin Finck } 632c2c66affSColin Finck if (res) goto end; 633c2c66affSColin Finck } 634c2c66affSColin Finck 635c2c66affSColin Finck len = MAX_PATH * sizeof(WCHAR); 636140aa11cSKatayama Hirofumi MZ res = SHRegQueryValueExW(hkApp, NULL, NULL, &dwType, (LPBYTE)lpResult, &len); 637140aa11cSKatayama Hirofumi MZ if (res != ERROR_SUCCESS || dwType != REG_SZ) 638140aa11cSKatayama Hirofumi MZ goto end; 639140aa11cSKatayama Hirofumi MZ 640c2c66affSColin Finck found = TRUE; 641c2c66affSColin Finck 642c2c66affSColin Finck if (env) 643c2c66affSColin Finck { 644140aa11cSKatayama Hirofumi MZ len = sizeof(buffer); 645140aa11cSKatayama Hirofumi MZ res = SHRegQueryValueExW(hkApp, L"Path", NULL, &dwType, (LPBYTE)buffer, &len); 646140aa11cSKatayama Hirofumi MZ if (res == ERROR_SUCCESS && dwType == REG_SZ && buffer[0]) 647c2c66affSColin Finck *env = SHELL_BuildEnvW(buffer); 648c2c66affSColin Finck } 649c2c66affSColin Finck 650c2c66affSColin Finck end: 651c2c66affSColin Finck if (hkApp) RegCloseKey(hkApp); 652c2c66affSColin Finck return found; 653c2c66affSColin Finck } 654c2c66affSColin Finck 655c2c66affSColin Finck /************************************************************************* 656c2c66affSColin Finck * SHELL_FindExecutableByVerb [Internal] 657c2c66affSColin Finck * 658c2c66affSColin Finck * called from SHELL_FindExecutable or SHELL_execute_class 659c2c66affSColin Finck * in/out: 660c2c66affSColin Finck * classname a buffer, big enough, to get the key name to do actually the 661c2c66affSColin Finck * command "WordPad.Document.1\\shell\\open\\command" 662c2c66affSColin Finck * passed as "WordPad.Document.1" 663c2c66affSColin Finck * in: 664c2c66affSColin Finck * lpVerb the operation on it (open) 665c2c66affSColin Finck * commandlen the size of command buffer (in bytes) 666c2c66affSColin Finck * out: 667c2c66affSColin Finck * command a buffer, to store the command to do the 668c2c66affSColin Finck * operation on the file 669c2c66affSColin Finck * key a buffer, big enough, to get the key name to do actually the 670c2c66affSColin Finck * command "WordPad.Document.1\\shell\\open\\command" 671c2c66affSColin Finck * Can be NULL 672c2c66affSColin Finck */ 673c2c66affSColin Finck static UINT SHELL_FindExecutableByVerb(LPCWSTR lpVerb, LPWSTR key, LPWSTR classname, LPWSTR command, LONG commandlen) 674c2c66affSColin Finck { 675c2c66affSColin Finck HKEY hkeyClass; 676c2c66affSColin Finck WCHAR verb[MAX_PATH]; 677c2c66affSColin Finck 678c2c66affSColin Finck if (RegOpenKeyExW(HKEY_CLASSES_ROOT, classname, 0, 0x02000000, &hkeyClass)) 679c2c66affSColin Finck return SE_ERR_NOASSOC; 68083be315aSHermès Bélusca-Maïto if (!HCR_GetDefaultVerbW(hkeyClass, lpVerb, verb, ARRAY_SIZE(verb))) 681c2c66affSColin Finck return SE_ERR_NOASSOC; 682c2c66affSColin Finck RegCloseKey(hkeyClass); 683c2c66affSColin Finck 684c2c66affSColin Finck /* Looking for ...buffer\shell\<verb>\command */ 685c2c66affSColin Finck wcscat(classname, L"\\shell\\"); 686c2c66affSColin Finck wcscat(classname, verb); 68783be315aSHermès Bélusca-Maïto wcscat(classname, L"\\command"); 688c2c66affSColin Finck 689c2c66affSColin Finck if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, command, 690c2c66affSColin Finck &commandlen) == ERROR_SUCCESS) 691c2c66affSColin Finck { 692c2c66affSColin Finck commandlen /= sizeof(WCHAR); 693c2c66affSColin Finck if (key) wcscpy(key, classname); 694c2c66affSColin Finck #if 0 695c2c66affSColin Finck LPWSTR tmp; 696c2c66affSColin Finck WCHAR param[256]; 697c2c66affSColin Finck LONG paramlen = sizeof(param); 698c2c66affSColin Finck 699c2c66affSColin Finck /* FIXME: it seems all Windows version don't behave the same here. 700c2c66affSColin Finck * the doc states that this ddeexec information can be found after 701c2c66affSColin Finck * the exec names. 702c2c66affSColin Finck * on Win98, it doesn't appear, but I think it does on Win2k 703c2c66affSColin Finck */ 704c2c66affSColin Finck /* Get the parameters needed by the application 705c2c66affSColin Finck from the associated ddeexec key */ 70683be315aSHermès Bélusca-Maïto tmp = strstrW(classname, L"\\command"); 707c2c66affSColin Finck tmp[0] = '\0'; 708c2c66affSColin Finck wcscat(classname, wDdeexec); 709c2c66affSColin Finck if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, param, 710c2c66affSColin Finck ¶mlen) == ERROR_SUCCESS) 711c2c66affSColin Finck { 712c2c66affSColin Finck paramlen /= sizeof(WCHAR); 71383be315aSHermès Bélusca-Maïto wcscat(command, L" "); 714c2c66affSColin Finck wcscat(command, param); 715c2c66affSColin Finck commandlen += paramlen; 716c2c66affSColin Finck } 717c2c66affSColin Finck #endif 718c2c66affSColin Finck 719c2c66affSColin Finck command[commandlen] = '\0'; 720c2c66affSColin Finck 721c2c66affSColin Finck return 33; /* FIXME see SHELL_FindExecutable() */ 722c2c66affSColin Finck } 723c2c66affSColin Finck 724c2c66affSColin Finck return SE_ERR_NOASSOC; 725c2c66affSColin Finck } 726c2c66affSColin Finck 727c2c66affSColin Finck /************************************************************************* 728c2c66affSColin Finck * SHELL_FindExecutable [Internal] 729c2c66affSColin Finck * 730c2c66affSColin Finck * Utility for code sharing between FindExecutable and ShellExecute 731c2c66affSColin Finck * in: 732c2c66affSColin Finck * lpFile the name of a file 733c2c66affSColin Finck * lpVerb the operation on it (open) 734c2c66affSColin Finck * out: 735c2c66affSColin Finck * lpResult a buffer, big enough :-(, to store the command to do the 736c2c66affSColin Finck * operation on the file 737c2c66affSColin Finck * key a buffer, big enough, to get the key name to do actually the 738c2c66affSColin Finck * command (it'll be used afterwards for more information 739c2c66affSColin Finck * on the operation) 740c2c66affSColin Finck */ 741c2c66affSColin Finck static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, 742c2c66affSColin Finck LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args) 743c2c66affSColin Finck { 744c2c66affSColin Finck WCHAR *extension = NULL; /* pointer to file extension */ 745c2c66affSColin Finck WCHAR classname[256]; /* registry name for this file type */ 746c2c66affSColin Finck LONG classnamelen = sizeof(classname); /* length of above */ 747c2c66affSColin Finck WCHAR command[1024]; /* command from registry */ 748c2c66affSColin Finck WCHAR wBuffer[256]; /* Used to GetProfileString */ 749c2c66affSColin Finck UINT retval = SE_ERR_NOASSOC; 750c2c66affSColin Finck WCHAR *tok; /* token pointer */ 75142d5dfd3SOleg Dubinskiy WCHAR xlpFile[MAX_PATH]; /* result of SearchPath */ 752c2c66affSColin Finck DWORD attribs; /* file attributes */ 75342d5dfd3SOleg Dubinskiy WCHAR curdir[MAX_PATH]; 75442d5dfd3SOleg Dubinskiy const WCHAR *search_paths[3] = {0}; 755c2c66affSColin Finck 756c2c66affSColin Finck TRACE("%s\n", debugstr_w(lpFile)); 757c2c66affSColin Finck 758c2c66affSColin Finck if (!lpResult) 759c2c66affSColin Finck return ERROR_INVALID_PARAMETER; 760c2c66affSColin Finck 761c2c66affSColin Finck xlpFile[0] = '\0'; 762c2c66affSColin Finck lpResult[0] = '\0'; /* Start off with an empty return string */ 763c2c66affSColin Finck if (key) *key = '\0'; 764c2c66affSColin Finck 765c2c66affSColin Finck /* trap NULL parameters on entry */ 766c2c66affSColin Finck if (!lpFile) 767c2c66affSColin Finck { 768c2c66affSColin Finck WARN("(lpFile=%s,lpResult=%s): NULL parameter\n", 769c2c66affSColin Finck debugstr_w(lpFile), debugstr_w(lpResult)); 770c2c66affSColin Finck return ERROR_FILE_NOT_FOUND; /* File not found. Close enough, I guess. */ 771c2c66affSColin Finck } 772c2c66affSColin Finck 773c2c66affSColin Finck if (SHELL_TryAppPathW( lpFile, lpResult, env )) 774c2c66affSColin Finck { 775c2c66affSColin Finck TRACE("found %s via App Paths\n", debugstr_w(lpResult)); 776c2c66affSColin Finck return 33; 777c2c66affSColin Finck } 778c2c66affSColin Finck 77942d5dfd3SOleg Dubinskiy GetCurrentDirectoryW(ARRAY_SIZE(curdir), curdir); 78042d5dfd3SOleg Dubinskiy if (!PathIsFileSpecW(lpFile)) 781c2c66affSColin Finck { 78242d5dfd3SOleg Dubinskiy BOOL found = FALSE; 78342d5dfd3SOleg Dubinskiy if (lpPath && *lpPath) 78442d5dfd3SOleg Dubinskiy { 78542d5dfd3SOleg Dubinskiy TRACE("lpPath %s\n", debugstr_w(lpPath)); 78642d5dfd3SOleg Dubinskiy PathCombineW(xlpFile, lpPath, lpFile); 78742d5dfd3SOleg Dubinskiy if (PathFileExistsDefExtW(xlpFile, WHICH_DEFAULT | WHICH_OPTIONAL) || PathFileExistsW(xlpFile)) 78842d5dfd3SOleg Dubinskiy { 78942d5dfd3SOleg Dubinskiy GetFullPathNameW(xlpFile, ARRAY_SIZE(xlpFile), xlpFile, NULL); 79042d5dfd3SOleg Dubinskiy found = TRUE; 791c2c66affSColin Finck } 79242d5dfd3SOleg Dubinskiy } 79342d5dfd3SOleg Dubinskiy if (!found) 794c2c66affSColin Finck { 79542d5dfd3SOleg Dubinskiy lstrcpyW(xlpFile, lpFile); 79642d5dfd3SOleg Dubinskiy if (PathFileExistsDefExtW(xlpFile, WHICH_DEFAULT | WHICH_OPTIONAL) || PathFileExistsW(xlpFile)) 79742d5dfd3SOleg Dubinskiy { 79842d5dfd3SOleg Dubinskiy GetFullPathNameW(xlpFile, ARRAY_SIZE(xlpFile), xlpFile, NULL); 79942d5dfd3SOleg Dubinskiy found = TRUE; 80042d5dfd3SOleg Dubinskiy } 80142d5dfd3SOleg Dubinskiy } 80242d5dfd3SOleg Dubinskiy if (found) 80342d5dfd3SOleg Dubinskiy { 804c2c66affSColin Finck lpFile = xlpFile; 80542d5dfd3SOleg Dubinskiy lstrcpyW(lpResult, xlpFile); 80642d5dfd3SOleg Dubinskiy } 80742d5dfd3SOleg Dubinskiy else 80842d5dfd3SOleg Dubinskiy xlpFile[0] = '\0'; 80942d5dfd3SOleg Dubinskiy } 81042d5dfd3SOleg Dubinskiy else 81142d5dfd3SOleg Dubinskiy { 81242d5dfd3SOleg Dubinskiy if (lpPath && *lpPath) 81342d5dfd3SOleg Dubinskiy { 81442d5dfd3SOleg Dubinskiy search_paths[0] = lpPath; 81542d5dfd3SOleg Dubinskiy search_paths[1] = curdir; 81642d5dfd3SOleg Dubinskiy } 81742d5dfd3SOleg Dubinskiy else 81842d5dfd3SOleg Dubinskiy search_paths[0] = curdir; 81942d5dfd3SOleg Dubinskiy lstrcpyW(xlpFile, lpFile); 82042d5dfd3SOleg Dubinskiy if (PathResolveW(xlpFile, search_paths, PRF_TRYPROGRAMEXTENSIONS | PRF_VERIFYEXISTS)) 82142d5dfd3SOleg Dubinskiy { 82242d5dfd3SOleg Dubinskiy TRACE("PathResolveW returned non-zero\n"); 82342d5dfd3SOleg Dubinskiy lpFile = xlpFile; 82442d5dfd3SOleg Dubinskiy lstrcpyW(lpResult, xlpFile); 82542d5dfd3SOleg Dubinskiy /* The file was found in lpPath or one of the directories in the system-wide search path */ 82642d5dfd3SOleg Dubinskiy } 82742d5dfd3SOleg Dubinskiy else 82842d5dfd3SOleg Dubinskiy xlpFile[0] = '\0'; 829c2c66affSColin Finck } 830c2c66affSColin Finck 831c2c66affSColin Finck attribs = GetFileAttributesW(lpFile); 832c2c66affSColin Finck if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY)) 833c2c66affSColin Finck { 834c2c66affSColin Finck wcscpy(classname, L"Folder"); 835c2c66affSColin Finck } 836c2c66affSColin Finck else 837c2c66affSColin Finck { 838c2c66affSColin Finck /* Did we get something? Anything? */ 839c2c66affSColin Finck if (xlpFile[0] == 0) 840c2c66affSColin Finck { 841c2c66affSColin Finck TRACE("Returning SE_ERR_FNF\n"); 842c2c66affSColin Finck return SE_ERR_FNF; 843c2c66affSColin Finck } 844c2c66affSColin Finck /* First thing we need is the file's extension */ 845c2c66affSColin Finck extension = wcsrchr(xlpFile, '.'); /* Assume last "." is the one; */ 846c2c66affSColin Finck /* File->Run in progman uses */ 847c2c66affSColin Finck /* .\FILE.EXE :( */ 848c2c66affSColin Finck TRACE("xlpFile=%s,extension=%s\n", debugstr_w(xlpFile), debugstr_w(extension)); 849c2c66affSColin Finck 850c2c66affSColin Finck if (extension == NULL || extension[1] == 0) 851c2c66affSColin Finck { 852c2c66affSColin Finck WARN("Returning SE_ERR_NOASSOC\n"); 853c2c66affSColin Finck return SE_ERR_NOASSOC; 854c2c66affSColin Finck } 855c2c66affSColin Finck 856c2c66affSColin Finck /* Three places to check: */ 857c2c66affSColin Finck /* 1. win.ini, [windows], programs (NB no leading '.') */ 858c2c66affSColin Finck /* 2. Registry, HKEY_CLASS_ROOT\<classname>\shell\open\command */ 859c2c66affSColin Finck /* 3. win.ini, [extensions], extension (NB no leading '.' */ 860c2c66affSColin Finck /* All I know of the order is that registry is checked before */ 861c2c66affSColin Finck /* extensions; however, it'd make sense to check the programs */ 862c2c66affSColin Finck /* section first, so that's what happens here. */ 863c2c66affSColin Finck 864c2c66affSColin Finck /* See if it's a program - if GetProfileString fails, we skip this 865c2c66affSColin Finck * section. Actually, if GetProfileString fails, we've probably 866c2c66affSColin Finck * got a lot more to worry about than running a program... */ 86783be315aSHermès Bélusca-Maïto if (GetProfileStringW(L"windows", L"programs", L"exe pif bat cmd com", wBuffer, ARRAY_SIZE(wBuffer)) > 0) 868c2c66affSColin Finck { 869c2c66affSColin Finck CharLowerW(wBuffer); 870c2c66affSColin Finck tok = wBuffer; 871c2c66affSColin Finck while (*tok) 872c2c66affSColin Finck { 873c2c66affSColin Finck WCHAR *p = tok; 874c2c66affSColin Finck while (*p && *p != ' ' && *p != '\t') p++; 875c2c66affSColin Finck if (*p) 876c2c66affSColin Finck { 877c2c66affSColin Finck *p++ = 0; 878c2c66affSColin Finck while (*p == ' ' || *p == '\t') p++; 879c2c66affSColin Finck } 880c2c66affSColin Finck 881e4930be4STimo Kreuzer if (_wcsicmp(tok, &extension[1]) == 0) /* have to skip the leading "." */ 882c2c66affSColin Finck { 883c2c66affSColin Finck wcscpy(lpResult, xlpFile); 884c2c66affSColin Finck /* Need to perhaps check that the file has a path 885c2c66affSColin Finck * attached */ 886c2c66affSColin Finck TRACE("found %s\n", debugstr_w(lpResult)); 887c2c66affSColin Finck return 33; 888c2c66affSColin Finck /* Greater than 32 to indicate success */ 889c2c66affSColin Finck } 890c2c66affSColin Finck tok = p; 891c2c66affSColin Finck } 892c2c66affSColin Finck } 893c2c66affSColin Finck 894c2c66affSColin Finck /* Check registry */ 895c2c66affSColin Finck if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, classname, 896c2c66affSColin Finck &classnamelen) == ERROR_SUCCESS) 897c2c66affSColin Finck { 898c2c66affSColin Finck classnamelen /= sizeof(WCHAR); 89983be315aSHermès Bélusca-Maïto if (classnamelen == ARRAY_SIZE(classname)) 900c2c66affSColin Finck classnamelen--; 901c2c66affSColin Finck 902c2c66affSColin Finck classname[classnamelen] = '\0'; 903c2c66affSColin Finck TRACE("File type: %s\n", debugstr_w(classname)); 904c2c66affSColin Finck } 905c2c66affSColin Finck else 906c2c66affSColin Finck { 907c2c66affSColin Finck *classname = '\0'; 908c2c66affSColin Finck } 909c2c66affSColin Finck } 910c2c66affSColin Finck 911c2c66affSColin Finck if (*classname) 912c2c66affSColin Finck { 913c2c66affSColin Finck /* pass the verb string to SHELL_FindExecutableByVerb() */ 914c2c66affSColin Finck retval = SHELL_FindExecutableByVerb(lpVerb, key, classname, command, sizeof(command)); 915c2c66affSColin Finck 916c2c66affSColin Finck if (retval > 32) 917c2c66affSColin Finck { 918c2c66affSColin Finck DWORD finishedLen; 919e018cceaSKatayama Hirofumi MZ SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen, lpPath); 920c2c66affSColin Finck if (finishedLen > resultLen) 921c2c66affSColin Finck ERR("Argify buffer not large enough.. truncated\n"); 922c2c66affSColin Finck /* Remove double quotation marks and command line arguments */ 923c2c66affSColin Finck if (*lpResult == '"') 924c2c66affSColin Finck { 925c2c66affSColin Finck WCHAR *p = lpResult; 926c2c66affSColin Finck while (*(p + 1) != '"') 927c2c66affSColin Finck { 928c2c66affSColin Finck *p = *(p + 1); 929c2c66affSColin Finck p++; 930c2c66affSColin Finck } 931c2c66affSColin Finck *p = '\0'; 932c2c66affSColin Finck } 933c2c66affSColin Finck else 934c2c66affSColin Finck { 935c2c66affSColin Finck /* Truncate on first space */ 936c2c66affSColin Finck WCHAR *p = lpResult; 937c2c66affSColin Finck while (*p != ' ' && *p != '\0') 938c2c66affSColin Finck p++; 939c2c66affSColin Finck *p = '\0'; 940c2c66affSColin Finck } 941c2c66affSColin Finck } 942c2c66affSColin Finck } 943c2c66affSColin Finck else /* Check win.ini */ 944c2c66affSColin Finck { 945c2c66affSColin Finck /* Toss the leading dot */ 946c2c66affSColin Finck extension++; 94783be315aSHermès Bélusca-Maïto if (GetProfileStringW(L"extensions", extension, L"", command, ARRAY_SIZE(command)) > 0) 948c2c66affSColin Finck { 949c2c66affSColin Finck if (wcslen(command) != 0) 950c2c66affSColin Finck { 951c2c66affSColin Finck wcscpy(lpResult, command); 952c2c66affSColin Finck tok = wcschr(lpResult, '^'); /* should be ^.extension? */ 953c2c66affSColin Finck if (tok != NULL) 954c2c66affSColin Finck { 955c2c66affSColin Finck tok[0] = '\0'; 956c2c66affSColin Finck wcscat(lpResult, xlpFile); /* what if no dir in xlpFile? */ 957c2c66affSColin Finck tok = wcschr(command, '^'); /* see above */ 958c2c66affSColin Finck if ((tok != NULL) && (wcslen(tok) > 5)) 959c2c66affSColin Finck { 960c2c66affSColin Finck wcscat(lpResult, &tok[5]); 961c2c66affSColin Finck } 962c2c66affSColin Finck } 963c2c66affSColin Finck retval = 33; /* FIXME - see above */ 964c2c66affSColin Finck } 965c2c66affSColin Finck } 966c2c66affSColin Finck } 967c2c66affSColin Finck 96842d5dfd3SOleg Dubinskiy TRACE("returning path %s, retval %d\n", debugstr_w(lpResult), retval); 969c2c66affSColin Finck return retval; 970c2c66affSColin Finck } 971c2c66affSColin Finck 972c2c66affSColin Finck /****************************************************************** 973c2c66affSColin Finck * dde_cb 974c2c66affSColin Finck * 975c2c66affSColin Finck * callback for the DDE connection. not really useful 976c2c66affSColin Finck */ 977c2c66affSColin Finck static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv, 978c2c66affSColin Finck HSZ hsz1, HSZ hsz2, HDDEDATA hData, 979c2c66affSColin Finck ULONG_PTR dwData1, ULONG_PTR dwData2) 980c2c66affSColin Finck { 981c2c66affSColin Finck TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n", 982c2c66affSColin Finck uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2); 983c2c66affSColin Finck return NULL; 984c2c66affSColin Finck } 985c2c66affSColin Finck 986c2c66affSColin Finck /****************************************************************** 987c2c66affSColin Finck * dde_connect 988c2c66affSColin Finck * 989c2c66affSColin Finck * ShellExecute helper. Used to do an operation with a DDE connection 990c2c66affSColin Finck * 991c2c66affSColin Finck * Handles both the direct connection (try #1), and if it fails, 992c2c66affSColin Finck * launching an application and trying (#2) to connect to it 993c2c66affSColin Finck * 994c2c66affSColin Finck */ 995c2c66affSColin Finck static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec, 996c2c66affSColin Finck const WCHAR* lpFile, WCHAR *env, 997c2c66affSColin Finck LPCWSTR szCommandline, LPITEMIDLIST pidl, SHELL_ExecuteW32 execfunc, 998c2c66affSColin Finck const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out) 999c2c66affSColin Finck { 1000c2c66affSColin Finck WCHAR regkey[256]; 1001c2c66affSColin Finck WCHAR * endkey = regkey + wcslen(key); 1002c2c66affSColin Finck WCHAR app[256], topic[256], ifexec[256], static_res[256]; 100306b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> dynamic_res; 1004c2c66affSColin Finck WCHAR * res; 1005c2c66affSColin Finck LONG applen, topiclen, ifexeclen; 1006c2c66affSColin Finck WCHAR * exec; 1007c2c66affSColin Finck DWORD ddeInst = 0; 1008c2c66affSColin Finck DWORD tid; 1009c2c66affSColin Finck DWORD resultLen, endkeyLen; 1010c2c66affSColin Finck HSZ hszApp, hszTopic; 1011c2c66affSColin Finck HCONV hConv; 1012c2c66affSColin Finck HDDEDATA hDdeData; 1013c2c66affSColin Finck unsigned ret = SE_ERR_NOASSOC; 1014c2c66affSColin Finck BOOL unicode = !(GetVersion() & 0x80000000); 1015c2c66affSColin Finck 101683be315aSHermès Bélusca-Maïto if (strlenW(key) + 1 > ARRAY_SIZE(regkey)) 1017c2c66affSColin Finck { 1018c2c66affSColin Finck FIXME("input parameter %s larger than buffer\n", debugstr_w(key)); 1019c2c66affSColin Finck return 2; 1020c2c66affSColin Finck } 1021c2c66affSColin Finck wcscpy(regkey, key); 102283be315aSHermès Bélusca-Maïto endkeyLen = ARRAY_SIZE(regkey) - (endkey - regkey); 102383be315aSHermès Bélusca-Maïto if (strlenW(L"\\application") + 1 > endkeyLen) 1024c2c66affSColin Finck { 102583be315aSHermès Bélusca-Maïto FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\application")); 1026c2c66affSColin Finck return 2; 1027c2c66affSColin Finck } 102883be315aSHermès Bélusca-Maïto wcscpy(endkey, L"\\application"); 1029c2c66affSColin Finck applen = sizeof(app); 1030c2c66affSColin Finck if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, app, &applen) != ERROR_SUCCESS) 1031c2c66affSColin Finck { 1032c2c66affSColin Finck WCHAR command[1024], fullpath[MAX_PATH]; 1033c2c66affSColin Finck LPWSTR ptr = NULL; 1034c2c66affSColin Finck DWORD ret = 0; 1035c2c66affSColin Finck 1036c2c66affSColin Finck /* Get application command from start string and find filename of application */ 1037c2c66affSColin Finck if (*start == '"') 1038c2c66affSColin Finck { 103983be315aSHermès Bélusca-Maïto if (strlenW(start + 1) + 1 > ARRAY_SIZE(command)) 1040c2c66affSColin Finck { 1041c2c66affSColin Finck FIXME("size of input parameter %s larger than buffer\n", 1042c2c66affSColin Finck debugstr_w(start + 1)); 1043c2c66affSColin Finck return 2; 1044c2c66affSColin Finck } 1045c2c66affSColin Finck wcscpy(command, start + 1); 1046c2c66affSColin Finck if ((ptr = wcschr(command, '"'))) 1047c2c66affSColin Finck * ptr = 0; 104883be315aSHermès Bélusca-Maïto ret = SearchPathW(NULL, command, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr); 1049c2c66affSColin Finck } 1050c2c66affSColin Finck else 1051c2c66affSColin Finck { 1052c2c66affSColin Finck LPCWSTR p; 1053c2c66affSColin Finck LPWSTR space; 1054c2c66affSColin Finck for (p = start; (space = const_cast<LPWSTR>(strchrW(p, ' '))); p = space + 1) 1055c2c66affSColin Finck { 1056c2c66affSColin Finck int idx = space - start; 1057c2c66affSColin Finck memcpy(command, start, idx * sizeof(WCHAR)); 1058c2c66affSColin Finck command[idx] = '\0'; 105983be315aSHermès Bélusca-Maïto if ((ret = SearchPathW(NULL, command, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr))) 1060c2c66affSColin Finck break; 1061c2c66affSColin Finck } 1062c2c66affSColin Finck if (!ret) 106383be315aSHermès Bélusca-Maïto ret = SearchPathW(NULL, start, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr); 1064c2c66affSColin Finck } 1065c2c66affSColin Finck 1066c2c66affSColin Finck if (!ret) 1067c2c66affSColin Finck { 1068c2c66affSColin Finck ERR("Unable to find application path for command %s\n", debugstr_w(start)); 1069c2c66affSColin Finck return ERROR_ACCESS_DENIED; 1070c2c66affSColin Finck } 107183be315aSHermès Bélusca-Maïto if (strlenW(ptr) + 1 > ARRAY_SIZE(app)) 1072c2c66affSColin Finck { 1073c2c66affSColin Finck FIXME("size of found path %s larger than buffer\n", debugstr_w(ptr)); 1074c2c66affSColin Finck return 2; 1075c2c66affSColin Finck } 1076c2c66affSColin Finck wcscpy(app, ptr); 1077c2c66affSColin Finck 1078c2c66affSColin Finck /* Remove extensions (including .so) */ 107983be315aSHermès Bélusca-Maïto ptr = app + wcslen(app) - 3; 108083be315aSHermès Bélusca-Maïto if (ptr > app && !wcscmp(ptr, L".so")) 1081c2c66affSColin Finck *ptr = 0; 1082c2c66affSColin Finck 1083c2c66affSColin Finck ptr = const_cast<LPWSTR>(strrchrW(app, '.')); 1084c2c66affSColin Finck assert(ptr); 1085c2c66affSColin Finck *ptr = 0; 1086c2c66affSColin Finck } 1087c2c66affSColin Finck 108883be315aSHermès Bélusca-Maïto if (strlenW(L"\\topic") + 1 > endkeyLen) 1089c2c66affSColin Finck { 109083be315aSHermès Bélusca-Maïto FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\topic")); 1091c2c66affSColin Finck return 2; 1092c2c66affSColin Finck } 109383be315aSHermès Bélusca-Maïto wcscpy(endkey, L"\\topic"); 1094c2c66affSColin Finck topiclen = sizeof(topic); 1095c2c66affSColin Finck if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, topic, &topiclen) != ERROR_SUCCESS) 1096c2c66affSColin Finck { 1097c2c66affSColin Finck wcscpy(topic, L"System"); 1098c2c66affSColin Finck } 1099c2c66affSColin Finck 1100c2c66affSColin Finck if (unicode) 1101c2c66affSColin Finck { 1102c2c66affSColin Finck if (DdeInitializeW(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR) 1103c2c66affSColin Finck return 2; 1104c2c66affSColin Finck } 1105c2c66affSColin Finck else 1106c2c66affSColin Finck { 1107c2c66affSColin Finck if (DdeInitializeA(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR) 1108c2c66affSColin Finck return 2; 1109c2c66affSColin Finck } 1110c2c66affSColin Finck 1111c2c66affSColin Finck hszApp = DdeCreateStringHandleW(ddeInst, app, CP_WINUNICODE); 1112c2c66affSColin Finck hszTopic = DdeCreateStringHandleW(ddeInst, topic, CP_WINUNICODE); 1113c2c66affSColin Finck 1114c2c66affSColin Finck hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL); 1115c2c66affSColin Finck exec = ddeexec; 1116c2c66affSColin Finck if (!hConv) 1117c2c66affSColin Finck { 1118c2c66affSColin Finck TRACE("Launching %s\n", debugstr_w(start)); 1119c2c66affSColin Finck ret = execfunc(start, env, TRUE, psei, psei_out); 1120c2c66affSColin Finck if (ret <= 32) 1121c2c66affSColin Finck { 1122c2c66affSColin Finck TRACE("Couldn't launch\n"); 1123c2c66affSColin Finck goto error; 1124c2c66affSColin Finck } 11254e721f78SDoug Lyons /* if ddeexec is NULL, then we just need to exit here */ 11264e721f78SDoug Lyons if (ddeexec == NULL) 11274e721f78SDoug Lyons { 11284e721f78SDoug Lyons TRACE("Exiting because ddeexec is NULL. ret=42.\n"); 11294e721f78SDoug Lyons /* See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew */ 11304e721f78SDoug Lyons /* for reason why we use 42 here and also "Shell32_apitest ShellExecuteW" regression test */ 11314e721f78SDoug Lyons return 42; 11324e721f78SDoug Lyons } 11334e721f78SDoug Lyons /* if ddeexec is 'empty string', then we just need to exit here */ 11344e721f78SDoug Lyons if (wcscmp(ddeexec, L"") == 0) 11354e721f78SDoug Lyons { 11364e721f78SDoug Lyons TRACE("Exiting because ddeexec is 'empty string'. ret=42.\n"); 11374e721f78SDoug Lyons /* See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew */ 11384e721f78SDoug Lyons /* for reason why we use 42 here and also "Shell32_apitest ShellExecuteW" regression test */ 11394e721f78SDoug Lyons return 42; 11404e721f78SDoug Lyons } 1141c2c66affSColin Finck hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL); 1142c2c66affSColin Finck if (!hConv) 1143c2c66affSColin Finck { 1144c2c66affSColin Finck TRACE("Couldn't connect. ret=%d\n", ret); 1145c2c66affSColin Finck DdeUninitialize(ddeInst); 1146c2c66affSColin Finck SetLastError(ERROR_DDE_FAIL); 1147c2c66affSColin Finck return 30; /* whatever */ 1148c2c66affSColin Finck } 114983be315aSHermès Bélusca-Maïto if (strlenW(L"\\ifexec") + 1 > endkeyLen) 1150c2c66affSColin Finck { 115183be315aSHermès Bélusca-Maïto FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\ifexec")); 1152c2c66affSColin Finck return 2; 1153c2c66affSColin Finck } 115483be315aSHermès Bélusca-Maïto strcpyW(endkey, L"\\ifexec"); 1155c2c66affSColin Finck ifexeclen = sizeof(ifexec); 1156c2c66affSColin Finck if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, ifexec, &ifexeclen) == ERROR_SUCCESS) 1157c2c66affSColin Finck { 1158c2c66affSColin Finck exec = ifexec; 1159c2c66affSColin Finck } 1160c2c66affSColin Finck } 1161c2c66affSColin Finck 116283be315aSHermès Bélusca-Maïto SHELL_ArgifyW(static_res, ARRAY_SIZE(static_res), exec, lpFile, pidl, szCommandline, &resultLen, NULL); 116383be315aSHermès Bélusca-Maïto if (resultLen > ARRAY_SIZE(static_res)) 1164c2c66affSColin Finck { 116506b6833cSKatayama Hirofumi MZ dynamic_res.Allocate(resultLen); 116606b6833cSKatayama Hirofumi MZ res = dynamic_res; 1167e018cceaSKatayama Hirofumi MZ SHELL_ArgifyW(dynamic_res, resultLen, exec, lpFile, pidl, szCommandline, NULL, NULL); 1168c2c66affSColin Finck } 1169c2c66affSColin Finck else 1170c2c66affSColin Finck res = static_res; 1171c2c66affSColin Finck TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res)); 1172c2c66affSColin Finck 1173c2c66affSColin Finck /* It's documented in the KB 330337 that IE has a bug and returns 1174c2c66affSColin Finck * error DMLERR_NOTPROCESSED on XTYP_EXECUTE request. 1175c2c66affSColin Finck */ 1176c2c66affSColin Finck if (unicode) 1177c2c66affSColin Finck hDdeData = DdeClientTransaction((LPBYTE)res, (strlenW(res) + 1) * sizeof(WCHAR), hConv, 0L, 0, XTYP_EXECUTE, 30000, &tid); 1178c2c66affSColin Finck else 1179c2c66affSColin Finck { 1180c2c66affSColin Finck DWORD lenA = WideCharToMultiByte(CP_ACP, 0, res, -1, NULL, 0, NULL, NULL); 118106b6833cSKatayama Hirofumi MZ CHeapPtr<char, CLocalAllocator> resA; 118206b6833cSKatayama Hirofumi MZ resA.Allocate(lenA); 1183c2c66affSColin Finck WideCharToMultiByte(CP_ACP, 0, res, -1, resA, lenA, NULL, NULL); 118406b6833cSKatayama Hirofumi MZ hDdeData = DdeClientTransaction( (LPBYTE)(LPSTR)resA, lenA, hConv, 0L, 0, 1185c2c66affSColin Finck XTYP_EXECUTE, 10000, &tid ); 1186c2c66affSColin Finck } 1187c2c66affSColin Finck if (hDdeData) 1188c2c66affSColin Finck DdeFreeDataHandle(hDdeData); 1189c2c66affSColin Finck else 1190c2c66affSColin Finck WARN("DdeClientTransaction failed with error %04x\n", DdeGetLastError(ddeInst)); 1191c2c66affSColin Finck ret = 33; 1192c2c66affSColin Finck 1193c2c66affSColin Finck DdeDisconnect(hConv); 1194c2c66affSColin Finck 1195c2c66affSColin Finck error: 1196c2c66affSColin Finck DdeUninitialize(ddeInst); 1197c2c66affSColin Finck 1198c2c66affSColin Finck return ret; 1199c2c66affSColin Finck } 1200c2c66affSColin Finck 1201c2c66affSColin Finck /************************************************************************* 1202c2c66affSColin Finck * execute_from_key [Internal] 1203c2c66affSColin Finck */ 1204c2c66affSColin Finck static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env, 1205c2c66affSColin Finck LPCWSTR szCommandline, LPCWSTR executable_name, 1206c2c66affSColin Finck SHELL_ExecuteW32 execfunc, 1207c2c66affSColin Finck LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out) 1208c2c66affSColin Finck { 1209c2c66affSColin Finck WCHAR cmd[256], param[1024], ddeexec[256]; 1210c2c66affSColin Finck DWORD cmdlen = sizeof(cmd), ddeexeclen = sizeof(ddeexec); 1211c2c66affSColin Finck UINT_PTR retval = SE_ERR_NOASSOC; 1212c2c66affSColin Finck DWORD resultLen; 1213c2c66affSColin Finck LPWSTR tmp; 1214c2c66affSColin Finck 1215c2c66affSColin Finck TRACE("%s %s %s %s %s\n", debugstr_w(key), debugstr_w(lpFile), debugstr_w(env), 1216c2c66affSColin Finck debugstr_w(szCommandline), debugstr_w(executable_name)); 1217c2c66affSColin Finck 1218c2c66affSColin Finck cmd[0] = '\0'; 1219c2c66affSColin Finck param[0] = '\0'; 1220c2c66affSColin Finck 1221c2c66affSColin Finck /* Get the application from the registry */ 1222c2c66affSColin Finck if (RegQueryValueW(HKEY_CLASSES_ROOT, key, cmd, (LONG *)&cmdlen) == ERROR_SUCCESS) 1223c2c66affSColin Finck { 1224c2c66affSColin Finck TRACE("got cmd: %s\n", debugstr_w(cmd)); 1225c2c66affSColin Finck 1226c2c66affSColin Finck /* Is there a replace() function anywhere? */ 1227c2c66affSColin Finck cmdlen /= sizeof(WCHAR); 122883be315aSHermès Bélusca-Maïto if (cmdlen >= ARRAY_SIZE(cmd)) 122983be315aSHermès Bélusca-Maïto cmdlen = ARRAY_SIZE(cmd) - 1; 1230c2c66affSColin Finck cmd[cmdlen] = '\0'; 123183be315aSHermès Bélusca-Maïto SHELL_ArgifyW(param, ARRAY_SIZE(param), cmd, lpFile, (LPITEMIDLIST)psei->lpIDList, szCommandline, &resultLen, 1232e018cceaSKatayama Hirofumi MZ (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL); 123383be315aSHermès Bélusca-Maïto if (resultLen > ARRAY_SIZE(param)) 1234c2c66affSColin Finck ERR("Argify buffer not large enough, truncating\n"); 1235c2c66affSColin Finck } 1236c2c66affSColin Finck 1237c2c66affSColin Finck /* Get the parameters needed by the application 1238c2c66affSColin Finck from the associated ddeexec key */ 1239c2c66affSColin Finck tmp = const_cast<LPWSTR>(strstrW(key, L"command")); 1240c2c66affSColin Finck assert(tmp); 1241c2c66affSColin Finck wcscpy(tmp, L"ddeexec"); 1242c2c66affSColin Finck 1243c2c66affSColin Finck if (RegQueryValueW(HKEY_CLASSES_ROOT, key, ddeexec, (LONG *)&ddeexeclen) == ERROR_SUCCESS) 1244c2c66affSColin Finck { 1245c2c66affSColin Finck TRACE("Got ddeexec %s => %s\n", debugstr_w(key), debugstr_w(ddeexec)); 1246c2c66affSColin Finck if (!param[0]) strcpyW(param, executable_name); 1247c2c66affSColin Finck retval = dde_connect(key, param, ddeexec, lpFile, env, szCommandline, (LPITEMIDLIST)psei->lpIDList, execfunc, psei, psei_out); 1248c2c66affSColin Finck } 1249c2c66affSColin Finck else if (param[0]) 1250c2c66affSColin Finck { 1251c2c66affSColin Finck TRACE("executing: %s\n", debugstr_w(param)); 1252c2c66affSColin Finck retval = execfunc(param, env, FALSE, psei, psei_out); 1253c2c66affSColin Finck } 1254c2c66affSColin Finck else 1255c2c66affSColin Finck WARN("Nothing appropriate found for %s\n", debugstr_w(key)); 1256c2c66affSColin Finck 1257c2c66affSColin Finck return retval; 1258c2c66affSColin Finck } 1259c2c66affSColin Finck 1260c2c66affSColin Finck /************************************************************************* 1261c2c66affSColin Finck * FindExecutableA [SHELL32.@] 1262c2c66affSColin Finck */ 1263c2c66affSColin Finck HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult) 1264c2c66affSColin Finck { 1265c2c66affSColin Finck HINSTANCE retval; 1266c2c66affSColin Finck WCHAR *wFile = NULL, *wDirectory = NULL; 1267c2c66affSColin Finck WCHAR wResult[MAX_PATH]; 1268c2c66affSColin Finck 1269c2c66affSColin Finck if (lpFile) __SHCloneStrAtoW(&wFile, lpFile); 1270c2c66affSColin Finck if (lpDirectory) __SHCloneStrAtoW(&wDirectory, lpDirectory); 1271c2c66affSColin Finck 1272c2c66affSColin Finck retval = FindExecutableW(wFile, wDirectory, wResult); 1273c2c66affSColin Finck WideCharToMultiByte(CP_ACP, 0, wResult, -1, lpResult, MAX_PATH, NULL, NULL); 1274c2c66affSColin Finck SHFree(wFile); 1275c2c66affSColin Finck SHFree(wDirectory); 1276c2c66affSColin Finck 1277c2c66affSColin Finck TRACE("returning %s\n", lpResult); 1278c2c66affSColin Finck return retval; 1279c2c66affSColin Finck } 1280c2c66affSColin Finck 1281c2c66affSColin Finck /************************************************************************* 1282c2c66affSColin Finck * FindExecutableW [SHELL32.@] 1283c2c66affSColin Finck * 1284c2c66affSColin Finck * This function returns the executable associated with the specified file 1285c2c66affSColin Finck * for the default verb. 1286c2c66affSColin Finck * 1287c2c66affSColin Finck * PARAMS 1288c2c66affSColin Finck * lpFile [I] The file to find the association for. This must refer to 1289c2c66affSColin Finck * an existing file otherwise FindExecutable fails and returns 1290c2c66affSColin Finck * SE_ERR_FNF. 1291c2c66affSColin Finck * lpResult [O] Points to a buffer into which the executable path is 1292c2c66affSColin Finck * copied. This parameter must not be NULL otherwise 1293c2c66affSColin Finck * FindExecutable() segfaults. The buffer must be of size at 1294c2c66affSColin Finck * least MAX_PATH characters. 1295c2c66affSColin Finck * 1296c2c66affSColin Finck * RETURNS 1297c2c66affSColin Finck * A value greater than 32 on success, less than or equal to 32 otherwise. 1298c2c66affSColin Finck * See the SE_ERR_* constants. 1299c2c66affSColin Finck * 1300c2c66affSColin Finck * NOTES 1301c2c66affSColin Finck * On Windows XP and 2003, FindExecutable() seems to first convert the 1302c2c66affSColin Finck * filename into 8.3 format, thus taking into account only the first three 1303c2c66affSColin Finck * characters of the extension, and expects to find an association for those. 1304c2c66affSColin Finck * However other Windows versions behave sanely. 1305c2c66affSColin Finck */ 1306c2c66affSColin Finck HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult) 1307c2c66affSColin Finck { 1308f9a55858SKatayama Hirofumi MZ UINT_PTR retval; 1309f9a55858SKatayama Hirofumi MZ WCHAR old_dir[MAX_PATH], res[MAX_PATH]; 1310f9a55858SKatayama Hirofumi MZ DWORD cch = _countof(res); 1311f9a55858SKatayama Hirofumi MZ LPCWSTR dirs[2]; 1312c2c66affSColin Finck 1313c2c66affSColin Finck TRACE("File %s, Dir %s\n", debugstr_w(lpFile), debugstr_w(lpDirectory)); 1314c2c66affSColin Finck 1315f9a55858SKatayama Hirofumi MZ *lpResult = UNICODE_NULL; 1316c2c66affSColin Finck 1317f9a55858SKatayama Hirofumi MZ GetCurrentDirectoryW(_countof(old_dir), old_dir); 1318f9a55858SKatayama Hirofumi MZ 1319f9a55858SKatayama Hirofumi MZ if (lpDirectory && *lpDirectory) 1320c2c66affSColin Finck { 1321c2c66affSColin Finck SetCurrentDirectoryW(lpDirectory); 1322f9a55858SKatayama Hirofumi MZ dirs[0] = lpDirectory; 1323f9a55858SKatayama Hirofumi MZ } 1324f9a55858SKatayama Hirofumi MZ else 1325f9a55858SKatayama Hirofumi MZ { 1326f9a55858SKatayama Hirofumi MZ dirs[0] = old_dir; 1327f9a55858SKatayama Hirofumi MZ } 1328f9a55858SKatayama Hirofumi MZ dirs[1] = NULL; 1329f9a55858SKatayama Hirofumi MZ 1330f9a55858SKatayama Hirofumi MZ if (!GetShortPathNameW(lpFile, res, _countof(res))) 1331f9a55858SKatayama Hirofumi MZ StringCchCopyW(res, _countof(res), lpFile); 1332f9a55858SKatayama Hirofumi MZ 133384f15b15SKatayama Hirofumi MZ if (PathResolveW(res, dirs, PRF_TRYPROGRAMEXTENSIONS | PRF_FIRSTDIRDEF)) 1334f9a55858SKatayama Hirofumi MZ { 1335f9a55858SKatayama Hirofumi MZ // NOTE: The last parameter of this AssocQueryStringW call is "strange" in Windows. 1336f9a55858SKatayama Hirofumi MZ if (PathIsExeW(res) || 1337f9a55858SKatayama Hirofumi MZ SUCCEEDED(AssocQueryStringW(ASSOCF_NONE, ASSOCSTR_EXECUTABLE, res, NULL, res, &cch))) 1338f9a55858SKatayama Hirofumi MZ { 1339f9a55858SKatayama Hirofumi MZ StringCchCopyW(lpResult, MAX_PATH, res); 1340f9a55858SKatayama Hirofumi MZ retval = 42; 1341f9a55858SKatayama Hirofumi MZ } 1342f9a55858SKatayama Hirofumi MZ else 1343f9a55858SKatayama Hirofumi MZ { 1344f9a55858SKatayama Hirofumi MZ retval = SE_ERR_NOASSOC; 1345f9a55858SKatayama Hirofumi MZ } 1346f9a55858SKatayama Hirofumi MZ } 1347f9a55858SKatayama Hirofumi MZ else 1348f9a55858SKatayama Hirofumi MZ { 1349f9a55858SKatayama Hirofumi MZ retval = SE_ERR_FNF; 1350c2c66affSColin Finck } 1351c2c66affSColin Finck 1352c2c66affSColin Finck TRACE("returning %s\n", debugstr_w(lpResult)); 1353c2c66affSColin Finck SetCurrentDirectoryW(old_dir); 1354c2c66affSColin Finck return (HINSTANCE)retval; 1355c2c66affSColin Finck } 1356c2c66affSColin Finck 1357c2c66affSColin Finck /* FIXME: is this already implemented somewhere else? */ 1358c2c66affSColin Finck static HKEY ShellExecute_GetClassKey(const SHELLEXECUTEINFOW *sei) 1359c2c66affSColin Finck { 1360c2c66affSColin Finck LPCWSTR ext = NULL, lpClass = NULL; 136106b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> cls; 1362c2c66affSColin Finck DWORD type = 0, sz = 0; 1363c2c66affSColin Finck HKEY hkey = 0; 1364c2c66affSColin Finck LONG r; 1365c2c66affSColin Finck 1366c2c66affSColin Finck if (sei->fMask & SEE_MASK_CLASSALL) 1367c2c66affSColin Finck return sei->hkeyClass; 1368c2c66affSColin Finck 1369c2c66affSColin Finck if (sei->fMask & SEE_MASK_CLASSNAME) 1370c2c66affSColin Finck lpClass = sei->lpClass; 1371c2c66affSColin Finck else 1372c2c66affSColin Finck { 1373c2c66affSColin Finck ext = PathFindExtensionW(sei->lpFile); 1374c2c66affSColin Finck TRACE("ext = %s\n", debugstr_w(ext)); 1375c2c66affSColin Finck if (!ext) 1376c2c66affSColin Finck return hkey; 1377c2c66affSColin Finck 1378c2c66affSColin Finck r = RegOpenKeyW(HKEY_CLASSES_ROOT, ext, &hkey); 1379c2c66affSColin Finck if (r != ERROR_SUCCESS) 1380c2c66affSColin Finck return hkey; 1381c2c66affSColin Finck 1382c2c66affSColin Finck r = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &sz); 1383c2c66affSColin Finck if (r == ERROR_SUCCESS && type == REG_SZ) 1384c2c66affSColin Finck { 1385c2c66affSColin Finck sz += sizeof (WCHAR); 138606b6833cSKatayama Hirofumi MZ cls.Allocate(sz / sizeof(WCHAR)); 1387c2c66affSColin Finck cls[0] = 0; 138806b6833cSKatayama Hirofumi MZ RegQueryValueExW(hkey, NULL, 0, &type, (LPBYTE)(LPWSTR)cls, &sz); 1389c2c66affSColin Finck } 1390c2c66affSColin Finck 1391c2c66affSColin Finck RegCloseKey( hkey ); 1392c2c66affSColin Finck lpClass = cls; 1393c2c66affSColin Finck } 1394c2c66affSColin Finck 1395c2c66affSColin Finck TRACE("class = %s\n", debugstr_w(lpClass)); 1396c2c66affSColin Finck 1397c2c66affSColin Finck hkey = 0; 1398c2c66affSColin Finck if (lpClass) 1399c2c66affSColin Finck RegOpenKeyW( HKEY_CLASSES_ROOT, lpClass, &hkey); 1400c2c66affSColin Finck 1401c2c66affSColin Finck return hkey; 1402c2c66affSColin Finck } 1403c2c66affSColin Finck 1404f6f5490aSMark Jansen static HRESULT shellex_get_dataobj( LPSHELLEXECUTEINFOW sei, CComPtr<IDataObject>& dataObj) 1405c2c66affSColin Finck { 1406f6f5490aSMark Jansen CComHeapPtr<ITEMIDLIST> allocatedPidl; 1407c2c66affSColin Finck LPITEMIDLIST pidl = NULL; 1408c2c66affSColin Finck 1409c2c66affSColin Finck if (sei->fMask & SEE_MASK_CLASSALL) 1410f6f5490aSMark Jansen { 1411c2c66affSColin Finck pidl = (LPITEMIDLIST)sei->lpIDList; 1412f6f5490aSMark Jansen } 1413c2c66affSColin Finck else 1414c2c66affSColin Finck { 1415c2c66affSColin Finck WCHAR fullpath[MAX_PATH]; 1416c2c66affSColin Finck BOOL ret; 1417c2c66affSColin Finck 1418c2c66affSColin Finck fullpath[0] = 0; 1419c2c66affSColin Finck ret = GetFullPathNameW(sei->lpFile, MAX_PATH, fullpath, NULL); 1420c2c66affSColin Finck if (!ret) 1421f6f5490aSMark Jansen return HRESULT_FROM_WIN32(GetLastError()); 1422c2c66affSColin Finck 1423c2c66affSColin Finck pidl = ILCreateFromPathW(fullpath); 1424f6f5490aSMark Jansen allocatedPidl.Attach(pidl); 1425c2c66affSColin Finck } 142628399a21SWhindmar Saksit return SHELL_GetUIObjectOfAbsoluteItem(NULL, pidl, IID_PPV_ARG(IDataObject, &dataObj)); 1427c2c66affSColin Finck } 1428c2c66affSColin Finck 1429c2c66affSColin Finck static HRESULT shellex_run_context_menu_default(IShellExtInit *obj, 1430c2c66affSColin Finck LPSHELLEXECUTEINFOW sei) 1431c2c66affSColin Finck { 1432c2c66affSColin Finck CComPtr<IContextMenu> cm = NULL; 1433c2c66affSColin Finck CMINVOKECOMMANDINFOEX ici; 1434c2c66affSColin Finck MENUITEMINFOW info; 1435c2c66affSColin Finck WCHAR string[0x80]; 1436c2c66affSColin Finck INT i, n, def = -1; 1437c2c66affSColin Finck HMENU hmenu = 0; 1438c2c66affSColin Finck HRESULT r; 1439c2c66affSColin Finck 1440c2c66affSColin Finck TRACE("%p %p\n", obj, sei); 1441c2c66affSColin Finck 1442c2c66affSColin Finck r = obj->QueryInterface(IID_PPV_ARG(IContextMenu, &cm)); 1443c2c66affSColin Finck if (FAILED(r)) 1444c2c66affSColin Finck return r; 1445c2c66affSColin Finck 1446c2c66affSColin Finck hmenu = CreateMenu(); 1447c2c66affSColin Finck if (!hmenu) 1448c2c66affSColin Finck goto end; 1449c2c66affSColin Finck 1450c2c66affSColin Finck /* the number of the last menu added is returned in r */ 1451c2c66affSColin Finck r = cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY); 1452c2c66affSColin Finck if (FAILED(r)) 1453c2c66affSColin Finck goto end; 1454c2c66affSColin Finck 1455c2c66affSColin Finck n = GetMenuItemCount(hmenu); 1456c2c66affSColin Finck for (i = 0; i < n; i++) 1457c2c66affSColin Finck { 1458c2c66affSColin Finck memset(&info, 0, sizeof(info)); 1459c2c66affSColin Finck info.cbSize = sizeof info; 1460c2c66affSColin Finck info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID; 1461c2c66affSColin Finck info.dwTypeData = string; 1462c2c66affSColin Finck info.cch = sizeof string; 1463c2c66affSColin Finck string[0] = 0; 1464c2c66affSColin Finck GetMenuItemInfoW(hmenu, i, TRUE, &info); 1465c2c66affSColin Finck 1466c2c66affSColin Finck TRACE("menu %d %s %08x %08lx %08x %08x\n", i, debugstr_w(string), 1467c2c66affSColin Finck info.fState, info.dwItemData, info.fType, info.wID); 1468c2c66affSColin Finck if ((!sei->lpVerb && (info.fState & MFS_DEFAULT)) || 1469c2c66affSColin Finck (sei->lpVerb && !lstrcmpiW(sei->lpVerb, string))) 1470c2c66affSColin Finck { 1471c2c66affSColin Finck def = i; 1472c2c66affSColin Finck break; 1473c2c66affSColin Finck } 1474c2c66affSColin Finck } 1475c2c66affSColin Finck 1476c2c66affSColin Finck r = E_FAIL; 1477c2c66affSColin Finck if (def == -1) 1478c2c66affSColin Finck goto end; 1479c2c66affSColin Finck 1480c2c66affSColin Finck memset(&ici, 0, sizeof ici); 1481c2c66affSColin Finck ici.cbSize = sizeof ici; 1482c2c66affSColin Finck ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI)); 1483c2c66affSColin Finck ici.nShow = sei->nShow; 1484c2c66affSColin Finck ici.lpVerb = MAKEINTRESOURCEA(def); 1485c2c66affSColin Finck ici.hwnd = sei->hwnd; 1486c2c66affSColin Finck ici.lpParametersW = sei->lpParameters; 1487c2c66affSColin Finck 1488c2c66affSColin Finck r = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici); 1489c2c66affSColin Finck 1490c2c66affSColin Finck TRACE("invoke command returned %08x\n", r); 1491c2c66affSColin Finck 1492c2c66affSColin Finck end: 1493c2c66affSColin Finck if (hmenu) 1494c2c66affSColin Finck DestroyMenu( hmenu ); 1495c2c66affSColin Finck return r; 1496c2c66affSColin Finck } 1497c2c66affSColin Finck 1498c2c66affSColin Finck static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW sei) 1499c2c66affSColin Finck { 1500c2c66affSColin Finck TRACE("%p %s %p\n", hkey, debugstr_guid(guid), sei); 1501c2c66affSColin Finck 1502f6f5490aSMark Jansen CCoInit coInit; 1503c2c66affSColin Finck 1504d82185f1SMark Jansen if (FAILED_UNEXPECTEDLY(coInit.hr)) 1505d82185f1SMark Jansen return coInit.hr; 1506f6f5490aSMark Jansen 1507f6f5490aSMark Jansen CComPtr<IShellExtInit> obj; 1508f6f5490aSMark Jansen HRESULT hr = CoCreateInstance(*guid, NULL, CLSCTX_INPROC_SERVER, 1509c2c66affSColin Finck IID_PPV_ARG(IShellExtInit, &obj)); 1510f6f5490aSMark Jansen if (FAILED_UNEXPECTEDLY(hr)) 1511f6f5490aSMark Jansen return hr; 1512c2c66affSColin Finck 1513f6f5490aSMark Jansen CComPtr<IDataObject> dataobj; 1514f6f5490aSMark Jansen hr = shellex_get_dataobj(sei, dataobj); 1515f6f5490aSMark Jansen if (FAILED_UNEXPECTEDLY(hr)) 1516f6f5490aSMark Jansen return hr; 1517c2c66affSColin Finck 1518f6f5490aSMark Jansen hr = obj->Initialize(NULL, dataobj, hkey); 1519f6f5490aSMark Jansen if (FAILED_UNEXPECTEDLY(hr)) 1520f6f5490aSMark Jansen return hr; 1521c2c66affSColin Finck 1522f6f5490aSMark Jansen CComPtr<IObjectWithSite> ows; 1523f6f5490aSMark Jansen hr = obj->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ows)); 1524f6f5490aSMark Jansen if (FAILED_UNEXPECTEDLY(hr)) 1525f6f5490aSMark Jansen return hr; 1526c2c66affSColin Finck 1527c2c66affSColin Finck ows->SetSite(NULL); 1528c2c66affSColin Finck 1529f6f5490aSMark Jansen return shellex_run_context_menu_default(obj, sei); 1530c2c66affSColin Finck } 1531c2c66affSColin Finck 1532f6f5490aSMark Jansen static HRESULT shellex_get_contextmenu(LPSHELLEXECUTEINFOW sei, CComPtr<IContextMenu>& cm) 1533f6f5490aSMark Jansen { 1534f6f5490aSMark Jansen CComHeapPtr<ITEMIDLIST> allocatedPidl; 1535f6f5490aSMark Jansen LPITEMIDLIST pidl = NULL; 1536f6f5490aSMark Jansen 1537f6f5490aSMark Jansen if (sei->lpIDList) 1538f6f5490aSMark Jansen { 1539f6f5490aSMark Jansen pidl = (LPITEMIDLIST)sei->lpIDList; 1540f6f5490aSMark Jansen } 1541f6f5490aSMark Jansen else 1542f6f5490aSMark Jansen { 1543f6f5490aSMark Jansen SFGAOF sfga = 0; 1544f6f5490aSMark Jansen HRESULT hr = SHParseDisplayName(sei->lpFile, NULL, &allocatedPidl, SFGAO_STORAGECAPMASK, &sfga); 1545f6f5490aSMark Jansen if (FAILED(hr)) 154693fac553SMark Jansen { 154793fac553SMark Jansen WCHAR Buffer[MAX_PATH] = {}; 154893fac553SMark Jansen // FIXME: MAX_PATH..... 154993fac553SMark Jansen UINT retval = SHELL_FindExecutable(sei->lpDirectory, sei->lpFile, sei->lpVerb, Buffer, _countof(Buffer), NULL, NULL, NULL, sei->lpParameters); 155093fac553SMark Jansen if (retval <= 32) 155193fac553SMark Jansen return HRESULT_FROM_WIN32(retval); 155293fac553SMark Jansen 155393fac553SMark Jansen hr = SHParseDisplayName(Buffer, NULL, &allocatedPidl, SFGAO_STORAGECAPMASK, &sfga); 155493fac553SMark Jansen // This should not happen, we found it... 155593fac553SMark Jansen if (FAILED_UNEXPECTEDLY(hr)) 1556f6f5490aSMark Jansen return hr; 155793fac553SMark Jansen } 1558f6f5490aSMark Jansen 1559f6f5490aSMark Jansen pidl = allocatedPidl; 1560f6f5490aSMark Jansen } 1561f6f5490aSMark Jansen 1562f6f5490aSMark Jansen CComPtr<IShellFolder> shf; 1563f6f5490aSMark Jansen LPCITEMIDLIST pidllast = NULL; 1564f6f5490aSMark Jansen HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf), &pidllast); 1565f6f5490aSMark Jansen if (FAILED(hr)) 1566f6f5490aSMark Jansen return hr; 1567f6f5490aSMark Jansen 1568f6f5490aSMark Jansen return shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IContextMenu, &cm)); 1569f6f5490aSMark Jansen } 1570f6f5490aSMark Jansen 1571ce306b83SMark Jansen static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei) 1572f6f5490aSMark Jansen { 1573f6f5490aSMark Jansen TRACE("%p\n", sei); 1574f6f5490aSMark Jansen 1575f6f5490aSMark Jansen CCoInit coInit; 1576f6f5490aSMark Jansen 1577d82185f1SMark Jansen if (FAILED_UNEXPECTEDLY(coInit.hr)) 1578d82185f1SMark Jansen return coInit.hr; 1579f6f5490aSMark Jansen 1580f6f5490aSMark Jansen CComPtr<IContextMenu> cm; 1581f6f5490aSMark Jansen HRESULT hr = shellex_get_contextmenu(sei, cm); 1582f6f5490aSMark Jansen if (FAILED_UNEXPECTEDLY(hr)) 1583f6f5490aSMark Jansen return hr; 1584f6f5490aSMark Jansen 1585a5099417SWhindmar Saksit CComHeapPtr<char> verb, parameters, dir; 1586f6f5490aSMark Jansen __SHCloneStrWtoA(&verb, sei->lpVerb); 1587f6f5490aSMark Jansen __SHCloneStrWtoA(¶meters, sei->lpParameters); 1588a5099417SWhindmar Saksit __SHCloneStrWtoA(&dir, sei->lpDirectory); 1589f6f5490aSMark Jansen 1590724b20d4SWhindmar Saksit BOOL fDefault = StrIsNullOrEmpty(sei->lpVerb); 1591f6a25d48SWhindmar Saksit CMINVOKECOMMANDINFOEX ici = { sizeof(ici) }; 1592724b20d4SWhindmar Saksit ici.fMask = SeeFlagsToCmicFlags(sei->fMask) | CMIC_MASK_UNICODE; 1593f6f5490aSMark Jansen ici.nShow = sei->nShow; 1594f6a25d48SWhindmar Saksit if (!fDefault) 1595f6a25d48SWhindmar Saksit { 1596f6f5490aSMark Jansen ici.lpVerb = verb; 1597f6a25d48SWhindmar Saksit ici.lpVerbW = sei->lpVerb; 1598f6a25d48SWhindmar Saksit } 1599f6f5490aSMark Jansen ici.hwnd = sei->hwnd; 1600f6f5490aSMark Jansen ici.lpParameters = parameters; 1601f6a25d48SWhindmar Saksit ici.lpParametersW = sei->lpParameters; 1602a5099417SWhindmar Saksit ici.lpDirectory = dir; 1603a5099417SWhindmar Saksit ici.lpDirectoryW = sei->lpDirectory; 1604724b20d4SWhindmar Saksit ici.dwHotKey = sei->dwHotKey; 1605724b20d4SWhindmar Saksit ici.hIcon = sei->hIcon; 1606724b20d4SWhindmar Saksit if (ici.fMask & (CMIC_MASK_HASLINKNAME | CMIC_MASK_HASTITLE)) 1607f6a25d48SWhindmar Saksit ici.lpTitleW = sei->lpClass; 1608f6f5490aSMark Jansen 1609724b20d4SWhindmar Saksit enum { idFirst = 1, idLast = 0x7fff }; 1610f6f5490aSMark Jansen HMENU hMenu = CreatePopupMenu(); 161128399a21SWhindmar Saksit // Note: Windows does not pass CMF_EXTENDEDVERBS so "hidden" verbs cannot be executed 1612724b20d4SWhindmar Saksit hr = cm->QueryContextMenu(hMenu, 0, idFirst, idLast, fDefault ? CMF_DEFAULTONLY : 0); 1613f6f5490aSMark Jansen if (!FAILED_UNEXPECTEDLY(hr)) 1614f6f5490aSMark Jansen { 1615f6f5490aSMark Jansen if (fDefault) 1616f6f5490aSMark Jansen { 1617f6f5490aSMark Jansen INT uDefault = GetMenuDefaultItem(hMenu, FALSE, 0); 1618724b20d4SWhindmar Saksit uDefault = (uDefault != -1) ? uDefault - idFirst : 0; 1619f6f5490aSMark Jansen ici.lpVerb = MAKEINTRESOURCEA(uDefault); 1620f6a25d48SWhindmar Saksit ici.lpVerbW = MAKEINTRESOURCEW(uDefault); 1621f6f5490aSMark Jansen } 1622f6f5490aSMark Jansen 1623f6f5490aSMark Jansen hr = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici); 1624f6f5490aSMark Jansen if (!FAILED_UNEXPECTEDLY(hr)) 1625f6f5490aSMark Jansen hr = S_OK; 1626f6f5490aSMark Jansen } 1627f6f5490aSMark Jansen 1628f6f5490aSMark Jansen DestroyMenu(hMenu); 1629f6f5490aSMark Jansen 1630f6f5490aSMark Jansen return hr; 1631f6f5490aSMark Jansen } 1632f6f5490aSMark Jansen 1633f6f5490aSMark Jansen 1634c2c66affSColin Finck /************************************************************************* 1635c2c66affSColin Finck * ShellExecute_FromContextMenu [Internal] 1636c2c66affSColin Finck */ 1637ce306b83SMark Jansen static LONG ShellExecute_FromContextMenuHandlers( LPSHELLEXECUTEINFOW sei ) 1638c2c66affSColin Finck { 1639c2c66affSColin Finck HKEY hkey, hkeycm = 0; 1640c2c66affSColin Finck WCHAR szguid[39]; 1641c2c66affSColin Finck HRESULT hr; 1642c2c66affSColin Finck GUID guid; 1643c2c66affSColin Finck DWORD i; 1644c2c66affSColin Finck LONG r; 1645c2c66affSColin Finck 1646c2c66affSColin Finck TRACE("%s\n", debugstr_w(sei->lpFile)); 1647c2c66affSColin Finck 1648c2c66affSColin Finck hkey = ShellExecute_GetClassKey(sei); 1649c2c66affSColin Finck if (!hkey) 1650c2c66affSColin Finck return ERROR_FUNCTION_FAILED; 1651c2c66affSColin Finck 1652c2c66affSColin Finck r = RegOpenKeyW(hkey, L"shellex\\ContextMenuHandlers", &hkeycm); 1653c2c66affSColin Finck if (r == ERROR_SUCCESS) 1654c2c66affSColin Finck { 1655c2c66affSColin Finck i = 0; 1656c2c66affSColin Finck while (1) 1657c2c66affSColin Finck { 165883be315aSHermès Bélusca-Maïto r = RegEnumKeyW(hkeycm, i++, szguid, ARRAY_SIZE(szguid)); 1659c2c66affSColin Finck if (r != ERROR_SUCCESS) 1660c2c66affSColin Finck break; 1661c2c66affSColin Finck 1662c2c66affSColin Finck hr = CLSIDFromString(szguid, &guid); 1663c2c66affSColin Finck if (SUCCEEDED(hr)) 1664c2c66affSColin Finck { 1665c2c66affSColin Finck /* stop at the first one that succeeds in running */ 1666c2c66affSColin Finck hr = shellex_load_object_and_run(hkey, &guid, sei); 1667c2c66affSColin Finck if (SUCCEEDED(hr)) 1668c2c66affSColin Finck break; 1669c2c66affSColin Finck } 1670c2c66affSColin Finck } 1671c2c66affSColin Finck RegCloseKey(hkeycm); 1672c2c66affSColin Finck } 1673c2c66affSColin Finck 1674c2c66affSColin Finck if (hkey != sei->hkeyClass) 1675c2c66affSColin Finck RegCloseKey(hkey); 1676c2c66affSColin Finck return r; 1677c2c66affSColin Finck } 1678c2c66affSColin Finck 1679c2c66affSColin Finck 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); 1680c2c66affSColin Finck 1681c2c66affSColin Finck static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc) 1682c2c66affSColin Finck { 1683c2c66affSColin Finck WCHAR execCmd[1024], classname[1024]; 1684c2c66affSColin Finck /* launch a document by fileclass like 'WordPad.Document.1' */ 1685c2c66affSColin Finck /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */ 1686c2c66affSColin Finck /* FIXME: wcmd should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */ 1687c2c66affSColin Finck ULONG cmask = (psei->fMask & SEE_MASK_CLASSALL); 1688c2c66affSColin Finck DWORD resultLen; 1689c2c66affSColin Finck BOOL done; 1690c2c66affSColin Finck UINT_PTR rslt; 1691c2c66affSColin Finck 1692c2c66affSColin Finck /* FIXME: remove following block when SHELL_quote_and_execute supports hkeyClass parameter */ 1693c2c66affSColin Finck if (cmask != SEE_MASK_CLASSNAME) 1694c2c66affSColin Finck { 1695c2c66affSColin Finck WCHAR wcmd[1024]; 1696c2c66affSColin Finck HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL, 1697c2c66affSColin Finck (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL, 1698c2c66affSColin Finck psei->lpVerb, 1699c2c66affSColin Finck execCmd, sizeof(execCmd)); 1700c2c66affSColin Finck 1701c2c66affSColin Finck /* FIXME: get the extension of lpFile, check if it fits to the lpClass */ 1702c2c66affSColin Finck TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName)); 1703c2c66affSColin Finck 1704c2c66affSColin Finck wcmd[0] = '\0'; 1705d5aca440SWhindmar Saksit done = SHELL_ArgifyW(wcmd, ARRAY_SIZE(wcmd), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, psei->lpParameters, 1706d5aca440SWhindmar Saksit &resultLen, (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL); 1707c2c66affSColin Finck if (!done && wszApplicationName[0]) 1708c2c66affSColin Finck { 1709724b20d4SWhindmar Saksit #if 0 // Given HKCR\.test=SZ:"test" and HKCR\test\shell\open\command=SZ:"cmd.exe /K echo.Hello", no filename is 1710724b20d4SWhindmar Saksit // appended on Windows when there is no %1 nor %L when executed with: shlextdbg.exe /shellexec=c:\file.test /INVOKE 1711c2c66affSColin Finck strcatW(wcmd, L" "); 1712c2c66affSColin Finck if (*wszApplicationName != '"') 1713c2c66affSColin Finck { 1714c2c66affSColin Finck strcatW(wcmd, L"\""); 1715c2c66affSColin Finck strcatW(wcmd, wszApplicationName); 1716c2c66affSColin Finck strcatW(wcmd, L"\""); 1717c2c66affSColin Finck } 1718c2c66affSColin Finck else 1719c2c66affSColin Finck strcatW(wcmd, wszApplicationName); 1720724b20d4SWhindmar Saksit #endif 1721c2c66affSColin Finck } 172283be315aSHermès Bélusca-Maïto if (resultLen > ARRAY_SIZE(wcmd)) 1723c2c66affSColin Finck ERR("Argify buffer not large enough... truncating\n"); 1724c2c66affSColin Finck return execfunc(wcmd, NULL, FALSE, psei, psei_out); 1725c2c66affSColin Finck } 1726c2c66affSColin Finck 1727c2c66affSColin Finck strcpyW(classname, psei->lpClass); 1728c2c66affSColin Finck rslt = SHELL_FindExecutableByVerb(psei->lpVerb, NULL, classname, execCmd, sizeof(execCmd)); 1729c2c66affSColin Finck 1730c2c66affSColin Finck TRACE("SHELL_FindExecutableByVerb returned %u (%s, %s)\n", (unsigned int)rslt, debugstr_w(classname), debugstr_w(execCmd)); 1731c2c66affSColin Finck if (33 > rslt) 1732c2c66affSColin Finck return rslt; 1733c2c66affSColin Finck rslt = SHELL_quote_and_execute( execCmd, L"", classname, 1734c2c66affSColin Finck wszApplicationName, NULL, psei, 1735c2c66affSColin Finck psei_out, execfunc ); 1736c2c66affSColin Finck return rslt; 1737c2c66affSColin Finck 1738c2c66affSColin Finck } 1739c2c66affSColin Finck 1740c2c66affSColin Finck static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen) 1741c2c66affSColin Finck { 1742c2c66affSColin Finck WCHAR buffer[MAX_PATH]; 1743c2c66affSColin Finck BOOL appKnownSingular = FALSE; 1744c2c66affSColin Finck 1745c2c66affSColin Finck /* last chance to translate IDList: now also allow CLSID paths */ 174683be315aSHermès Bélusca-Maïto if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, ARRAY_SIZE(buffer)))) { 1747c2c66affSColin Finck if (buffer[0] == ':' && buffer[1] == ':') { 1748c2c66affSColin Finck /* open shell folder for the specified class GUID */ 1749c2c66affSColin Finck if (strlenW(buffer) + 1 > parametersLen) 1750c2c66affSColin Finck ERR("parameters len exceeds buffer size (%i > %i), truncating\n", 1751c2c66affSColin Finck lstrlenW(buffer) + 1, parametersLen); 1752c2c66affSColin Finck lstrcpynW(wszParameters, buffer, parametersLen); 175383be315aSHermès Bélusca-Maïto if (strlenW(L"explorer.exe") > dwApplicationNameLen) 175483be315aSHermès Bélusca-Maïto ERR("application len exceeds buffer size (%i), truncating\n", 175583be315aSHermès Bélusca-Maïto dwApplicationNameLen); 175683be315aSHermès Bélusca-Maïto lstrcpynW(wszApplicationName, L"explorer.exe", dwApplicationNameLen); 1757c2c66affSColin Finck appKnownSingular = TRUE; 1758c2c66affSColin Finck 1759c2c66affSColin Finck sei->fMask &= ~SEE_MASK_INVOKEIDLIST; 1760c2c66affSColin Finck } else { 1761ea87f910SWhindmar Saksit WCHAR target[max(MAX_PATH, _countof(buffer))]; 1762c2c66affSColin Finck DWORD attribs; 1763c2c66affSColin Finck DWORD resultLen; 1764c2c66affSColin Finck /* Check if we're executing a directory and if so use the 1765c2c66affSColin Finck handler for the Folder class */ 1766c2c66affSColin Finck strcpyW(target, buffer); 1767c2c66affSColin Finck attribs = GetFileAttributesW(buffer); 1768c2c66affSColin Finck if (attribs != INVALID_FILE_ATTRIBUTES && 1769c2c66affSColin Finck (attribs & FILE_ATTRIBUTE_DIRECTORY) && 1770c2c66affSColin Finck HCR_GetExecuteCommandW(0, L"Folder", 1771c2c66affSColin Finck sei->lpVerb, 1772c2c66affSColin Finck buffer, sizeof(buffer))) { 1773c2c66affSColin Finck SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen, 1774e018cceaSKatayama Hirofumi MZ buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen, 1775ea87f910SWhindmar Saksit !StrIsNullOrEmpty(sei->lpDirectory) ? sei->lpDirectory : NULL); 1776c2c66affSColin Finck if (resultLen > dwApplicationNameLen) 1777ea87f910SWhindmar Saksit ERR("Argify buffer not large enough... truncating\n"); // FIXME: Report this to the caller? 1778c2c66affSColin Finck appKnownSingular = FALSE; 1779ea87f910SWhindmar Saksit // HACKFIX: We really want the !appKnownSingular code in SHELL_execute to split the 1780ea87f910SWhindmar Saksit // parameters for us but we cannot guarantee that the exe in the registry is quoted. 1781ea87f910SWhindmar Saksit // We have now turned 'explorer.exe "%1" into 'explorer.exe "c:\path\from\pidl"' and 1782ea87f910SWhindmar Saksit // need to split to application and parameters. 1783ea87f910SWhindmar Saksit LPCWSTR params = PathGetArgsW(wszApplicationName); 1784ea87f910SWhindmar Saksit lstrcpynW(wszParameters, params, parametersLen); 1785ea87f910SWhindmar Saksit PathRemoveArgsW(wszApplicationName); 1786ea87f910SWhindmar Saksit PathUnquoteSpacesW(wszApplicationName); 1787ea87f910SWhindmar Saksit appKnownSingular = TRUE; 1788c2c66affSColin Finck } 1789c2c66affSColin Finck sei->fMask &= ~SEE_MASK_INVOKEIDLIST; 1790c2c66affSColin Finck } 1791c2c66affSColin Finck } 1792c2c66affSColin Finck return appKnownSingular; 1793c2c66affSColin Finck } 1794c2c66affSColin Finck 17956f277e97SKatayama Hirofumi MZ static BOOL 17966f277e97SKatayama Hirofumi MZ SHELL_InvokePidl( 17976f277e97SKatayama Hirofumi MZ _In_ LPSHELLEXECUTEINFOW sei, 17986f277e97SKatayama Hirofumi MZ _In_ LPCITEMIDLIST pidl) 17996f277e97SKatayama Hirofumi MZ { 18006f277e97SKatayama Hirofumi MZ // Bind pidl 18016f277e97SKatayama Hirofumi MZ CComPtr<IShellFolder> psfFolder; 18026f277e97SKatayama Hirofumi MZ LPCITEMIDLIST pidlLast; 18036f277e97SKatayama Hirofumi MZ HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psfFolder), &pidlLast); 18046f277e97SKatayama Hirofumi MZ if (FAILED_UNEXPECTEDLY(hr)) 18056f277e97SKatayama Hirofumi MZ return FALSE; 18066f277e97SKatayama Hirofumi MZ 18076f277e97SKatayama Hirofumi MZ // Get the context menu to invoke a command 18086f277e97SKatayama Hirofumi MZ CComPtr<IContextMenu> pCM; 18096f277e97SKatayama Hirofumi MZ hr = psfFolder->GetUIObjectOf(NULL, 1, &pidlLast, IID_NULL_PPV_ARG(IContextMenu, &pCM)); 18106f277e97SKatayama Hirofumi MZ if (FAILED_UNEXPECTEDLY(hr)) 18116f277e97SKatayama Hirofumi MZ return FALSE; 18126f277e97SKatayama Hirofumi MZ 18136f277e97SKatayama Hirofumi MZ // Invoke a command 18146f277e97SKatayama Hirofumi MZ CMINVOKECOMMANDINFO ici = { sizeof(ici) }; 18156f277e97SKatayama Hirofumi MZ ici.fMask = (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI)); 18166f277e97SKatayama Hirofumi MZ ici.nShow = sei->nShow; 18176f277e97SKatayama Hirofumi MZ ici.hwnd = sei->hwnd; 18186f277e97SKatayama Hirofumi MZ char szVerb[VERBKEY_CCHMAX]; 18196f277e97SKatayama Hirofumi MZ if (sei->lpVerb && sei->lpVerb[0]) 18206f277e97SKatayama Hirofumi MZ { 18216f277e97SKatayama Hirofumi MZ WideCharToMultiByte(CP_ACP, 0, sei->lpVerb, -1, szVerb, _countof(szVerb), NULL, NULL); 18226f277e97SKatayama Hirofumi MZ szVerb[_countof(szVerb) - 1] = ANSI_NULL; // Avoid buffer overrun 18236f277e97SKatayama Hirofumi MZ ici.lpVerb = szVerb; 18246f277e97SKatayama Hirofumi MZ } 18256f277e97SKatayama Hirofumi MZ else // The default verb? 18266f277e97SKatayama Hirofumi MZ { 18276f277e97SKatayama Hirofumi MZ HMENU hMenu = CreatePopupMenu(); 18286f277e97SKatayama Hirofumi MZ const INT idCmdFirst = 1, idCmdLast = 0x7FFF; 18296f277e97SKatayama Hirofumi MZ hr = pCM->QueryContextMenu(hMenu, 0, idCmdFirst, idCmdLast, CMF_DEFAULTONLY); 18306f277e97SKatayama Hirofumi MZ if (FAILED_UNEXPECTEDLY(hr)) 18316f277e97SKatayama Hirofumi MZ { 18326f277e97SKatayama Hirofumi MZ DestroyMenu(hMenu); 18336f277e97SKatayama Hirofumi MZ return FALSE; 18346f277e97SKatayama Hirofumi MZ } 18356f277e97SKatayama Hirofumi MZ 18366f277e97SKatayama Hirofumi MZ INT nDefaultID = GetMenuDefaultItem(hMenu, FALSE, 0); 18376f277e97SKatayama Hirofumi MZ DestroyMenu(hMenu); 18386f277e97SKatayama Hirofumi MZ if (nDefaultID == -1) 18396f277e97SKatayama Hirofumi MZ nDefaultID = idCmdFirst; 18406f277e97SKatayama Hirofumi MZ 18416f277e97SKatayama Hirofumi MZ ici.lpVerb = MAKEINTRESOURCEA(nDefaultID - idCmdFirst); 18426f277e97SKatayama Hirofumi MZ } 18436f277e97SKatayama Hirofumi MZ hr = pCM->InvokeCommand(&ici); 18446f277e97SKatayama Hirofumi MZ 18456f277e97SKatayama Hirofumi MZ return !FAILED_UNEXPECTEDLY(hr); 18466f277e97SKatayama Hirofumi MZ } 18476f277e97SKatayama Hirofumi MZ 1848c2c66affSColin Finck 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) 1849c2c66affSColin Finck { 1850c2c66affSColin Finck UINT_PTR retval; 1851c2c66affSColin Finck DWORD len; 185206b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> wszQuotedCmd; 1853c2c66affSColin Finck 1854c2c66affSColin Finck /* Length of quotes plus length of command plus NULL terminator */ 1855c2c66affSColin Finck len = 2 + lstrlenW(wcmd) + 1; 1856c2c66affSColin Finck if (wszParameters[0]) 1857c2c66affSColin Finck { 1858c2c66affSColin Finck /* Length of space plus length of parameters */ 1859c2c66affSColin Finck len += 1 + lstrlenW(wszParameters); 1860c2c66affSColin Finck } 186106b6833cSKatayama Hirofumi MZ wszQuotedCmd.Allocate(len); 1862c2c66affSColin Finck /* Must quote to handle case where cmd contains spaces, 1863c2c66affSColin Finck * else security hole if malicious user creates executable file "C:\\Program" 1864c2c66affSColin Finck */ 1865c2c66affSColin Finck strcpyW(wszQuotedCmd, L"\""); 1866c2c66affSColin Finck strcatW(wszQuotedCmd, wcmd); 1867c2c66affSColin Finck strcatW(wszQuotedCmd, L"\""); 1868c2c66affSColin Finck if (wszParameters[0]) 1869c2c66affSColin Finck { 1870c2c66affSColin Finck strcatW(wszQuotedCmd, L" "); 1871c2c66affSColin Finck strcatW(wszQuotedCmd, wszParameters); 1872c2c66affSColin Finck } 1873c2c66affSColin Finck 1874c2c66affSColin Finck TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(wszKeyname)); 1875c2c66affSColin Finck 1876c2c66affSColin Finck if (*wszKeyname) 1877c2c66affSColin Finck retval = execute_from_key(wszKeyname, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out); 1878c2c66affSColin Finck else 1879c2c66affSColin Finck retval = execfunc(wszQuotedCmd, env, FALSE, psei, psei_out); 188006b6833cSKatayama Hirofumi MZ 1881c2c66affSColin Finck return retval; 1882c2c66affSColin Finck } 1883c2c66affSColin Finck 1884c2c66affSColin Finck static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc) 1885c2c66affSColin Finck { 1886c2c66affSColin Finck UINT_PTR retval; 188706b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> lpstrProtocol; 1888c2c66affSColin Finck LPCWSTR lpstrRes; 1889c2c66affSColin Finck INT iSize; 1890c2c66affSColin Finck DWORD len; 1891c2c66affSColin Finck 1892c2c66affSColin Finck lpstrRes = strchrW(lpFile, ':'); 1893c2c66affSColin Finck if (lpstrRes) 1894c2c66affSColin Finck iSize = lpstrRes - lpFile; 1895c2c66affSColin Finck else 1896c2c66affSColin Finck iSize = strlenW(lpFile); 1897c2c66affSColin Finck 1898c2c66affSColin Finck TRACE("Got URL: %s\n", debugstr_w(lpFile)); 1899c2c66affSColin Finck /* Looking for ...<protocol>\shell\<lpVerb>\command */ 190083be315aSHermès Bélusca-Maïto len = iSize + lstrlenW(L"\\shell\\") + lstrlenW(L"\\command") + 1; 1901c2c66affSColin Finck if (psei->lpVerb && *psei->lpVerb) 1902c2c66affSColin Finck len += lstrlenW(psei->lpVerb); 1903c2c66affSColin Finck else 190483be315aSHermès Bélusca-Maïto len += lstrlenW(L"open"); 190506b6833cSKatayama Hirofumi MZ lpstrProtocol.Allocate(len); 1906c2c66affSColin Finck memcpy(lpstrProtocol, lpFile, iSize * sizeof(WCHAR)); 1907c2c66affSColin Finck lpstrProtocol[iSize] = '\0'; 190883be315aSHermès Bélusca-Maïto strcatW(lpstrProtocol, L"\\shell\\"); 190983be315aSHermès Bélusca-Maïto strcatW(lpstrProtocol, psei->lpVerb && *psei->lpVerb ? psei->lpVerb : L"open"); 191083be315aSHermès Bélusca-Maïto strcatW(lpstrProtocol, L"\\command"); 1911c2c66affSColin Finck 1912c2c66affSColin Finck retval = execute_from_key(lpstrProtocol, lpFile, NULL, psei->lpParameters, 1913c2c66affSColin Finck wcmd, execfunc, psei, psei_out); 191406b6833cSKatayama Hirofumi MZ 1915c2c66affSColin Finck return retval; 1916c2c66affSColin Finck } 1917c2c66affSColin Finck 1918c2c66affSColin Finck static void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename) 1919c2c66affSColin Finck { 1920c2c66affSColin Finck WCHAR msg[2048]; 1921c2c66affSColin Finck DWORD_PTR msgArguments[3] = { (DWORD_PTR)filename, 0, 0 }; 1922c2c66affSColin Finck DWORD error_code; 1923c2c66affSColin Finck 1924c2c66affSColin Finck error_code = GetLastError(); 1925c2c66affSColin Finck if (retval == SE_ERR_NOASSOC) 192683be315aSHermès Bélusca-Maïto LoadStringW(shell32_hInstance, IDS_SHLEXEC_NOASSOC, msg, ARRAY_SIZE(msg)); 1927c2c66affSColin Finck else 1928c2c66affSColin Finck FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, 1929c2c66affSColin Finck NULL, 1930c2c66affSColin Finck error_code, 1931c2c66affSColin Finck LANG_USER_DEFAULT, 1932c2c66affSColin Finck msg, 193383be315aSHermès Bélusca-Maïto ARRAY_SIZE(msg), 1934c2c66affSColin Finck (va_list*)msgArguments); 1935c2c66affSColin Finck 1936c2c66affSColin Finck MessageBoxW(hwnd, msg, NULL, MB_ICONERROR); 1937c2c66affSColin Finck } 1938c2c66affSColin Finck 1939c2c66affSColin Finck static WCHAR *expand_environment( const WCHAR *str ) 1940c2c66affSColin Finck { 194106b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> buf; 1942c2c66affSColin Finck DWORD len; 1943c2c66affSColin Finck 1944c2c66affSColin Finck len = ExpandEnvironmentStringsW(str, NULL, 0); 1945c2c66affSColin Finck if (!len) return NULL; 1946c2c66affSColin Finck 194706b6833cSKatayama Hirofumi MZ if (!buf.Allocate(len)) 194806b6833cSKatayama Hirofumi MZ return NULL; 1949c2c66affSColin Finck 1950c2c66affSColin Finck len = ExpandEnvironmentStringsW(str, buf, len); 1951c2c66affSColin Finck if (!len) 1952c2c66affSColin Finck return NULL; 195306b6833cSKatayama Hirofumi MZ 195406b6833cSKatayama Hirofumi MZ return buf.Detach(); 1955c2c66affSColin Finck } 1956c2c66affSColin Finck 1957c2c66affSColin Finck /************************************************************************* 1958c2c66affSColin Finck * SHELL_execute [Internal] 1959c2c66affSColin Finck */ 1960c2c66affSColin Finck static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) 1961c2c66affSColin Finck { 1962c2c66affSColin Finck static const DWORD unsupportedFlags = 1963f6f5490aSMark Jansen SEE_MASK_ICON | SEE_MASK_HOTKEY | 1964c2c66affSColin Finck SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT | 19655c22ce37SRatin Gao SEE_MASK_ASYNCOK | SEE_MASK_HMONITOR; 1966c2c66affSColin Finck 1967c2c66affSColin Finck DWORD len; 1968c2c66affSColin Finck UINT_PTR retval = SE_ERR_NOASSOC; 1969c2c66affSColin Finck BOOL appKnownSingular = FALSE; 1970c2c66affSColin Finck 1971c2c66affSColin Finck /* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */ 197206b6833cSKatayama Hirofumi MZ SHELLEXECUTEINFOW sei_tmp = *sei; 1973c2c66affSColin Finck 1974c2c66affSColin Finck TRACE("mask=0x%08x hwnd=%p verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n", 1975c2c66affSColin Finck sei_tmp.fMask, sei_tmp.hwnd, debugstr_w(sei_tmp.lpVerb), 1976c2c66affSColin Finck debugstr_w(sei_tmp.lpFile), debugstr_w(sei_tmp.lpParameters), 1977c2c66affSColin Finck debugstr_w(sei_tmp.lpDirectory), sei_tmp.nShow, 1978c2c66affSColin Finck ((sei_tmp.fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME) ? 1979c2c66affSColin Finck debugstr_w(sei_tmp.lpClass) : "not used"); 1980c2c66affSColin Finck 1981c2c66affSColin Finck sei->hProcess = NULL; 1982c2c66affSColin Finck 1983c2c66affSColin Finck /* make copies of all path/command strings */ 198406b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> wszApplicationName; 198506b6833cSKatayama Hirofumi MZ DWORD dwApplicationNameLen = MAX_PATH + 2; 1986c2c66affSColin Finck if (!sei_tmp.lpFile) 1987c2c66affSColin Finck { 198806b6833cSKatayama Hirofumi MZ wszApplicationName.Allocate(dwApplicationNameLen); 1989c2c66affSColin Finck *wszApplicationName = '\0'; 1990c2c66affSColin Finck } 1991c2c66affSColin Finck else if (*sei_tmp.lpFile == '\"' && sei_tmp.lpFile[(len = strlenW(sei_tmp.lpFile))-1] == '\"') 1992c2c66affSColin Finck { 1993c2c66affSColin Finck if(len-1 >= dwApplicationNameLen) 1994c2c66affSColin Finck dwApplicationNameLen = len; 1995c2c66affSColin Finck 199606b6833cSKatayama Hirofumi MZ wszApplicationName.Allocate(dwApplicationNameLen); 1997c2c66affSColin Finck memcpy(wszApplicationName, sei_tmp.lpFile + 1, len * sizeof(WCHAR)); 1998c2c66affSColin Finck 1999c2c66affSColin Finck if(len > 2) 2000c2c66affSColin Finck wszApplicationName[len-2] = '\0'; 2001c2c66affSColin Finck appKnownSingular = TRUE; 2002c2c66affSColin Finck 2003c2c66affSColin Finck TRACE("wszApplicationName=%s\n", debugstr_w(wszApplicationName)); 2004c2c66affSColin Finck } 2005c2c66affSColin Finck else 2006c2c66affSColin Finck { 2007c2c66affSColin Finck DWORD l = strlenW(sei_tmp.lpFile) + 1; 2008c2c66affSColin Finck if(l > dwApplicationNameLen) dwApplicationNameLen = l + 1; 200906b6833cSKatayama Hirofumi MZ wszApplicationName.Allocate(dwApplicationNameLen); 2010c2c66affSColin Finck memcpy(wszApplicationName, sei_tmp.lpFile, l * sizeof(WCHAR)); 2011d3285841SKatayama Hirofumi MZ 2012d3285841SKatayama Hirofumi MZ if (wszApplicationName[2] == 0 && wszApplicationName[1] == L':' && 2013d3285841SKatayama Hirofumi MZ ((L'A' <= wszApplicationName[0] && wszApplicationName[0] <= L'Z') || 2014d3285841SKatayama Hirofumi MZ (L'a' <= wszApplicationName[0] && wszApplicationName[0] <= L'z'))) 2015d3285841SKatayama Hirofumi MZ { 2016d3285841SKatayama Hirofumi MZ // 'C:' --> 'C:\' 2017d3285841SKatayama Hirofumi MZ PathAddBackslashW(wszApplicationName); 2018d3285841SKatayama Hirofumi MZ } 2019c2c66affSColin Finck } 2020c2c66affSColin Finck 202106b6833cSKatayama Hirofumi MZ WCHAR parametersBuffer[1024]; 202206b6833cSKatayama Hirofumi MZ LPWSTR wszParameters = parametersBuffer; 202306b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> wszParamAlloc; 202406b6833cSKatayama Hirofumi MZ DWORD parametersLen = _countof(parametersBuffer); 202506b6833cSKatayama Hirofumi MZ 2026c2c66affSColin Finck if (sei_tmp.lpParameters) 2027c2c66affSColin Finck { 2028c2c66affSColin Finck len = lstrlenW(sei_tmp.lpParameters) + 1; 2029c2c66affSColin Finck if (len > parametersLen) 2030c2c66affSColin Finck { 203106b6833cSKatayama Hirofumi MZ wszParamAlloc.Allocate(len); 203206b6833cSKatayama Hirofumi MZ wszParameters = wszParamAlloc; 2033c2c66affSColin Finck parametersLen = len; 2034c2c66affSColin Finck } 2035c2c66affSColin Finck strcpyW(wszParameters, sei_tmp.lpParameters); 2036c2c66affSColin Finck } 2037c2c66affSColin Finck else 2038c2c66affSColin Finck *wszParameters = L'\0'; 2039c2c66affSColin Finck 2040089788a5SKatayama Hirofumi MZ // Get the working directory 204106b6833cSKatayama Hirofumi MZ WCHAR dirBuffer[MAX_PATH]; 204206b6833cSKatayama Hirofumi MZ LPWSTR wszDir = dirBuffer; 2043089788a5SKatayama Hirofumi MZ wszDir[0] = UNICODE_NULL; 204406b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> wszDirAlloc; 2045089788a5SKatayama Hirofumi MZ if (sei_tmp.lpDirectory && *sei_tmp.lpDirectory) 2046c2c66affSColin Finck { 2047089788a5SKatayama Hirofumi MZ if (sei_tmp.fMask & SEE_MASK_DOENVSUBST) 2048c2c66affSColin Finck { 2049089788a5SKatayama Hirofumi MZ LPWSTR tmp = expand_environment(sei_tmp.lpDirectory); 2050089788a5SKatayama Hirofumi MZ if (tmp) 2051089788a5SKatayama Hirofumi MZ { 2052089788a5SKatayama Hirofumi MZ wszDirAlloc.Attach(tmp); 205306b6833cSKatayama Hirofumi MZ wszDir = wszDirAlloc; 2054c2c66affSColin Finck } 2055c2c66affSColin Finck } 2056c2c66affSColin Finck else 2057089788a5SKatayama Hirofumi MZ { 2058089788a5SKatayama Hirofumi MZ __SHCloneStrW(&wszDirAlloc, sei_tmp.lpDirectory); 2059089788a5SKatayama Hirofumi MZ if (wszDirAlloc) 2060089788a5SKatayama Hirofumi MZ wszDir = wszDirAlloc; 2061089788a5SKatayama Hirofumi MZ } 2062089788a5SKatayama Hirofumi MZ } 2063089788a5SKatayama Hirofumi MZ if (!wszDir[0]) 2064089788a5SKatayama Hirofumi MZ { 2065089788a5SKatayama Hirofumi MZ ::GetCurrentDirectoryW(_countof(dirBuffer), dirBuffer); 2066089788a5SKatayama Hirofumi MZ wszDir = dirBuffer; 2067089788a5SKatayama Hirofumi MZ } 2068089788a5SKatayama Hirofumi MZ // NOTE: ShellExecute should accept the invalid working directory for historical reason. 2069089788a5SKatayama Hirofumi MZ if (!PathIsDirectoryW(wszDir)) 2070089788a5SKatayama Hirofumi MZ { 2071089788a5SKatayama Hirofumi MZ INT iDrive = PathGetDriveNumberW(wszDir); 2072089788a5SKatayama Hirofumi MZ if (iDrive >= 0) 2073089788a5SKatayama Hirofumi MZ { 2074089788a5SKatayama Hirofumi MZ PathStripToRootW(wszDir); 2075089788a5SKatayama Hirofumi MZ if (!PathIsDirectoryW(wszDir)) 2076089788a5SKatayama Hirofumi MZ { 2077089788a5SKatayama Hirofumi MZ ::GetWindowsDirectoryW(dirBuffer, _countof(dirBuffer)); 2078089788a5SKatayama Hirofumi MZ wszDir = dirBuffer; 2079089788a5SKatayama Hirofumi MZ } 2080089788a5SKatayama Hirofumi MZ } 2081089788a5SKatayama Hirofumi MZ } 2082c2c66affSColin Finck 2083c2c66affSColin Finck /* adjust string pointers to point to the new buffers */ 2084c2c66affSColin Finck sei_tmp.lpFile = wszApplicationName; 2085c2c66affSColin Finck sei_tmp.lpParameters = wszParameters; 2086c2c66affSColin Finck sei_tmp.lpDirectory = wszDir; 2087c2c66affSColin Finck 2088c2c66affSColin Finck if (sei_tmp.fMask & unsupportedFlags) 2089c2c66affSColin Finck { 2090c2c66affSColin Finck FIXME("flags ignored: 0x%08x\n", sei_tmp.fMask & unsupportedFlags); 2091c2c66affSColin Finck } 2092c2c66affSColin Finck 2093c2c66affSColin Finck /* process the IDList */ 2094f6f5490aSMark Jansen if (sei_tmp.fMask & SEE_MASK_IDLIST && 2095f6f5490aSMark Jansen (sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) != SEE_MASK_INVOKEIDLIST) 2096c2c66affSColin Finck { 2097c2c66affSColin Finck CComPtr<IShellExecuteHookW> pSEH; 2098c2c66affSColin Finck 2099c2c66affSColin Finck HRESULT hr = SHBindToParent((LPCITEMIDLIST)sei_tmp.lpIDList, IID_PPV_ARG(IShellExecuteHookW, &pSEH), NULL); 2100c2c66affSColin Finck 2101c2c66affSColin Finck if (SUCCEEDED(hr)) 2102c2c66affSColin Finck { 2103c2c66affSColin Finck hr = pSEH->Execute(&sei_tmp); 2104c2c66affSColin Finck if (hr == S_OK) 2105c2c66affSColin Finck return TRUE; 2106c2c66affSColin Finck } 2107c2c66affSColin Finck 2108c2c66affSColin Finck SHGetPathFromIDListW((LPCITEMIDLIST)sei_tmp.lpIDList, wszApplicationName); 2109c2c66affSColin Finck appKnownSingular = TRUE; 2110c2c66affSColin Finck TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName)); 2111c2c66affSColin Finck } 2112c2c66affSColin Finck 2113766d04d9SKatayama Hirofumi MZ if ((sei_tmp.fMask & SEE_MASK_DOENVSUBST) && !StrIsNullOrEmpty(sei_tmp.lpFile)) 2114c2c66affSColin Finck { 211506b6833cSKatayama Hirofumi MZ WCHAR *tmp = expand_environment(sei_tmp.lpFile); 211606b6833cSKatayama Hirofumi MZ if (tmp) 2117c2c66affSColin Finck { 211806b6833cSKatayama Hirofumi MZ wszApplicationName.Attach(tmp); 211906b6833cSKatayama Hirofumi MZ sei_tmp.lpFile = wszApplicationName; 2120c2c66affSColin Finck } 2121c2c66affSColin Finck } 2122c2c66affSColin Finck 2123f6f5490aSMark Jansen if ((sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_INVOKEIDLIST) 2124f6f5490aSMark Jansen { 2125ce306b83SMark Jansen HRESULT hr = ShellExecute_ContextMenuVerb(&sei_tmp); 2126f6f5490aSMark Jansen if (SUCCEEDED(hr)) 2127f6f5490aSMark Jansen { 2128f6f5490aSMark Jansen sei->hInstApp = (HINSTANCE)42; 2129f6f5490aSMark Jansen return TRUE; 2130f6f5490aSMark Jansen } 2131f6f5490aSMark Jansen } 2132f6f5490aSMark Jansen 2133ce306b83SMark Jansen if (ERROR_SUCCESS == ShellExecute_FromContextMenuHandlers(&sei_tmp)) 2134c2c66affSColin Finck { 2135c2c66affSColin Finck sei->hInstApp = (HINSTANCE) 33; 2136c2c66affSColin Finck return TRUE; 2137c2c66affSColin Finck } 2138c2c66affSColin Finck 2139c2c66affSColin Finck if (sei_tmp.fMask & SEE_MASK_CLASSALL) 2140c2c66affSColin Finck { 2141c2c66affSColin Finck retval = SHELL_execute_class(wszApplicationName, &sei_tmp, sei, execfunc); 2142c2c66affSColin Finck if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI)) 2143c2c66affSColin Finck { 2144c2c66affSColin Finck OPENASINFO Info; 2145c2c66affSColin Finck 2146c2c66affSColin Finck //FIXME 2147c2c66affSColin Finck // need full path 2148c2c66affSColin Finck 2149c2c66affSColin Finck Info.pcszFile = wszApplicationName; 2150c2c66affSColin Finck Info.pcszClass = NULL; 2151c2c66affSColin Finck Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC; 2152c2c66affSColin Finck 2153c2c66affSColin Finck //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK) 2154c2c66affSColin Finck DBG_UNREFERENCED_LOCAL_VARIABLE(Info); 2155c2c66affSColin Finck do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName); 2156c2c66affSColin Finck } 2157c2c66affSColin Finck return retval > 32; 2158c2c66affSColin Finck } 2159c2c66affSColin Finck 21606f277e97SKatayama Hirofumi MZ if (!(sei_tmp.fMask & SEE_MASK_IDLIST) && // Not an ID List 21616f277e97SKatayama Hirofumi MZ (StrCmpNIW(sei_tmp.lpFile, L"shell:", 6) == 0 || 21626f277e97SKatayama Hirofumi MZ StrCmpNW(sei_tmp.lpFile, L"::{", 3) == 0)) 21636f277e97SKatayama Hirofumi MZ { 21646f277e97SKatayama Hirofumi MZ CComHeapPtr<ITEMIDLIST> pidlParsed; 21656f277e97SKatayama Hirofumi MZ HRESULT hr = SHParseDisplayName(sei_tmp.lpFile, NULL, &pidlParsed, 0, NULL); 21666f277e97SKatayama Hirofumi MZ if (SUCCEEDED(hr) && SHELL_InvokePidl(&sei_tmp, pidlParsed)) 21676f277e97SKatayama Hirofumi MZ { 21686f277e97SKatayama Hirofumi MZ sei_tmp.hInstApp = (HINSTANCE)UlongToHandle(42); 21696f277e97SKatayama Hirofumi MZ return TRUE; 21706f277e97SKatayama Hirofumi MZ } 21716f277e97SKatayama Hirofumi MZ } 21726f277e97SKatayama Hirofumi MZ 2173c2c66affSColin Finck /* Has the IDList not yet been translated? */ 2174c2c66affSColin Finck if (sei_tmp.fMask & SEE_MASK_IDLIST) 2175c2c66affSColin Finck { 2176c2c66affSColin Finck appKnownSingular = SHELL_translate_idlist( &sei_tmp, wszParameters, 2177c2c66affSColin Finck parametersLen, 2178c2c66affSColin Finck wszApplicationName, 2179c2c66affSColin Finck dwApplicationNameLen ); 2180c2c66affSColin Finck } 2181c2c66affSColin Finck 2182c2c66affSColin Finck /* convert file URLs */ 2183c2c66affSColin Finck if (UrlIsFileUrlW(sei_tmp.lpFile)) 2184c2c66affSColin Finck { 218506b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> buf; 218606b6833cSKatayama Hirofumi MZ DWORD size = MAX_PATH; 218706b6833cSKatayama Hirofumi MZ if (!buf.Allocate(size) || FAILED(PathCreateFromUrlW(sei_tmp.lpFile, buf, &size, 0))) 2188c2c66affSColin Finck return SE_ERR_OOM; 2189c2c66affSColin Finck 219006b6833cSKatayama Hirofumi MZ wszApplicationName.Attach(buf.Detach()); 2191c2c66affSColin Finck sei_tmp.lpFile = wszApplicationName; 2192c2c66affSColin Finck } 2193c2c66affSColin Finck 2194c2c66affSColin Finck /* Else, try to execute the filename */ 2195c2c66affSColin Finck TRACE("execute: %s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir)); 2196c2c66affSColin Finck 2197c2c66affSColin Finck /* separate out command line arguments from executable file name */ 2198266e2e50SKatayama Hirofumi MZ LPCWSTR lpFile = sei_tmp.lpFile; 2199c2c66affSColin Finck if (!*sei_tmp.lpParameters && !appKnownSingular) 2200c2c66affSColin Finck { 2201c2c66affSColin Finck /* If the executable path is quoted, handle the rest of the command line as parameters. */ 2202c2c66affSColin Finck if (sei_tmp.lpFile[0] == L'"') 2203c2c66affSColin Finck { 2204266e2e50SKatayama Hirofumi MZ LPWSTR pszArgs = PathGetArgsW(wszApplicationName); 2205266e2e50SKatayama Hirofumi MZ PathRemoveArgsW(wszApplicationName); 2206266e2e50SKatayama Hirofumi MZ PathUnquoteSpacesW(wszApplicationName); 2207266e2e50SKatayama Hirofumi MZ parametersLen = lstrlenW(pszArgs); 2208266e2e50SKatayama Hirofumi MZ if (parametersLen < _countof(parametersBuffer)) 2209c2c66affSColin Finck { 2210266e2e50SKatayama Hirofumi MZ StringCchCopyW(parametersBuffer, _countof(parametersBuffer), pszArgs); 2211266e2e50SKatayama Hirofumi MZ wszParameters = parametersBuffer; 2212c2c66affSColin Finck } 2213c2c66affSColin Finck else 2214266e2e50SKatayama Hirofumi MZ { 2215266e2e50SKatayama Hirofumi MZ wszParamAlloc.Attach(StrDupW(pszArgs)); 2216266e2e50SKatayama Hirofumi MZ wszParameters = wszParamAlloc; 2217266e2e50SKatayama Hirofumi MZ } 2218c2c66affSColin Finck } 22191b3eed58SDoug Lyons /* We have to test sei instead of sei_tmp because sei_tmp had its 22201b3eed58SDoug Lyons * input fMask modified above in SHELL_translate_idlist. 22211b3eed58SDoug Lyons * This code is needed to handle the case where we only have an 22221b3eed58SDoug Lyons * lpIDList with multiple CLSID/PIDL's (not 'My Computer' only) */ 22231b3eed58SDoug Lyons else if ((sei->fMask & SEE_MASK_IDLIST) == SEE_MASK_IDLIST) 22241b3eed58SDoug Lyons { 22251b3eed58SDoug Lyons WCHAR buffer[MAX_PATH], xlpFile[MAX_PATH]; 22261b3eed58SDoug Lyons LPWSTR space, s; 22271b3eed58SDoug Lyons 22281b3eed58SDoug Lyons LPWSTR beg = wszApplicationName; 22291b3eed58SDoug Lyons for(s = beg; (space = const_cast<LPWSTR>(strchrW(s, L' '))); s = space + 1) 22301b3eed58SDoug Lyons { 22311b3eed58SDoug Lyons int idx = space - sei_tmp.lpFile; 22321b3eed58SDoug Lyons memcpy(buffer, sei_tmp.lpFile, idx * sizeof(WCHAR)); 22331b3eed58SDoug Lyons buffer[idx] = '\0'; 22341b3eed58SDoug Lyons 22351b3eed58SDoug Lyons if (SearchPathW(*sei_tmp.lpDirectory ? sei_tmp.lpDirectory : NULL, 22361b3eed58SDoug Lyons buffer, L".exe", _countof(xlpFile), xlpFile, NULL)) 22371b3eed58SDoug Lyons { 22381b3eed58SDoug Lyons /* separate out command from parameter string */ 22391b3eed58SDoug Lyons LPCWSTR p = space + 1; 22401b3eed58SDoug Lyons 22411b3eed58SDoug Lyons while(isspaceW(*p)) 22421b3eed58SDoug Lyons ++p; 22431b3eed58SDoug Lyons 22441b3eed58SDoug Lyons strcpyW(wszParameters, p); 22451b3eed58SDoug Lyons *space = L'\0'; 22461b3eed58SDoug Lyons 22471b3eed58SDoug Lyons break; 22481b3eed58SDoug Lyons } 22491b3eed58SDoug Lyons } 2250c2c66affSColin Finck } 2251c2c66affSColin Finck } 2252c2c66affSColin Finck 225306b6833cSKatayama Hirofumi MZ WCHAR wcmdBuffer[1024]; 225406b6833cSKatayama Hirofumi MZ LPWSTR wcmd = wcmdBuffer; 225506b6833cSKatayama Hirofumi MZ DWORD wcmdLen = _countof(wcmdBuffer); 225606b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> wcmdAlloc; 22579b716539SAlex Miccolis 22589b716539SAlex Miccolis /* Only execute if it has an executable extension */ 22599b716539SAlex Miccolis if (PathIsExeW(lpFile)) 22609b716539SAlex Miccolis { 2261c2c66affSColin Finck len = lstrlenW(wszApplicationName) + 3; 2262c2c66affSColin Finck if (sei_tmp.lpParameters[0]) 2263c2c66affSColin Finck len += 1 + lstrlenW(wszParameters); 2264c2c66affSColin Finck if (len > wcmdLen) 2265c2c66affSColin Finck { 226606b6833cSKatayama Hirofumi MZ wcmdAlloc.Allocate(len); 226706b6833cSKatayama Hirofumi MZ wcmd = wcmdAlloc; 2268c2c66affSColin Finck wcmdLen = len; 2269c2c66affSColin Finck } 227006b6833cSKatayama Hirofumi MZ swprintf(wcmd, L"\"%s\"", (LPWSTR)wszApplicationName); 2271c2c66affSColin Finck if (sei_tmp.lpParameters[0]) 2272c2c66affSColin Finck { 2273c2c66affSColin Finck strcatW(wcmd, L" "); 2274c2c66affSColin Finck strcatW(wcmd, wszParameters); 2275c2c66affSColin Finck } 2276c2c66affSColin Finck 2277c2c66affSColin Finck retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei); 2278c2c66affSColin Finck if (retval > 32) 2279c2c66affSColin Finck return TRUE; 2280c2c66affSColin Finck } 2281c2c66affSColin Finck 2282c2c66affSColin Finck /* Else, try to find the executable */ 228306b6833cSKatayama Hirofumi MZ WCHAR wszKeyname[256]; 228406b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> env; 228506b6833cSKatayama Hirofumi MZ wcmd[0] = UNICODE_NULL; 2286c2c66affSColin Finck retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, wszKeyname, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters); 2287c2c66affSColin Finck if (retval > 32) /* Found */ 2288c2c66affSColin Finck { 2289c2c66affSColin Finck retval = SHELL_quote_and_execute(wcmd, wszParameters, wszKeyname, 2290c2c66affSColin Finck wszApplicationName, env, &sei_tmp, 2291c2c66affSColin Finck sei, execfunc); 2292c2c66affSColin Finck } 2293c2c66affSColin Finck else if (PathIsDirectoryW(lpFile)) 2294c2c66affSColin Finck { 2295c2c66affSColin Finck WCHAR wExec[MAX_PATH]; 229606b6833cSKatayama Hirofumi MZ CHeapPtr<WCHAR, CLocalAllocator> lpQuotedFile; 229706b6833cSKatayama Hirofumi MZ if (lpQuotedFile.Allocate(strlenW(lpFile) + 3)) 2298c2c66affSColin Finck { 2299c2c66affSColin Finck retval = SHELL_FindExecutable(sei_tmp.lpDirectory, L"explorer", 230083be315aSHermès Bélusca-Maïto L"open", wExec, MAX_PATH, 2301c2c66affSColin Finck NULL, &env, NULL, NULL); 2302c2c66affSColin Finck if (retval > 32) 2303c2c66affSColin Finck { 2304c2c66affSColin Finck swprintf(lpQuotedFile, L"\"%s\"", lpFile); 2305c2c66affSColin Finck retval = SHELL_quote_and_execute(wExec, lpQuotedFile, 2306c2c66affSColin Finck wszKeyname, 2307c2c66affSColin Finck wszApplicationName, env, 2308c2c66affSColin Finck &sei_tmp, sei, execfunc); 2309c2c66affSColin Finck } 2310c2c66affSColin Finck } 2311c2c66affSColin Finck else 2312c2c66affSColin Finck retval = 0; /* Out of memory */ 2313c2c66affSColin Finck } 2314c2c66affSColin Finck else if (PathIsURLW(lpFile)) /* File not found, check for URL */ 2315c2c66affSColin Finck { 2316c2c66affSColin Finck retval = SHELL_execute_url(lpFile, wcmd, &sei_tmp, sei, execfunc ); 2317c2c66affSColin Finck } 2318c2c66affSColin Finck /* Check if file specified is in the form www.??????.*** */ 2319c2c66affSColin Finck else if (!strncmpiW(lpFile, L"www", 3)) 2320c2c66affSColin Finck { 2321c2c66affSColin Finck /* if so, prefix lpFile with http:// and call ShellExecute */ 2322c2c66affSColin Finck WCHAR lpstrTmpFile[256]; 2323c2c66affSColin Finck strcpyW(lpstrTmpFile, L"http://"); 2324c2c66affSColin Finck strcatW(lpstrTmpFile, lpFile); 2325c2c66affSColin Finck retval = (UINT_PTR)ShellExecuteW(sei_tmp.hwnd, sei_tmp.lpVerb, lpstrTmpFile, NULL, NULL, 0); 2326c2c66affSColin Finck } 2327c2c66affSColin Finck 2328c2c66affSColin Finck TRACE("retval %lu\n", retval); 2329c2c66affSColin Finck 2330c2c66affSColin Finck if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI)) 2331c2c66affSColin Finck { 2332c2c66affSColin Finck OPENASINFO Info; 2333c2c66affSColin Finck 2334c2c66affSColin Finck //FIXME 2335c2c66affSColin Finck // need full path 2336c2c66affSColin Finck 2337c2c66affSColin Finck Info.pcszFile = wszApplicationName; 2338c2c66affSColin Finck Info.pcszClass = NULL; 2339c2c66affSColin Finck Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC; 2340c2c66affSColin Finck 2341c2c66affSColin Finck //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK) 2342c2c66affSColin Finck DBG_UNREFERENCED_LOCAL_VARIABLE(Info); 2343c2c66affSColin Finck do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName); 2344c2c66affSColin Finck } 2345c2c66affSColin Finck 2346c2c66affSColin Finck sei->hInstApp = (HINSTANCE)(retval > 32 ? 33 : retval); 2347c2c66affSColin Finck 2348c2c66affSColin Finck return retval > 32; 2349c2c66affSColin Finck } 2350c2c66affSColin Finck 2351c2c66affSColin Finck /************************************************************************* 2352c2c66affSColin Finck * ShellExecuteA [SHELL32.290] 2353c2c66affSColin Finck */ 2354c2c66affSColin Finck HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile, 2355c2c66affSColin Finck LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd) 2356c2c66affSColin Finck { 2357c2c66affSColin Finck SHELLEXECUTEINFOA sei; 2358c2c66affSColin Finck 2359c2c66affSColin Finck TRACE("%p,%s,%s,%s,%s,%d\n", 2360c2c66affSColin Finck hWnd, debugstr_a(lpVerb), debugstr_a(lpFile), 2361c2c66affSColin Finck debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd); 2362c2c66affSColin Finck 2363c2c66affSColin Finck sei.cbSize = sizeof(sei); 2364c2c66affSColin Finck sei.fMask = SEE_MASK_FLAG_NO_UI; 2365c2c66affSColin Finck sei.hwnd = hWnd; 2366c2c66affSColin Finck sei.lpVerb = lpVerb; 2367c2c66affSColin Finck sei.lpFile = lpFile; 2368c2c66affSColin Finck sei.lpParameters = lpParameters; 2369c2c66affSColin Finck sei.lpDirectory = lpDirectory; 2370c2c66affSColin Finck sei.nShow = iShowCmd; 2371c2c66affSColin Finck sei.lpIDList = 0; 2372c2c66affSColin Finck sei.lpClass = 0; 2373c2c66affSColin Finck sei.hkeyClass = 0; 2374c2c66affSColin Finck sei.dwHotKey = 0; 2375c2c66affSColin Finck sei.hProcess = 0; 2376c2c66affSColin Finck 2377fd41270dSWhindmar Saksit if (!(SHGetAppCompatFlags(SHACF_WIN95SHLEXEC) & SHACF_WIN95SHLEXEC)) 2378fd41270dSWhindmar Saksit sei.fMask |= SEE_MASK_NOASYNC; 2379c2c66affSColin Finck ShellExecuteExA(&sei); 2380c2c66affSColin Finck return sei.hInstApp; 2381c2c66affSColin Finck } 2382c2c66affSColin Finck 2383044f1819SKatayama Hirofumi MZ static DWORD 2384044f1819SKatayama Hirofumi MZ ShellExecute_Normal(_Inout_ LPSHELLEXECUTEINFOW sei) 2385044f1819SKatayama Hirofumi MZ { 2386044f1819SKatayama Hirofumi MZ // FIXME 2387044f1819SKatayama Hirofumi MZ return SHELL_execute(sei, SHELL_ExecuteW) ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND; 2388044f1819SKatayama Hirofumi MZ } 2389044f1819SKatayama Hirofumi MZ 2390044f1819SKatayama Hirofumi MZ static VOID 2391044f1819SKatayama Hirofumi MZ ShellExecute_ShowError( 2392044f1819SKatayama Hirofumi MZ _In_ const SHELLEXECUTEINFOW *ExecInfo, 2393044f1819SKatayama Hirofumi MZ _In_opt_ LPCWSTR pszCaption, 2394044f1819SKatayama Hirofumi MZ _In_ DWORD dwError) 2395044f1819SKatayama Hirofumi MZ { 2396044f1819SKatayama Hirofumi MZ // FIXME: Show error message 2397044f1819SKatayama Hirofumi MZ } 2398044f1819SKatayama Hirofumi MZ 2399c2c66affSColin Finck /************************************************************************* 2400c2c66affSColin Finck * ShellExecuteExA [SHELL32.292] 2401c2c66affSColin Finck */ 2402c2c66affSColin Finck BOOL 2403c2c66affSColin Finck WINAPI 2404c2c66affSColin Finck DECLSPEC_HOTPATCH 2405c2c66affSColin Finck ShellExecuteExA(LPSHELLEXECUTEINFOA sei) 2406c2c66affSColin Finck { 2407c2c66affSColin Finck SHELLEXECUTEINFOW seiW; 2408c2c66affSColin Finck BOOL ret; 2409c2c66affSColin Finck WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL, *wClass = NULL; 2410c2c66affSColin Finck 2411c2c66affSColin Finck TRACE("%p\n", sei); 2412c2c66affSColin Finck 2413044f1819SKatayama Hirofumi MZ if (sei->cbSize != sizeof(SHELLEXECUTEINFOA)) 2414044f1819SKatayama Hirofumi MZ { 2415044f1819SKatayama Hirofumi MZ sei->hInstApp = (HINSTANCE)ERROR_ACCESS_DENIED; 2416044f1819SKatayama Hirofumi MZ SetLastError(ERROR_ACCESS_DENIED); 2417044f1819SKatayama Hirofumi MZ return FALSE; 2418044f1819SKatayama Hirofumi MZ } 2419044f1819SKatayama Hirofumi MZ 2420c2c66affSColin Finck memcpy(&seiW, sei, sizeof(SHELLEXECUTEINFOW)); 2421c2c66affSColin Finck 2422044f1819SKatayama Hirofumi MZ seiW.cbSize = sizeof(SHELLEXECUTEINFOW); 2423044f1819SKatayama Hirofumi MZ 2424c2c66affSColin Finck if (sei->lpVerb) 2425c2c66affSColin Finck seiW.lpVerb = __SHCloneStrAtoW(&wVerb, sei->lpVerb); 2426c2c66affSColin Finck 2427c2c66affSColin Finck if (sei->lpFile) 2428c2c66affSColin Finck seiW.lpFile = __SHCloneStrAtoW(&wFile, sei->lpFile); 2429c2c66affSColin Finck 2430c2c66affSColin Finck if (sei->lpParameters) 2431c2c66affSColin Finck seiW.lpParameters = __SHCloneStrAtoW(&wParameters, sei->lpParameters); 2432c2c66affSColin Finck 2433c2c66affSColin Finck if (sei->lpDirectory) 2434c2c66affSColin Finck seiW.lpDirectory = __SHCloneStrAtoW(&wDirectory, sei->lpDirectory); 2435c2c66affSColin Finck 2436c2c66affSColin Finck if ((sei->fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME && sei->lpClass) 2437c2c66affSColin Finck seiW.lpClass = __SHCloneStrAtoW(&wClass, sei->lpClass); 2438c2c66affSColin Finck else 2439c2c66affSColin Finck seiW.lpClass = NULL; 2440c2c66affSColin Finck 2441044f1819SKatayama Hirofumi MZ ret = ShellExecuteExW(&seiW); 2442c2c66affSColin Finck 2443c2c66affSColin Finck sei->hInstApp = seiW.hInstApp; 2444c2c66affSColin Finck 2445c2c66affSColin Finck if (sei->fMask & SEE_MASK_NOCLOSEPROCESS) 2446c2c66affSColin Finck sei->hProcess = seiW.hProcess; 2447c2c66affSColin Finck 2448c2c66affSColin Finck SHFree(wVerb); 2449c2c66affSColin Finck SHFree(wFile); 2450c2c66affSColin Finck SHFree(wParameters); 2451c2c66affSColin Finck SHFree(wDirectory); 2452c2c66affSColin Finck SHFree(wClass); 2453c2c66affSColin Finck 2454c2c66affSColin Finck return ret; 2455c2c66affSColin Finck } 2456c2c66affSColin Finck 2457c2c66affSColin Finck /************************************************************************* 2458c2c66affSColin Finck * ShellExecuteExW [SHELL32.293] 2459c2c66affSColin Finck */ 2460c2c66affSColin Finck BOOL 2461c2c66affSColin Finck WINAPI 2462c2c66affSColin Finck DECLSPEC_HOTPATCH 2463c2c66affSColin Finck ShellExecuteExW(LPSHELLEXECUTEINFOW sei) 2464c2c66affSColin Finck { 2465044f1819SKatayama Hirofumi MZ HRESULT hrCoInit; 2466044f1819SKatayama Hirofumi MZ DWORD dwError; 2467044f1819SKatayama Hirofumi MZ ULONG fOldMask; 2468044f1819SKatayama Hirofumi MZ 2469044f1819SKatayama Hirofumi MZ if (sei->cbSize != sizeof(SHELLEXECUTEINFOW)) 2470044f1819SKatayama Hirofumi MZ { 24713e97f76aSKatayama Hirofumi MZ sei->hInstApp = (HINSTANCE)UlongToHandle(SE_ERR_ACCESSDENIED); 24723e97f76aSKatayama Hirofumi MZ SetLastError(ERROR_ACCESS_DENIED); 24733e97f76aSKatayama Hirofumi MZ return FALSE; 2474044f1819SKatayama Hirofumi MZ } 24753e97f76aSKatayama Hirofumi MZ 24763e97f76aSKatayama Hirofumi MZ hrCoInit = SHCoInitializeAnyApartment(); 24773e97f76aSKatayama Hirofumi MZ 2478044f1819SKatayama Hirofumi MZ if (SHRegGetBoolUSValueW(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", 2479044f1819SKatayama Hirofumi MZ L"MaximizeApps", FALSE, FALSE)) 2480044f1819SKatayama Hirofumi MZ { 2481044f1819SKatayama Hirofumi MZ switch (sei->nShow) 2482044f1819SKatayama Hirofumi MZ { 2483044f1819SKatayama Hirofumi MZ case SW_SHOW: 2484044f1819SKatayama Hirofumi MZ case SW_SHOWDEFAULT: 2485044f1819SKatayama Hirofumi MZ case SW_SHOWNORMAL: 2486044f1819SKatayama Hirofumi MZ case SW_RESTORE: 2487044f1819SKatayama Hirofumi MZ sei->nShow = SW_SHOWMAXIMIZED; 2488044f1819SKatayama Hirofumi MZ break; 2489044f1819SKatayama Hirofumi MZ default: 2490044f1819SKatayama Hirofumi MZ break; 2491044f1819SKatayama Hirofumi MZ } 2492044f1819SKatayama Hirofumi MZ } 2493044f1819SKatayama Hirofumi MZ 2494044f1819SKatayama Hirofumi MZ fOldMask = sei->fMask; 2495044f1819SKatayama Hirofumi MZ 2496044f1819SKatayama Hirofumi MZ if (!(fOldMask & SEE_MASK_NOASYNC) && SHELL_InRunDllProcess()) 2497044f1819SKatayama Hirofumi MZ sei->fMask |= SEE_MASK_WAITFORINPUTIDLE | SEE_MASK_NOASYNC; 2498044f1819SKatayama Hirofumi MZ 2499044f1819SKatayama Hirofumi MZ dwError = ShellExecute_Normal(sei); 2500044f1819SKatayama Hirofumi MZ 2501044f1819SKatayama Hirofumi MZ if (dwError && dwError != ERROR_DLL_NOT_FOUND && dwError != ERROR_CANCELLED) 2502044f1819SKatayama Hirofumi MZ ShellExecute_ShowError(sei, NULL, dwError); 2503044f1819SKatayama Hirofumi MZ 2504044f1819SKatayama Hirofumi MZ sei->fMask = fOldMask; 2505044f1819SKatayama Hirofumi MZ 2506044f1819SKatayama Hirofumi MZ if (SUCCEEDED(hrCoInit)) 2507044f1819SKatayama Hirofumi MZ CoUninitialize(); 2508044f1819SKatayama Hirofumi MZ 2509044f1819SKatayama Hirofumi MZ if (dwError) 2510044f1819SKatayama Hirofumi MZ SetLastError(dwError); 2511044f1819SKatayama Hirofumi MZ 2512044f1819SKatayama Hirofumi MZ return dwError == ERROR_SUCCESS; 2513c2c66affSColin Finck } 2514c2c66affSColin Finck 2515c2c66affSColin Finck /************************************************************************* 2516c2c66affSColin Finck * ShellExecuteW [SHELL32.294] 2517c2c66affSColin Finck */ 2518c2c66affSColin Finck HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, 2519c2c66affSColin Finck LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd) 2520c2c66affSColin Finck { 2521c2c66affSColin Finck SHELLEXECUTEINFOW sei; 2522c2c66affSColin Finck 2523c2c66affSColin Finck TRACE("\n"); 2524c2c66affSColin Finck sei.cbSize = sizeof(sei); 2525c2c66affSColin Finck sei.fMask = SEE_MASK_FLAG_NO_UI; 2526c2c66affSColin Finck sei.hwnd = hwnd; 2527c2c66affSColin Finck sei.lpVerb = lpVerb; 2528c2c66affSColin Finck sei.lpFile = lpFile; 2529c2c66affSColin Finck sei.lpParameters = lpParameters; 2530c2c66affSColin Finck sei.lpDirectory = lpDirectory; 2531c2c66affSColin Finck sei.nShow = nShowCmd; 2532c2c66affSColin Finck sei.lpIDList = 0; 2533c2c66affSColin Finck sei.lpClass = 0; 2534c2c66affSColin Finck sei.hkeyClass = 0; 2535c2c66affSColin Finck sei.dwHotKey = 0; 2536c2c66affSColin Finck sei.hProcess = 0; 2537c2c66affSColin Finck 2538fd41270dSWhindmar Saksit if (!(SHGetAppCompatFlags(SHACF_WIN95SHLEXEC) & SHACF_WIN95SHLEXEC)) 2539fd41270dSWhindmar Saksit sei.fMask |= SEE_MASK_NOASYNC; 2540fd41270dSWhindmar Saksit ShellExecuteExW(&sei); 2541c2c66affSColin Finck return sei.hInstApp; 2542c2c66affSColin Finck } 2543c2c66affSColin Finck 2544c2c66affSColin Finck /************************************************************************* 2545c2c66affSColin Finck * WOWShellExecute [SHELL32.@] 2546c2c66affSColin Finck * 2547c2c66affSColin Finck * FIXME: the callback function most likely doesn't work the same way on Windows. 2548c2c66affSColin Finck */ 2549c2c66affSColin Finck EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile, 2550c2c66affSColin Finck LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback) 2551c2c66affSColin Finck { 2552c2c66affSColin Finck SHELLEXECUTEINFOW seiW; 2553c2c66affSColin Finck WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL; 2554c2c66affSColin Finck HANDLE hProcess = 0; 2555c2c66affSColin Finck 2556c2c66affSColin Finck seiW.lpVerb = lpVerb ? __SHCloneStrAtoW(&wVerb, lpVerb) : NULL; 2557c2c66affSColin Finck seiW.lpFile = lpFile ? __SHCloneStrAtoW(&wFile, lpFile) : NULL; 2558c2c66affSColin Finck seiW.lpParameters = lpParameters ? __SHCloneStrAtoW(&wParameters, lpParameters) : NULL; 2559c2c66affSColin Finck seiW.lpDirectory = lpDirectory ? __SHCloneStrAtoW(&wDirectory, lpDirectory) : NULL; 2560c2c66affSColin Finck 2561c2c66affSColin Finck seiW.cbSize = sizeof(seiW); 2562c2c66affSColin Finck seiW.fMask = 0; 2563c2c66affSColin Finck seiW.hwnd = hWnd; 2564c2c66affSColin Finck seiW.nShow = iShowCmd; 2565c2c66affSColin Finck seiW.lpIDList = 0; 2566c2c66affSColin Finck seiW.lpClass = 0; 2567c2c66affSColin Finck seiW.hkeyClass = 0; 2568c2c66affSColin Finck seiW.dwHotKey = 0; 2569c2c66affSColin Finck seiW.hProcess = hProcess; 2570c2c66affSColin Finck 2571c2c66affSColin Finck SHELL_execute(&seiW, (SHELL_ExecuteW32)callback); 2572c2c66affSColin Finck 2573c2c66affSColin Finck SHFree(wVerb); 2574c2c66affSColin Finck SHFree(wFile); 2575c2c66affSColin Finck SHFree(wParameters); 2576c2c66affSColin Finck SHFree(wDirectory); 2577c2c66affSColin Finck return seiW.hInstApp; 2578c2c66affSColin Finck } 2579c2c66affSColin Finck 2580c2c66affSColin Finck /************************************************************************* 2581cc8b2717SKatayama Hirofumi MZ * OpenAs_RunDLLW [SHELL32.@] 2582c2c66affSColin Finck */ 2583cc8b2717SKatayama Hirofumi MZ EXTERN_C void WINAPI 2584cc8b2717SKatayama Hirofumi MZ OpenAs_RunDLLW(HWND hwnd, HINSTANCE hinst, LPCWSTR cmdline, int cmdshow) 2585c2c66affSColin Finck { 2586cc8b2717SKatayama Hirofumi MZ OPENASINFO info; 2587cc8b2717SKatayama Hirofumi MZ TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_w(cmdline), cmdshow); 2588cc8b2717SKatayama Hirofumi MZ 2589cc8b2717SKatayama Hirofumi MZ ZeroMemory(&info, sizeof(info)); 2590cc8b2717SKatayama Hirofumi MZ info.pcszFile = cmdline; 2591cc8b2717SKatayama Hirofumi MZ info.pcszClass = NULL; 2592cc8b2717SKatayama Hirofumi MZ info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC; 2593cc8b2717SKatayama Hirofumi MZ 2594cc8b2717SKatayama Hirofumi MZ SHOpenWithDialog(hwnd, &info); 2595c2c66affSColin Finck } 2596c2c66affSColin Finck 2597c2c66affSColin Finck /************************************************************************* 2598cc8b2717SKatayama Hirofumi MZ * OpenAs_RunDLLA [SHELL32.@] 2599c2c66affSColin Finck */ 2600cc8b2717SKatayama Hirofumi MZ EXTERN_C void WINAPI 2601cc8b2717SKatayama Hirofumi MZ OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int cmdshow) 2602c2c66affSColin Finck { 2603cc8b2717SKatayama Hirofumi MZ LPWSTR pszCmdLineW = NULL; 2604cc8b2717SKatayama Hirofumi MZ TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_a(cmdline), cmdshow); 2605cc8b2717SKatayama Hirofumi MZ 26063904fd62SMark Jansen if (cmdline) 2607cc8b2717SKatayama Hirofumi MZ __SHCloneStrAtoW(&pszCmdLineW, cmdline); 2608cc8b2717SKatayama Hirofumi MZ OpenAs_RunDLLW(hwnd, hinst, pszCmdLineW, cmdshow); 2609cc8b2717SKatayama Hirofumi MZ SHFree(pszCmdLineW); 2610c2c66affSColin Finck } 2611bfcbda22SKatayama Hirofumi MZ 2612bfcbda22SKatayama Hirofumi MZ /*************************************************************************/ 2613bfcbda22SKatayama Hirofumi MZ 2614bfcbda22SKatayama Hirofumi MZ static LPCWSTR 2615bfcbda22SKatayama Hirofumi MZ SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0) 2616bfcbda22SKatayama Hirofumi MZ { 2617bfcbda22SKatayama Hirofumi MZ LPCWSTR pch; 2618bfcbda22SKatayama Hirofumi MZ size_t ich = 0; 2619bfcbda22SKatayama Hirofumi MZ if (*psz == L'"') 2620bfcbda22SKatayama Hirofumi MZ { 2621bfcbda22SKatayama Hirofumi MZ // 1st argument is quoted. the string in quotes is quoted 1st argument. 2622bfcbda22SKatayama Hirofumi MZ // [pch] --> [pszArg0+ich] 2623bfcbda22SKatayama Hirofumi MZ for (pch = psz + 1; *pch && ich + 1 < cchArg0; ++ich, ++pch) 2624bfcbda22SKatayama Hirofumi MZ { 2625bfcbda22SKatayama Hirofumi MZ if (*pch == L'"' && pch[1] == L'"') 2626bfcbda22SKatayama Hirofumi MZ { 2627bfcbda22SKatayama Hirofumi MZ // doubled double quotations found! 2628bfcbda22SKatayama Hirofumi MZ pszArg0[ich] = L'"'; 2629bfcbda22SKatayama Hirofumi MZ } 2630bfcbda22SKatayama Hirofumi MZ else if (*pch == L'"') 2631bfcbda22SKatayama Hirofumi MZ { 2632bfcbda22SKatayama Hirofumi MZ // single double quotation found! 2633bfcbda22SKatayama Hirofumi MZ ++pch; 2634bfcbda22SKatayama Hirofumi MZ break; 2635bfcbda22SKatayama Hirofumi MZ } 2636bfcbda22SKatayama Hirofumi MZ else 2637bfcbda22SKatayama Hirofumi MZ { 2638bfcbda22SKatayama Hirofumi MZ // otherwise 2639bfcbda22SKatayama Hirofumi MZ pszArg0[ich] = *pch; 2640bfcbda22SKatayama Hirofumi MZ } 2641bfcbda22SKatayama Hirofumi MZ } 2642bfcbda22SKatayama Hirofumi MZ } 2643bfcbda22SKatayama Hirofumi MZ else 2644bfcbda22SKatayama Hirofumi MZ { 2645bfcbda22SKatayama Hirofumi MZ // 1st argument is unquoted. non-space sequence is 1st argument. 2646bfcbda22SKatayama Hirofumi MZ // [pch] --> [pszArg0+ich] 2647bfcbda22SKatayama Hirofumi MZ for (pch = psz; *pch && !iswspace(*pch) && ich + 1 < cchArg0; ++ich, ++pch) 2648bfcbda22SKatayama Hirofumi MZ { 2649bfcbda22SKatayama Hirofumi MZ pszArg0[ich] = *pch; 2650bfcbda22SKatayama Hirofumi MZ } 2651bfcbda22SKatayama Hirofumi MZ } 2652bfcbda22SKatayama Hirofumi MZ pszArg0[ich] = 0; 2653bfcbda22SKatayama Hirofumi MZ 2654bfcbda22SKatayama Hirofumi MZ // skip space 2655bfcbda22SKatayama Hirofumi MZ while (iswspace(*pch)) 2656bfcbda22SKatayama Hirofumi MZ ++pch; 2657bfcbda22SKatayama Hirofumi MZ 2658bfcbda22SKatayama Hirofumi MZ return pch; 2659bfcbda22SKatayama Hirofumi MZ } 2660bfcbda22SKatayama Hirofumi MZ 2661bfcbda22SKatayama Hirofumi MZ HRESULT WINAPI ShellExecCmdLine( 2662bfcbda22SKatayama Hirofumi MZ HWND hwnd, 2663bfcbda22SKatayama Hirofumi MZ LPCWSTR pwszCommand, 2664bfcbda22SKatayama Hirofumi MZ LPCWSTR pwszStartDir, 2665bfcbda22SKatayama Hirofumi MZ int nShow, 2666bfcbda22SKatayama Hirofumi MZ LPVOID pUnused, 2667bfcbda22SKatayama Hirofumi MZ DWORD dwSeclFlags) 2668bfcbda22SKatayama Hirofumi MZ { 2669bfcbda22SKatayama Hirofumi MZ SHELLEXECUTEINFOW info; 2670bfcbda22SKatayama Hirofumi MZ DWORD dwSize, dwError, dwType, dwFlags = SEE_MASK_DOENVSUBST | SEE_MASK_NOASYNC; 2671bfcbda22SKatayama Hirofumi MZ LPCWSTR pszVerb = NULL; 2672bfcbda22SKatayama Hirofumi MZ WCHAR szFile[MAX_PATH], szFile2[MAX_PATH]; 2673bfcbda22SKatayama Hirofumi MZ HRESULT hr; 2674bfcbda22SKatayama Hirofumi MZ LPCWSTR pchParams; 2675bfcbda22SKatayama Hirofumi MZ LPWSTR lpCommand = NULL; 2676bfcbda22SKatayama Hirofumi MZ 2677bfcbda22SKatayama Hirofumi MZ if (pwszCommand == NULL) 2678bfcbda22SKatayama Hirofumi MZ RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 2679bfcbda22SKatayama Hirofumi MZ 1, (ULONG_PTR*)pwszCommand); 2680bfcbda22SKatayama Hirofumi MZ 2681bfcbda22SKatayama Hirofumi MZ __SHCloneStrW(&lpCommand, pwszCommand); 2682bfcbda22SKatayama Hirofumi MZ StrTrimW(lpCommand, L" \t"); 2683bfcbda22SKatayama Hirofumi MZ 2684bfcbda22SKatayama Hirofumi MZ if (dwSeclFlags & SECL_NO_UI) 2685bfcbda22SKatayama Hirofumi MZ dwFlags |= SEE_MASK_FLAG_NO_UI; 2686bfcbda22SKatayama Hirofumi MZ if (dwSeclFlags & SECL_LOG_USAGE) 2687bfcbda22SKatayama Hirofumi MZ dwFlags |= SEE_MASK_FLAG_LOG_USAGE; 2688bfcbda22SKatayama Hirofumi MZ if (dwSeclFlags & SECL_USE_IDLIST) 2689bfcbda22SKatayama Hirofumi MZ dwFlags |= SEE_MASK_INVOKEIDLIST; 2690bfcbda22SKatayama Hirofumi MZ 2691bfcbda22SKatayama Hirofumi MZ if (dwSeclFlags & SECL_RUNAS) 2692bfcbda22SKatayama Hirofumi MZ { 2693bfcbda22SKatayama Hirofumi MZ dwSize = 0; 2694f9a55858SKatayama Hirofumi MZ hr = AssocQueryStringW(ASSOCF_NONE, ASSOCSTR_COMMAND, lpCommand, L"RunAs", NULL, &dwSize); 2695bfcbda22SKatayama Hirofumi MZ if (SUCCEEDED(hr) && dwSize != 0) 2696bfcbda22SKatayama Hirofumi MZ { 2697bfcbda22SKatayama Hirofumi MZ pszVerb = L"runas"; 2698bfcbda22SKatayama Hirofumi MZ } 2699bfcbda22SKatayama Hirofumi MZ } 2700bfcbda22SKatayama Hirofumi MZ 2701c94ca812SKatayama Hirofumi MZ if (PathIsURLW(lpCommand) || UrlIsW(lpCommand, URLIS_APPLIABLE)) 2702bfcbda22SKatayama Hirofumi MZ { 2703bfcbda22SKatayama Hirofumi MZ StringCchCopyW(szFile, _countof(szFile), lpCommand); 2704bfcbda22SKatayama Hirofumi MZ pchParams = NULL; 2705bfcbda22SKatayama Hirofumi MZ } 2706bfcbda22SKatayama Hirofumi MZ else 2707bfcbda22SKatayama Hirofumi MZ { 2708f691efefSJose Carlos Jesus PCWSTR apPathList[2]; 2709f691efefSJose Carlos Jesus 2710bfcbda22SKatayama Hirofumi MZ pchParams = SplitParams(lpCommand, szFile, _countof(szFile)); 2711932a812cSKatayama Hirofumi MZ if (szFile[0] != UNICODE_NULL && szFile[1] == L':' && 2712932a812cSKatayama Hirofumi MZ szFile[2] == UNICODE_NULL) 2713932a812cSKatayama Hirofumi MZ { 2714932a812cSKatayama Hirofumi MZ PathAddBackslashW(szFile); 2715932a812cSKatayama Hirofumi MZ } 2716fc11cf78SKatayama Hirofumi MZ 2717fc11cf78SKatayama Hirofumi MZ WCHAR szCurDir[MAX_PATH]; 2718fc11cf78SKatayama Hirofumi MZ GetCurrentDirectoryW(_countof(szCurDir), szCurDir); 2719fc11cf78SKatayama Hirofumi MZ if (pwszStartDir) 2720fc11cf78SKatayama Hirofumi MZ { 2721fc11cf78SKatayama Hirofumi MZ SetCurrentDirectoryW(pwszStartDir); 2722fc11cf78SKatayama Hirofumi MZ } 2723fc11cf78SKatayama Hirofumi MZ 2724b40046f4SKatayama Hirofumi MZ if ((PathIsRelativeW(szFile) && 2725fc11cf78SKatayama Hirofumi MZ GetFullPathNameW(szFile, _countof(szFile2), szFile2, NULL) && 2726b40046f4SKatayama Hirofumi MZ PathFileExistsW(szFile2)) || 2727b40046f4SKatayama Hirofumi MZ SearchPathW(NULL, szFile, NULL, _countof(szFile2), szFile2, NULL)) 2728fc11cf78SKatayama Hirofumi MZ { 2729fc11cf78SKatayama Hirofumi MZ StringCchCopyW(szFile, _countof(szFile), szFile2); 2730fc11cf78SKatayama Hirofumi MZ } 2731bfcbda22SKatayama Hirofumi MZ 2732f691efefSJose Carlos Jesus apPathList[0] = pwszStartDir; 2733f691efefSJose Carlos Jesus apPathList[1] = NULL; 2734f691efefSJose Carlos Jesus PathFindOnPathExW(szFile, apPathList, WHICH_DEFAULT); 2735fc11cf78SKatayama Hirofumi MZ 2736bfcbda22SKatayama Hirofumi MZ if (!(dwSeclFlags & SECL_ALLOW_NONEXE)) 2737bfcbda22SKatayama Hirofumi MZ { 2738bfcbda22SKatayama Hirofumi MZ if (!GetBinaryTypeW(szFile, &dwType)) 2739bfcbda22SKatayama Hirofumi MZ { 2740bfcbda22SKatayama Hirofumi MZ SHFree(lpCommand); 2741bfcbda22SKatayama Hirofumi MZ 2742bfcbda22SKatayama Hirofumi MZ if (!(dwSeclFlags & SECL_NO_UI)) 2743bfcbda22SKatayama Hirofumi MZ { 2744bfcbda22SKatayama Hirofumi MZ WCHAR szText[128 + MAX_PATH], szFormat[128]; 2745bfcbda22SKatayama Hirofumi MZ LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat)); 2746bfcbda22SKatayama Hirofumi MZ StringCchPrintfW(szText, _countof(szText), szFormat, szFile); 2747bfcbda22SKatayama Hirofumi MZ MessageBoxW(hwnd, szText, NULL, MB_ICONERROR); 2748bfcbda22SKatayama Hirofumi MZ } 2749bfcbda22SKatayama Hirofumi MZ return CO_E_APPNOTFOUND; 2750bfcbda22SKatayama Hirofumi MZ } 2751bfcbda22SKatayama Hirofumi MZ } 2752bfcbda22SKatayama Hirofumi MZ else 2753bfcbda22SKatayama Hirofumi MZ { 2754bfcbda22SKatayama Hirofumi MZ if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES) 2755bfcbda22SKatayama Hirofumi MZ { 2756bfcbda22SKatayama Hirofumi MZ SHFree(lpCommand); 2757bfcbda22SKatayama Hirofumi MZ 2758bfcbda22SKatayama Hirofumi MZ if (!(dwSeclFlags & SECL_NO_UI)) 2759bfcbda22SKatayama Hirofumi MZ { 2760bfcbda22SKatayama Hirofumi MZ WCHAR szText[128 + MAX_PATH], szFormat[128]; 2761bfcbda22SKatayama Hirofumi MZ LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat)); 2762bfcbda22SKatayama Hirofumi MZ StringCchPrintfW(szText, _countof(szText), szFormat, szFile); 2763bfcbda22SKatayama Hirofumi MZ MessageBoxW(hwnd, szText, NULL, MB_ICONERROR); 2764bfcbda22SKatayama Hirofumi MZ } 2765bfcbda22SKatayama Hirofumi MZ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 2766bfcbda22SKatayama Hirofumi MZ } 2767bfcbda22SKatayama Hirofumi MZ } 2768bfcbda22SKatayama Hirofumi MZ } 2769bfcbda22SKatayama Hirofumi MZ 2770bfcbda22SKatayama Hirofumi MZ ZeroMemory(&info, sizeof(info)); 2771bfcbda22SKatayama Hirofumi MZ info.cbSize = sizeof(info); 2772bfcbda22SKatayama Hirofumi MZ info.fMask = dwFlags; 2773bfcbda22SKatayama Hirofumi MZ info.hwnd = hwnd; 2774bfcbda22SKatayama Hirofumi MZ info.lpVerb = pszVerb; 2775bfcbda22SKatayama Hirofumi MZ info.lpFile = szFile; 2776bfcbda22SKatayama Hirofumi MZ info.lpParameters = (pchParams && *pchParams) ? pchParams : NULL; 2777bfcbda22SKatayama Hirofumi MZ info.lpDirectory = pwszStartDir; 2778bfcbda22SKatayama Hirofumi MZ info.nShow = nShow; 2779bfcbda22SKatayama Hirofumi MZ if (ShellExecuteExW(&info)) 2780bfcbda22SKatayama Hirofumi MZ { 2781bfcbda22SKatayama Hirofumi MZ if (info.lpIDList) 2782bfcbda22SKatayama Hirofumi MZ CoTaskMemFree(info.lpIDList); 2783bfcbda22SKatayama Hirofumi MZ 2784bfcbda22SKatayama Hirofumi MZ SHFree(lpCommand); 2785bfcbda22SKatayama Hirofumi MZ 2786bfcbda22SKatayama Hirofumi MZ return S_OK; 2787bfcbda22SKatayama Hirofumi MZ } 2788bfcbda22SKatayama Hirofumi MZ 2789bfcbda22SKatayama Hirofumi MZ dwError = GetLastError(); 2790bfcbda22SKatayama Hirofumi MZ 2791bfcbda22SKatayama Hirofumi MZ SHFree(lpCommand); 2792bfcbda22SKatayama Hirofumi MZ 2793bfcbda22SKatayama Hirofumi MZ return HRESULT_FROM_WIN32(dwError); 2794bfcbda22SKatayama Hirofumi MZ } 279510d9e9deSKatayama Hirofumi MZ 279610d9e9deSKatayama Hirofumi MZ /************************************************************************* 279710d9e9deSKatayama Hirofumi MZ * RealShellExecuteExA (SHELL32.266) 279810d9e9deSKatayama Hirofumi MZ */ 279910d9e9deSKatayama Hirofumi MZ EXTERN_C 280010d9e9deSKatayama Hirofumi MZ HINSTANCE WINAPI 280110d9e9deSKatayama Hirofumi MZ RealShellExecuteExA( 280210d9e9deSKatayama Hirofumi MZ _In_opt_ HWND hwnd, 280310d9e9deSKatayama Hirofumi MZ _In_opt_ LPCSTR lpOperation, 280410d9e9deSKatayama Hirofumi MZ _In_opt_ LPCSTR lpFile, 280510d9e9deSKatayama Hirofumi MZ _In_opt_ LPCSTR lpParameters, 280610d9e9deSKatayama Hirofumi MZ _In_opt_ LPCSTR lpDirectory, 280710d9e9deSKatayama Hirofumi MZ _In_opt_ LPSTR lpReturn, 280810d9e9deSKatayama Hirofumi MZ _In_opt_ LPCSTR lpTitle, 280910d9e9deSKatayama Hirofumi MZ _In_opt_ LPVOID lpReserved, 281010d9e9deSKatayama Hirofumi MZ _In_ INT nCmdShow, 281110d9e9deSKatayama Hirofumi MZ _Out_opt_ PHANDLE lphProcess, 281210d9e9deSKatayama Hirofumi MZ _In_ DWORD dwFlags) 281310d9e9deSKatayama Hirofumi MZ { 281410d9e9deSKatayama Hirofumi MZ SHELLEXECUTEINFOA ExecInfo; 281510d9e9deSKatayama Hirofumi MZ 281610d9e9deSKatayama Hirofumi MZ TRACE("(%p, %s, %s, %s, %s, %p, %s, %p, %u, %p, %lu)\n", 281710d9e9deSKatayama Hirofumi MZ hwnd, debugstr_a(lpOperation), debugstr_a(lpFile), debugstr_a(lpParameters), 281810d9e9deSKatayama Hirofumi MZ debugstr_a(lpDirectory), lpReserved, debugstr_a(lpTitle), 281910d9e9deSKatayama Hirofumi MZ lpReserved, nCmdShow, lphProcess, dwFlags); 282010d9e9deSKatayama Hirofumi MZ 282110d9e9deSKatayama Hirofumi MZ ZeroMemory(&ExecInfo, sizeof(ExecInfo)); 282210d9e9deSKatayama Hirofumi MZ ExecInfo.cbSize = sizeof(ExecInfo); 282310d9e9deSKatayama Hirofumi MZ ExecInfo.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_UNKNOWN_0x1000; 282410d9e9deSKatayama Hirofumi MZ ExecInfo.hwnd = hwnd; 282510d9e9deSKatayama Hirofumi MZ ExecInfo.lpVerb = lpOperation; 282610d9e9deSKatayama Hirofumi MZ ExecInfo.lpFile = lpFile; 282710d9e9deSKatayama Hirofumi MZ ExecInfo.lpParameters = lpParameters; 282810d9e9deSKatayama Hirofumi MZ ExecInfo.lpDirectory = lpDirectory; 282910d9e9deSKatayama Hirofumi MZ ExecInfo.nShow = (WORD)nCmdShow; 283010d9e9deSKatayama Hirofumi MZ 283110d9e9deSKatayama Hirofumi MZ if (lpReserved) 283210d9e9deSKatayama Hirofumi MZ { 283310d9e9deSKatayama Hirofumi MZ ExecInfo.fMask |= SEE_MASK_USE_RESERVED; 283410d9e9deSKatayama Hirofumi MZ ExecInfo.hInstApp = (HINSTANCE)lpReserved; 283510d9e9deSKatayama Hirofumi MZ } 283610d9e9deSKatayama Hirofumi MZ 283710d9e9deSKatayama Hirofumi MZ if (lpTitle) 283810d9e9deSKatayama Hirofumi MZ { 283910d9e9deSKatayama Hirofumi MZ ExecInfo.fMask |= SEE_MASK_HASTITLE; 284010d9e9deSKatayama Hirofumi MZ ExecInfo.lpClass = lpTitle; 284110d9e9deSKatayama Hirofumi MZ } 284210d9e9deSKatayama Hirofumi MZ 284310d9e9deSKatayama Hirofumi MZ if (dwFlags & 1) 284410d9e9deSKatayama Hirofumi MZ ExecInfo.fMask |= SEE_MASK_FLAG_SEPVDM; 284510d9e9deSKatayama Hirofumi MZ 284610d9e9deSKatayama Hirofumi MZ if (dwFlags & 2) 284710d9e9deSKatayama Hirofumi MZ ExecInfo.fMask |= SEE_MASK_NO_CONSOLE; 284810d9e9deSKatayama Hirofumi MZ 284910d9e9deSKatayama Hirofumi MZ if (lphProcess == NULL) 285010d9e9deSKatayama Hirofumi MZ { 285110d9e9deSKatayama Hirofumi MZ ShellExecuteExA(&ExecInfo); 285210d9e9deSKatayama Hirofumi MZ } 285310d9e9deSKatayama Hirofumi MZ else 285410d9e9deSKatayama Hirofumi MZ { 285510d9e9deSKatayama Hirofumi MZ ExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS; 285610d9e9deSKatayama Hirofumi MZ ShellExecuteExA(&ExecInfo); 285710d9e9deSKatayama Hirofumi MZ *lphProcess = ExecInfo.hProcess; 285810d9e9deSKatayama Hirofumi MZ } 285910d9e9deSKatayama Hirofumi MZ 286010d9e9deSKatayama Hirofumi MZ return ExecInfo.hInstApp; 286110d9e9deSKatayama Hirofumi MZ } 286210d9e9deSKatayama Hirofumi MZ 286310d9e9deSKatayama Hirofumi MZ /************************************************************************* 286410d9e9deSKatayama Hirofumi MZ * RealShellExecuteExW (SHELL32.267) 286510d9e9deSKatayama Hirofumi MZ */ 286610d9e9deSKatayama Hirofumi MZ EXTERN_C 286710d9e9deSKatayama Hirofumi MZ HINSTANCE WINAPI 286810d9e9deSKatayama Hirofumi MZ RealShellExecuteExW( 286910d9e9deSKatayama Hirofumi MZ _In_opt_ HWND hwnd, 287010d9e9deSKatayama Hirofumi MZ _In_opt_ LPCWSTR lpOperation, 287110d9e9deSKatayama Hirofumi MZ _In_opt_ LPCWSTR lpFile, 287210d9e9deSKatayama Hirofumi MZ _In_opt_ LPCWSTR lpParameters, 287310d9e9deSKatayama Hirofumi MZ _In_opt_ LPCWSTR lpDirectory, 287410d9e9deSKatayama Hirofumi MZ _In_opt_ LPWSTR lpReturn, 287510d9e9deSKatayama Hirofumi MZ _In_opt_ LPCWSTR lpTitle, 287610d9e9deSKatayama Hirofumi MZ _In_opt_ LPVOID lpReserved, 287710d9e9deSKatayama Hirofumi MZ _In_ INT nCmdShow, 287810d9e9deSKatayama Hirofumi MZ _Out_opt_ PHANDLE lphProcess, 287910d9e9deSKatayama Hirofumi MZ _In_ DWORD dwFlags) 288010d9e9deSKatayama Hirofumi MZ { 288110d9e9deSKatayama Hirofumi MZ SHELLEXECUTEINFOW ExecInfo; 288210d9e9deSKatayama Hirofumi MZ 288310d9e9deSKatayama Hirofumi MZ TRACE("(%p, %s, %s, %s, %s, %p, %s, %p, %u, %p, %lu)\n", 288410d9e9deSKatayama Hirofumi MZ hwnd, debugstr_w(lpOperation), debugstr_w(lpFile), debugstr_w(lpParameters), 288510d9e9deSKatayama Hirofumi MZ debugstr_w(lpDirectory), lpReserved, debugstr_w(lpTitle), 288610d9e9deSKatayama Hirofumi MZ lpReserved, nCmdShow, lphProcess, dwFlags); 288710d9e9deSKatayama Hirofumi MZ 288810d9e9deSKatayama Hirofumi MZ ZeroMemory(&ExecInfo, sizeof(ExecInfo)); 288910d9e9deSKatayama Hirofumi MZ ExecInfo.cbSize = sizeof(ExecInfo); 289010d9e9deSKatayama Hirofumi MZ ExecInfo.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_UNKNOWN_0x1000; 289110d9e9deSKatayama Hirofumi MZ ExecInfo.hwnd = hwnd; 289210d9e9deSKatayama Hirofumi MZ ExecInfo.lpVerb = lpOperation; 289310d9e9deSKatayama Hirofumi MZ ExecInfo.lpFile = lpFile; 289410d9e9deSKatayama Hirofumi MZ ExecInfo.lpParameters = lpParameters; 289510d9e9deSKatayama Hirofumi MZ ExecInfo.lpDirectory = lpDirectory; 289610d9e9deSKatayama Hirofumi MZ ExecInfo.nShow = (WORD)nCmdShow; 289710d9e9deSKatayama Hirofumi MZ 289810d9e9deSKatayama Hirofumi MZ if (lpReserved) 289910d9e9deSKatayama Hirofumi MZ { 290010d9e9deSKatayama Hirofumi MZ ExecInfo.fMask |= SEE_MASK_USE_RESERVED; 290110d9e9deSKatayama Hirofumi MZ ExecInfo.hInstApp = (HINSTANCE)lpReserved; 290210d9e9deSKatayama Hirofumi MZ } 290310d9e9deSKatayama Hirofumi MZ 290410d9e9deSKatayama Hirofumi MZ if (lpTitle) 290510d9e9deSKatayama Hirofumi MZ { 290610d9e9deSKatayama Hirofumi MZ ExecInfo.fMask |= SEE_MASK_HASTITLE; 290710d9e9deSKatayama Hirofumi MZ ExecInfo.lpClass = lpTitle; 290810d9e9deSKatayama Hirofumi MZ } 290910d9e9deSKatayama Hirofumi MZ 291010d9e9deSKatayama Hirofumi MZ if (dwFlags & 1) 291110d9e9deSKatayama Hirofumi MZ ExecInfo.fMask |= SEE_MASK_FLAG_SEPVDM; 291210d9e9deSKatayama Hirofumi MZ 291310d9e9deSKatayama Hirofumi MZ if (dwFlags & 2) 291410d9e9deSKatayama Hirofumi MZ ExecInfo.fMask |= SEE_MASK_NO_CONSOLE; 291510d9e9deSKatayama Hirofumi MZ 291610d9e9deSKatayama Hirofumi MZ if (lphProcess == NULL) 291710d9e9deSKatayama Hirofumi MZ { 291810d9e9deSKatayama Hirofumi MZ ShellExecuteExW(&ExecInfo); 291910d9e9deSKatayama Hirofumi MZ } 292010d9e9deSKatayama Hirofumi MZ else 292110d9e9deSKatayama Hirofumi MZ { 292210d9e9deSKatayama Hirofumi MZ ExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS; 292310d9e9deSKatayama Hirofumi MZ ShellExecuteExW(&ExecInfo); 292410d9e9deSKatayama Hirofumi MZ *lphProcess = ExecInfo.hProcess; 292510d9e9deSKatayama Hirofumi MZ } 292610d9e9deSKatayama Hirofumi MZ 292710d9e9deSKatayama Hirofumi MZ return ExecInfo.hInstApp; 292810d9e9deSKatayama Hirofumi MZ } 292910d9e9deSKatayama Hirofumi MZ 293010d9e9deSKatayama Hirofumi MZ /************************************************************************* 293110d9e9deSKatayama Hirofumi MZ * RealShellExecuteA (SHELL32.265) 293210d9e9deSKatayama Hirofumi MZ */ 293310d9e9deSKatayama Hirofumi MZ EXTERN_C 293410d9e9deSKatayama Hirofumi MZ HINSTANCE WINAPI 293510d9e9deSKatayama Hirofumi MZ RealShellExecuteA( 293610d9e9deSKatayama Hirofumi MZ _In_opt_ HWND hwnd, 293710d9e9deSKatayama Hirofumi MZ _In_opt_ LPCSTR lpOperation, 293810d9e9deSKatayama Hirofumi MZ _In_opt_ LPCSTR lpFile, 293910d9e9deSKatayama Hirofumi MZ _In_opt_ LPCSTR lpParameters, 294010d9e9deSKatayama Hirofumi MZ _In_opt_ LPCSTR lpDirectory, 294110d9e9deSKatayama Hirofumi MZ _In_opt_ LPSTR lpReturn, 294210d9e9deSKatayama Hirofumi MZ _In_opt_ LPCSTR lpTitle, 294310d9e9deSKatayama Hirofumi MZ _In_opt_ LPVOID lpReserved, 294410d9e9deSKatayama Hirofumi MZ _In_ INT nCmdShow, 294510d9e9deSKatayama Hirofumi MZ _Out_opt_ PHANDLE lphProcess) 294610d9e9deSKatayama Hirofumi MZ { 294710d9e9deSKatayama Hirofumi MZ return RealShellExecuteExA(hwnd, 294810d9e9deSKatayama Hirofumi MZ lpOperation, 294910d9e9deSKatayama Hirofumi MZ lpFile, 295010d9e9deSKatayama Hirofumi MZ lpParameters, 295110d9e9deSKatayama Hirofumi MZ lpDirectory, 295210d9e9deSKatayama Hirofumi MZ lpReturn, 295310d9e9deSKatayama Hirofumi MZ lpTitle, 295410d9e9deSKatayama Hirofumi MZ lpReserved, 295510d9e9deSKatayama Hirofumi MZ nCmdShow, 295610d9e9deSKatayama Hirofumi MZ lphProcess, 295710d9e9deSKatayama Hirofumi MZ 0); 295810d9e9deSKatayama Hirofumi MZ } 295910d9e9deSKatayama Hirofumi MZ 296010d9e9deSKatayama Hirofumi MZ /************************************************************************* 296110d9e9deSKatayama Hirofumi MZ * RealShellExecuteW (SHELL32.268) 296210d9e9deSKatayama Hirofumi MZ */ 296310d9e9deSKatayama Hirofumi MZ EXTERN_C 296410d9e9deSKatayama Hirofumi MZ HINSTANCE WINAPI 296510d9e9deSKatayama Hirofumi MZ RealShellExecuteW( 296610d9e9deSKatayama Hirofumi MZ _In_opt_ HWND hwnd, 296710d9e9deSKatayama Hirofumi MZ _In_opt_ LPCWSTR lpOperation, 296810d9e9deSKatayama Hirofumi MZ _In_opt_ LPCWSTR lpFile, 296910d9e9deSKatayama Hirofumi MZ _In_opt_ LPCWSTR lpParameters, 297010d9e9deSKatayama Hirofumi MZ _In_opt_ LPCWSTR lpDirectory, 297110d9e9deSKatayama Hirofumi MZ _In_opt_ LPWSTR lpReturn, 297210d9e9deSKatayama Hirofumi MZ _In_opt_ LPCWSTR lpTitle, 297310d9e9deSKatayama Hirofumi MZ _In_opt_ LPVOID lpReserved, 297410d9e9deSKatayama Hirofumi MZ _In_ INT nCmdShow, 297510d9e9deSKatayama Hirofumi MZ _Out_opt_ PHANDLE lphProcess) 297610d9e9deSKatayama Hirofumi MZ { 297710d9e9deSKatayama Hirofumi MZ return RealShellExecuteExW(hwnd, 297810d9e9deSKatayama Hirofumi MZ lpOperation, 297910d9e9deSKatayama Hirofumi MZ lpFile, 298010d9e9deSKatayama Hirofumi MZ lpParameters, 298110d9e9deSKatayama Hirofumi MZ lpDirectory, 298210d9e9deSKatayama Hirofumi MZ lpReturn, 298310d9e9deSKatayama Hirofumi MZ lpTitle, 298410d9e9deSKatayama Hirofumi MZ lpReserved, 298510d9e9deSKatayama Hirofumi MZ nCmdShow, 298610d9e9deSKatayama Hirofumi MZ lphProcess, 298710d9e9deSKatayama Hirofumi MZ 0); 298810d9e9deSKatayama Hirofumi MZ } 2989