X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=dll%2Fwin32%2Fshell32%2Fshlexec.cpp;h=55b3d051fefacfe195b94ce508a71d310ecb2e97;hp=f850ead46eb8c802a314bd6218a7ab061d846a4b;hb=bfcbda227f99c1b59e8ed71f5e0f59f793d496a1;hpb=87f326521707b050e5a974d58625927850b21210 diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp index f850ead46eb..55b3d051fef 100644 --- a/dll/win32/shell32/shlexec.cpp +++ b/dll/win32/shell32/shlexec.cpp @@ -3,6 +3,7 @@ * * Copyright 1998 Marcus Meissner * Copyright 2002 Eric Pouech + * Copyright 2018 Katayama Hirofumi MZ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,11 +21,13 @@ */ #include "precomp.h" +#include WINE_DEFAULT_DEBUG_CHANNEL(exec); static const WCHAR wszOpen[] = L"open"; static const WCHAR wszExe[] = L".exe"; +static const WCHAR wszCom[] = L".com"; #define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY) @@ -178,7 +181,7 @@ static void ParseTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, * - use rules from here http://www.autohotkey.net/~deleyd/parameters/parameters.htm */ -static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len) +static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len, const WCHAR* lpDir) { WCHAR xlpFile[1024]; BOOL done = FALSE; @@ -265,7 +268,7 @@ static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* if (!done || (*fmt == '1')) { /*FIXME Is the call to SearchPathW() really needed? We already have separated out the parameter string in args. */ - if (SearchPathW(NULL, lpFile, wszExe, sizeof(xlpFile) / sizeof(WCHAR), xlpFile, NULL)) + if (SearchPathW(lpDir, lpFile, wszExe, sizeof(xlpFile) / sizeof(WCHAR), xlpFile, NULL)) cmd = xlpFile; else cmd = lpFile; @@ -576,7 +579,15 @@ static BOOL SHELL_TryAppPathW( LPCWSTR szName, LPWSTR lpResult, WCHAR **env) wcscpy(buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"); wcscat(buffer, szName); res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp); - if (res) goto end; + if (res) + { + // Add ".exe" extension, if extension does not exists + if (PathAddExtensionW(buffer, wszExe)) + { + res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp); + } + if (res) goto end; + } len = MAX_PATH * sizeof(WCHAR); res = RegQueryValueW(hkApp, NULL, lpResult, &len); @@ -820,7 +831,7 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, if (retval > 32) { DWORD finishedLen; - SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen); + SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen, lpPath); if (finishedLen > resultLen) ERR("Argify buffer not large enough.. truncated\n"); /* Remove double quotation marks and command line arguments */ @@ -1053,11 +1064,11 @@ static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec } } - SHELL_ArgifyW(static_res, sizeof(static_res)/sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen); + SHELL_ArgifyW(static_res, sizeof(static_res)/sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen, NULL); if (resultLen > sizeof(static_res)/sizeof(WCHAR)) { res = dynamic_res = static_cast(HeapAlloc(GetProcessHeap(), 0, resultLen * sizeof(WCHAR))); - SHELL_ArgifyW(dynamic_res, resultLen, exec, lpFile, pidl, szCommandline, NULL); + SHELL_ArgifyW(dynamic_res, resultLen, exec, lpFile, pidl, szCommandline, NULL, NULL); } else res = static_res; @@ -1123,7 +1134,8 @@ static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env, if (cmdlen >= sizeof(cmd) / sizeof(WCHAR)) cmdlen = sizeof(cmd) / sizeof(WCHAR) - 1; cmd[cmdlen] = '\0'; - SHELL_ArgifyW(param, sizeof(param) / sizeof(WCHAR), cmd, lpFile, (LPITEMIDLIST)psei->lpIDList, szCommandline, &resultLen); + SHELL_ArgifyW(param, sizeof(param) / sizeof(WCHAR), cmd, lpFile, (LPITEMIDLIST)psei->lpIDList, szCommandline, &resultLen, + (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL); if (resultLen > sizeof(param) / sizeof(WCHAR)) ERR("Argify buffer not large enough, truncating\n"); } @@ -1201,6 +1213,7 @@ HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpR { UINT_PTR retval = SE_ERR_NOASSOC; WCHAR old_dir[1024]; + WCHAR res[MAX_PATH]; TRACE("File %s, Dir %s\n", debugstr_w(lpFile), debugstr_w(lpDirectory)); @@ -1214,7 +1227,9 @@ HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpR SetCurrentDirectoryW(lpDirectory); } - retval = SHELL_FindExecutable(lpDirectory, lpFile, wszOpen, lpResult, MAX_PATH, NULL, NULL, NULL, NULL); + retval = SHELL_FindExecutable(lpDirectory, lpFile, wszOpen, res, MAX_PATH, NULL, NULL, NULL, NULL); + if (retval > 32) + strcpyW(lpResult, res); TRACE("returning %s\n", debugstr_w(lpResult)); if (lpDirectory) @@ -1401,6 +1416,7 @@ static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECU if (!dataobj) { ERR("failed to get data object\n"); + r = E_FAIL; goto end; } @@ -1499,7 +1515,8 @@ static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEIN TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName)); wcmd[0] = '\0'; - done = SHELL_ArgifyW(wcmd, sizeof(wcmd) / sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen); + done = SHELL_ArgifyW(wcmd, sizeof(wcmd) / sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen, + (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL); if (!done && wszApplicationName[0]) { strcatW(wcmd, L" "); @@ -1565,7 +1582,8 @@ static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters sei->lpVerb, buffer, sizeof(buffer))) { SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen, - buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen); + buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen, + (sei->lpDirectory && *sei->lpDirectory) ? sei->lpDirectory : NULL); if (resultLen > dwApplicationNameLen) ERR("Argify buffer not large enough... truncating\n"); appKnownSingular = FALSE; @@ -1655,7 +1673,6 @@ static void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename) DWORD error_code; error_code = GetLastError(); - if (retval == SE_ERR_NOASSOC) LoadStringW(shell32_hInstance, IDS_SHLEXEC_NOASSOC, msg, sizeof(msg) / sizeof(WCHAR)); else @@ -1670,6 +1687,26 @@ static void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename) MessageBoxW(hwnd, msg, NULL, MB_ICONERROR); } +static WCHAR *expand_environment( const WCHAR *str ) +{ + WCHAR *buf; + DWORD len; + + len = ExpandEnvironmentStringsW(str, NULL, 0); + if (!len) return NULL; + + buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!buf) return NULL; + + len = ExpandEnvironmentStringsW(str, buf, len); + if (!len) + { + HeapFree(GetProcessHeap(), 0, buf); + return NULL; + } + return buf; +} + /************************************************************************* * SHELL_execute [Internal] */ @@ -1713,17 +1750,16 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR)); *wszApplicationName = '\0'; } - else if (*sei_tmp.lpFile == '\"') + else if (*sei_tmp.lpFile == '\"' && sei_tmp.lpFile[(len = strlenW(sei_tmp.lpFile))-1] == '\"') { - DWORD l = strlenW(sei_tmp.lpFile + 1); - if(l >= dwApplicationNameLen) - dwApplicationNameLen = l + 1; + if(len-1 >= dwApplicationNameLen) + dwApplicationNameLen = len; wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR)); - memcpy(wszApplicationName, sei_tmp.lpFile + 1, (l + 1)*sizeof(WCHAR)); + memcpy(wszApplicationName, sei_tmp.lpFile + 1, len * sizeof(WCHAR)); - if (wszApplicationName[l-1] == L'\"') - wszApplicationName[l-1] = L'\0'; + if(len > 2) + wszApplicationName[len-2] = '\0'; appKnownSingular = TRUE; TRACE("wszApplicationName=%s\n", debugstr_w(wszApplicationName)); @@ -1801,6 +1837,27 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName)); } + if (sei_tmp.fMask & SEE_MASK_DOENVSUBST) + { + WCHAR *tmp; + + tmp = expand_environment(sei_tmp.lpFile); + if (!tmp) + { + return FALSE; + } + HeapFree(GetProcessHeap(), 0, wszApplicationName); + sei_tmp.lpFile = wszApplicationName = tmp; + + tmp = expand_environment(sei_tmp.lpDirectory); + if (!tmp) + { + return FALSE; + } + if (wszDir != dirBuffer) HeapFree(GetProcessHeap(), 0, wszDir); + sei_tmp.lpDirectory = wszDir = tmp; + } + if (ERROR_SUCCESS == ShellExecute_FromContextMenu(&sei_tmp)) { sei->hInstApp = (HINSTANCE) 33; @@ -1862,7 +1919,6 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) } HeapFree(GetProcessHeap(), 0, wszApplicationName); - dwApplicationNameLen = lstrlenW(buf) + 1; wszApplicationName = buf; sei_tmp.lpFile = wszApplicationName; } @@ -1876,7 +1932,6 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len + 1); HeapFree(GetProcessHeap(), 0, wszApplicationName); - dwApplicationNameLen = len + 1; wszApplicationName = buf; /* appKnownSingular unmodified */ @@ -1923,7 +1978,7 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc) { end = ++src; - while(isspace(*src)) + while(isspaceW(*src)) ++src; } else @@ -2239,17 +2294,211 @@ EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFil } /************************************************************************* - * OpenAs_RunDLLA [SHELL32.@] + * OpenAs_RunDLLW [SHELL32.@] */ -EXTERN_C void WINAPI OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int cmdshow) +EXTERN_C void WINAPI +OpenAs_RunDLLW(HWND hwnd, HINSTANCE hinst, LPCWSTR cmdline, int cmdshow) { - FIXME("%p, %p, %s, %d\n", hwnd, hinst, debugstr_a(cmdline), cmdshow); + OPENASINFO info; + TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_w(cmdline), cmdshow); + + ZeroMemory(&info, sizeof(info)); + info.pcszFile = cmdline; + info.pcszClass = NULL; + info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC; + + SHOpenWithDialog(hwnd, &info); } /************************************************************************* - * OpenAs_RunDLLW [SHELL32.@] + * OpenAs_RunDLLA [SHELL32.@] */ -EXTERN_C void WINAPI OpenAs_RunDLLW(HWND hwnd, HINSTANCE hinst, LPCWSTR cmdline, int cmdshow) +EXTERN_C void WINAPI +OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int cmdshow) +{ + LPWSTR pszCmdLineW = NULL; + TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_a(cmdline), cmdshow); + + if (cmdline) + __SHCloneStrAtoW(&pszCmdLineW, cmdline); + OpenAs_RunDLLW(hwnd, hinst, pszCmdLineW, cmdshow); + SHFree(pszCmdLineW); +} + +/*************************************************************************/ + +static LPCWSTR +SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0) +{ + LPCWSTR pch; + size_t ich = 0; + if (*psz == L'"') + { + // 1st argument is quoted. the string in quotes is quoted 1st argument. + // [pch] --> [pszArg0+ich] + for (pch = psz + 1; *pch && ich + 1 < cchArg0; ++ich, ++pch) + { + if (*pch == L'"' && pch[1] == L'"') + { + // doubled double quotations found! + pszArg0[ich] = L'"'; + } + else if (*pch == L'"') + { + // single double quotation found! + ++pch; + break; + } + else + { + // otherwise + pszArg0[ich] = *pch; + } + } + } + else + { + // 1st argument is unquoted. non-space sequence is 1st argument. + // [pch] --> [pszArg0+ich] + for (pch = psz; *pch && !iswspace(*pch) && ich + 1 < cchArg0; ++ich, ++pch) + { + pszArg0[ich] = *pch; + } + } + pszArg0[ich] = 0; + + // skip space + while (iswspace(*pch)) + ++pch; + + return pch; +} + +HRESULT WINAPI ShellExecCmdLine( + HWND hwnd, + LPCWSTR pwszCommand, + LPCWSTR pwszStartDir, + int nShow, + LPVOID pUnused, + DWORD dwSeclFlags) { - FIXME("%p, %p, %s, %d\n", hwnd, hinst, debugstr_w(cmdline), cmdshow); + SHELLEXECUTEINFOW info; + DWORD dwSize, dwError, dwType, dwFlags = SEE_MASK_DOENVSUBST | SEE_MASK_NOASYNC; + LPCWSTR pszVerb = NULL; + WCHAR szFile[MAX_PATH], szFile2[MAX_PATH]; + HRESULT hr; + LPCWSTR pchParams; + LPWSTR lpCommand = NULL; + + if (pwszCommand == NULL) + RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, + 1, (ULONG_PTR*)pwszCommand); + + __SHCloneStrW(&lpCommand, pwszCommand); + StrTrimW(lpCommand, L" \t"); + + if (dwSeclFlags & SECL_NO_UI) + dwFlags |= SEE_MASK_FLAG_NO_UI; + if (dwSeclFlags & SECL_LOG_USAGE) + dwFlags |= SEE_MASK_FLAG_LOG_USAGE; + if (dwSeclFlags & SECL_USE_IDLIST) + dwFlags |= SEE_MASK_INVOKEIDLIST; + + if (dwSeclFlags & SECL_RUNAS) + { + dwSize = 0; + hr = AssocQueryStringW(0, ASSOCSTR_COMMAND, lpCommand, L"RunAs", NULL, &dwSize); + if (SUCCEEDED(hr) && dwSize != 0) + { + pszVerb = L"runas"; + } + } + + if (UrlIsFileUrlW(lpCommand)) + { + StringCchCopyW(szFile, _countof(szFile), lpCommand); + pchParams = NULL; + } + else + { + pchParams = SplitParams(lpCommand, szFile, _countof(szFile)); + if (SearchPathW(NULL, szFile, NULL, _countof(szFile2), szFile2, NULL) || + SearchPathW(NULL, szFile, wszExe, _countof(szFile2), szFile2, NULL) || + SearchPathW(NULL, szFile, wszCom, _countof(szFile2), szFile2, NULL) || + SearchPathW(pwszStartDir, szFile, NULL, _countof(szFile2), szFile2, NULL) || + SearchPathW(pwszStartDir, szFile, wszExe, _countof(szFile2), szFile2, NULL) || + SearchPathW(pwszStartDir, szFile, wszCom, _countof(szFile2), szFile2, NULL)) + { + StringCchCopyW(szFile, _countof(szFile), szFile2); + pchParams = NULL; + } + else if (SearchPathW(NULL, lpCommand, NULL, _countof(szFile2), szFile2, NULL) || + SearchPathW(NULL, lpCommand, wszExe, _countof(szFile2), szFile2, NULL) || + SearchPathW(NULL, lpCommand, wszCom, _countof(szFile2), szFile2, NULL) || + SearchPathW(pwszStartDir, lpCommand, NULL, _countof(szFile2), szFile2, NULL) || + SearchPathW(pwszStartDir, lpCommand, wszExe, _countof(szFile2), szFile2, NULL) || + SearchPathW(pwszStartDir, lpCommand, wszCom, _countof(szFile2), szFile2, NULL)) + { + StringCchCopyW(szFile, _countof(szFile), szFile2); + pchParams = NULL; + } + + if (!(dwSeclFlags & SECL_ALLOW_NONEXE)) + { + if (!GetBinaryTypeW(szFile, &dwType)) + { + SHFree(lpCommand); + + if (!(dwSeclFlags & SECL_NO_UI)) + { + WCHAR szText[128 + MAX_PATH], szFormat[128]; + LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat)); + StringCchPrintfW(szText, _countof(szText), szFormat, szFile); + MessageBoxW(hwnd, szText, NULL, MB_ICONERROR); + } + return CO_E_APPNOTFOUND; + } + } + else + { + if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES) + { + SHFree(lpCommand); + + if (!(dwSeclFlags & SECL_NO_UI)) + { + WCHAR szText[128 + MAX_PATH], szFormat[128]; + LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat)); + StringCchPrintfW(szText, _countof(szText), szFormat, szFile); + MessageBoxW(hwnd, szText, NULL, MB_ICONERROR); + } + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + } + } + + ZeroMemory(&info, sizeof(info)); + info.cbSize = sizeof(info); + info.fMask = dwFlags; + info.hwnd = hwnd; + info.lpVerb = pszVerb; + info.lpFile = szFile; + info.lpParameters = (pchParams && *pchParams) ? pchParams : NULL; + info.lpDirectory = pwszStartDir; + info.nShow = nShow; + if (ShellExecuteExW(&info)) + { + if (info.lpIDList) + CoTaskMemFree(info.lpIDList); + + SHFree(lpCommand); + + return S_OK; + } + + dwError = GetLastError(); + + SHFree(lpCommand); + + return HRESULT_FROM_WIN32(dwError); }