[SHELL32] Implement DelegateExecute verb handler and basic IShellItemArray (#6972)

This commit is contained in:
Whindmar Saksit 2024-06-04 15:38:49 +02:00 committed by GitHub
parent 01fbf25dab
commit 0d10fb814f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 265 additions and 84 deletions

View file

@ -75,7 +75,6 @@ CCopyAsPathMenu::DoCopyAsPath(IDataObject *pdto)
{
CStringW paths;
DWORD i, count;
#if 0
CComPtr<IShellItemArray> array;
HRESULT hr = SHCreateShellItemArrayFromDataObject(pdto, IID_PPV_ARG(IShellItemArray, &array));
if (SUCCEEDED(hr))
@ -95,60 +94,6 @@ CCopyAsPathMenu::DoCopyAsPath(IDataObject *pdto)
}
}
}
#else
FIXME("Implement and use SHCreateShellItemArrayFromDataObject\n");
CDataObjectHIDA pCIDA(pdto);
HRESULT hr = pCIDA.hr();
if (SUCCEEDED(hr))
{
for (i = 0, count = pCIDA->cidl; i < count && SUCCEEDED(hr); ++i)
{
PCUIDLIST_ABSOLUTE folder = HIDA_GetPIDLFolder(pCIDA);
PCUIDLIST_RELATIVE item = HIDA_GetPIDLItem(pCIDA, i);
CComHeapPtr<ITEMIDLIST> full;
hr = SHILCombine(folder, item, &full);
if (SUCCEEDED(hr))
{
PCUITEMID_CHILD child;
CComPtr<IShellFolder> sf;
hr = SHBindToParent(full, IID_PPV_ARG(IShellFolder, &sf), &child);
if (SUCCEEDED(hr))
{
STRRET strret;
hr = sf->GetDisplayNameOf(child, SHGDN_FORPARSING, &strret);
if (SUCCEEDED(hr))
{
CComHeapPtr<WCHAR> path;
hr = StrRetToStrW(&strret, child, &path);
if (SUCCEEDED(hr))
{
AppendToPathList(paths, path, i);
}
}
}
}
}
}
else
{
FORMATETC fmte = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgm;
hr = pdto->GetData(&fmte, &stgm);
if (SUCCEEDED(hr))
{
for (i = 0, count = DragQueryFileW((HDROP)stgm.hGlobal, -1, NULL, 0); i < count && SUCCEEDED(hr); ++i)
{
WCHAR path[MAX_PATH];
if (DragQueryFileW((HDROP)stgm.hGlobal, i, path, _countof(path)))
{
AppendToPathList(paths, path, i);
}
}
ReleaseStgMedium(&stgm);
}
}
#endif
if (SUCCEEDED(hr))
{
DWORD err = SetClipboardFromString(paths);
@ -167,7 +112,7 @@ CCopyAsPathMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst,
hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
if ((uFlags & CMF_NOVERBS) || !(uFlags & CMF_EXTENDEDVERBS))
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst);
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
// Insert "Copy as path"
CStringW strText(MAKEINTRESOURCEW(IDS_COPYASPATHMENU));
@ -180,7 +125,7 @@ CCopyAsPathMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst,
if (InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, mii.wID - idCmdFirst + 1);
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst);
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
}
STDMETHODIMP

View file

@ -1304,7 +1304,17 @@ CDefaultContextMenu::InvokeRegVerb(
if (lpcmi->fMask & CMIC_MASK_PTINVOKE)
pPtl = (POINTL*)&lpcmi->ptInvoke;
// TODO: IExecuteCommand
CComPtr<IExecuteCommand> pEC;
hr = SHELL_GetRegCLSID(VerbKey, L"command", L"DelegateExecute", clsid);
if (SUCCEEDED(hr))
hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_PPV_ARG(IExecuteCommand, &pEC));
if (SUCCEEDED(hr))
{
CComPtr<IPropertyBag> pPB;
SHCreatePropertyBagOnRegKey(VerbKey, NULL, STGM_READ, IID_PPV_ARG(IPropertyBag, &pPB));
return InvokeIExecuteCommandWithDataObject(pEC, pEntry->Verb.GetString(), pPB, m_pDataObj,
lpcmi, static_cast<IContextMenu*>(this));
}
CComPtr<IDropTarget> pDT;
hr = SHELL_GetRegCLSID(VerbKey, L"DropTarget", L"CLSID", clsid);
@ -1312,7 +1322,10 @@ CDefaultContextMenu::InvokeRegVerb(
hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_PPV_ARG(IDropTarget, &pDT));
if (SUCCEEDED(hr))
{
CComPtr<IPropertyBag> pPB;
SHCreatePropertyBagOnRegKey(VerbKey, NULL, STGM_READ, IID_PPV_ARG(IPropertyBag, &pPB));
IUnknown_SetSite(pDT, static_cast<IContextMenu*>(this));
IUnknown_InitializeCommand(pDT, pEntry->Verb.GetString(), pPB);
hr = SHSimulateDrop(pDT, m_pDataObj, KeyState, pPtl, NULL);
IUnknown_SetSite(pDT, NULL);
return hr;

View file

@ -335,3 +335,98 @@ HRESULT WINAPI SHCreateShellItem(PCIDLIST_ABSOLUTE pidlParent,
return hr;
}
class CShellItemArray :
public CComCoClass<CShellItemArray, &CLSID_NULL>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IShellItemArray
{
CIDA *m_pCIDA;
STGMEDIUM m_Medium;
public:
CShellItemArray() : m_pCIDA(NULL)
{
m_Medium.tymed = TYMED_NULL;
}
virtual ~CShellItemArray()
{
CDataObjectHIDA::DestroyCIDA(m_pCIDA, m_Medium);
}
HRESULT Initialize(IDataObject *pdo)
{
return CDataObjectHIDA::CreateCIDA(pdo, &m_pCIDA, m_Medium);
}
inline UINT GetCount() const { return m_pCIDA->cidl; }
// IShellItemArray
STDMETHODIMP BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv) override
{
UNIMPLEMENTED;
*ppv = NULL;
return E_NOTIMPL;
}
STDMETHODIMP GetPropertyStore(GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) override
{
UNIMPLEMENTED;
*ppv = NULL;
return E_NOTIMPL;
}
STDMETHODIMP GetPropertyDescriptionList(REFPROPERTYKEY keyType, REFIID riid, void **ppv) override
{
UNIMPLEMENTED;
*ppv = NULL;
return E_NOTIMPL;
}
STDMETHODIMP GetAttributes(SIATTRIBFLAGS dwAttribFlags, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) override
{
UNIMPLEMENTED;
*psfgaoAttribs = 0;
return E_NOTIMPL;
}
STDMETHODIMP GetCount(DWORD*pCount) override
{
*pCount = m_pCIDA ? GetCount() : 0;
return S_OK;
}
STDMETHODIMP GetItemAt(DWORD nIndex, IShellItem **ppItem) override
{
if (!ppItem)
return E_INVALIDARG;
*ppItem = NULL;
if (!m_pCIDA)
return E_UNEXPECTED;
if (nIndex >= GetCount())
return E_FAIL;
return SHCreateShellItem(HIDA_GetPIDLFolder(m_pCIDA), NULL,
HIDA_GetPIDLItem(m_pCIDA, nIndex), ppItem);
}
STDMETHODIMP EnumItems(IEnumShellItems **ppESI) override
{
UNIMPLEMENTED;
*ppESI = NULL;
return E_NOTIMPL;
}
DECLARE_NO_REGISTRY()
DECLARE_NOT_AGGREGATABLE(CShellItemArray)
BEGIN_COM_MAP(CShellItemArray)
COM_INTERFACE_ENTRY_IID(IID_IShellItemArray, IShellItemArray)
END_COM_MAP()
};
EXTERN_C HRESULT WINAPI
SHCreateShellItemArrayFromDataObject(_In_ IDataObject *pdo, _In_ REFIID riid, _Out_ void **ppv)
{
return ShellObjectCreatorInit<CShellItemArray>(pdo, riid, ppv);
}

View file

@ -228,4 +228,26 @@ BOOL PathIsValidElement(_In_ LPCWSTR pszPath);
BOOL PathIsDosDevice(_In_ LPCWSTR pszName);
HRESULT SHILAppend(_Inout_ LPITEMIDLIST pidl, _Inout_ LPITEMIDLIST *ppidl);
EXTERN_C HRESULT
IUnknown_InitializeCommand(
_In_ IUnknown *pUnk,
_In_ PCWSTR pszCommandName,
_In_opt_ IPropertyBag *pPB);
EXTERN_C HRESULT
InvokeIExecuteCommand(
_In_ IExecuteCommand *pEC,
_In_ PCWSTR pszCommandName,
_In_opt_ IPropertyBag *pPB,
_In_opt_ IShellItemArray *pSIA,
_In_opt_ LPCMINVOKECOMMANDINFOEX pICI,
_In_opt_ IUnknown *pSite);
EXTERN_C HRESULT
InvokeIExecuteCommandWithDataObject(
_In_ IExecuteCommand *pEC,
_In_ PCWSTR pszCommandName,
_In_opt_ IPropertyBag *pPB,
_In_ IDataObject *pDO,
_In_opt_ LPCMINVOKECOMMANDINFOEX pICI,
_In_opt_ IUnknown *pSite);
#endif /* _PRECOMP_H__ */

View file

@ -280,6 +280,7 @@
281 stdcall SHCreateProcessAsUserW(ptr)
282 stdcall SHCreateQueryCancelAutoPlayMoniker(ptr)
283 stdcall SHCreateShellItem(ptr ptr ptr ptr)
@ stdcall -version=0x600+ SHCreateShellItemArrayFromDataObject(ptr ptr ptr)
284 stdcall SHEmptyRecycleBinA(long str long)
285 stdcall SHEmptyRecycleBinW(long wstr long)
286 stub SHEnableServiceObject

View file

@ -1295,6 +1295,74 @@ SHGetRealIDL(
return hr;
}
EXTERN_C HRESULT
IUnknown_InitializeCommand(
_In_ IUnknown *pUnk,
_In_ PCWSTR pszCommandName,
_In_opt_ IPropertyBag *pPB)
{
HRESULT hr;
CComPtr<IInitializeCommand> pIC;
if (SUCCEEDED(hr = pUnk->QueryInterface(IID_PPV_ARG(IInitializeCommand, &pIC))))
hr = pIC->Initialize(pszCommandName, pPB);
return hr;
}
EXTERN_C HRESULT
InvokeIExecuteCommand(
_In_ IExecuteCommand *pEC,
_In_ PCWSTR pszCommandName,
_In_opt_ IPropertyBag *pPB,
_In_opt_ IShellItemArray *pSIA,
_In_opt_ LPCMINVOKECOMMANDINFOEX pICI,
_In_opt_ IUnknown *pSite)
{
if (!pEC)
return E_INVALIDARG;
if (pSite)
IUnknown_SetSite(pEC, pSite);
IUnknown_InitializeCommand(pEC, pszCommandName, pPB);
CComPtr<IObjectWithSelection> pOWS;
if (pSIA && SUCCEEDED(pEC->QueryInterface(IID_PPV_ARG(IObjectWithSelection, &pOWS))))
pOWS->SetSelection(pSIA);
DWORD dwKeyState = 0, fMask = pICI ? pICI->fMask : 0;
pEC->SetNoShowUI((fMask & CMIC_MASK_FLAG_NO_UI) != 0);
pEC->SetShowWindow(pICI ? pICI->nShow : SW_SHOW);
if (fMask & CMIC_MASK_SHIFT_DOWN)
dwKeyState |= MK_SHIFT;
if (fMask & CMIC_MASK_CONTROL_DOWN)
dwKeyState |= MK_CONTROL;
pEC->SetKeyState(dwKeyState);
if ((fMask & CMIC_MASK_UNICODE) && pICI->lpDirectoryW)
pEC->SetDirectory(pICI->lpDirectoryW);
if ((fMask & CMIC_MASK_UNICODE) && pICI->lpParametersW)
pEC->SetParameters(pICI->lpParametersW);
if (fMask & CMIC_MASK_PTINVOKE)
pEC->SetPosition(pICI->ptInvoke);
HRESULT hr = pEC->Execute();
if (pSite)
IUnknown_SetSite(pEC, NULL);
return hr;
}
EXTERN_C HRESULT
InvokeIExecuteCommandWithDataObject(
_In_ IExecuteCommand *pEC,
_In_ PCWSTR pszCommandName,
_In_opt_ IPropertyBag *pPB,
_In_ IDataObject *pDO,
_In_opt_ LPCMINVOKECOMMANDINFOEX pICI,
_In_opt_ IUnknown *pSite)
{
CComPtr<IShellItemArray> pSIA;
HRESULT hr = SHCreateShellItemArrayFromDataObject(pDO, IID_PPV_ARG(IShellItemArray, &pSIA));
return SUCCEEDED(hr) ? InvokeIExecuteCommand(pEC, pszCommandName, pPB, pSIA, pICI, pSite) : hr;
}
static HRESULT
GetCommandStringA(_In_ IContextMenu *pCM, _In_ UINT_PTR Id, _In_ UINT GCS, _Out_writes_(cchMax) LPSTR Buf, _In_ UINT cchMax)
{

View file

@ -2316,7 +2316,7 @@ interface IInitializeCommand : IUnknown
{
HRESULT Initialize(
[in, string] LPCWSTR pszCommandName,
[in] IPropertyBag *ppb);
[in, optional] IPropertyBag *ppb);
}
@ -2371,6 +2371,39 @@ interface IExplorerCommandProvider : IUnknown
};
/*****************************************************************************
* IExecuteCommand interface (7+)
*/
[
uuid(7F9185B0-CB92-43C5-80A9-92277A4F7B54),
pointer_default(unique)
]
interface IExecuteCommand : IUnknown
{
HRESULT SetKeyState([in] DWORD grfKeyState);
HRESULT SetParameters([in, string] LPCWSTR pszParameters);
HRESULT SetPosition([in] POINT pt);
HRESULT SetShowWindow([in] int nShow);
HRESULT SetNoShowUI([in] BOOL fNoShowUI);
HRESULT SetDirectory([in, string] LPCWSTR pszDirectory);
HRESULT Execute();
};
/*****************************************************************************
* IObjectWithSelection interface (Vista+)
*/
[
uuid(1C9CD5BB-98E9-4491-A60F-31AACC72B83C),
pointer_default(unique)
]
interface IObjectWithSelection : IUnknown
{
HRESULT SetSelection([in] IShellItemArray *psia);
HRESULT GetSelection([in] REFIID riid, [out, iid_is(riid)] void **ppv);
};
/*****************************************************************************
* IOpenControlPanel interface (Vista+)
*/

View file

@ -609,34 +609,40 @@ public:
explicit CDataObjectHIDA(IDataObject* pDataObject)
: m_cida(nullptr)
{
m_medium.tymed = TYMED_NULL;
if (g_cfHIDA == NULL)
{
g_cfHIDA = (CLIPFORMAT)RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
}
FORMATETC fmt = { g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
m_hr = pDataObject->GetData(&fmt, &m_medium);
if (FAILED(m_hr))
{
m_medium.tymed = TYMED_NULL;
return;
}
m_cida = (CIDA*)::GlobalLock(m_medium.hGlobal);
if (m_cida == nullptr)
{
m_hr = E_UNEXPECTED;
}
m_hr = CreateCIDA(pDataObject, &m_cida, m_medium);
}
~CDataObjectHIDA()
{
if (m_cida)
::GlobalUnlock(m_cida);
DestroyCIDA(m_cida, m_medium);
}
ReleaseStgMedium(&m_medium);
static void DestroyCIDA(CIDA *pcida, STGMEDIUM &medium)
{
if (pcida)
::GlobalUnlock(medium.hGlobal);
ReleaseStgMedium(&medium);
}
static HRESULT CreateCIDA(IDataObject* pDataObject, CIDA **ppcida, STGMEDIUM &medium)
{
*ppcida = NULL;
medium.pUnkForRelease = NULL;
if (g_cfHIDA == NULL)
g_cfHIDA = (CLIPFORMAT)RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
FORMATETC fmt = { g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
HRESULT hr = pDataObject->GetData(&fmt, &medium);
if (SUCCEEDED(hr))
{
*ppcida = (CIDA*)::GlobalLock(medium.hGlobal);
if (*ppcida)
return S_OK;
ReleaseStgMedium(&medium);
hr = E_UNEXPECTED;
}
medium.tymed = TYMED_NULL;
return hr;
}
HRESULT hr() const

View file

@ -161,7 +161,6 @@ DEFINE_GUID(IID_IDelegateHostItemContainer,0x02468693, 0xE7E5, 0x4C6B, 0x99, 0x9
DEFINE_GUID(IID_IDrawPropertyControl, 0xE6DFF6FD, 0xBCD5, 0x4162, 0x9C, 0x65, 0xA3, 0xB1, 0x8C, 0x61, 0x6F, 0xDB);
DEFINE_GUID(IID_IEnumAssociationElements, 0xA6B0FB57, 0x7523, 0x4439, 0x94, 0x25, 0xEB, 0xE9, 0x98, 0x23, 0xB8, 0x28);
DEFINE_GUID(IID_IEnumerateAssociationElements,0x7513A16E,0xCF00,0x4817,0xA8, 0x90, 0xA2, 0x3C, 0x60, 0x8F, 0xE7, 0xB7);
DEFINE_GUID(IID_IExecuteCommand, 0x7F9185B0, 0xCB92, 0x43C5, 0x80, 0xA9, 0x92, 0x27, 0x7A, 0x4F, 0x7B, 0x54);
DEFINE_GUID(IID_IFilterCondition, 0xFCA2857D, 0x1760, 0x4AD3, 0x8C, 0x63, 0xC9, 0xB6, 0x02, 0xFC, 0xBA, 0xEA);
DEFINE_GUID(IID_IFolderNotify, 0x0FF22D71, 0x5172, 0x11D1, 0xA9, 0xC6, 0x08, 0x00, 0x36, 0xAF, 0x3F, 0x03);
DEFINE_GUID(IID_IFolderProperties, 0x7361EE29, 0x5BAD, 0x459D, 0xA9, 0xF5, 0xF6, 0x55, 0x06, 0x89, 0x82, 0xF0);
@ -175,7 +174,6 @@ DEFINE_GUID(IID_INewItemAdvisor, 0x24D16EE5, 0x10F5, 0x4DE3, 0x87, 0x6
DEFINE_GUID(IID_IObjectWithAssociationElement,0xE157C3A1,0xA532,0x4DE2,0x94, 0x80, 0x14, 0x52, 0xB7, 0x42, 0x6E, 0xEE);
DEFINE_GUID(IID_IObjectWithAssociationList,0xE6FFBB28, 0xBB79, 0x43B9, 0xA7, 0xBC, 0x6B, 0x57, 0x41, 0x0C, 0x81, 0x08);
DEFINE_GUID(IID_IObjectWithQuerySource, 0xB3DCB623, 0x4280, 0x4EB1, 0x84, 0xB3, 0x8D, 0x07, 0xE8, 0x4F, 0x29, 0x9A);
DEFINE_GUID(IID_IObjectWithSelection, 0x1C9CD5BB, 0x98E9, 0x4491, 0xA6, 0x0F, 0x31, 0xAA, 0xCC, 0x72, 0xB8, 0x3C);
DEFINE_GUID(IID_IPersistString2, 0x3C44BA76, 0xDE0E, 0x4049, 0xB6, 0xE4, 0x6B, 0x31, 0xA5, 0x26, 0x27, 0x07);
DEFINE_GUID(IID_IPrinterFolder, 0xEF99ABD4, 0x5B8D, 0x11D1, 0xA9, 0xC8, 0x00, 0x80, 0x36, 0xAF, 0x3F, 0x03);
DEFINE_GUID(IID_IPropertyControl, 0x5E82A4DD, 0x9561, 0x476A, 0x86, 0x34, 0x1B, 0xEB, 0xAC, 0xBA, 0x4A, 0x38);