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