https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f6f5490ab41a4446a6026…
commit f6f5490ab41a4446a6026c81bea4cc8255584184
Author: Mark Jansen <mark.jansen(a)reactos.org>
AuthorDate: Thu Feb 3 21:54:12 2022 +0100
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Mon Feb 7 20:56:21 2022 +0100
[SHELL32] ShellExecute: Implement SEE_MASK_INVOKEIDLIST
CORE-18035
Also simplify some error handling by using smart pointers
---
dll/win32/shell32/folders/CFSFolder.cpp | 4 +-
dll/win32/shell32/shlexec.cpp | 194 ++++++++++++++++++++++----------
2 files changed, 138 insertions(+), 60 deletions(-)
diff --git a/dll/win32/shell32/folders/CFSFolder.cpp
b/dll/win32/shell32/folders/CFSFolder.cpp
index 72325d3973b..c332d812d3a 100644
--- a/dll/win32/shell32/folders/CFSFolder.cpp
+++ b/dll/win32/shell32/folders/CFSFolder.cpp
@@ -1812,8 +1812,8 @@ HRESULT WINAPI CFSFolder::CallBack(IShellFolder *psf, HWND
hwndOwner, IDataObjec
PUITEMID_CHILD pidlChild = ILClone(ILFindLastID(m_pidlRoot));
LPITEMIDLIST pidlParent = ILClone(m_pidlRoot);
ILRemoveLastID(pidlParent);
- HRESULT hr = SH_ShowPropertiesDialog(m_sPathTarget, pidlParent,
&pidlChild);
- if (FAILED(hr))
+ BOOL bSuccess = SH_ShowPropertiesDialog(m_sPathTarget, pidlParent,
&pidlChild);
+ if (!bSuccess)
ERR("SH_ShowPropertiesDialog failed\n");
ILFree(pidlChild);
ILFree(pidlParent);
diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp
index 955d2af840e..7cfc0021470 100644
--- a/dll/win32/shell32/shlexec.cpp
+++ b/dll/win32/shell32/shlexec.cpp
@@ -1327,16 +1327,15 @@ static HKEY ShellExecute_GetClassKey(const SHELLEXECUTEINFOW
*sei)
return hkey;
}
-static IDataObject *shellex_get_dataobj( LPSHELLEXECUTEINFOW sei )
+static HRESULT shellex_get_dataobj( LPSHELLEXECUTEINFOW sei,
CComPtr<IDataObject>& dataObj)
{
- LPCITEMIDLIST pidllast = NULL;
- CComPtr<IDataObject> dataobj;
- CComPtr<IShellFolder> shf;
+ CComHeapPtr<ITEMIDLIST> allocatedPidl;
LPITEMIDLIST pidl = NULL;
- HRESULT r;
if (sei->fMask & SEE_MASK_CLASSALL)
+ {
pidl = (LPITEMIDLIST)sei->lpIDList;
+ }
else
{
WCHAR fullpath[MAX_PATH];
@@ -1345,21 +1344,19 @@ static IDataObject *shellex_get_dataobj( LPSHELLEXECUTEINFOW sei
)
fullpath[0] = 0;
ret = GetFullPathNameW(sei->lpFile, MAX_PATH, fullpath, NULL);
if (!ret)
- goto end;
+ return HRESULT_FROM_WIN32(GetLastError());
pidl = ILCreateFromPathW(fullpath);
+ allocatedPidl.Attach(pidl);
}
- r = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf), &pidllast);
- if (FAILED(r))
- goto end;
-
- shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IDataObject,
&dataobj));
+ CComPtr<IShellFolder> shf;
+ LPCITEMIDLIST pidllast = NULL;
+ HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf),
&pidllast);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
-end:
- if (pidl != sei->lpIDList)
- ILFree(pidl);
- return dataobj.Detach();
+ return shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IDataObject,
&dataObj));
}
static HRESULT shellex_run_context_menu_default(IShellExtInit *obj,
@@ -1431,60 +1428,128 @@ end:
return r;
}
-static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW
sei)
+namespace
{
- // 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;
- HRESULT r;
+ struct CCoInit
+ {
+ CCoInit() { hres = CoInitialize(NULL); }
+ ~CCoInit() { if (SUCCEEDED(hres)) { CoUninitialize(); } }
+ HRESULT hres;
+ };
+}
+static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW
sei)
+{
TRACE("%p %s %p\n", hkey, debugstr_guid(guid), sei);
- r = CoInitialize(NULL);
- if (FAILED(r))
- goto end;
+ CCoInit coInit;
+
+ if (FAILED_UNEXPECTEDLY(coInit.hres))
+ return coInit.hres;
- r = CoCreateInstance(*guid, NULL, CLSCTX_INPROC_SERVER,
+ CComPtr<IShellExtInit> obj;
+ HRESULT hr = CoCreateInstance(*guid, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARG(IShellExtInit, &obj));
- if (FAILED(r))
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ CComPtr<IDataObject> dataobj;
+ hr = shellex_get_dataobj(sei, dataobj);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = obj->Initialize(NULL, dataobj, hkey);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ CComPtr<IObjectWithSite> ows;
+ hr = obj->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ows));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ ows->SetSite(NULL);
+
+ return shellex_run_context_menu_default(obj, sei);
+}
+
+static HRESULT shellex_get_contextmenu(LPSHELLEXECUTEINFOW sei,
CComPtr<IContextMenu>& cm)
+{
+ CComHeapPtr<ITEMIDLIST> allocatedPidl;
+ LPITEMIDLIST pidl = NULL;
+
+ if (sei->lpIDList)
{
- ERR("failed %08x\n", r);
- goto end;
+ pidl = (LPITEMIDLIST)sei->lpIDList;
}
-
- dataobj = shellex_get_dataobj(sei);
- if (!dataobj)
+ else
{
- ERR("failed to get data object\n");
- r = E_FAIL;
- goto end;
+ SFGAOF sfga = 0;
+ HRESULT hr = SHParseDisplayName(sei->lpFile, NULL, &allocatedPidl,
SFGAO_STORAGECAPMASK, &sfga);
+ if (FAILED(hr))
+ return hr;
+
+ pidl = allocatedPidl;
}
- r = obj->Initialize(NULL, dataobj, hkey);
- if (FAILED(r))
- goto end;
+ CComPtr<IShellFolder> shf;
+ LPCITEMIDLIST pidllast = NULL;
+ HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf),
&pidllast);
+ if (FAILED(hr))
+ return hr;
- r = obj->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ows));
- if (FAILED(r))
- goto end;
+ return shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IContextMenu,
&cm));
+}
- ows->SetSite(NULL);
+static HRESULT IContextMenu_exec(LPSHELLEXECUTEINFOW sei)
+{
+ TRACE("%p\n", sei);
- r = shellex_run_context_menu_default(obj, sei);
+ CCoInit coInit;
-end:
- if (ows)
- ows->Release();
- if (dataobj)
- dataobj->Release();
- if (obj)
- obj->Release();
- CoUninitialize();
- return r;
+ if (FAILED_UNEXPECTEDLY(coInit.hres))
+ return coInit.hres;
+
+ CComPtr<IContextMenu> cm;
+ HRESULT hr = shellex_get_contextmenu(sei, cm);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ CComHeapPtr<char> verb, parameters;
+ __SHCloneStrWtoA(&verb, sei->lpVerb);
+ __SHCloneStrWtoA(¶meters, sei->lpParameters);
+
+ CMINVOKECOMMANDINFOEX ici = {};
+ ici.cbSize = sizeof ici;
+ ici.fMask = (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK |
SEE_MASK_FLAG_NO_UI));
+ ici.nShow = sei->nShow;
+ ici.lpVerb = verb;
+ ici.hwnd = sei->hwnd;
+ ici.lpParameters = parameters;
+
+ HMENU hMenu = CreatePopupMenu();
+ BOOL fDefault = !ici.lpVerb || !ici.lpVerb[0];
+ hr = cm->QueryContextMenu(hMenu, 0, 1, 0x7fff, fDefault ? CMF_DEFAULTONLY : 0);
+ if (!FAILED_UNEXPECTEDLY(hr))
+ {
+ if (fDefault)
+ {
+ INT uDefault = GetMenuDefaultItem(hMenu, FALSE, 0);
+ uDefault = (uDefault != -1) ? uDefault - 1 : 0;
+ ici.lpVerb = MAKEINTRESOURCEA(uDefault);
+ }
+
+ hr = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
+ if (!FAILED_UNEXPECTEDLY(hr))
+ hr = S_OK;
+ }
+
+ DestroyMenu(hMenu);
+
+ return hr;
}
+
/*************************************************************************
* ShellExecute_FromContextMenu [Internal]
*/
@@ -1751,7 +1816,7 @@ static WCHAR *expand_environment( const WCHAR *str )
static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
{
static const DWORD unsupportedFlags =
- SEE_MASK_INVOKEIDLIST | SEE_MASK_ICON | SEE_MASK_HOTKEY |
+ SEE_MASK_ICON | SEE_MASK_HOTKEY |
SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT |
SEE_MASK_UNICODE | SEE_MASK_ASYNCOK | SEE_MASK_HMONITOR;
@@ -1853,15 +1918,12 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei,
SHELL_ExecuteW32 execfunc)
if (sei_tmp.fMask & unsupportedFlags)
{
- // SEE_MASK_IDLIST is not in unsupportedFlags, but the check above passes because
SEE_MASK_INVOKEIDLIST is in it
- if ((sei_tmp.fMask & unsupportedFlags) != SEE_MASK_IDLIST)
- {
- FIXME("flags ignored: 0x%08x\n", sei_tmp.fMask &
unsupportedFlags);
- }
+ FIXME("flags ignored: 0x%08x\n", sei_tmp.fMask &
unsupportedFlags);
}
/* process the IDList */
- if (sei_tmp.fMask & SEE_MASK_IDLIST)
+ if (sei_tmp.fMask & SEE_MASK_IDLIST &&
+ (sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) != SEE_MASK_INVOKEIDLIST)
{
CComPtr<IShellExecuteHookW> pSEH;
@@ -1908,6 +1970,22 @@ static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32
execfunc)
sei_tmp.lpDirectory = wszDir = tmp;
}
+ if ((sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_INVOKEIDLIST)
+ {
+ HRESULT hr = IContextMenu_exec(&sei_tmp);
+ if (SUCCEEDED(hr))
+ {
+ sei->hInstApp = (HINSTANCE)42;
+ HeapFree(GetProcessHeap(), 0, wszApplicationName);
+ if (wszParameters != parametersBuffer)
+ HeapFree(GetProcessHeap(), 0, wszParameters);
+ if (wszDir != dirBuffer)
+ HeapFree(GetProcessHeap(), 0, wszDir);
+ return TRUE;
+ }
+ }
+
+
if (ERROR_SUCCESS == ShellExecute_FromContextMenu(&sei_tmp))
{
sei->hInstApp = (HINSTANCE) 33;