#define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)
+typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
+ const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out);
+
static void ParseNoTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
{
bool firstCharQuote = false;
}
}
- *res = '\0';
+ used++;
+ if (res - out < static_cast<int>(len))
+ *res = '\0';
+ else
+ out[len-1] = '\0';
+
TRACE("used %i of %i space\n", used, len);
if (out_len)
*out_len = used;
static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR pszPath, UINT uOutSize)
{
STRRET strret;
- IShellFolder *desktop;
+ CComPtr<IShellFolder> desktop;
HRESULT hr = SHGetDesktopFolder(&desktop);
if (SUCCEEDED(hr))
StrRetToStrNW(pszPath, uOutSize, &strret, pidl);
-
- desktop->Release();
}
return hr;
startup.cb = sizeof(STARTUPINFOW);
startup.dwFlags = STARTF_USESHOWWINDOW;
startup.wShowWindow = psei->nShow;
+ dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
+ if (!(psei->fMask & SEE_MASK_NO_CONSOLE))
+ dwCreationFlags |= CREATE_NEW_CONSOLE;
startup.lpTitle = (LPWSTR)(psei->fMask & (SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE) ? psei->lpClass : NULL);
if (psei->fMask & SEE_MASK_HASLINKNAME)
startup.dwFlags |= STARTF_TITLEISLINKNAME;
- dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
-
- if (psei->fMask & SEE_MASK_NO_CONSOLE)
- dwCreationFlags |= CREATE_NEW_CONSOLE;
-
if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env,
lpDirectory, &startup, &info))
{
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);
return found;
}
-static UINT SHELL_FindExecutableByOperation(LPCWSTR lpOperation, LPWSTR key, LPWSTR filetype, LPWSTR command, LONG commandlen)
+/*************************************************************************
+ * SHELL_FindExecutableByVerb [Internal]
+ *
+ * called from SHELL_FindExecutable or SHELL_execute_class
+ * in/out:
+ * classname a buffer, big enough, to get the key name to do actually the
+ * command "WordPad.Document.1\\shell\\open\\command"
+ * passed as "WordPad.Document.1"
+ * in:
+ * lpVerb the operation on it (open)
+ * commandlen the size of command buffer (in bytes)
+ * out:
+ * command a buffer, to store the command to do the
+ * operation on the file
+ * key a buffer, big enough, to get the key name to do actually the
+ * command "WordPad.Document.1\\shell\\open\\command"
+ * Can be NULL
+ */
+static UINT SHELL_FindExecutableByVerb(LPCWSTR lpVerb, LPWSTR key, LPWSTR classname, LPWSTR command, LONG commandlen)
{
static const WCHAR wCommand[] = L"\\command";
HKEY hkeyClass;
WCHAR verb[MAX_PATH];
- if (RegOpenKeyExW(HKEY_CLASSES_ROOT, filetype, 0, 0x02000000, &hkeyClass))
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, classname, 0, 0x02000000, &hkeyClass))
return SE_ERR_NOASSOC;
- if (!HCR_GetDefaultVerbW(hkeyClass, lpOperation, verb, sizeof(verb) / sizeof(verb[0])))
+ if (!HCR_GetDefaultVerbW(hkeyClass, lpVerb, verb, sizeof(verb) / sizeof(verb[0])))
return SE_ERR_NOASSOC;
RegCloseKey(hkeyClass);
/* Looking for ...buffer\shell\<verb>\command */
- wcscat(filetype, L"\\shell\\");
- wcscat(filetype, verb);
- wcscat(filetype, wCommand);
+ wcscat(classname, L"\\shell\\");
+ wcscat(classname, verb);
+ wcscat(classname, wCommand);
- if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, command,
+ if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, command,
&commandlen) == ERROR_SUCCESS)
{
commandlen /= sizeof(WCHAR);
- if (key) wcscpy(key, filetype);
+ if (key) wcscpy(key, classname);
#if 0
LPWSTR tmp;
WCHAR param[256];
*/
/* Get the parameters needed by the application
from the associated ddeexec key */
- tmp = strstrW(filetype, wCommand);
+ tmp = strstrW(classname, wCommand);
tmp[0] = '\0';
- wcscat(filetype, wDdeexec);
- if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, param,
+ wcscat(classname, wDdeexec);
+ if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, param,
¶mlen) == ERROR_SUCCESS)
{
paramlen /= sizeof(WCHAR);
* Utility for code sharing between FindExecutable and ShellExecute
* in:
* lpFile the name of a file
- * lpOperation the operation on it (open)
+ * lpVerb the operation on it (open)
* out:
* lpResult a buffer, big enough :-(, to store the command to do the
* operation on the file
* command (it'll be used afterwards for more information
* on the operation)
*/
-static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation,
+static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb,
LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args)
{
WCHAR *extension = NULL; /* pointer to file extension */
- WCHAR filetype[256]; /* registry name for this filetype */
- LONG filetypelen = sizeof(filetype); /* length of above */
+ WCHAR classname[256]; /* registry name for this file type */
+ LONG classnamelen = sizeof(classname); /* length of above */
WCHAR command[1024]; /* command from registry */
WCHAR wBuffer[256]; /* Used to GetProfileString */
UINT retval = SE_ERR_NOASSOC;
{
TRACE("SearchPathW returned non-zero\n");
lpFile = xlpFile;
- /* Hey, isn't this value ignored? Why make this call? Shouldn't we return here? --dank*/
+ /* The file was found in the application-supplied default directory (or the system search path) */
+ }
+ else if (lpPath && SearchPathW(NULL, lpFile, wszExe, sizeof(xlpFile)/sizeof(WCHAR), xlpFile, NULL))
+ {
+ TRACE("SearchPathW returned non-zero\n");
+ lpFile = xlpFile;
+ /* The file was found in one of the directories in the system-wide search path */
}
attribs = GetFileAttributesW(lpFile);
if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY))
{
- wcscpy(filetype, L"Folder");
- filetypelen = 6; /* strlen("Folder") */
+ wcscpy(classname, L"Folder");
}
else
{
/* Three places to check: */
/* 1. win.ini, [windows], programs (NB no leading '.') */
- /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
+ /* 2. Registry, HKEY_CLASS_ROOT\<classname>\shell\open\command */
/* 3. win.ini, [extensions], extension (NB no leading '.' */
/* All I know of the order is that registry is checked before */
/* extensions; however, it'd make sense to check the programs */
}
/* Check registry */
- if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, filetype,
- &filetypelen) == ERROR_SUCCESS)
+ if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, classname,
+ &classnamelen) == ERROR_SUCCESS)
{
- filetypelen /= sizeof(WCHAR);
- if (filetypelen == sizeof(filetype) / sizeof(WCHAR))
- filetypelen--;
+ classnamelen /= sizeof(WCHAR);
+ if (classnamelen == sizeof(classname) / sizeof(WCHAR))
+ classnamelen--;
- filetype[filetypelen] = '\0';
- TRACE("File type: %s\n", debugstr_w(filetype));
+ classname[classnamelen] = '\0';
+ TRACE("File type: %s\n", debugstr_w(classname));
}
else
{
- *filetype = '\0';
- filetypelen = 0;
+ *classname = '\0';
}
}
- if (*filetype)
+ if (*classname)
{
- /* pass the operation string to SHELL_FindExecutableByOperation() */
- filetype[filetypelen] = '\0';
- retval = SHELL_FindExecutableByOperation(lpOperation, key, filetype, command, sizeof(command));
+ /* pass the verb string to SHELL_FindExecutableByVerb() */
+ retval = SHELL_FindExecutableByVerb(lpVerb, key, classname, command, sizeof(command));
if (retval > 32)
{
{
WCHAR regkey[256];
WCHAR * endkey = regkey + wcslen(key);
- WCHAR app[256], topic[256], ifexec[256], res[256];
+ WCHAR app[256], topic[256], ifexec[256], static_res[256];
+ WCHAR * dynamic_res=NULL;
+ WCHAR * res;
LONG applen, topiclen, ifexeclen;
WCHAR * exec;
DWORD ddeInst = 0;
DWORD tid;
- DWORD resultLen;
+ DWORD resultLen, endkeyLen;
HSZ hszApp, hszTopic;
HCONV hConv;
HDDEDATA hDdeData;
unsigned ret = SE_ERR_NOASSOC;
BOOL unicode = !(GetVersion() & 0x80000000);
+ if (strlenW(key) + 1 > sizeof(regkey) / sizeof(regkey[0]))
+ {
+ FIXME("input parameter %s larger than buffer\n", debugstr_w(key));
+ return 2;
+ }
wcscpy(regkey, key);
- wcscpy(endkey, L"\\application");
+ static const WCHAR wApplication[] = L"\\application";
+ endkeyLen = sizeof(regkey) / sizeof(regkey[0]) - (endkey - regkey);
+ if (strlenW(wApplication) + 1 > endkeyLen)
+ {
+ FIXME("endkey %s overruns buffer\n", debugstr_w(wApplication));
+ return 2;
+ }
+ wcscpy(endkey, wApplication);
applen = sizeof(app);
if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, app, &applen) != ERROR_SUCCESS)
{
/* Get application command from start string and find filename of application */
if (*start == '"')
{
+ if (strlenW(start + 1) + 1 > sizeof(command) / sizeof(command[0]))
+ {
+ FIXME("size of input parameter %s larger than buffer\n",
+ debugstr_w(start + 1));
+ return 2;
+ }
wcscpy(command, start + 1);
if ((ptr = wcschr(command, '"')))
* ptr = 0;
}
else
{
- LPWSTR p, space;
- for (p = (LPWSTR)start; (space = const_cast<LPWSTR>(strchrW(p, ' '))); p = space + 1)
+ LPCWSTR p;
+ LPWSTR space;
+ for (p = start; (space = const_cast<LPWSTR>(strchrW(p, ' '))); p = space + 1)
{
int idx = space - start;
memcpy(command, start, idx * sizeof(WCHAR));
ERR("Unable to find application path for command %s\n", debugstr_w(start));
return ERROR_ACCESS_DENIED;
}
+ if (strlenW(ptr) + 1 > sizeof(app) / sizeof(app[0]))
+ {
+ FIXME("size of found path %s larger than buffer\n", debugstr_w(ptr));
+ return 2;
+ }
wcscpy(app, ptr);
/* Remove extensions (including .so) */
*ptr = 0;
}
- wcscpy(endkey, L"\\topic");
+ static const WCHAR wTopic[] = L"\\topic";
+ if (strlenW(wTopic) + 1 > endkeyLen)
+ {
+ FIXME("endkey %s overruns buffer\n", debugstr_w(wTopic));
+ return 2;
+ }
+ wcscpy(endkey, wTopic);
topiclen = sizeof(topic);
if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, topic, &topiclen) != ERROR_SUCCESS)
{
SetLastError(ERROR_DDE_FAIL);
return 30; /* whatever */
}
- strcpyW(endkey, L"\\ifexec");
+ static const WCHAR wIfexec[] = L"\\ifexec";
+ if (strlenW(wIfexec) + 1 > endkeyLen)
+ {
+ FIXME("endkey %s overruns buffer\n", debugstr_w(wIfexec));
+ return 2;
+ }
+ strcpyW(endkey, wIfexec);
ifexeclen = sizeof(ifexec);
if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, ifexec, &ifexeclen) == ERROR_SUCCESS)
{
}
}
- SHELL_ArgifyW(res, sizeof(res) / sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen);
- if (resultLen > sizeof(res) / sizeof(WCHAR))
- ERR("Argify buffer not large enough, truncated\n");
+ SHELL_ArgifyW(static_res, sizeof(static_res)/sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen);
+ if (resultLen > sizeof(static_res)/sizeof(WCHAR))
+ {
+ res = dynamic_res = static_cast<WCHAR *>(HeapAlloc(GetProcessHeap(), 0, resultLen * sizeof(WCHAR)));
+ SHELL_ArgifyW(dynamic_res, resultLen, exec, lpFile, pidl, szCommandline, NULL);
+ }
+ else
+ res = static_res;
TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res));
/* It's documented in the KB 330337 that IE has a bug and returns
WARN("DdeClientTransaction failed with error %04x\n", DdeGetLastError(ddeInst));
ret = 33;
+ HeapFree(GetProcessHeap(), 0, dynamic_res);
+
DdeDisconnect(hConv);
error:
{
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));
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)
static IDataObject *shellex_get_dataobj( LPSHELLEXECUTEINFOW sei )
{
LPCITEMIDLIST pidllast = NULL;
- IDataObject *dataobj = NULL;
- IShellFolder *shf = NULL;
+ CComPtr<IDataObject> dataobj;
+ CComPtr<IShellFolder> shf;
LPITEMIDLIST pidl = NULL;
HRESULT r;
pidl = ILCreateFromPathW(fullpath);
}
- r = SHBindToParent(pidl, IID_IShellFolder, (LPVOID*)&shf, &pidllast);
+ r = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf), &pidllast);
if (FAILED(r))
goto end;
- shf->GetUIObjectOf(NULL, 1, &pidllast,
- IID_IDataObject, NULL, (LPVOID*) &dataobj);
+ shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IDataObject, &dataobj));
end:
if (pidl != sei->lpIDList)
ILFree(pidl);
- if (shf)
- shf->Release();
- return dataobj;
+ return dataobj.Detach();
}
static HRESULT shellex_run_context_menu_default(IShellExtInit *obj,
LPSHELLEXECUTEINFOW sei)
{
- IContextMenu *cm = NULL;
+ CComPtr<IContextMenu> cm = NULL;
CMINVOKECOMMANDINFOEX ici;
MENUITEMINFOW info;
WCHAR string[0x80];
TRACE("%p %p\n", obj, sei);
- r = obj->QueryInterface(IID_IContextMenu, (LPVOID*) &cm);
+ r = obj->QueryInterface(IID_PPV_ARG(IContextMenu, &cm));
if (FAILED(r))
return r;
memset(&ici, 0, sizeof ici);
ici.cbSize = sizeof ici;
- ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI));
+ ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI));
ici.nShow = sei->nShow;
ici.lpVerb = MAKEINTRESOURCEA(def);
ici.hwnd = sei->hwnd;
end:
if (hmenu)
DestroyMenu( hmenu );
- if (cm)
- cm->Release();
return r;
}
static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW sei)
{
+ // Can not use CComPtr here because of CoUninitialize at the end, before the destructors would run.
IDataObject *dataobj = NULL;
IObjectWithSite *ows = NULL;
IShellExtInit *obj = NULL;
goto end;
r = CoCreateInstance(*guid, NULL, CLSCTX_INPROC_SERVER,
- IID_IShellExtInit, (LPVOID*)&obj);
+ IID_PPV_ARG(IShellExtInit, &obj));
if (FAILED(r))
{
ERR("failed %08x\n", r);
if (!dataobj)
{
ERR("failed to get data object\n");
+ r = E_FAIL;
goto end;
}
if (FAILED(r))
goto end;
- r = obj->QueryInterface(IID_IObjectWithSite, (LPVOID*) &ows);
+ r = obj->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ows));
if (FAILED(r))
goto end;
return r;
}
+static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR lpstrProtocol, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc);
+
static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
{
- WCHAR execCmd[1024], wcmd[1024];
+ WCHAR execCmd[1024], classname[1024];
/* launch a document by fileclass like 'WordPad.Document.1' */
/* the Commandline contains 'c:\Path\wordpad.exe "%1"' */
/* FIXME: wcmd should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */
ULONG cmask = (psei->fMask & SEE_MASK_CLASSALL);
DWORD resultLen;
BOOL done;
+ UINT_PTR rslt;
- HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL,
- (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL,
- psei->lpVerb,
- execCmd, sizeof(execCmd));
-
- /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
- TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName));
-
- wcmd[0] = '\0';
- done = SHELL_ArgifyW(wcmd, sizeof(wcmd) / sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen);
- if (!done && wszApplicationName[0])
+ /* FIXME: remove following block when SHELL_quote_and_execute supports hkeyClass parameter */
+ if (cmask != SEE_MASK_CLASSNAME)
{
- strcatW(wcmd, L" ");
- strcatW(wcmd, wszApplicationName);
+ WCHAR wcmd[1024];
+ HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL,
+ (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL,
+ psei->lpVerb,
+ execCmd, sizeof(execCmd));
+
+ /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
+ TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName));
+
+ wcmd[0] = '\0';
+ done = SHELL_ArgifyW(wcmd, sizeof(wcmd) / sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen);
+ if (!done && wszApplicationName[0])
+ {
+ strcatW(wcmd, L" ");
+ if (*wszApplicationName != '"')
+ {
+ strcatW(wcmd, L"\"");
+ strcatW(wcmd, wszApplicationName);
+ strcatW(wcmd, L"\"");
+ }
+ else
+ strcatW(wcmd, wszApplicationName);
+ }
+ if (resultLen > sizeof(wcmd) / sizeof(WCHAR))
+ ERR("Argify buffer not large enough... truncating\n");
+ return execfunc(wcmd, NULL, FALSE, psei, psei_out);
}
- if (resultLen > sizeof(wcmd) / sizeof(WCHAR))
- ERR("Argify buffer not large enough... truncating\n");
- return execfunc(wcmd, NULL, FALSE, psei, psei_out);
+
+ strcpyW(classname, psei->lpClass);
+ rslt = SHELL_FindExecutableByVerb(psei->lpVerb, NULL, classname, execCmd, sizeof(execCmd));
+
+ TRACE("SHELL_FindExecutableByVerb returned %u (%s, %s)\n", (unsigned int)rslt, debugstr_w(classname), debugstr_w(execCmd));
+ if (33 > rslt)
+ return rslt;
+ rslt = SHELL_quote_and_execute( execCmd, L"", classname,
+ wszApplicationName, NULL, psei,
+ psei_out, execfunc );
+ return rslt;
+
}
static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen)
BOOL appKnownSingular = FALSE;
/* last chance to translate IDList: now also allow CLSID paths */
- if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, sizeof(buffer)))) {
+ if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, sizeof(buffer)/sizeof(WCHAR)))) {
if (buffer[0] == ':' && buffer[1] == ':') {
/* open shell folder for the specified class GUID */
if (strlenW(buffer) + 1 > parametersLen)
return appKnownSingular;
}
-static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR lpstrProtocol, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
+static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR wszKeyname, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
{
UINT_PTR retval;
DWORD len;
strcatW(wszQuotedCmd, wszParameters);
}
- TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(lpstrProtocol));
+ TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(wszKeyname));
- if (*lpstrProtocol)
- retval = execute_from_key(lpstrProtocol, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
+ if (*wszKeyname)
+ retval = execute_from_key(wszKeyname, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
else
retval = execfunc(wszQuotedCmd, env, FALSE, psei, psei_out);
HeapFree(GetProcessHeap(), 0, wszQuotedCmd);
return retval;
}
-static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
+static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
{
static const WCHAR wShell[] = L"\\shell\\";
static const WCHAR wCommand[] = L"\\command";
iSize = strlenW(lpFile);
TRACE("Got URL: %s\n", debugstr_w(lpFile));
- /* Looking for ...protocol\shell\lpOperation\command */
+ /* Looking for ...<protocol>\shell\<lpVerb>\command */
len = iSize + lstrlenW(wShell) + lstrlenW(wCommand) + 1;
- if (psei->lpVerb)
+ if (psei->lpVerb && *psei->lpVerb)
len += lstrlenW(psei->lpVerb);
else
len += lstrlenW(wszOpen);
memcpy(lpstrProtocol, lpFile, iSize * sizeof(WCHAR));
lpstrProtocol[iSize] = '\0';
strcatW(lpstrProtocol, wShell);
- strcatW(lpstrProtocol, psei->lpVerb ? psei->lpVerb : wszOpen);
+ strcatW(lpstrProtocol, psei->lpVerb && *psei->lpVerb ? psei->lpVerb : wszOpen);
strcatW(lpstrProtocol, wCommand);
- /* Remove File Protocol from lpFile */
- /* In the case file://path/file */
- if (!strncmpiW(lpFile, wFile, iSize))
- {
- lpFile += iSize;
- while (*lpFile == ':') lpFile++;
- }
retval = execute_from_key(lpstrProtocol, lpFile, NULL, psei->lpParameters,
wcmd, execfunc, psei, psei_out);
HeapFree(GetProcessHeap(), 0, lpstrProtocol);
return retval;
}
-void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename)
+static void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename)
{
WCHAR msg[2048];
DWORD_PTR msgArguments[3] = { (DWORD_PTR)filename, 0, 0 };
DWORD error_code;
error_code = GetLastError();
-
if (retval == SE_ERR_NOASSOC)
LoadStringW(shell32_hInstance, IDS_SHLEXEC_NOASSOC, msg, sizeof(msg) / sizeof(WCHAR));
else
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]
*/
-BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
+static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
{
static const DWORD unsupportedFlags =
SEE_MASK_INVOKEIDLIST | SEE_MASK_ICON | SEE_MASK_HOTKEY |
SHELLEXECUTEINFOW sei_tmp; /* modifiable copy of SHELLEXECUTEINFO struct */
WCHAR wfileName[MAX_PATH];
WCHAR *env;
- WCHAR lpstrProtocol[256];
+ WCHAR wszKeyname[256];
LPCWSTR lpFile;
UINT_PTR retval = SE_ERR_NOASSOC;
BOOL appKnownSingular = FALSE;
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));
/* process the IDList */
if (sei_tmp.fMask & SEE_MASK_IDLIST)
{
- IShellExecuteHookW* pSEH;
+ CComPtr<IShellExecuteHookW> pSEH;
- HRESULT hr = SHBindToParent((LPCITEMIDLIST)sei_tmp.lpIDList, IID_IShellExecuteHookW, (LPVOID*)&pSEH, NULL);
+ HRESULT hr = SHBindToParent((LPCITEMIDLIST)sei_tmp.lpIDList, IID_PPV_ARG(IShellExecuteHookW, &pSEH), NULL);
if (SUCCEEDED(hr))
{
hr = pSEH->Execute(&sei_tmp);
- pSEH->Release();
-
if (hr == S_OK)
{
HeapFree(GetProcessHeap(), 0, wszApplicationName);
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;
Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
//if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
+ DBG_UNREFERENCED_LOCAL_VARIABLE(Info);
do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
}
HeapFree(GetProcessHeap(), 0, wszApplicationName);
dwApplicationNameLen );
}
- /* expand environment strings */
- len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0);
- if (len > 0)
+ /* convert file URLs */
+ if (UrlIsFileUrlW(sei_tmp.lpFile))
{
LPWSTR buf;
- buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+ DWORD size;
+
+ size = MAX_PATH;
+ buf = static_cast<LPWSTR>(HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)));
+ if (!buf || FAILED(PathCreateFromUrlW(sei_tmp.lpFile, buf, &size, 0)))
+ {
+ HeapFree(GetProcessHeap(), 0, buf);
+ return SE_ERR_OOM;
+ }
- ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len + 1);
HeapFree(GetProcessHeap(), 0, wszApplicationName);
- dwApplicationNameLen = len + 1;
wszApplicationName = buf;
- /* appKnownSingular unmodified */
-
sei_tmp.lpFile = wszApplicationName;
}
-
- if (*sei_tmp.lpParameters)
+ else /* or expand environment strings (not both!) */
{
- len = ExpandEnvironmentStringsW(sei_tmp.lpParameters, NULL, 0);
+ len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0);
if (len > 0)
{
LPWSTR buf;
- len++;
- buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
- ExpandEnvironmentStringsW(sei_tmp.lpParameters, buf, len);
- if (wszParameters != parametersBuffer)
- HeapFree(GetProcessHeap(), 0, wszParameters);
- wszParameters = buf;
- parametersLen = len;
- sei_tmp.lpParameters = wszParameters;
+ buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+
+ ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len + 1);
+ HeapFree(GetProcessHeap(), 0, wszApplicationName);
+ wszApplicationName = buf;
+ /* appKnownSingular unmodified */
+
+ sei_tmp.lpFile = wszApplicationName;
}
}
{
end = ++src;
- while(isspace(*src))
+ while(isspaceW(*src))
++src;
}
else
/* terminate previous command string after the quote character */
*end = L'\0';
+ lpFile = wfileName;
}
else
{
}
}
- lstrcpynW(wfileName, sei_tmp.lpFile, sizeof(wfileName) / sizeof(WCHAR));
+ lpFile = sei_tmp.lpFile;
}
}
else
- lstrcpynW(wfileName, sei_tmp.lpFile, sizeof(wfileName) / sizeof(WCHAR));
-
- lpFile = wfileName;
+ lpFile = sei_tmp.lpFile;
wcmd = wcmdBuffer;
len = lstrlenW(wszApplicationName) + 3;
/* Else, try to find the executable */
wcmd[0] = L'\0';
- retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, lpstrProtocol, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
+ retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, wszKeyname, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
if (retval > 32) /* Found */
{
- retval = SHELL_quote_and_execute(wcmd, wszParameters, lpstrProtocol,
+ retval = SHELL_quote_and_execute(wcmd, wszParameters, wszKeyname,
wszApplicationName, env, &sei_tmp,
sei, execfunc);
HeapFree(GetProcessHeap(), 0, env);
{
swprintf(lpQuotedFile, L"\"%s\"", lpFile);
retval = SHELL_quote_and_execute(wExec, lpQuotedFile,
- lpstrProtocol,
+ wszKeyname,
wszApplicationName, env,
&sei_tmp, sei, execfunc);
HeapFree(GetProcessHeap(), 0, env);
}
else if (PathIsURLW(lpFile)) /* File not found, check for URL */
{
- retval = SHELL_execute_url(lpFile, L"file", wcmd, &sei_tmp, sei, execfunc );
+ retval = SHELL_execute_url(lpFile, wcmd, &sei_tmp, sei, execfunc );
}
/* Check if file specified is in the form www.??????.*** */
else if (!strncmpiW(lpFile, L"www", 3))
{
- /* if so, append lpFile http:// and call ShellExecute */
+ /* if so, prefix lpFile with http:// and call ShellExecute */
WCHAR lpstrTmpFile[256];
strcpyW(lpstrTmpFile, L"http://");
strcatW(lpstrTmpFile, lpFile);
Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
//if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
+ DBG_UNREFERENCED_LOCAL_VARIABLE(Info);
do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
}
/*************************************************************************
* ShellExecuteA [SHELL32.290]
*/
-HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile,
+HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile,
LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
{
SHELLEXECUTEINFOA sei;
TRACE("%p,%s,%s,%s,%s,%d\n",
- hWnd, debugstr_a(lpOperation), debugstr_a(lpFile),
+ hWnd, debugstr_a(lpVerb), debugstr_a(lpFile),
debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd);
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_FLAG_NO_UI;
sei.hwnd = hWnd;
- sei.lpVerb = lpOperation;
+ sei.lpVerb = lpVerb;
sei.lpFile = lpFile;
sei.lpParameters = lpParameters;
sei.lpDirectory = lpDirectory;
* ShellExecuteExA [SHELL32.292]
*
*/
-BOOL WINAPI ShellExecuteExA(LPSHELLEXECUTEINFOA sei)
+BOOL
+WINAPI
+DECLSPEC_HOTPATCH
+ShellExecuteExA(LPSHELLEXECUTEINFOA sei)
{
SHELLEXECUTEINFOW seiW;
BOOL ret;
* ShellExecuteExW [SHELL32.293]
*
*/
-BOOL WINAPI ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
+BOOL
+WINAPI
+DECLSPEC_HOTPATCH
+ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
{
return SHELL_execute(sei, SHELL_ExecuteW);
}
/*************************************************************************
* ShellExecuteW [SHELL32.294]
* from shellapi.h
- * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpOperation,
+ * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpVerb,
* LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd);
*/
-HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile,
+HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile,
LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
{
SHELLEXECUTEINFOW sei;
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_FLAG_NO_UI;
sei.hwnd = hwnd;
- sei.lpVerb = lpOperation;
+ sei.lpVerb = lpVerb;
sei.lpFile = lpFile;
sei.lpParameters = lpParameters;
sei.lpDirectory = lpDirectory;
*
* FIXME: the callback function most likely doesn't work the same way on Windows.
*/
-EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile,
+EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile,
LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback)
{
SHELLEXECUTEINFOW seiW;
WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL;
HANDLE hProcess = 0;
- seiW.lpVerb = lpOperation ? __SHCloneStrAtoW(&wVerb, lpOperation) : NULL;
+ seiW.lpVerb = lpVerb ? __SHCloneStrAtoW(&wVerb, lpVerb) : NULL;
seiW.lpFile = lpFile ? __SHCloneStrAtoW(&wFile, lpFile) : NULL;
seiW.lpParameters = lpParameters ? __SHCloneStrAtoW(&wParameters, lpParameters) : NULL;
seiW.lpDirectory = lpDirectory ? __SHCloneStrAtoW(&wDirectory, lpDirectory) : NULL;