diff --git a/dll/win32/shell32/CCopyAsPathMenu.cpp b/dll/win32/shell32/CCopyAsPathMenu.cpp index 1c78776a8c8..f031874c5d4 100644 --- a/dll/win32/shell32/CCopyAsPathMenu.cpp +++ b/dll/win32/shell32/CCopyAsPathMenu.cpp @@ -75,7 +75,6 @@ CCopyAsPathMenu::DoCopyAsPath(IDataObject *pdto) { CStringW paths; DWORD i, count; -#if 0 CComPtr 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 full; - hr = SHILCombine(folder, item, &full); - if (SUCCEEDED(hr)) - { - PCUITEMID_CHILD child; - CComPtr 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 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 diff --git a/dll/win32/shell32/CDefaultContextMenu.cpp b/dll/win32/shell32/CDefaultContextMenu.cpp index 41713d04841..f051c794c2a 100644 --- a/dll/win32/shell32/CDefaultContextMenu.cpp +++ b/dll/win32/shell32/CDefaultContextMenu.cpp @@ -1304,7 +1304,17 @@ CDefaultContextMenu::InvokeRegVerb( if (lpcmi->fMask & CMIC_MASK_PTINVOKE) pPtl = (POINTL*)&lpcmi->ptInvoke; - // TODO: IExecuteCommand + CComPtr 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 pPB; + SHCreatePropertyBagOnRegKey(VerbKey, NULL, STGM_READ, IID_PPV_ARG(IPropertyBag, &pPB)); + return InvokeIExecuteCommandWithDataObject(pEC, pEntry->Verb.GetString(), pPB, m_pDataObj, + lpcmi, static_cast(this)); + } CComPtr 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 pPB; + SHCreatePropertyBagOnRegKey(VerbKey, NULL, STGM_READ, IID_PPV_ARG(IPropertyBag, &pPB)); IUnknown_SetSite(pDT, static_cast(this)); + IUnknown_InitializeCommand(pDT, pEntry->Verb.GetString(), pPB); hr = SHSimulateDrop(pDT, m_pDataObj, KeyState, pPtl, NULL); IUnknown_SetSite(pDT, NULL); return hr; diff --git a/dll/win32/shell32/CShellItem.cpp b/dll/win32/shell32/CShellItem.cpp index b95eb4cf0f8..de43586cdb6 100644 --- a/dll/win32/shell32/CShellItem.cpp +++ b/dll/win32/shell32/CShellItem.cpp @@ -335,3 +335,98 @@ HRESULT WINAPI SHCreateShellItem(PCIDLIST_ABSOLUTE pidlParent, return hr; } + +class CShellItemArray : + public CComCoClass, + public CComObjectRootEx, + 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(pdo, riid, ppv); +} diff --git a/dll/win32/shell32/precomp.h b/dll/win32/shell32/precomp.h index cd53f7f3f58..0d60f51fa2f 100644 --- a/dll/win32/shell32/precomp.h +++ b/dll/win32/shell32/precomp.h @@ -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__ */ diff --git a/dll/win32/shell32/shell32.spec b/dll/win32/shell32/shell32.spec index e3f096b78f2..759f4676e94 100644 --- a/dll/win32/shell32/shell32.spec +++ b/dll/win32/shell32/shell32.spec @@ -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 diff --git a/dll/win32/shell32/utils.cpp b/dll/win32/shell32/utils.cpp index d7238aad86c..80a9d6fcbb3 100644 --- a/dll/win32/shell32/utils.cpp +++ b/dll/win32/shell32/utils.cpp @@ -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 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 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 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) { diff --git a/sdk/include/psdk/shobjidl.idl b/sdk/include/psdk/shobjidl.idl index b7958e2e8fe..f137d474de4 100644 --- a/sdk/include/psdk/shobjidl.idl +++ b/sdk/include/psdk/shobjidl.idl @@ -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+) */ diff --git a/sdk/include/reactos/shellutils.h b/sdk/include/reactos/shellutils.h index 8eed78e33d6..6eede011d85 100644 --- a/sdk/include/reactos/shellutils.h +++ b/sdk/include/reactos/shellutils.h @@ -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 diff --git a/sdk/include/reactos/shlguid_undoc.h b/sdk/include/reactos/shlguid_undoc.h index 19c7178a3a3..99baa6ccf58 100644 --- a/sdk/include/reactos/shlguid_undoc.h +++ b/sdk/include/reactos/shlguid_undoc.h @@ -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);