Commit df0a00ed authored by Martin Fuchs's avatar Martin Fuchs Committed by Alexandre Julliard

Resolve shell shortcuts and process ID lists in ShellExecute()

functions.
parent 49b2f6d9
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include "wine/winbase16.h" #include "wine/winbase16.h"
#include "shell32_main.h" #include "shell32_main.h"
#include "undocshell.h" #include "undocshell.h"
#include "pidl.h"
#include "wine/debug.h" #include "wine/debug.h"
...@@ -56,6 +57,8 @@ static const WCHAR wszOpen[] = {'o','p','e','n',0}; ...@@ -56,6 +57,8 @@ static const WCHAR wszOpen[] = {'o','p','e','n',0};
static const WCHAR wszExe[] = {'.','e','x','e',0}; static const WCHAR wszExe[] = {'.','e','x','e',0};
static const WCHAR wszILPtr[] = {':','%','p',0}; static const WCHAR wszILPtr[] = {':','%','p',0};
static const WCHAR wszShell[] = {'\\','s','h','e','l','l','\\',0}; static const WCHAR wszShell[] = {'\\','s','h','e','l','l','\\',0};
static const WCHAR wszFolder[] = {'F','o','l','d','e','r',0};
static const WCHAR wszEmpty[] = {0};
/*********************************************************************** /***********************************************************************
...@@ -186,6 +189,108 @@ static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lp ...@@ -186,6 +189,108 @@ static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lp
return done; return done;
} }
HRESULT SHELL_GetPathFromIDListForExecuteA(LPCITEMIDLIST pidl, LPSTR pszPath, UINT uOutSize)
{
STRRET strret;
IShellFolder* desktop;
HRESULT hr = SHGetDesktopFolder(&desktop);
if (SUCCEEDED(hr)) {
hr = IShellFolder_GetDisplayNameOf(desktop, pidl, SHGDN_FORPARSING, &strret);
if (SUCCEEDED(hr))
StrRetToStrNA(pszPath, uOutSize, &strret, pidl);
IShellFolder_Release(desktop);
}
return hr;
}
HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR pszPath, UINT uOutSize)
{
STRRET strret;
IShellFolder* desktop;
HRESULT hr = SHGetDesktopFolder(&desktop);
if (SUCCEEDED(hr)) {
hr = IShellFolder_GetDisplayNameOf(desktop, pidl, SHGDN_FORPARSING, &strret);
if (SUCCEEDED(hr))
StrRetToStrNW(pszPath, uOutSize, &strret, pidl);
IShellFolder_Release(desktop);
}
return hr;
}
/*************************************************************************
* SHELL_ResolveShortCutW [Internal]
* read shortcut file at 'wcmd'
*/
static HRESULT SHELL_ResolveShortCutW(LPWSTR wcmd, LPWSTR wargs, LPWSTR wdir, HWND hwnd, LPCWSTR lpVerb, int* pshowcmd, LPITEMIDLIST* ppidl)
{
IShellFolder* psf;
HRESULT hr = SHGetDesktopFolder(&psf);
*ppidl = NULL;
if (SUCCEEDED(hr)) {
LPITEMIDLIST pidl;
ULONG l;
hr = IShellFolder_ParseDisplayName(psf, 0, 0, wcmd, &l, &pidl, 0);
if (SUCCEEDED(hr)) {
IShellLinkW* psl;
hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl, &IID_IShellLinkW, NULL, (LPVOID*)&psl);
if (SUCCEEDED(hr)) {
hr = IShellLinkW_Resolve(psl, hwnd, 0);
if (SUCCEEDED(hr)) {
hr = IShellLinkW_GetPath(psl, wcmd, MAX_PATH, NULL, SLGP_UNCPRIORITY);
if (SUCCEEDED(hr)) {
if (!*wcmd) {
/* We could not translate the PIDL in the shell link into a valid file system path - so return the PIDL instead. */
hr = IShellLinkW_GetIDList(psl, ppidl);
if (SUCCEEDED(hr) && *ppidl) {
/* We got a PIDL instead of a file system path - try to translate it. */
if (SUCCEEDED(SHELL_GetPathFromIDListW(*ppidl, wcmd, MAX_PATH))) {
SHFree(*ppidl);
*ppidl = NULL;
}
}
}
if (SUCCEEDED(hr)) {
/* get command line arguments, working directory and display mode if available */
IShellLinkW_GetWorkingDirectory(psl, wdir, MAX_PATH);
IShellLinkW_GetArguments(psl, wargs, MAX_PATH);
IShellLinkW_GetShowCmd(psl, pshowcmd);
}
}
}
IShellLinkW_Release(psl);
}
SHFree(pidl);
}
IShellFolder_Release(psf);
}
return hr;
}
/************************************************************************* /*************************************************************************
* SHELL_ExecuteW [Internal] * SHELL_ExecuteW [Internal]
* *
...@@ -570,11 +675,10 @@ UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation, ...@@ -570,11 +675,10 @@ UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation,
else /* Check win.ini */ else /* Check win.ini */
{ {
static const WCHAR wExtensions[] = {'e','x','t','e','n','s','i','o','n','s',0}; static const WCHAR wExtensions[] = {'e','x','t','e','n','s','i','o','n','s',0};
static const WCHAR wEmpty[] = {0};
/* Toss the leading dot */ /* Toss the leading dot */
extension++; extension++;
if (GetProfileStringW(wExtensions, extension, wEmpty, command, sizeof(command)/sizeof(WCHAR)) > 0) if (GetProfileStringW(wExtensions, extension, wszEmpty, command, sizeof(command)/sizeof(WCHAR)) > 0)
{ {
if (strlenW(command) != 0) if (strlenW(command) != 0)
{ {
...@@ -816,6 +920,8 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun ...@@ -816,6 +920,8 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun
static const WCHAR wWww[] = {'w','w','w',0}; static const WCHAR wWww[] = {'w','w','w',0};
static const WCHAR wFile[] = {'f','i','l','e',0}; static const WCHAR wFile[] = {'f','i','l','e',0};
static const WCHAR wHttp[] = {'h','t','t','p',':','/','/',0}; static const WCHAR wHttp[] = {'h','t','t','p',':','/','/',0};
static const WCHAR wExtLnk[] = {'.','l','n','k',0};
static const WCHAR wExplorer[] = {'e','x','p','l','o','r','e','r','.','e','x','e',0};
WCHAR wszApplicationName[MAX_PATH+2], wszCommandline[1024], wszDir[MAX_PATH]; WCHAR wszApplicationName[MAX_PATH+2], wszCommandline[1024], wszDir[MAX_PATH];
SHELLEXECUTEINFOW sei_tmp; /* modifyable copy of SHELLEXECUTEINFO struct */ SHELLEXECUTEINFOW sei_tmp; /* modifyable copy of SHELLEXECUTEINFO struct */
...@@ -826,6 +932,7 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun ...@@ -826,6 +932,7 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun
UINT retval = 31; UINT retval = 31;
WCHAR wcmd[1024]; WCHAR wcmd[1024];
WCHAR buffer[MAX_PATH]; WCHAR buffer[MAX_PATH];
const WCHAR* ext;
BOOL done; BOOL done;
/* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */ /* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */
...@@ -918,6 +1025,73 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun ...@@ -918,6 +1025,73 @@ BOOL WINAPI ShellExecuteExW32 (LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfun
return FALSE; return FALSE;
} }
/* resolve shell shortcuts */
ext = PathFindExtensionW(sei_tmp.lpFile);
if (ext && !strcmpiW(ext, wExtLnk)) /* or check for: shell_attribs & SFGAO_LINK */
{
HRESULT hr;
/* expand paths before reading shell link */
if (ExpandEnvironmentStringsW(sei_tmp.lpFile, buffer, MAX_PATH))
lstrcpyW(wszApplicationName/*sei_tmp.lpFile*/, buffer);
if (*sei_tmp.lpParameters)
if (ExpandEnvironmentStringsW(sei_tmp.lpParameters, buffer, MAX_PATH))
lstrcpyW(wszCommandline/*sei_tmp.lpParameters*/, buffer);
hr = SHELL_ResolveShortCutW((LPWSTR)sei_tmp.lpFile, (LPWSTR)sei_tmp.lpParameters, (LPWSTR)sei_tmp.lpDirectory,
sei_tmp.hwnd, sei_tmp.lpVerb?sei_tmp.lpVerb:wszEmpty, &sei_tmp.nShow, (LPITEMIDLIST*)&sei_tmp.lpIDList);
if (sei->lpIDList)
sei->fMask |= SEE_MASK_IDLIST;
if (SUCCEEDED(hr))
{
/* repeat IDList processing if needed */
if (sei_tmp.fMask & SEE_MASK_IDLIST)
{
IShellExecuteHookW* pSEH;
HRESULT hr = SHBindToParent(sei_tmp.lpIDList, &IID_IShellExecuteHookW, (LPVOID*)&pSEH, NULL);
if (SUCCEEDED(hr))
{
hr = IShellExecuteHookW_Execute(pSEH, sei);
IShellExecuteHookW_Release(pSEH);
if (hr == S_OK)
return TRUE;
}
TRACE("-- idlist=%p (%s)\n", debugstr_w(sei_tmp.lpIDList), debugstr_w(sei_tmp.lpFile));
}
}
}
/* Has the IDList not yet been translated? */
if (sei_tmp.fMask & SEE_MASK_IDLIST)
{
/* last chance to translate IDList: now also allow CLSID paths */
if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW(sei_tmp.lpIDList, buffer, sizeof(buffer)))) {
if (buffer[0]==':' && buffer[1]==':') {
/* open shell folder for the specified class GUID */
strcpyW(wszCommandline, buffer);
strcpyW(wszApplicationName, wExplorer);
sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST;
} else if (HCR_GetExecuteCommandW(0, wszFolder, sei_tmp.lpVerb?sei_tmp.lpVerb:wszOpen, buffer, sizeof(buffer))) {
SHELL_ArgifyW(wszApplicationName, sizeof(wszApplicationName)/sizeof(WCHAR), buffer, NULL, sei_tmp.lpIDList, NULL);
sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST;
}
}
}
/* expand environment strings */ /* expand environment strings */
if (ExpandEnvironmentStringsW(sei_tmp.lpFile, buffer, MAX_PATH)) if (ExpandEnvironmentStringsW(sei_tmp.lpFile, buffer, MAX_PATH))
lstrcpyW(wszApplicationName, buffer); lstrcpyW(wszApplicationName, buffer);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment